Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
### Added
### Fixed
### Changed
- Move magic methods (`__radd__`, `__sub__`, `__rsub__`, `__rmul__`, `__richcmp__`, `__neg__`, and `__rtruediv__`) to `ExprLike` base class
### Removed

## 6.2.1 - 2026.05.16
Expand Down
70 changes: 25 additions & 45 deletions src/pyscipopt/expr.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,27 @@ cdef class ExprLike:

return NotImplemented

def __radd__(self, other, /):
return self + other

def __sub__(self, other, /):
return self + (-other)

def __rsub__(self, other, /):
return (-self) + other

def __rmul__(self, other, /):
return self * other

def __rtruediv__(self, other, /):
return buildGenExprObj(other) / self

def __richcmp__(self, other, int op):
return _expr_richcmp(self, other, op)

def __neg__(self):
return self * -1.0

def __abs__(self) -> GenExpr:
return UnaryExpr(Operator.fabs, buildGenExprObj(self))

Expand Down Expand Up @@ -364,11 +385,10 @@ cdef class Expr(ExprLike):
return 1.0 / other * self
return buildGenExprObj(self) / other

def __rtruediv__(self, other):
''' other / self '''
def __rtruediv__(self, other, /):
if not _is_expr_compatible(other):
return NotImplemented
return buildGenExprObj(other) / self
return super().__rtruediv__(other)

def __pow__(self, other, modulo):
if float(other).is_integer() and other >= 0:
Expand All @@ -393,25 +413,6 @@ cdef class Expr(ExprLike):
raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base)
return (self * Constant(base).log()).exp()

def __neg__(self):
return Expr({v:-c for v,c in self.terms.items()})

def __sub__(self, other):
return self + (-other)

def __radd__(self, other):
return self.__add__(other)

def __rmul__(self, other):
return self.__mul__(other)

def __rsub__(self, other):
return -1.0 * self + other

def __richcmp__(self, other, int op):
'''turn it into a constraint'''
return _expr_richcmp(self, other, op)

def normalize(self):
'''remove terms with coefficient of 0'''
self.terms = {t:c for (t,c) in self.terms.items() if c != 0.0}
Expand Down Expand Up @@ -470,7 +471,6 @@ cdef class ExprCons:
if not self._rhs is None:
self._rhs -= c


def __richcmp__(self, other, op):
'''turn it into a constraint'''
if not _is_number(other):
Expand Down Expand Up @@ -696,30 +696,10 @@ cdef class GenExpr(ExprLike):
raise ZeroDivisionError("cannot divide by 0")
return self * divisor**(-1)

def __rtruediv__(self, other):
''' other / self '''
def __rtruediv__(self, other, /):
if not _is_genexpr_compatible(other):
return NotImplemented
return buildGenExprObj(other) / self

def __neg__(self):
return -1.0 * self

def __sub__(self, other):
return self + (-other)

def __radd__(self, other):
return self.__add__(other)

def __rmul__(self, other):
return self.__mul__(other)

def __rsub__(self, other):
return -1.0 * self + other

def __richcmp__(self, other, int op):
'''turn it into a constraint'''
return _expr_richcmp(self, other, op)
return super().__rtruediv__(other)

def degree(self):
'''Note: none of these expressions should be polynomial'''
Expand Down
22 changes: 8 additions & 14 deletions src/pyscipopt/scip.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ class ExprLike:
*args: Incomplete,
**kwargs: Incomplete,
) -> Incomplete: ...
def __radd__(self, other: object, /) -> object: ...
def __sub__(self, other: object, /) -> object: ...
def __rsub__(self, other: object, /) -> object: ...
def __rmul__(self, other: object, /) -> object: ...
def __rtruediv__(self, other: object, /) -> object: ...
def __neg__(self) -> object: ...
Comment on lines +334 to +339
def __abs__(self) -> GenExpr: ...
def exp(self) -> GenExpr: ...
def log(self) -> GenExpr: ...
Expand All @@ -344,7 +350,6 @@ class Expr(ExprLike):
def __init__(self, terms: Incomplete = ...) -> None: ...
def degree(self) -> Incomplete: ...
def normalize(self) -> Incomplete: ...
def __abs__(self) -> GenExpr: ...
def __add__(self, other: Incomplete, /) -> Incomplete: ...
def __eq__(self, other: object, /) -> bool: ...
def __ge__(self, other: object, /) -> bool: ...
Expand All @@ -356,15 +361,10 @@ class Expr(ExprLike):
def __lt__(self, other: object, /) -> bool: ...
def __mul__(self, other: Incomplete, /) -> Incomplete: ...
def __ne__(self, other: object, /) -> bool: ...
def __neg__(self) -> Incomplete: ...
def __pow__(self, other: Incomplete, modulo: Incomplete = ..., /) -> Incomplete: ...
def __radd__(self, other: Incomplete, /) -> Incomplete: ...
def __rmul__(self, other: Incomplete, /) -> Incomplete: ...
def __rpow__(self, other: Incomplete, /) -> Incomplete: ...
def __rsub__(self, other: Incomplete, /) -> Incomplete: ...
def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ...
def __sub__(self, other: Incomplete, /) -> Incomplete: ...
def __truediv__(self, other: Incomplete, /) -> Incomplete: ...
def __rtruediv__(self, other: object, /) -> object: ...

Comment on lines 363 to 368
@disjoint_base
class ExprCons:
Expand All @@ -390,7 +390,6 @@ class GenExpr(ExprLike):
def __init__(self) -> None: ...
def degree(self) -> Incomplete: ...
def getOp(self) -> Incomplete: ...
def __abs__(self) -> GenExpr: ...
def __add__(self, other: Incomplete, /) -> Incomplete: ...
def __eq__(self, other: object, /) -> bool: ...
def __ge__(self, other: object, /) -> bool: ...
Expand All @@ -399,15 +398,10 @@ class GenExpr(ExprLike):
def __lt__(self, other: object, /) -> bool: ...
def __mul__(self, other: Incomplete, /) -> Incomplete: ...
def __ne__(self, other: object, /) -> bool: ...
def __neg__(self) -> Incomplete: ...
def __pow__(self, other: Incomplete, modulo: Incomplete = ..., /) -> Incomplete: ...
def __radd__(self, other: Incomplete, /) -> Incomplete: ...
def __rmul__(self, other: Incomplete, /) -> Incomplete: ...
def __rpow__(self, other: Incomplete, /) -> Incomplete: ...
def __rsub__(self, other: Incomplete, /) -> Incomplete: ...
def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ...
def __sub__(self, other: Incomplete, /) -> Incomplete: ...
def __truediv__(self, other: Incomplete, /) -> Incomplete: ...
def __rtruediv__(self, other: object, /) -> object: ...

@disjoint_base
class Heur:
Expand Down
Loading