@@ -2597,6 +2597,7 @@ cdef class Model:
25972597 self ._freescip = True
25982598 self ._modelvars = {}
25992599 self ._generated_event_handlers_count = 0
2600+ self ._benders_subproblems = [] # Keep references to Benders subproblem Models
26002601
26012602 if not createscip:
26022603 # if no SCIP instance should be created, then an empty Model object is created.
@@ -2668,10 +2669,29 @@ cdef class Model:
26682669 self .includeEventhdlr(event_handler, name, description)
26692670
26702671 def __dealloc__ (self ):
2672+ # Declare all C variables at the beginning for Cython compatibility
2673+ cdef SCIP_BENDERS** benders
2674+ cdef int nbenders
2675+ cdef int nsubproblems
2676+ cdef int i, j
2677+
26712678 # call C function directly, because we can no longer call this object's methods, according to
26722679 # http://docs.cython.org/src/reference/extension_types.html#finalization-dealloc
26732680 if self ._scip is not NULL and self ._freescip and PY_SCIP_CALL:
2674- PY_SCIP_CALL( SCIPfree(& self ._scip) )
2681+ # Free Benders subproblems before freeing the main SCIP instance
2682+ if self ._benders_subproblems:
2683+ benders = SCIPgetBenders(self ._scip)
2684+ nbenders = SCIPgetNActiveBenders(self ._scip)
2685+
2686+ for i in range (nbenders):
2687+ nsubproblems = SCIPbendersGetNSubproblems(benders[i])
2688+ for j in range (nsubproblems):
2689+ PY_SCIP_CALL(SCIPfreeBendersSubproblem(self ._scip, benders[i], j))
2690+
2691+ # Clear the references to allow Python GC to clean up the Model objects
2692+ self ._benders_subproblems = []
2693+
2694+ PY_SCIP_CALL( SCIPfree(& self ._scip) )
26752695
26762696 def __hash__ (self ):
26772697 return hash (< size_t> self ._scip)
@@ -2700,6 +2720,7 @@ cdef class Model:
27002720 model = Model(createscip = False )
27012721 model._scip = scip
27022722 model._bestSol = Solution.create(scip, SCIPgetBestSol(scip))
2723+ model._benders_subproblems = [] # Initialize Benders subproblems list
27032724 return model
27042725
27052726 @property
@@ -8353,6 +8374,21 @@ cdef class Model:
83538374 PY_SCIP_CALL(SCIPcreateBendersDefault(self ._scip, subprobs, nsubproblems))
83548375 benders = SCIPfindBenders(self ._scip, " default" )
83558376
8377+ # Free the temporary array (SCIPcreateBendersDefault copies the pointers internally)
8378+ free(subprobs)
8379+
8380+ # Store references to subproblem Models and transfer ownership to master.
8381+ # The master will free the Benders subproblems in its __dealloc__ method.
8382+ # Set _freescip = False on the subproblem Model(s) to prevent double-free
8383+ # if they are deallocated before the master.
8384+ if isdict:
8385+ self ._benders_subproblems = list (subproblems.values())
8386+ for subprob in self ._benders_subproblems:
8387+ (< Model> subprob)._freescip = False
8388+ else :
8389+ self ._benders_subproblems = [subproblems]
8390+ (< Model> subproblems)._freescip = False
8391+
83568392 # activating the Benders' decomposition constraint handlers
83578393 self .setBoolParam(" constraints/benderslp/active" , True )
83588394 self .setBoolParam(" constraints/benders/active" , True )
@@ -8383,20 +8419,22 @@ cdef class Model:
83838419 benders[i], self ._bestSol.sol, j, & infeasible, solvecip, NULL ))
83848420
83858421 def freeBendersSubproblems (self ):
8386- """ Calls the free subproblem function for the Benders' decomposition.
8387- This will free all subproblems for all decompositions. """
8388- cdef SCIP_BENDERS** benders = SCIPgetBenders(self ._scip)
8389- cdef int nbenders = SCIPgetNActiveBenders(self ._scip)
8390- cdef int nsubproblems
8391- cdef int i
8392- cdef int j
8393-
8394- # solving all subproblems from all Benders' decompositions
8395- for i in range (nbenders):
8396- nsubproblems = SCIPbendersGetNSubproblems(benders[i])
8397- for j in range (nsubproblems):
8398- PY_SCIP_CALL(SCIPfreeBendersSubproblem(self ._scip, benders[i],
8399- j))
8422+ """ Deprecated: This method is no longer needed.
8423+
8424+ Benders subproblems are now automatically managed and freed by the master
8425+ Model when it is deallocated. Calling this method explicitly has no effect.
8426+
8427+ .. deprecated:: 5.7.0
8428+ This method is deprecated and will be removed in a future version.
8429+ Subproblem memory management is now handled automatically.
8430+ """
8431+ warnings.warn(
8432+ " freeBendersSubproblems() is deprecated and no longer needed. "
8433+ " Benders subproblems are automatically freed when the master Model "
8434+ " is deallocated." ,
8435+ DeprecationWarning ,
8436+ stacklevel = 2
8437+ )
84008438
84018439 def updateBendersLowerbounds (self , lowerbounds , Benders benders = None ):
84028440 """
0 commit comments