Skip to content

Commit 28f2185

Browse files
Variables in exponent with basis other than e (#1091)
* should be it * remove forgotten stuff * remove duplicate code * code was just out of place * Update src/pyscipopt/expr.pxi Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/pyscipopt/expr.pxi Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * improve error message * typo --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 6ac699a commit 28f2185

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44
### Added
5+
- Added possibility of having variables in exponent.
56
- Added basic type stubs to help with IDE autocompletion and type checking.
67
### Fixed
78
- Implemented all binary operations between MatrixExpr and GenExpr

src/pyscipopt/expr.pxi

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,19 @@ cdef class Expr:
272272
res *= self
273273
return res
274274

275+
def __rpow__(self, other):
276+
"""
277+
Implements base**x as scip.exp(x * scip.log(base)).
278+
Note: base must be positive.
279+
"""
280+
if _is_number(other):
281+
base = float(other)
282+
if base <= 0.0:
283+
raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base)
284+
return exp(self * log(base))
285+
else:
286+
raise TypeError(f"Unsupported base type {type(other)} for exponentiation.")
287+
275288
def __neg__(self):
276289
return Expr({v:-c for v,c in self.terms.items()})
277290

@@ -544,6 +557,19 @@ cdef class GenExpr:
544557

545558
return ans
546559

560+
def __rpow__(self, other):
561+
"""
562+
Implements base**x as scip.exp(x * scip.log(base)).
563+
Note: base must be positive.
564+
"""
565+
if _is_number(other):
566+
base = float(other)
567+
if base <= 0.0:
568+
raise ValueError("Base of a**x must be positive, as expression is reformulated to scip.exp(x * scip.log(a)); got %g" % base)
569+
return exp(self * log(base))
570+
else:
571+
raise TypeError(f"Unsupported base type {type(other)} for exponentiation.")
572+
547573
#TODO: ipow, idiv, etc
548574
def __truediv__(self,other):
549575
divisor = buildGenExprObj(other)

tests/test_expr.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,14 @@ def test_equation(model):
177177
assert isinstance(equat.expr, GenExpr)
178178
assert equat._lhs == equat._rhs
179179
assert equat._lhs == 0.0
180+
181+
def test_rpow_constant_base(model):
182+
m, x, y, z = model
183+
a = 2**x
184+
b = exp(x * log(2.0))
185+
assert isinstance(a, GenExpr)
186+
assert repr(a) == repr(b) # Structural equality is not implemented; compare strings
187+
m.addCons(2**x <= 1)
188+
189+
with pytest.raises(ValueError):
190+
c = (-2)**x

0 commit comments

Comments
 (0)