diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e1944cf..dcf1aa014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### Changed - Speed up `constant * Expr` via C-level API - Speed up `Term.__eq__` via the C-level API +- Move magic methods (`__radd__`, `__sub__`, `__rsub__`, `__rmul__`, `__richcmp__`, `__neg__`, and `__rtruediv__`) to `ExprLike` base class ### Removed - Removed outdated warning about Make build system incompatibility - Removed `Term.ptrtuple` to optimize `Term` memory usage diff --git a/src/pyscipopt/expr.pxi b/src/pyscipopt/expr.pxi index b26b87997..83ef4b5c9 100644 --- a/src/pyscipopt/expr.pxi +++ b/src/pyscipopt/expr.pxi @@ -261,6 +261,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)) @@ -383,10 +404,6 @@ cdef class Expr(ExprLike): selfexpr = buildGenExprObj(self) return selfexpr.__truediv__(other) - def __rtruediv__(self, other): - ''' other / self ''' - return buildGenExprObj(other) / self - def __pow__(self, other, modulo): if float(other).is_integer() and other >= 0: exp = int(other) @@ -411,25 +428,6 @@ cdef class Expr(ExprLike): else: raise TypeError(f"Unsupported base type {type(other)} for exponentiation.") - 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, 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} @@ -488,7 +486,6 @@ cdef class ExprCons: if not self._rhs is None: self._rhs -= c - def __richcmp__(self, other, op): '''turn it into a constraint''' if op == 1: # <= @@ -715,30 +712,6 @@ cdef class GenExpr(ExprLike): raise ZeroDivisionError("cannot divide by 0") return self * divisor**(-1) - def __rtruediv__(self, other): - ''' other / self ''' - otherexpr = buildGenExprObj(other) - return otherexpr.__truediv__(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, op): - '''turn it into a constraint''' - return _expr_richcmp(self, other, op) - def degree(self): '''Note: none of these expressions should be polynomial''' return float('inf') diff --git a/src/pyscipopt/scip.pyi b/src/pyscipopt/scip.pyi index 741e35ff9..c46527a62 100644 --- a/src/pyscipopt/scip.pyi +++ b/src/pyscipopt/scip.pyi @@ -333,6 +333,12 @@ class ExprLike: *args: Incomplete, **kwargs: Incomplete, ) -> Incomplete: ... + def __radd__(self, other: Incomplete, /) -> Incomplete: ... + def __sub__(self, other: Incomplete, /) -> Incomplete: ... + def __rsub__(self, other: Incomplete, /) -> Incomplete: ... + def __rmul__(self, other: Incomplete, /) -> Incomplete: ... + def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ... + def __neg__(self) -> Incomplete: ... def __abs__(self) -> GenExpr: ... def exp(self) -> GenExpr: ... def log(self) -> GenExpr: ... @@ -346,7 +352,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: ... @@ -358,14 +363,8 @@ 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: ... @disjoint_base @@ -392,7 +391,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: ... @@ -401,14 +399,8 @@ 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: ... @disjoint_base