diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d891c599..b4d64a6d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased ### Added +- Added possibility of having variables in exponent. - Added basic type stubs to help with IDE autocompletion and type checking. ### Fixed - Implemented all binary operations between MatrixExpr and GenExpr diff --git a/src/pyscipopt/expr.pxi b/src/pyscipopt/expr.pxi index 431a4abd4..f0c406fcb 100644 --- a/src/pyscipopt/expr.pxi +++ b/src/pyscipopt/expr.pxi @@ -272,6 +272,19 @@ cdef class Expr: res *= self return res + def __rpow__(self, other): + """ + Implements base**x as scip.exp(x * scip.log(base)). + Note: base must be positive. + """ + if _is_number(other): + base = float(other) + if base <= 0.0: + raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base) + return exp(self * log(base)) + 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()}) @@ -544,6 +557,19 @@ cdef class GenExpr: return ans + def __rpow__(self, other): + """ + Implements base**x as scip.exp(x * scip.log(base)). + Note: base must be positive. + """ + if _is_number(other): + base = float(other) + if base <= 0.0: + raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base) + return exp(self * log(base)) + else: + raise TypeError(f"Unsupported base type {type(other)} for exponentiation.") + #TODO: ipow, idiv, etc def __truediv__(self,other): divisor = buildGenExprObj(other) diff --git a/tests/test_expr.py b/tests/test_expr.py index ccc2d797c..ce79b7cc5 100644 --- a/tests/test_expr.py +++ b/tests/test_expr.py @@ -177,3 +177,14 @@ def test_equation(model): assert isinstance(equat.expr, GenExpr) assert equat._lhs == equat._rhs assert equat._lhs == 0.0 + +def test_rpow_constant_base(model): + m, x, y, z = model + a = 2**x + b = exp(x * log(2.0)) + assert isinstance(a, GenExpr) + assert repr(a) == repr(b) # Structural equality is not implemented; compare strings + m.addCons(2**x <= 1) + + with pytest.raises(ValueError): + c = (-2)**x