Skip to content

Conversation

@Zeroto521
Copy link
Contributor

@Zeroto521 Zeroto521 commented Jan 24, 2026

Current abs(abs(x)) will return abs(abs(x)). This will slow addCons and increase the difficulty to solve model. An easy way to fix this is to return abs(x).

Introduces a copy method to GenExpr and its subclasses for duplicating expression objects, with optional deep copy of children and coefficients. Also adds __abs__ support to UnaryExpr, enabling correct handling of absolute value expressions.
Introduces a test to verify that applying abs() twice to a variable results in the same string representation as applying it once, ensuring correct simplification in expression handling.
Documented that abs now returns itself as UnaryExpr(Operator.fabs) in the CHANGELOG.
Changed the return type of __abs__ in GenExpr from Incomplete to GenExpr and added the __abs__ method to UnaryExpr. This improves type hinting and consistency in the class hierarchy.
Changed the declaration of 'cls' in GenExpr.copy from a Python variable to a Cython object to ensure proper type handling.
Replaces the use of type(self) with Py_TYPE(self) in the GenExpr.copy method for more efficient class retrieval in Cython. Also reorders cimport statements for clarity.
Copilot AI review requested due to automatic review settings January 24, 2026 09:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR ensures that applying abs twice to an expression yields the same expression as a single abs, avoiding nested abs(abs(x)) trees that can slow constraint handling (e.g. addCons).

Changes:

  • Add a regression test that asserts str(abs(abs(x))) == str(abs(x)) for a model variable.
  • Introduce a GenExpr.copy() helper and override UnaryExpr.__abs__ to return the existing absolute-expression (via a copy) instead of wrapping it again, while preserving behavior for other unary operators.
  • Update type stubs (scip.pyi) and the changelog to reflect the new __abs__ behavior on GenExpr/UnaryExpr.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
tests/test_expr.py Adds a focused test verifying that abs(abs(x)) produces the same printed form as abs(x), guarding against regressions in expression simplification.
src/pyscipopt/scip.pyi Adjusts type hints so GenExpr.__abs__ and UnaryExpr.__abs__ are declared to return GenExpr, matching the implementation.
src/pyscipopt/expr.pxi Adds a generic GenExpr.copy() helper and special-cases UnaryExpr.__abs__ to avoid nested absolute expressions while keeping evaluation semantics unchanged.
CHANGELOG.md Documents the new behavior for abs on UnaryExpr(Operator.fabs, ...) under the Unreleased “Changed” section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changed the type of 'cls' from 'object' to 'type' in the GenExpr.copy method to ensure correct class instantiation using Py_TYPE.
The __abs__ method in the UnaryExpr class now includes a return type annotation, improving type clarity and static analysis.
The @disjoint_base decorator was removed from the UnaryExpr class in the type stub. This may reflect a change in class hierarchy or decorator usage.
Corrects attribute assignments in the GenExpr.copy method by explicitly casting to the appropriate subclass (SumExpr, ProdExpr, PowExpr) before setting subclass-specific attributes. This ensures proper copying of attributes and avoids potential attribute errors.
Explicitly cast the result of Py_TYPE(self) to <type> in the GenExpr.copy method for clarity and type safety.
@Joao-Dionisio
Copy link
Member

Hmm I'm not 10000% certain that this should be done in PySCIPOpt, it feels like it's something SCIP should do on its own. Same with squaring integer variables, for example. What do you think, @Zeroto521 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants