Skip to content

Speed up MatrixExpr.add.reduce via quicksum#1157

Merged
Joao-Dionisio merged 21 commits intoscipopt:masterfrom
Zeroto521:issue/1156
Jan 20, 2026
Merged

Speed up MatrixExpr.add.reduce via quicksum#1157
Joao-Dionisio merged 21 commits intoscipopt:masterfrom
Zeroto521:issue/1156

Conversation

@Zeroto521
Copy link
Contributor

@Zeroto521 Zeroto521 commented Jan 16, 2026

closes to #1153
np.add.reduce is the inner function for np.ndarray.sum, np.ndarray.mean, and more.

Implements the __array_ufunc__ method in MatrixExpr to handle numpy ufuncs, specifically enabling correct behavior for reductions like np.add.reduce by delegating to the sum method. This improves compatibility with numpy operations.
Moved the sum computation logic from MatrixExpr.sum and __array_ufunc__ into a new _core_sum function for better code reuse and maintainability.
Introduces tests to compare the performance of the mean operation on matrix variables and checks the return types of mean with and without axis argument.
Documented the speed improvement for MatrixExpr.add.reduce using quicksum in the changelog.
The sum method was removed from the MatrixExpr class, consolidating summation logic in the _core_sum function. The docstring for _core_sum was expanded to include detailed parameter and return value descriptions, improving code clarity and maintainability.
Deleted the type stub for the sum method in MatrixExpr, likely to reflect changes in the underlying implementation or to correct type information.
Enhanced the __array_ufunc__ method in MatrixExpr to ensure proper array conversion and consistent return types. Added the _ensure_array helper for argument handling. Also removed an unused include of matrix.pxi from expr.pxi.
Updated MatrixExpr.__matmul__ to return the correct type when the result is not an ndarray. Adjusted tests to reflect the expected return type for 1D matrix multiplication and improved performance test timing logic.
Simplifies timing measurement in matrix sum performance tests by directly calculating elapsed time instead of storing start and end times separately. This improves code readability and reduces variable usage.
Changed the expected type of 1D @ 1D matrix multiplication from MatrixExpr to Expr in test_matrix_matmul_return_type to reflect updated behavior.
Updated tests to use x.view(MatrixExpr) and x.view(np.ndarray) instead of direct subclass method calls. This clarifies the intent and ensures the correct method resolution for sum and mean operations in performance and result comparison tests.
@Joao-Dionisio
Copy link
Member

Oh @Zeroto521 , I've been forgetting about the tutorials! Can you please take a look at docs/tutorials/matrix.rst and see if any of your changes impacted anything? You can see the compiled tutorial here

Reorganize logic in MatrixExpr.__array_ufunc__ to handle the 'reduce' method and argument conversion more clearly. This improves readability and ensures correct handling of the 'out' keyword and argument conversion only when necessary.
@Zeroto521
Copy link
Contributor Author

Oh @Zeroto521 , I've been forgetting about the tutorials! Can you please take a look at docs/tutorials/matrix.rst and see if any of your changes impacted anything? You can see the compiled tutorial here

I see that. The current matrix only has performance changes. We can add some introduction about this later.

Enhanced the MatrixExpr.__array_ufunc__ method with detailed type annotations and a comprehensive docstring. This improves code clarity and developer experience when working with custom NumPy ufunc behavior.
A comment was added to explain that the 'reduce' method handles reductions like np.sum(a), improving code readability.
@Joao-Dionisio
Copy link
Member

@Zeroto521 can you please fix the conflicts that arose from merging the other PR?

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 optimizes MatrixExpr array reduction operations by implementing __array_ufunc__ to intercept np.add.reduce calls and route them through the optimized quicksum function. This approach automatically speeds up sum(), mean(), and other operations that internally use add.reduce.

Changes:

  • Replaced the custom sum method with __array_ufunc__ to intercept np.add.reduce operations
  • Refactored the sum logic into a standalone _core_sum function
  • Updated __matmul__ to correctly handle scalar vs array results
  • Added tests for mean functionality and updated existing tests to use proper API patterns

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/pyscipopt/matrix.pxi Implements __array_ufunc__ to intercept np.add.reduce and route to optimized quicksum; refactors sum logic to _core_sum; adds _ensure_array helper; improves __matmul__ return type handling
tests/test_matrix_variable.py Updates tests to use public API (e[CONST] instead of e.terms[CONST]); modifies performance tests to use view(np.ndarray); adds mean functionality tests
src/pyscipopt/scip.pyi Removes explicit sum method type hint since now handled via __array_ufunc__
src/pyscipopt/expr.pxi Removes redundant include "matrix.pxi" (still included in scip.pxi)
CHANGELOG.md Documents the performance optimization

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

Updated test_matrix_sum_result to extract and cast the result of the MatrixExpr sum operation before assertions. This improves clarity and ensures type consistency between the expected and actual results.
Updates the __array_ufunc__ method in MatrixExpr to ensure all elements in the 'out' tuple are unboxed with _ensure_array, preventing recursion issues when 'out' is provided as a tuple.
Updated comments in test_matrix_mean_performance to correctly refer to 'mean' instead of 'sum', reflecting the actual operations being performed in the test.
@Zeroto521
Copy link
Contributor Author

@Zeroto521 can you please fix the conflicts that arose from merging the other PR?

Done

@Joao-Dionisio Joao-Dionisio merged commit 4c3391d into scipopt:master Jan 20, 2026
3 checks passed
@Zeroto521 Zeroto521 deleted the issue/1156 branch January 21, 2026 02:35
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.

3 participants