Skip to content

Commit 321caa5

Browse files
committed
Merge remote-tracking branch 'origin/v10-minor'
2 parents 38e68a4 + 9f5c8da commit 321caa5

File tree

6 files changed

+137
-138
lines changed

6 files changed

+137
-138
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ Fixed bugs
417417
- fixed stopping when there is a candidate with a change in the LP bound for both children in strong branching of branch_fullstrong
418418
- fixed detection of sinks in varbound detection from cumulative constraints
419419
- fixed memory allocation when adding strong SBCs for enclosing orbit of symmetric subgroups (disabled by default)
420+
- free paths of branch-and-bound tree iteratively instead of recursively to avoid stack overflow
420421

421422
Build system
422423
------------

src/lpiexact/lpiexact_spx.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@
8585
#endif
8686

8787
#ifndef SOPLEX_WITH_GMP
88-
#error "SOPLEX_WITH_GMP not defined: SoPlex must be build with GMP to be used with LPIEX=spx"
88+
#error "SOPLEX_WITH_GMP not defined: SoPlex must be build with GMP to be used with LPSEXACT=spx"
8989
#endif
9090

9191
#ifndef SOPLEX_WITH_MPFR
92-
#error "SOPLEX_WITH_MPFR not defined: SoPlex must be build with MPFR to be used with LPIEX=spx"
92+
#error "SOPLEX_WITH_MPFR not defined: SoPlex must be build with MPFR to be used with LPSEXACT=spx"
9393
#endif
9494

9595
#ifndef SOPLEX_WITH_BOOST
96-
#error "SOPLEX_WITH_BOOST not defined: SoPlex must be build with BOOST to be used with LPIEX=spx"
96+
#error "SOPLEX_WITH_BOOST not defined: SoPlex must be build with BOOST to be used with LPSEXACT=spx"
9797
#endif
9898

9999
/* reset the SCIP_DEBUG define to its original SCIP value */

src/scip/stat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ SCIP_RETCODE SCIPstatFree(
177177
return SCIP_OKAY;
178178
}
179179

180-
/** diables the collection of any statistic for a variable */
180+
/** disables the collection of any statistic for a variable */
181181
void SCIPstatDisableVarHistory(
182182
SCIP_STAT* stat /**< problem statistics data */
183183
)

src/scip/stat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ SCIP_RETCODE SCIPstatFree(
6666
BMS_BLKMEM* blkmem /**< block memory */
6767
);
6868

69-
/** diables the collection of any statistic for a variable */
69+
/** disables the collection of any statistic for a variable */
7070
void SCIPstatDisableVarHistory(
7171
SCIP_STAT* stat /**< problem statistics data */
7272
);

src/scip/tree.c

Lines changed: 130 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -849,42 +849,37 @@ SCIP_RETCODE nodeAssignParent(
849849
return SCIP_OKAY;
850850
}
851851

