Skip to content

Commit 2be24bd

Browse files
committed
LinExpr update and added tests
1 parent f7e5fd6 commit 2be24bd

File tree

2 files changed

+532
-88
lines changed

2 files changed

+532
-88
lines changed

mip/entities.py

Lines changed: 16 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,6 @@ def __radd__(
118118
) -> "mip.LinExpr":
119119
return self.__add__(other)
120120

121-
def __iadd__(
122-
self,
123-
other: Union["mip.Var", "mip.LinExpr", numbers.Real],
124-
) -> "mip.LinExpr":
125-
if isinstance(other, Var):
126-
self.add_var(other, 1)
127-
elif isinstance(other, LinExpr):
128-
self.add_expr(other)
129-
elif isinstance(other, numbers.Real):
130-
self.add_const(other)
131-
else:
132-
raise TypeError("type {} not supported".format(type(other)))
133-
return self
134-
135121
def __sub__(
136122
self,
137123
other: Union["mip.Var", "mip.LinExpr", numbers.Real],
@@ -153,27 +139,11 @@ def __rsub__(
153139
) -> "mip.LinExpr":
154140
return (-self).__add__(other)
155141

156-
def __isub__(
157-
self,
158-
other: Union["mip.Var", "mip.LinExpr", numbers.Real],
159-
) -> "mip.LinExpr":
160-
if isinstance(other, Var):
161-
self.add_var(other, -1)
162-
elif isinstance(other, LinExpr):
163-
self.add_expr(other, -1)
164-
elif isinstance(other, numbers.Real):
165-
self.add_const(-other)
166-
else:
167-
raise TypeError("type {} not supported".format(type(other)))
168-
return self
169-
170-
def __mul__(self, other: numbers.Real) -> Union["mip.LinExpr", numbers.Real]:
142+
def __mul__(self, other: numbers.Real) -> "mip.LinExpr":
171143
if not isinstance(other, numbers.Real):
172144
raise TypeError("Can not multiply with type {}".format(type(other)))
173145

174-
if fabs(other) < mip.EPS:
175-
return other
176-
elif fabs(other - 1) < mip.EPS:
146+
if fabs(other - 1) < mip.EPS:
177147
return self
178148

179149
result = self.copy()
@@ -185,50 +155,12 @@ def __mul__(self, other: numbers.Real) -> Union["mip.LinExpr", numbers.Real]:
185155
def __rmul__(self, other: numbers.Real) -> "mip.LinExpr":
186156
return self.__mul__(other)
187157

188-
def __imul__(self, other: numbers.Real) -> "mip.LinExpr":
189-
if not isinstance(other, numbers.Real):
190-
raise TypeError("Can not multiply with type {}".format(type(other)))
191-
192-
if fabs(other) < mip.EPS:
193-
self.__const = 0.0
194-
self.__expr = {} # type: Dict[mip.Var, numbers.Real]
195-
return self
196-
elif fabs(other - 1) < mip.EPS:
197-
return self
198-
199-
self.__const *= other
200-
for var in self.__expr.keys():
201-
self.__expr[var] *= other
202-
return self
203-
204158
def __truediv__(self, other: numbers.Real) -> "mip.LinExpr":
205159
if not isinstance(other, numbers.Real):
206160
raise TypeError("Can not divide with type {}".format(type(other)))
207-
208-
if fabs(other) < mip.EPS:
209-
raise ZeroDivisionError()
210-
elif fabs(other - 1) < mip.EPS:
211-
return self
212-
213-
result = self.copy()
214-
result.__const /= other
215-
for var in result.__expr.keys():
216-
result.__expr[var] /= other
217-
return result
218-
219-
def __itruediv__(self, other: numbers.Real) -> "mip.LinExpr":
220-
if not isinstance(other, numbers.Real):
221-
raise TypeError("Can not divide with type {}".format(type(other)))
222-
223161
if fabs(other) < mip.EPS:
224-
raise ZeroDivisionError()
225-
elif fabs(other - 1) < mip.EPS:
226-
return self
227-
228-
self.__const /= other
229-
for var in self.__expr.keys():
230-
self.__expr[var] /= other
231-
return self
162+
raise ZeroDivisionError("Expression division by zero")
163+
return self.__mul__(1.0 / other)
232164

233165
def __neg__(self) -> "LinExpr":
234166
return self.__mul__(-1)
@@ -295,7 +227,7 @@ def __len__(self):
295227

296228
def add_const(self, val: numbers.Real):
297229
"""adds a constant value to the linear expression, in the case of
298-
a constraint this correspond to the right-hand-side
230+
a constraint this corresponds to the right-hand-side
299231
300232
Args:
301233
val(numbers.Real): a real number
@@ -334,7 +266,7 @@ def add_term(
334266
elif isinstance(term, LinExpr):
335267
self.add_expr(term, coeff)
336268
elif isinstance(term, numbers.Real):
337-
self.add_const(term)
269+
self.add_const(term * coeff)
338270
else:
339271
raise TypeError("type {} not supported".format(type(term)))
340272

@@ -345,13 +277,8 @@ def add_var(self, var: "mip.Var", coeff: numbers.Real = 1):
345277
var (mip.Var) : a variable
346278
coeff (numbers.Real) : coefficient which the variable will be added
347279
"""
348-
if var in self.__expr:
349-
if -mip.EPS <= self.__expr[var] + coeff <= mip.EPS:
350-
del self.__expr[var]
351-
else:
352-
self.__expr[var] += coeff
353-
else:
354-
self.__expr[var] = coeff
280+
self.__expr.setdefault(var, 0)
281+
self.__expr[var] += coeff
355282

356283
def set_expr(self: "LinExpr", expr: Dict["mip.Var", numbers.Real]):
357284
"""Sets terms of the linear expression
@@ -364,11 +291,7 @@ def set_expr(self: "LinExpr", expr: Dict["mip.Var", numbers.Real]):
364291
self.__expr = expr
365292

366293
def copy(self) -> "mip.LinExpr":
367-
copy = LinExpr()
368-
copy.__const = self.__const
369-
copy.__expr = self.__expr.copy()
370-
copy.__sense = self.__sense
371-
return copy
294+
return LinExpr(const=self.__const, sense=self.__sense, expr=self.__expr)
372295

373296
def equals(self, other: "mip.LinExpr") -> bool:
374297
"""returns true if a linear expression equals to another,
@@ -439,9 +362,14 @@ def violation(self) -> Optional[numbers.Real]:
439362
If a solution is available, than this property indicates how much
440363
the current solution violates this constraint.
441364
"""
365+
# No violation can be computed for something that isn't a constraint
366+
# or has no solution yet
367+
if self.sense == "" or self.x is None:
368+
return None
369+
442370
lhs = sum(coef * var.x for (var, coef) in self.__expr.items())
443371
rhs = -self.const
444-
viol = None
372+
445373
if self.sense == "=":
446374
viol = abs(lhs - rhs)
447375
elif self.sense == "<":
@@ -666,7 +594,7 @@ def __rmul__(self, other: numbers.Real) -> LinExpr:
666594
def __truediv__(self, other: numbers.Real) -> LinExpr:
667595
if not isinstance(other, numbers.Real):
668596
raise TypeError("Can not divide with type {}".format(type(other)))
669-
if isinstance(other, numbers.Real) and abs(other) < mip.EPS:
597+
if abs(other) < mip.EPS:
670598
raise ZeroDivisionError("Variable division by zero")
671599
return self.__mul__(1.0 / other)
672600

0 commit comments

Comments
 (0)