diff --git a/CHANGELOG b/CHANGELOG index 80b973877d..e6c37b911a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -163,6 +163,7 @@ Fixed bugs - fixed bug in calculation of "fractionality score" for spatial branching candidates in cons_nonlinear - fixed bug with installing symmetry dialog in sub-SCIPs - add copy callbacks for default plugins presolver dualagg, presolver redvub, branchrule lookahead, branchrule cloud, heuristic dualval, heuristic repair, propagator nlobbt, separator gauge, and separator convexproj missing in SCIPsetCopyPlugins() +- respect maximal round setting of separation by running remaining delayed separators in last round Unit tests ---------- diff --git a/doc/scipfooter.html b/doc/scipfooter.html index a53c1a9735..0518db8c1e 100644 --- a/doc/scipfooter.html +++ b/doc/scipfooter.html @@ -1,4 +1,4 @@ - +
- | |
$searchbox |
.c,h
and should not be included in the public API.
- * - Internal API functions usually do not take a SCIP*
parameter, but a pointer to the component as first argument and pointers to internal structures like SCIP_SET*
or SCIP_STAT*
, where necessary.
- * - The name of internal API functions follows the style `SCIPSCIPvarCreate()
or SCIPvarAddLocks()
.
- * - pub_.h
declares the functions of the public API that do not need a SCIP pointer.
+ * - The internal implementation should be in a file `SCIPvarCreateOriginal()
or SCIPvarAddLocks()
.
+ * - `pub_pub_.h
follow the same naming style as those in .h
and are used by the implementation of the internal API as well.
- * - scip_.h
declares the functions of the public API that need a SCIP instance (SCIP*
), e.g., \ref scip_var.h for public variable manipulation functions.
- * Functions declared in scip_.h
are often thin wrappers that call the internal API functions from .h
.
- * These functions should follow the naming style `SCIPSCIPcreateVar()
or SCIPaddVarLocks
.
+ * - Functions in `pub_SCIPcreateVarOriginal()
or SCIPaddVarLocks()
.
* - To ensure functions of the public API being reachable in shared libraries, their declaration needs to contain the SCIP_EXPORT
attribute.
- * - Public types (typedef's, enumerations) are defined in file type_.h
.
- * Type names follow the style SCIP_...
. For every struct, we have a typedef that shortens the name
- * (so one could for instance use SCIP_PARAM
instead of struct SCIP_Param
).
+ * - Public types (typedef's, enumerations) are defined in file `type_struct_.h
.
- * struct_.h
is usually included only by .c
and maybe scip_.c
.
+ * - Structs that need to be accessed by several source files are defined in `struct__.c,h
, e.g.,
+ * - Each plugin is defined in files `_.h
.
- * - API functions of plugins are named as SCIP...
, e.g., SCIPincludeConshdlrAnd()
, SCIPcreateConsAnd()
, or SCIPgetNVarsAnd()
.
+ * - Public types that belong to a plugin are declared in its header, `SCIPincludeConshdlrAnd()
, SCIPcreateConsAnd()
, or SCIPgetNVarsAnd()
.
* - Plugins access only the public API.
* - Plugins that need to be included by default should be registered in src/scip/scipdefplugins.c
.
*/
diff --git a/src/scip/def.h b/src/scip/def.h
index d371a53d4f..4b2c72c22b 100644
--- a/src/scip/def.h
+++ b/src/scip/def.h
@@ -104,11 +104,11 @@
*/
#ifndef SCIP_EXPORT
#if defined(_WIN32)
-#define SCIP_EXPORT __declspec(dllexport)
+#define SCIP_EXPORT __declspec(dllexport) /**< mark symbol to be exported in DLL */
#elif defined(__GNUC__) && __GNUC__ >= 4
-#define SCIP_EXPORT __attribute__((__visibility__("default")))
+#define SCIP_EXPORT __attribute__((__visibility__("default"))) /**< mark symbol to be visible in shared library */
#else
-#define SCIP_EXPORT
+#define SCIP_EXPORT /**< no symbol export attribute known for current compiler */
#endif
#endif
diff --git a/src/scip/scip_expr.c b/src/scip/scip_expr.c
index 25664cbfb2..b7d5a1aac4 100644
--- a/src/scip/scip_expr.c
+++ b/src/scip/scip_expr.c
@@ -1366,12 +1366,12 @@ SCIP_RETCODE SCIPcopyExpr(
* a `Term` is a product of `Factors` and an `Expression` is a sum of `Terms`.
*
* The actual definition:
- * + * ``` * Expression -> ["+" | "-"] Term { [ ("+" | "-" | "number *") Term | ("number"+ * ``` * where `[a|b]` means `a` or `b` or none, `(a|b)` means `a` or `b`, `{a}` means 0 or more `a`. * * Note that `Op` and `OpExpression` are undefined. diff --git a/src/scip/scip_expr.h b/src/scip/scip_expr.h index 5bf845be6a..139839928d 100644 --- a/src/scip/scip_expr.h +++ b/src/scip/scip_expr.h @@ -277,12 +277,12 @@ SCIP_RETCODE SCIPcopyExpr( * a `Term` is a product of `Factors` and an `Expression` is a sum of `Terms`. * * The actual definition: - *) ] } * Term -> Factor { ("*" | "/" ) Factor } * Factor -> Base [ "^" "number" | "^(" "number" ")" ] * Base -> "number" | " " | "(" Expression ")" | Op "(" OpExpression ") - *
+ * ``` * Expression -> ["+" | "-"] Term { [ ("+" | "-" | "number *") Term | ("number"+ * ``` * where `[a|b]` means `a` or `b` or none, `(a|b)` means `a` or `b`, `{a}` means 0 or more `a`. * * Note that `Op` and `OpExpression` are undefined. diff --git a/src/scip/solve.c b/src/scip/solve.c index 13a211ae52..a30f878efa 100644 --- a/src/scip/solve.c +++ b/src/scip/solve.c @@ -2507,8 +2507,9 @@ SCIP_RETCODE priceAndCutLoop( SCIP_Bool root; SCIP_Bool allowlocal; int maxseparounds; + int maxsepapartialrounds; int nsepastallrounds; - int maxnsepastallrounds; + int maxsepastallrounds; int stallnfracs; int actdepth; int npricedcolvars; @@ -2542,17 +2543,22 @@ SCIP_RETCODE priceAndCutLoop( allowlocal = SCIPsetIsLE(set, bounddist, set->sepa_maxlocalbounddist); separate = (set->sepa_maxruns == -1 || stat->nruns < set->sepa_maxruns); - /* get maximal number of separation rounds */ + /* determine maximal number of separation rounds */ maxseparounds = (root ? set->sepa_maxroundsroot : set->sepa_maxrounds); if( maxseparounds == -1 ) maxseparounds = INT_MAX; if( stat->nruns > 1 && root && set->sepa_maxroundsrootsubrun >= 0 ) maxseparounds = MIN(maxseparounds, set->sepa_maxroundsrootsubrun); + + /* determine maximal number of partial rounds excluding delayed round */ + maxsepapartialrounds = INT_MAX; if( !fullseparation && set->sepa_maxaddrounds >= 0 ) - maxseparounds = MIN(maxseparounds, stat->nseparounds + set->sepa_maxaddrounds); - maxnsepastallrounds = root ? set->sepa_maxstallroundsroot : set->sepa_maxstallrounds; - if( maxnsepastallrounds == -1 ) - maxnsepastallrounds = INT_MAX; + maxsepapartialrounds = stat->nseparounds + set->sepa_maxaddrounds; + + /* determine maximal number of stalling rounds */ + maxsepastallrounds = root ? set->sepa_maxstallroundsroot : set->sepa_maxstallrounds; + if( maxsepastallrounds == -1 ) + maxsepastallrounds = INT_MAX; /* solve initial LP of price-and-cut loop */ SCIPsetDebugMsg(set, "node: solve LP with price and cut\n"); @@ -2576,7 +2582,7 @@ SCIP_RETCODE priceAndCutLoop( stalllpobjval = SCIP_REAL_MIN; stallnfracs = INT_MAX; lp->installing = FALSE; - while( !(*cutoff) && !(*unbounded) && !(*lperror) && (mustprice || mustsepa || delayedsepa) ) + while( !(*cutoff) && !(*unbounded) && !(*lperror) && ( mustprice || mustsepa ) ) { SCIPsetDebugMsg(set, "-------- node solving loop --------\n"); assert(lp->flushed); @@ -2714,33 +2720,17 @@ SCIP_RETCODE priceAndCutLoop( assert(lp->flushed || *cutoff || *unbounded); assert(lp->solved || *lperror || *cutoff || *unbounded); - /* check, if we exceeded the separation round limit */ - mustsepa = mustsepa + /* if we are infeasible, unbounded, exceeded a separation round, the objective, or a global performance limit, + * we don't need to separate cuts + * (the global limits are only checked at the root node in order to not query system time too often) + */ + mustsepa = mustsepa && separate && !(*cutoff) && !(*unbounded) && stat->nseparounds < maxseparounds - && nsepastallrounds < maxnsepastallrounds - && !(*cutoff); - - /* if separators were delayed, we want to apply a final separation round with the delayed separators */ - delayedsepa = delayedsepa && !mustsepa && !(*cutoff); /* if regular separation applies, we ignore delayed separators */ - mustsepa = mustsepa || delayedsepa; - - if( mustsepa ) - { - /* if the LP is infeasible, unbounded, exceeded the objective limit or a global performance limit was reached, - * we don't need to separate cuts - * (the global limits are only checked at the root node in order to not query system time too often) - */ - if( !separate || (*cutoff) || (*unbounded) - || (SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_UNBOUNDEDRAY) - || SCIPsetIsGE(set, SCIPnodeGetLowerbound(focusnode), primal->cutoffbound) - || (root && SCIPsolveIsStopped(set, stat, FALSE)) ) - { - mustsepa = FALSE; - delayedsepa = FALSE; - } - else - assert(!(*lperror)); - } + && ( delayedsepa || stat->nseparounds < maxsepapartialrounds ) + && nsepastallrounds < maxsepastallrounds + && ( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY ) + && SCIPsetIsLT(set, SCIPnodeGetLowerbound(focusnode), primal->cutoffbound) + && ( !root || !SCIPsolveIsStopped(set, stat, FALSE) ); /* separation (needs not to be done completely, because we just want to increase the lower bound) */ if( mustsepa ) @@ -2759,6 +2749,7 @@ SCIP_RETCODE priceAndCutLoop( oldninitconssadded = stat->ninitconssadded; mustsepa = FALSE; + delayedsepa = delayedsepa && stat->nseparounds >= maxsepapartialrounds; enoughcuts = SCIPsetIsZero(set, SCIPsetGetSepaMaxcutsGenFactor(set, root) * SCIPsetGetSepaMaxcuts(set, root)); /* global cut pool separation */ @@ -2789,10 +2780,10 @@ SCIP_RETCODE priceAndCutLoop( &delayedsepa, &enoughcuts, cutoff, lperror, &mustsepa, &mustprice) ); assert(BMSgetNUsedBufferMemory(mem->buffer) == 0); - /* if we are close to the stall round limit, also call the delayed separators */ - if( !(*cutoff) && !(*lperror) && !enoughcuts && lp->solved - && (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY) - && nsepastallrounds >= maxnsepastallrounds-1 && delayedsepa ) + /* if we are in the last separation or stall round, also call the delayed separators */ + if( !(*cutoff) && !(*lperror) && lp->solved && !enoughcuts && delayedsepa + && ( stat->nseparounds + 1 >= maxseparounds || nsepastallrounds + 1 >= maxsepastallrounds ) + && ( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY ) ) { SCIP_CALL( separationRoundLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, primal, tree, lp, sepastore, actdepth, bounddist, allowlocal, delayedsepa, @@ -2980,32 +2971,33 @@ SCIP_RETCODE priceAndCutLoop( } else { - nsepastallrounds++; + ++nsepastallrounds; } stalllpsolstat = SCIPlpGetSolstat(lp); - /* tell LP that we are (close to) stalling */ - if( nsepastallrounds >= maxnsepastallrounds-2 ) + /* tell LP that we are stalling */ + if( nsepastallrounds + 1 >= maxsepastallrounds ) lp->installing = TRUE; - SCIPsetDebugMsg(set, " -> nsepastallrounds=%d/%d\n", nsepastallrounds, maxnsepastallrounds); + + SCIPsetDebugMsg(set, " -> nsepastallrounds=%d/%d\n", nsepastallrounds, maxsepastallrounds); } } } } assert(*cutoff || *lperror || (lp->flushed && lp->solved)); /* cutoff: LP may be unsolved due to bound changes */ - SCIPsetDebugMsg(set, "separation round %d/%d finished (%d/%d stall rounds): mustprice=%u, mustsepa=%u, delayedsepa=%u, propagateagain=%u\n", - stat->nseparounds, maxseparounds, nsepastallrounds, maxnsepastallrounds, mustprice, mustsepa, delayedsepa, *propagateagain); - /* increase separation round counter */ - stat->nseparounds++; + ++stat->nseparounds; + + SCIPsetDebugMsg(set, "separation round %d/%d finished (%d/%d stall rounds): mustprice=%u, mustsepa=%u, delayedsepa=%u, propagateagain=%u\n", + stat->nseparounds, maxseparounds, nsepastallrounds, maxsepastallrounds, mustprice, mustsepa, delayedsepa, *propagateagain); } } - if( root && nsepastallrounds >= maxnsepastallrounds ) + if( root && nsepastallrounds >= maxsepastallrounds ) { SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL, - "Truncate separation round because of stalling (%d stall rounds).\n", maxnsepastallrounds); + "Truncate separation round because of stalling (%d stall rounds).\n", maxsepastallrounds); } if( !*lperror )) ] } * Term -> Factor { ("*" | "/" ) Factor } * Factor -> Base [ "^" "number" | "^(" "number" ")" ] * Base -> "number" | " " | "(" Expression ")" | Op "(" OpExpression ") - *