852-
/** decreases number of children of the parent, frees it if no children are left */
852+
/** frees node memory, decreases number of children of the parent, and replaces node with parent if no children left */
853853
static
854854
SCIP_RETCODE nodeReleaseParent(
855-
SCIP_NODE* node, /**< child node */
855+
SCIP_NODE** node, /**< child node */
856856
BMS_BLKMEM* blkmem, /**< block memory buffer */
857857
SCIP_SET* set, /**< global SCIP settings */
858-
SCIP_STAT* stat, /**< problem statistics */
859-
SCIP_EVENTQUEUE* eventqueue, /**< event queue */
860-
SCIP_EVENTFILTER* eventfilter, /**< global event filter */
861-
SCIP_TREE* tree, /**< branch and bound tree */
862-
SCIP_LP* lp /**< current LP data */
858+
SCIP_TREE* tree /**< branch and bound tree */
863859
)
864860
{
865861
SCIP_NODE* parent;
862+
SCIP_Bool freeParent = FALSE;
866863

867-
assert(node != NULL);
868-
assert(blkmem != NULL);
869864
assert(tree != NULL);
865+
assert(node != NULL);
866+
assert(*node != NULL);
870867

871868
SCIPsetDebugMsg(set, "releasing parent-child relationship of node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d with parent #%" SCIP_LONGINT_FORMAT " of type %d\n",
872-
SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPnodeGetType(node),
873-
node->parent != NULL ? SCIPnodeGetNumber(node->parent) : -1,
874-
node->parent != NULL ? (int)SCIPnodeGetType(node->parent) : -1);
875-
parent = node->parent;
869+
SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), SCIPnodeGetType(*node),
870+
(*node)->parent != NULL ? SCIPnodeGetNumber((*node)->parent) : -1,
871+
(*node)->parent != NULL ? (int)SCIPnodeGetType((*node)->parent) : -1);
872+
parent = (*node)->parent;
876873
if( parent != NULL )
877874
{
878-
SCIP_Bool freeParent = FALSE;
879-
880875
switch( SCIPnodeGetType(parent) )
881876
{
882877
case SCIP_NODETYPE_FOCUSNODE:
883878
assert(parent->active);
884-
assert(SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE
885-
|| SCIPnodeGetType(node) == SCIP_NODETYPE_LEAF);
886-
if( SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD )
887-
treeRemoveChild(tree, node);
879+
assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD || SCIPnodeGetType(*node) == SCIP_NODETYPE_PROBINGNODE
880+
|| SCIPnodeGetType(*node) == SCIP_NODETYPE_LEAF);
881+
if( SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD )
882+
treeRemoveChild(tree, *node);
888883
/* don't kill the focus node at this point => freeParent = FALSE */
889884
break;
890885
case SCIP_NODETYPE_PROBINGNODE:
@@ -931,23 +926,18 @@ SCIP_RETCODE nodeReleaseParent(
931926
* we don't want to free the refocused node, because we first have to convert it back to its original
932927
* type (where it possibly has children) => freeParent = FALSE
933928
*/
934-
assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
929+
assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_PROBINGNODE);
935930
assert(!SCIPtreeProbing(tree));
936931
break;
937932
default:
938933
SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(parent));
939934
return SCIP_INVALIDDATA;
940935
}
941936

942-
/* free parent if it is not on the current active path */
943-
if( freeParent && !parent->active )
944-
{
945-
SCIP_CALL( SCIPnodeFree(&node->parent, blkmem, set, stat, eventqueue, eventfilter, tree, lp) );
946-
}
947937
/* update the effective root depth if active parent has children and neither reoptimization nor certificate
948938
* printing is enabled
949939
*/
950-
else if( freeParent == !parent->active && !set->reopt_enable && !SCIPisCertified(set->scip) )
940+
if( !freeParent && parent->active && !set->reopt_enable && !SCIPisCertified(set->scip) )
951941
{
952942
SCIP_Bool singleChild = FALSE;
953943
int focusdepth = SCIPtreeGetFocusDepth(tree);
@@ -1005,13 +995,19 @@ SCIP_RETCODE nodeReleaseParent(
1005995

1006996
SCIPsetDebugMsg(set,
1007997
"unlinked node #%" SCIP_LONGINT_FORMAT " in depth %d -> new effective root depth: %d\n",
1008-
SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->updatedeffectiverootdepth);
998+
SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), tree->updatedeffectiverootdepth);
1009999
}
10101000

10111001
assert(!singleChild || tree->updatedeffectiverootdepth == SCIPtreeGetFocusDepth(tree));
10121002
}
10131003
}
10141004

1005+
BMSfreeBlockMemory(blkmem, node);
1006+
1007+
/* free parent iteratively if it is not on the current active path */
1008+
if( freeParent && !parent->active )
1009+
*node = parent;
1010+
10151011
return SCIP_OKAY;
10161012
}
10171013

@@ -1115,7 +1111,7 @@ SCIP_Bool SCIPtreeWasNodeLastBranchParent(
11151111
return FALSE;
11161112
}
11171113

