-
Notifications
You must be signed in to change notification settings - Fork 271
BUG: MatrixExpr can't be compared with Expr #1069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d33379c
6c48a73
b578ea5
e8db5a1
aae9df9
d8a9377
99446bc
a09be1a
771437b
2b9a3c0
b7b1321
987c219
7a1275d
f1dc2fa
b6dcf42
64ae70e
f69ce7e
3700261
c677b34
bca7262
cb600b2
a3a6239
06f8ebc
ef5aecf
ceaab05
3861420
a2ae9c9
6afa150
88a935f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,15 +44,7 @@ | |
# Modifying the expression directly would be a bug, given that the expression might be re-used by the user. </pre> | ||
include "matrix.pxi" | ||
|
||
def _is_number(e): | ||
try: | ||
f = float(e) | ||
return True | ||
except ValueError: # for malformed strings | ||
return False | ||
except TypeError: # for other types (Variable, Expr) | ||
return False | ||
|
||
|
||
def _expr_richcmp(self, other, op): | ||
if op == 1: # <= | ||
if isinstance(other, Expr) or isinstance(other, GenExpr): | ||
|
@@ -62,7 +54,7 @@ def _expr_richcmp(self, other, op): | |
elif isinstance(other, MatrixExpr): | ||
return _expr_richcmp(other, self, 5) | ||
else: | ||
raise NotImplementedError | ||
raise TypeError(f"Unsupported type {type(other)}") | ||
elif op == 5: # >= | ||
if isinstance(other, Expr) or isinstance(other, GenExpr): | ||
return (self - other) >= 0.0 | ||
|
@@ -71,7 +63,7 @@ def _expr_richcmp(self, other, op): | |
elif isinstance(other, MatrixExpr): | ||
return _expr_richcmp(other, self, 1) | ||
else: | ||
raise NotImplementedError | ||
raise TypeError(f"Unsupported type {type(other)}") | ||
elif op == 2: # == | ||
if isinstance(other, Expr) or isinstance(other, GenExpr): | ||
return (self - other) == 0.0 | ||
|
@@ -80,7 +72,7 @@ def _expr_richcmp(self, other, op): | |
elif isinstance(other, MatrixExpr): | ||
return _expr_richcmp(other, self, 2) | ||
else: | ||
raise NotImplementedError | ||
raise TypeError(f"Unsupported type {type(other)}") | ||
else: | ||
raise NotImplementedError("Can only support constraints with '<=', '>=', or '=='.") | ||
|
||
|
@@ -201,7 +193,7 @@ cdef class Expr: | |
elif isinstance(right, MatrixExpr): | ||
return right + left | ||
else: | ||
raise NotImplementedError | ||
raise TypeError(f"Unsupported type {type(right)}") | ||
|
||
return Expr(terms) | ||
|
||
|
@@ -218,7 +210,7 @@ cdef class Expr: | |
# TypeError: Cannot convert pyscipopt.scip.SumExpr to pyscipopt.scip.Expr | ||
return buildGenExprObj(self) + other | ||
else: | ||
raise NotImplementedError | ||
raise TypeError(f"Unsupported type {type(other)}") | ||
|
||
return self | ||
|
||
|
@@ -334,26 +326,26 @@ cdef class ExprCons: | |
def __richcmp__(self, other, op): | ||
'''turn it into a constraint''' | ||
if op == 1: # <= | ||
if not self._rhs is None: | ||
raise TypeError('ExprCons already has upper bound') | ||
assert not self._lhs is None | ||
if not self._rhs is None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use 4 spaces as the indent |
||
raise TypeError('ExprCons already has upper bound') | ||
assert not self._lhs is None | ||
|
||
if not _is_number(other): | ||
raise TypeError('Ranged ExprCons is not well defined!') | ||
if not _is_number(other): | ||
raise TypeError('Ranged ExprCons is not well defined!') | ||
|
||
return ExprCons(self.expr, lhs=self._lhs, rhs=float(other)) | ||
return ExprCons(self.expr, lhs=self._lhs, rhs=float(other)) | ||
elif op == 5: # >= | ||
if not self._lhs is None: | ||
raise TypeError('ExprCons already has lower bound') | ||
assert self._lhs is None | ||
assert not self._rhs is None | ||
if not self._lhs is None: | ||
raise TypeError('ExprCons already has lower bound') | ||
assert self._lhs is None | ||
assert not self._rhs is None | ||
|
||
if not _is_number(other): | ||
raise TypeError('Ranged ExprCons is not well defined!') | ||
if not _is_number(other): | ||
raise TypeError('Ranged ExprCons is not well defined!') | ||
|
||
return ExprCons(self.expr, lhs=float(other), rhs=self._rhs) | ||
return ExprCons(self.expr, lhs=float(other), rhs=self._rhs) | ||
else: | ||
raise TypeError | ||
raise NotImplementedError("Ranged ExprCons can only support with '<=' or '>='.") | ||
|
||
def __repr__(self): | ||
return 'ExprCons(%s, %s, %s)' % (self.expr, self._lhs, self._rhs) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
import numpy as np | ||||||||||||||||||||||||||||||||||||||||||||||||
from typing import Union | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def _is_number(e): | ||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||
f = float(e) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -15,6 +16,33 @@ def _is_number(e): | |||||||||||||||||||||||||||||||||||||||||||||||
except TypeError: # for other types (Variable, Expr) | ||||||||||||||||||||||||||||||||||||||||||||||||
return False | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def _matrixexpr_richcmp(self, other, op): | ||||||||||||||||||||||||||||||||||||||||||||||||
def _richcmp(self, other, op): | ||||||||||||||||||||||||||||||||||||||||||||||||
if op == 1: # <= | ||||||||||||||||||||||||||||||||||||||||||||||||
return self.__le__(other) | ||||||||||||||||||||||||||||||||||||||||||||||||
elif op == 5: # >= | ||||||||||||||||||||||||||||||||||||||||||||||||
return self.__ge__(other) | ||||||||||||||||||||||||||||||||||||||||||||||||
elif op == 2: # == | ||||||||||||||||||||||||||||||||||||||||||||||||
return self.__eq__(other) | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError("Can only support constraints with '<=', '>=', or '=='.") | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+21
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't use |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
res = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Expr): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
res[idx] = _richcmp(self[idx], other, op) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
res[idx] = _richcmp(self[idx], other[idx], op) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return res.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
class MatrixExpr(np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
def sum(self, **kwargs): | ||||||||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -24,51 +52,15 @@ class MatrixExpr(np.ndarray): | |||||||||||||||||||||||||||||||||||||||||||||||
res = super().sum(**kwargs) | ||||||||||||||||||||||||||||||||||||||||||||||||
return res if res.size > 1 else res.item() | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __le__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Variable): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] <= other | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] <= other[idx] | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
def __le__(self, other: Union[float, int, Expr, np.ndarray, 'MatrixExpr']) -> MatrixExprCons: | ||||||||||||||||||||||||||||||||||||||||||||||||
return _matrixexpr_richcmp(self, other, 1) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return expr_cons_matrix.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
def __ge__(self, other: Union[float, int, Expr, np.ndarray, 'MatrixExpr']) -> MatrixExprCons: | ||||||||||||||||||||||||||||||||||||||||||||||||
return _matrixexpr_richcmp(self, other, 5) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __ge__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Variable): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] >= other | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] >= other[idx] | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
def __eq__(self, other: Union[float, int, Expr, np.ndarray, 'MatrixExpr']) -> MatrixExprCons: | ||||||||||||||||||||||||||||||||||||||||||||||||
return _matrixexpr_richcmp(self, other, 2) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return expr_cons_matrix.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __eq__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Variable): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] == other | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] == other[idx] | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return expr_cons_matrix.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __add__(self, other): | ||||||||||||||||||||||||||||||||||||||||||||||||
return super().__add__(other).view(MatrixExpr) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -104,41 +96,11 @@ class MatrixGenExpr(MatrixExpr): | |||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
class MatrixExprCons(np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __le__(self, other: Union[float, int, Variable, MatrixExpr]) -> np.ndarray: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
if not _is_number(other) or not isinstance(other, MatrixExpr): | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError('Ranged MatrixExprCons is not well defined!') | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Variable): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] <= other | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] <= other[idx] | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return expr_cons_matrix.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __ge__(self, other: Union[float, int, Variable, MatrixExpr]) -> np.ndarray: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
if not _is_number(other) or not isinstance(other, MatrixExpr): | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError('Ranged MatrixExprCons is not well defined!') | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
-127
to
-128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This checking is duplicated to |
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix = np.empty(self.shape, dtype=object) | ||||||||||||||||||||||||||||||||||||||||||||||||
if _is_number(other) or isinstance(other, Variable): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] >= other | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(other, np.ndarray): | ||||||||||||||||||||||||||||||||||||||||||||||||
for idx in np.ndindex(self.shape): | ||||||||||||||||||||||||||||||||||||||||||||||||
expr_cons_matrix[idx] = self[idx] >= other[idx] | ||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError(f"Unsupported type {type(other)}") | ||||||||||||||||||||||||||||||||||||||||||||||||
def __le__(self, other: Union[float, int, np.ndarray]) -> MatrixExprCons: | ||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ranged ExprCons can only support numbers. PySCIPOpt/src/pyscipopt/expr.pxi Lines 334 to 356 in c681f94
A toy demo to show that from pyscipopt import Model
m = Model()
x = m.addVar(vtype="B", ub=0)
y = m.addVar(vtype="B", ub=0)
# (x <= 1) >= y # left is (x <= 1) (ExprCons), right is y (Variable)
# Traceback (most recent call last):
# line 6, in <module>
# (x <= 1) >= y
# File "src/pyscipopt/expr.pxi", line 352, in pyscipopt.scip.ExprCons.__richcmp__
# TypeError: Ranged ExprCons is not well defined!
y <= (x <= 1) # left is y (Variable), right is (x <= 1) (ExprCons)
# Traceback (most recent call last):
# line 12, in <module>
# y <= (x <= 1)
# File "src/pyscipopt/expr.pxi", line 287, in pyscipopt.scip.Expr.__richcmp__
# File "src/pyscipopt/expr.pxi", line 65, in pyscipopt.scip._expr_richcmp
# NotImplementedError |
||||||||||||||||||||||||||||||||||||||||||||||||
return _matrixexpr_richcmp(self, other, 1) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return expr_cons_matrix.view(MatrixExprCons) | ||||||||||||||||||||||||||||||||||||||||||||||||
def __ge__(self, other: Union[float, int, np.ndarray]) -> MatrixExprCons: | ||||||||||||||||||||||||||||||||||||||||||||||||
return _matrixexpr_richcmp(self, other, 5) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
def __eq__(self, other): | ||||||||||||||||||||||||||||||||||||||||||||||||
raise TypeError | ||||||||||||||||||||||||||||||||||||||||||||||||
raise NotImplementedError("Cannot compare MatrixExprCons with '=='.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicated parts. It also appears in matrix.pxi