@@ -55,6 +55,7 @@ from cpython.object cimport Py_LE, Py_EQ, Py_GE, Py_TYPE
5555from cpython.ref cimport PyObject
5656from cpython.tuple cimport PyTuple_GET_ITEM
5757
58+ cimport numpy as cnp
5859from pyscipopt.scip cimport Variable, Solution
5960
6061
@@ -321,29 +322,22 @@ cdef class Expr(ExprLike):
321322 if not _is_expr_compatible(other):
322323 return NotImplemented
323324
324- left = self
325- right = other
326- terms = left.terms.copy()
325+ if _is_number(other):
326+ terms = self .terms.copy()
327+ terms[CONST] = terms.get(CONST, 0.0 ) + < double > other
328+ return Expr(terms)
327329
328- if isinstance (right, Expr):
329- # merge the terms by component-wise addition
330- for v,c in right.terms.items():
331- terms[v] = terms.get(v, 0.0 ) + c
332- elif _is_number(right):
333- c = float (right)
334- terms[CONST] = terms.get(CONST, 0.0 ) + c
335- return Expr(terms)
330+ return Expr(_to_dict(self , other, copy = True ))
336331
337332 def __iadd__ (self , other ):
338333 if not _is_expr_compatible(other):
339334 return NotImplemented
340335
341- if isinstance (other, Expr):
342- for v,c in other.terms.items():
343- self .terms[v] = self .terms.get(v, 0.0 ) + c
344- elif _is_number(other):
345- c = float (other)
346- self .terms[CONST] = self .terms.get(CONST, 0.0 ) + c
336+ if _is_number(other):
337+ self .terms[CONST] = self .terms.get(CONST, 0.0 ) + < double > other
338+ else :
339+ _to_dict(self , other, copy = False )
340+
347341 return self
348342
349343 def __mul__ (self , other ):
@@ -999,6 +993,26 @@ cdef inline object _ensure_matrix(object arg):
999993 matrix = MatrixExpr if isinstance (arg, Expr) else MatrixGenExpr
1000994 return np.array(arg, dtype = object ).view(matrix)
1001995
996+ cdef dict _to_dict(Expr expr, Expr other, bool copy = True ):
997+ cdef dict children = expr.terms.copy() if copy else expr.terms
998+ cdef Py_ssize_t pos = < Py_ssize_t> 0
999+ cdef PyObject* k_ptr = NULL
1000+ cdef PyObject* v_ptr = NULL
1001+ cdef PyObject* old_v_ptr = NULL
1002+ cdef double other_v
1003+ cdef object k_obj
1004+
1005+ while PyDict_Next(other.terms, & pos, & k_ptr, & v_ptr):
1006+ other_v = < double > (< object > v_ptr)
1007+ k_obj = < object > k_ptr
1008+ old_v_ptr = PyDict_GetItem(children, k_obj)
1009+ if old_v_ptr != NULL :
1010+ children[k_obj] = < double > (< object > old_v_ptr) + other_v
1011+ else :
1012+ children[k_obj] = other_v
1013+
1014+ return children
1015+
10021016
10031017def expr_to_nodes (expr ):
10041018 ''' transforms tree to an array of nodes. each node is an operator and the position of the
0 commit comments