Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
- Made `test_markDoNotAggrVar_and_getStatus` robust to SCIP presolve changes by discovering the aggregated/multi-aggregated variables instead of hardcoding them
### Changed
- Move magic methods (`__radd__`, `__sub__`, `__rsub__`, `__rmul__`, `__richcmp__`, `__neg__`, and `__rtruediv__`) to `ExprLike` base class (#1204)
- Speed up `Expr.__add__` and `Expr.__iadd__` via the C-level API
- Speed up `Expr.__add__` and `Expr.__iadd__` via the C-level API (#1205)
- Speed up `ProdExpr.__neg__` and `Constant.__neg__` via C-level API (#1250)
- Extended `structured_optimization_trace` recipe to support context-managed JSONL tracing with final `run_end` records, alongside the existing attach-style in-memory tracing.
### Removed

Expand Down
10 changes: 10 additions & 0 deletions src/pyscipopt/expr.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,11 @@ cdef class ProdExpr(GenExpr):
self.children = []
self._op = Operator.prod

def __neg__(self, /) -> ProdExpr:
cdef ProdExpr res = self.copy(copy=True)
res.constant = -res.constant
return res

def __repr__(self):
return self._op + "(" + str(self.constant) + "," + ",".join(map(lambda child : child.__repr__(), self.children)) + ")"

Expand Down Expand Up @@ -850,11 +855,16 @@ cdef class UnaryExpr(GenExpr):

# class for constant expressions
cdef class Constant(GenExpr):

cdef public number

def __init__(self,number):
self.number = number
self._op = Operator.const

def __neg__(self, /) -> Constant:
return Constant(-self.number)

def __repr__(self):
return str(self.number)

Expand Down
5 changes: 4 additions & 1 deletion src/pyscipopt/scip.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ class Conshdlr:
class Constant(GenExpr):
number: Incomplete
def __init__(self, *args: Incomplete, **kwargs: Incomplete) -> None: ...
def __neg__(self, /) -> Constant: ...
def __pow__( # type: ignore[override]
self, other: float | Constant, mod: Incomplete = ..., /
) -> Constant: ...
Expand Down Expand Up @@ -355,6 +356,7 @@ class ExprLike:
**kwargs: Incomplete,
) -> Incomplete: ...
def __pos__(self, /) -> Self: ...
def __neg__(self, /) -> ExprLike: ...
def __abs__(self, /) -> UnaryExpr: ...
def exp(self) -> UnaryExpr: ...
def log(self) -> UnaryExpr: ...
Expand Down Expand Up @@ -444,7 +446,7 @@ class GenExpr(ExprLike):
def __init__(self) -> None: ...
def degree(self) -> Incomplete: ...
def getOp(self) -> Incomplete: ...
def __neg__(self, /) -> ProdExpr: ...
def __neg__(self, /) -> ProdExpr | Constant: ...
@overload
def __add__(self, other: float | ExprLike, /) -> SumExpr: ...
@overload
Expand Down Expand Up @@ -2127,6 +2129,7 @@ class Pricer:
class ProdExpr(GenExpr):
constant: Incomplete
def __init__(self, *args: Incomplete, **kwargs: Incomplete) -> None: ...
def __neg__(self, /) -> ProdExpr: ...

@disjoint_base
class Prop:
Expand Down
32 changes: 31 additions & 1 deletion tests/test_expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
import pytest

from pyscipopt import Model, cos, exp, log, quickprod, sin, sqrt
from pyscipopt.scip import CONST, Expr, ExprCons, GenExpr, MatrixGenExpr
from pyscipopt.scip import (
CONST,
Constant,
Expr,
ExprCons,
GenExpr,
MatrixGenExpr,
ProdExpr,
)


@pytest.fixture(scope="module")
Expand Down Expand Up @@ -594,3 +602,25 @@ def test_pos():
e = +c
assert str(e) == str(c)
assert e is not c

def test_neg():
m = Model()
x = m.addVar(name="x")

expr = (x + 1) ** 3
neg_expr = -expr
assert isinstance(expr, Expr)
assert isinstance(neg_expr, Expr)
assert (
str(neg_expr)
== "Expr({Term(x, x, x): -1.0, Term(x, x): -3.0, Term(x): -3.0, Term(): -1.0})"
)

base = sqrt(x)
expr = base * -1
neg_expr = -expr
assert isinstance(expr, ProdExpr)
assert isinstance(neg_expr, ProdExpr)
assert str(neg_expr) == "prod(1.0,sqrt(sum(0.0,prod(1.0,x))))"

assert str(-Constant(3.0)) == "-3.0"
Loading