1118-
/** frees node */
1114+
/** frees node and inactive path iteratively */
11191115
SCIP_RETCODE SCIPnodeFree(
11201116
SCIP_NODE** node, /**< node data */
11211117
BMS_BLKMEM* blkmem, /**< block memory buffer */
@@ -1129,130 +1125,132 @@ SCIP_RETCODE SCIPnodeFree(
11291125
{
11301126
SCIP_Bool isroot;
11311127

1128+
assert(tree != NULL);
11321129
assert(node != NULL);
11331130
assert(*node != NULL);
1134-
assert(!(*node)->active);
1135-
assert(blkmem != NULL);
1136-
assert(tree != NULL);
1137-
1138-
SCIPsetDebugMsg(set, "free node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d\n", SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), SCIPnodeGetType(*node));
1139-
1140-
/* if certificate is active, unsplit current node and free the memory in hashmap of certificate */
1141-
SCIP_CALL( SCIPcertificatePrintUnsplitting(set, stat->certificate, *node) );
1142-
1143-
/* check lower bound w.r.t. debugging solution */
1144-
SCIP_CALL( SCIPdebugCheckGlobalLowerbound(blkmem, set) );
11451131

1146-
if( SCIPnodeGetType(*node) != SCIP_NODETYPE_PROBINGNODE )
1132+
do
11471133
{
1148-
SCIP_EVENT event;
1134+
assert(!(*node)->active);
11491135

1150-
/* trigger a node deletion event */
1151-
SCIP_CALL( SCIPeventChgType(&event, SCIP_EVENTTYPE_NODEDELETE) );
1152-
SCIP_CALL( SCIPeventChgNode(&event, *node) );
1153-
SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
1154-
}
1136+
SCIPsetDebugMsg(set, "free node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d\n", SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), SCIPnodeGetType(*node));
11551137

1156-
/* inform solution debugger, that the node has been freed */
1157-
SCIP_CALL( SCIPdebugRemoveNode(blkmem, set, *node) );
1138+
/* if certificate is active, unsplit current node and free the memory in hashmap of certificate */
1139+
SCIP_CALL( SCIPcertificatePrintUnsplitting(set, stat->certificate, *node) );
11581140

1159-
/* check, if the node to be freed is the root node */
1160-
isroot = (SCIPnodeGetDepth(*node) == 0);
1141+
/* check lower bound w.r.t. debugging solution */
1142+
SCIP_CALL( SCIPdebugCheckGlobalLowerbound(blkmem, set) );
11611143

1162-
/* free nodetype specific data, and release no longer needed LPI states */
1163-
switch( SCIPnodeGetType(*node) )
1164-
{
1165-
case SCIP_NODETYPE_FOCUSNODE:
1166-
assert(tree->focusnode == *node);
1167-
assert(!SCIPtreeProbing(tree));
1168-
SCIPerrorMessage("cannot free focus node - has to be converted into a dead end first\n");
1169-
return SCIP_INVALIDDATA;
1170-
case SCIP_NODETYPE_PROBINGNODE:
1171-
assert(SCIPtreeProbing(tree));
1172-
assert(SCIPnodeGetDepth(tree->probingroot) <= SCIPnodeGetDepth(*node));
1173-
assert(SCIPnodeGetDepth(*node) > 0);
1174-
SCIP_CALL( probingnodeFree(&((*node)->data.probingnode), blkmem, lp) );
1175-
break;
1176-
case SCIP_NODETYPE_SIBLING:
1177-
assert((*node)->data.sibling.arraypos >= 0);
1178-
assert((*node)->data.sibling.arraypos < tree->nsiblings);
1179-
assert(tree->siblings[(*node)->data.sibling.arraypos] == *node);
1180-
if( tree->focuslpstatefork != NULL )
1144+
if( SCIPnodeGetType(*node) != SCIP_NODETYPE_PROBINGNODE )
11811145
{
1182-
assert(SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_FORK
1183-
|| SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_SUBROOT);
1184-
SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
1185-
}
1186-
treeRemoveSibling(tree, *node);
1187-
break;
1188-
case SCIP_NODETYPE_CHILD:
1189-
assert((*node)->data.child.arraypos >= 0);
1190-
assert((*node)->data.child.arraypos < tree->nchildren);
1191-
assert(tree->children[(*node)->data.child.arraypos] == *node);
1192-
/* The children capture the LPI state at the moment, where the focus node is
1193-
* converted into a junction, pseudofork, fork, or subroot, and a new node is focused.
1194-
* At the same time, they become siblings or leaves, such that freeing a child
1195-
* of the focus node doesn't require to release the LPI state;
1196-
* we don't need to call treeRemoveChild(), because this is done in nodeReleaseParent()
1197-
*/
1198-
break;
1199-
case SCIP_NODETYPE_LEAF:
1200-
if( (*node)->data.leaf.lpstatefork != NULL )
1201-
{
1202-
SCIP_CALL( SCIPnodeReleaseLPIState((*node)->data.leaf.lpstatefork, blkmem, lp) );
1146+
SCIP_EVENT event;
1147+
1148+
/* trigger a node deletion event */
1149+
SCIP_CALL( SCIPeventChgType(&event, SCIP_EVENTTYPE_NODEDELETE) );
1150+
SCIP_CALL( SCIPeventChgNode(&event, *node) );
1151+
SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
12031152
}
1204-
break;
1205-
case SCIP_NODETYPE_DEADEND:
1206-
case SCIP_NODETYPE_JUNCTION:
1207-
break;
1208-
case SCIP_NODETYPE_PSEUDOFORK:
1209-
SCIP_CALL( pseudoforkFree(&((*node)->data.pseudofork), blkmem, set, lp) );
1210-
break;
1211-
case SCIP_NODETYPE_FORK:
12121153

1213-
/* release special root LPI state capture which is used to keep the root LPI state over the whole solving
1214-
* process
1215-
*/
1216-
if( isroot )
1154+
/* inform solution debugger, that the node has been freed */
1155+
SCIP_CALL( SCIPdebugRemoveNode(blkmem, set, *node) );
1156+
1157+
/* check, if the node to be freed is the root node */
1158+
isroot = (SCIPnodeGetDepth(*node) == 0);
1159+
1160+
/* free nodetype specific data, and release no longer needed LPI states */
1161+
switch( SCIPnodeGetType(*node) )
12171162
{
1218-
SCIP_CALL( SCIPnodeReleaseLPIState(*node, blkmem, lp) );
1163+
case SCIP_NODETYPE_FOCUSNODE:
1164+
assert(tree->focusnode == *node);
1165+
assert(!SCIPtreeProbing(tree));
1166+
SCIPerrorMessage("cannot free focus node - has to be converted into a dead end first\n");
1167+
return SCIP_INVALIDDATA;
1168+
case SCIP_NODETYPE_PROBINGNODE:
1169+
assert(SCIPtreeProbing(tree));
1170+
assert(SCIPnodeGetDepth(tree->probingroot) <= SCIPnodeGetDepth(*node));
1171+
assert(SCIPnodeGetDepth(*node) > 0);
1172+
SCIP_CALL( probingnodeFree(&((*node)->data.probingnode), blkmem, lp) );
1173+
break;
1174+
case SCIP_NODETYPE_SIBLING:
1175+
assert((*node)->data.sibling.arraypos >= 0);
1176+
assert((*node)->data.sibling.arraypos < tree->nsiblings);
1177+
assert(tree->siblings[(*node)->data.sibling.arraypos] == *node);
1178+
if( tree->focuslpstatefork != NULL )
1179+
{
1180+
assert(SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_FORK
1181+
|| SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_SUBROOT);
1182+
SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
1183+
}
1184+
treeRemoveSibling(tree, *node);
1185+
break;
1186+
case SCIP_NODETYPE_CHILD:
1187+
assert((*node)->data.child.arraypos >= 0);
1188+
assert((*node)->data.child.arraypos < tree->nchildren);
1189+
assert(tree->children[(*node)->data.child.arraypos] == *node);
1190+
/* The children capture the LPI state at the moment, where the focus node is
1191+
* converted into a junction, pseudofork, fork, or subroot, and a new node is focused.
1192+
* At the same time, they become siblings or leaves, such that freeing a child
1193+
* of the focus node doesn't require to release the LPI state;
1194+
* we don't need to call treeRemoveChild(), because this is done in nodeReleaseParent()
1195+
*/
1196+
break;
1197+
case SCIP_NODETYPE_LEAF:
1198+
if( (*node)->data.leaf.lpstatefork != NULL )
1199+
{
1200+
SCIP_CALL( SCIPnodeReleaseLPIState((*node)->data.leaf.lpstatefork, blkmem, lp) );
1201+
}
1202+
break;
1203+
case SCIP_NODETYPE_DEADEND:
1204+
case SCIP_NODETYPE_JUNCTION:
1205+
break;
1206+
case SCIP_NODETYPE_PSEUDOFORK:
1207+
SCIP_CALL( pseudoforkFree(&((*node)->data.pseudofork), blkmem, set, lp) );
1208+
break;
1209+
case SCIP_NODETYPE_FORK:
1210+
/* release special root LPI state capture which is used to keep the root LPI state over the whole solving
1211+
* process
1212+
*/
1213+
if( isroot )
1214+
{
1215+
SCIP_CALL( SCIPnodeReleaseLPIState(*node, blkmem, lp) );
1216+
}
1217+
SCIP_CALL( forkFree(&((*node)->data.fork), blkmem, set, lp) );
1218+
break;
1219+
case SCIP_NODETYPE_SUBROOT:
1220+
SCIP_CALL( subrootFree(&((*node)->data.subroot), blkmem, set, lp) );
1221+
break;
1222+
case SCIP_NODETYPE_REFOCUSNODE:
1223+
SCIPerrorMessage("cannot free node as long it is refocused\n");
1224+
return SCIP_INVALIDDATA;
1225+
default:
1226+
SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(*node));
1227+
return SCIP_INVALIDDATA;
12191228
}
1220-
SCIP_CALL( forkFree(&((*node)->data.fork), blkmem, set, lp) );
1221-
break;
1222-
case SCIP_NODETYPE_SUBROOT:
1223-
SCIP_CALL( subrootFree(&((*node)->data.subroot), blkmem, set, lp) );
1224-
break;
1225-
case SCIP_NODETYPE_REFOCUSNODE:
1226-
SCIPerrorMessage("cannot free node as long it is refocused\n");
1227-
return SCIP_INVALIDDATA;
1228-
default:
1229-
SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(*node));
1230-
return SCIP_INVALIDDATA;
1231-
}
12321229

