@@ -5887,13 +5887,6 @@ cdef class Model:
58875887
58885888 PyCons = Constraint.create(scip_cons)
58895889
5890- # Store the original polynomial expression on the constraint so that
5891- # helpers such as getTermsQuadratic can reconstruct full linear terms
5892- # even if SCIP's internal quadratic representation does not expose
5893- # all linear coefficients explicitly.
5894- if PyCons.data is None :
5895- PyCons.data = quadcons.expr
5896-
58975890 return PyCons
58985891
58995892 def _createConsNonlinear (self , cons , **kwargs ):
@@ -8310,14 +8303,13 @@ cdef class Model:
83108303 Triples ``(var1, var2, coef)`` for terms of the form
83118304 ``coef * var1 * var2`` with ``var1 != var2``.
83128305 quadterms : list of tuple
8313- Triples ``(var, sqrcoef, lincoef)`` corresponding to diagonal
8314- quadratic terms of the form ``sqrcoef * var**2 `` and the linear
8315- coefficient ``lincoef`` associated with the same variable when it
8316- also appears linearly in the quadratic part .
8306+ Triples ``(var, sqrcoef, lincoef)`` for variables that appear in
8307+ quadratic or bilinear terms. ``sqrcoef`` is the coefficient of
8308+ ``var**2``, and ``lincoef`` is the linear coefficient of ``var``
8309+ if it also appears linearly.
83178310 linterms : list of tuple
8318- Pairs ``(var, coef)`` for all variables with a nonzero linear
8319- coefficient in the constraint, including variables that also
8320- appear in quadratic or bilinear terms.
8311+ Pairs ``(var, coef)`` for purely linear variables, i.e.,
8312+ variables that do not participate in any quadratic or bilinear term.
83218313
83228314 """
83238315 cdef SCIP_EXPR* expr
@@ -8336,6 +8328,7 @@ cdef class Model:
83368328 cdef int nbilinterms
83378329
83388330 # quadratic terms
8331+ cdef SCIP_EXPR* quadexpr
83398332 cdef SCIP_EXPR* sqrexpr
83408333 cdef SCIP_Real sqrcoef
83418334 cdef int nquadterms
@@ -8353,28 +8346,44 @@ cdef class Model:
83538346
83548347 linterms = []
83558348 bilinterms = []
8356- quadterms = []
83578349
8350+ # Purely linear terms (variables not in any quadratic/bilinear term)
83588351 for termidx in range (nlinvars):
83598352 var = self ._getOrCreateVar(SCIPgetVarExprVar(linexprs[termidx]))
83608353 linterms.append((var, lincoefs[termidx]))
83618354
8355+ # Collect quadratic terms in a dict so we can merge entries for the same variable.
8356+ quaddict = {} # var.ptr() -> [var, sqrcoef, lincoef]
8357+
83628358 for termidx in range (nbilinterms):
83638359 SCIPexprGetQuadraticBilinTerm(expr, termidx, & bilinterm1, & bilinterm2, & bilincoef, NULL , NULL )
83648360 scipvar1 = SCIPgetVarExprVar(bilinterm1)
83658361 scipvar2 = SCIPgetVarExprVar(bilinterm2)
83668362 var1 = self ._getOrCreateVar(scipvar1)
83678363 var2 = self ._getOrCreateVar(scipvar2)
83688364 if scipvar1 != scipvar2:
8369- bilinterms.append((var1,var2,bilincoef))
8365+ bilinterms.append((var1, var2, bilincoef))
83708366 else :
8371- quadterms.append((var1,bilincoef,0.0 ))
8367+ # Squared term reported as bilinear var*var
8368+ key = var1.ptr()
8369+ if key in quaddict:
8370+ quaddict[key][1 ] += bilincoef
8371+ else :
8372+ quaddict[key] = [var1, bilincoef, 0.0 ]
8373+
8374+ # Also collect linear coefficients from the quadratic terms
83728375 for termidx in range (nquadterms):
8373- SCIPexprGetQuadraticQuadTerm(expr, termidx, NULL , & lincoef, & sqrcoef, NULL , NULL , & sqrexpr)
8374- if sqrexpr == NULL :
8375- continue
8376- var = self ._getOrCreateVar(SCIPgetVarExprVar(sqrexpr))
8377- quadterms.append((var,sqrcoef,lincoef))
8376+ SCIPexprGetQuadraticQuadTerm(expr, termidx, & quadexpr, & lincoef, & sqrcoef, NULL , NULL , & sqrexpr)
8377+ scipvar1 = SCIPgetVarExprVar(quadexpr)
8378+ var = self ._getOrCreateVar(scipvar1)
8379+ key = var.ptr()
8380+ if key in quaddict:
8381+ quaddict[key][1 ] += sqrcoef
8382+ quaddict[key][2 ] += lincoef
8383+ else :
8384+ quaddict[key] = [var, sqrcoef, lincoef]
8385+
8386+ quadterms = [(entry[0 ], entry[1 ], entry[2 ]) for entry in quaddict.values()]
83788387
83798388 return (bilinterms, quadterms, linterms)
83808389
0 commit comments