1233-
/* free common data */
1234-
SCIP_CALL( SCIPconssetchgFree(&(*node)->conssetchg, blkmem, set) );
1235-
SCIP_CALL( SCIPdomchgFree(&(*node)->domchg, blkmem, set, eventqueue, lp) );
1236-
SCIP_CALL( nodeReleaseParent(*node, blkmem, set, stat, eventqueue, eventfilter, tree, lp) );
1230+
/* free common data */
1231+
SCIP_CALL( SCIPconssetchgFree(&(*node)->conssetchg, blkmem, set) );
1232+
SCIP_CALL( SCIPdomchgFree(&(*node)->domchg, blkmem, set, eventqueue, lp) );
12371233

1238-
/* check, if the node is the current probing root */
1239-
if( *node == tree->probingroot )
1240-
{
1241-
assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_PROBINGNODE);
1242-
tree->probingroot = NULL;
1243-
}
1234+
/* check, if the node is the current probing root */
1235+
if( *node == tree->probingroot )
1236+
{
1237+
assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_PROBINGNODE);
1238+
tree->probingroot = NULL;
1239+
}
12441240

1245-
if( set->exact_enable )
1246-
SCIPrationalFreeBlock(blkmem, &(*node)->lowerboundexact);
1241+
if( set->exact_enable )
1242+
SCIPrationalFreeBlock(blkmem, &(*node)->lowerboundexact);
12471243

1248-
BMSfreeBlockMemory(blkmem, node);
1244+
/* delete the tree's root node pointer, if the freed node was the root */
1245+
if( isroot )
1246+
tree->root = NULL;
12491247

1250-
/* delete the tree's root node pointer, if the freed node was the root */
1251-
if( isroot )
1252-
tree->root = NULL;
1248+
SCIP_CALL( nodeReleaseParent(node, blkmem, set, tree) );
1249+
}
1250+
while( *node != NULL );
12531251

12541252
return SCIP_OKAY;
1255-
}
1253+
} /*lint !e715*/
12561254

12571255
/** cuts off node and whole sub tree from branch and bound tree
12581256
*

0 commit comments

Comments
 (0)