Skip to content

Conversation

@NDevanathan
Copy link
Contributor

@NDevanathan NDevanathan commented Oct 14, 2025

Description

I implemented an einsum atom (based on numpy.einsum). The atom is affine and provides a simple interface for describing linear operations on tensors in CVXPY expressions. I wrote tests for the atom in cvxpy/tests/test_einsum.py. All but one of the tests is passing.

The last block of asserts in test_einsum_solve() in cvxpy/tests/test_einsum.py fails (at solve time) non-deterministically on my machine (it seems to fail roughly 50% of the time). Specifically, I get an error reshaping a CVXPY expression with shape (4,) to shape (4,1), and I am unsure of how to resolve this issue.

Issue link (if applicable): N/A

Type of change

  • New feature (backwards compatible)
  • New feature (breaking API changes)
  • Bug fix
  • Other (Documentation, CI, ...)

Contribution checklist

  • Add our license to new files.
  • Check that your code adheres to our coding style.
  • Write unittests.
  • Run the unittests and check that they’re passing.
  • Run the benchmarks to make sure your change doesn’t introduce a regression.

@CLAassistant
Copy link

CLAassistant commented Oct 14, 2025

CLA assistant check
All committers have signed the CLA.

@github-actions
Copy link

github-actions bot commented Oct 14, 2025

Benchmarks that have stayed the same:

   before           after         ratio
 [c78d671a]       [123d7f69]
      1.37±0s          1.46±0s     1.07  matrix_stuffing.ParamConeMatrixStuffing.time_compile_problem
      558±0ms          588±0ms     1.05  simple_QP_benchmarks.ParametrizedQPBenchmark.time_compile_problem
      278±0ms          292±0ms     1.05  matrix_stuffing.ParamSmallMatrixStuffing.time_compile_problem
      1.08±0s          1.12±0s     1.03  gini_portfolio.Cajas.time_compile_problem
      2.32±0s          2.38±0s     1.03  simple_LP_benchmarks.SimpleFullyParametrizedLPBenchmark.time_compile_problem
      1.65±0s          1.69±0s     1.02  tv_inpainting.TvInpainting.time_compile_problem
      12.9±0s          13.1±0s     1.02  finance.CVaRBenchmark.time_compile_problem
      520±0ms          527±0ms     1.01  semidefinite_programming.SemidefiniteProgramming.time_compile_problem
      233±0ms          236±0ms     1.01  gini_portfolio.Murray.time_compile_problem
     38.7±0ms         39.1±0ms     1.01  matrix_stuffing.SmallMatrixStuffing.time_compile_problem
      22.4±0s          22.6±0s     1.01  sdp_segfault_1132_benchmark.SDPSegfault1132Benchmark.time_compile_problem
      1.09±0s          1.10±0s     1.00  finance.FactorCovarianceModel.time_compile_problem
      340±0ms          340±0ms     1.00  gini_portfolio.Yitzhaki.time_compile_problem
      4.95±0s          4.95±0s     1.00  optimal_advertising.OptimalAdvertising.time_compile_problem
      243±0ms          243±0ms     1.00  high_dim_convex_plasticity.ConvexPlasticity.time_compile_problem
      11.4±0s          11.3±0s     1.00  simple_LP_benchmarks.SimpleLPBenchmark.time_compile_problem
      294±0ms          292±0ms     1.00  slow_pruning_1668_benchmark.SlowPruningBenchmark.time_compile_problem
      4.64±0s          4.62±0s     0.99  huber_regression.HuberRegression.time_compile_problem
      256±0ms          255±0ms     0.99  simple_QP_benchmarks.SimpleQPBenchmark.time_compile_problem
      5.17±0s          5.12±0s     0.99  svm_l1_regularization.SVMWithL1Regularization.time_compile_problem
      827±0ms          819±0ms     0.99  simple_QP_benchmarks.LeastSquares.time_compile_problem
      677±0ms          669±0ms     0.99  matrix_stuffing.ConeMatrixStuffingBench.time_compile_problem
      2.87±0s          2.83±0s     0.99  quantum_hilbert_matrix.QuantumHilbertMatrix.time_compile_problem
      1.88±0s          1.86±0s     0.99  simple_QP_benchmarks.UnconstrainedQP.time_compile_problem
      952±0ms          937±0ms     0.98  simple_LP_benchmarks.SimpleScalarParametrizedLPBenchmark.time_compile_problem

Copy link
Collaborator

@Transurgeon Transurgeon left a comment

Choose a reason for hiding this comment

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

@NDevanathan sorry it took so long to review your code. I noticed one small nitpicky import in your einsum implementation.
Otherwise I think overall the code is a bit difficult to follow but definitely seems to be correct (seeing all the tests you wrote pass). We still need to understand why the flaky test is happening (it is really so weird! could it be because we are importing some numpy core functions?).
One thing on my end would be to add more docstrings and also add the einsum atom to the documentation somewhere (there is a table and also some API references to update).

Thanks for doing this, really great work!


from cvxpy.atoms.affine.binary_operators import (
multiply,
reshape,
Copy link
Collaborator

@Transurgeon Transurgeon Oct 20, 2025

Choose a reason for hiding this comment

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

I just checked and there is no reshape in binary_operators? Are you sure you are importing the right one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I fixed the reshape import.

@NDevanathan
Copy link
Contributor Author

One thing on my end would be to add more docstrings and also add the einsum atom to the documentation somewhere (there is a table and also some API references to update).

I updated the docstrings to be better. I will try to add einsum to the docs.

@NDevanathan
Copy link
Contributor Author

Otherwise I think overall the code is a bit difficult to follow but definitely seems to be correct (seeing all the tests you wrote pass). We still need to understand why the flaky test is happening (it is really so weird! could it be because we are importing some numpy core functions?).

I think there might be an issue with how I implement einsum and how DGP problems are canonicalized. The error occurs at solve time, and DCP solves work. So, I think the issue occurs in doing the DGP canonicalization chain of einsum. I will also try to dig into this issue.

@NDevanathan
Copy link
Contributor Author

Sorry for the great delay, I have fixed the issues that were leading to test failures I think @Transurgeon . I will add docs today or tomorrow.

Copy link
Collaborator

@PTNobel PTNobel left a comment

Choose a reason for hiding this comment

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

Awesome work Nikhil; the tests look great.

Here's what I'd like to see:

  1. Some plan to handle if NumPy changes their internal function names in the future (see below)
  2. A tad more documentation at the top of einsum on either the algorithm being applied, or just linking to a reference.

Expression
The contracted expression.
"""
# Initial parsing
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add a comment that provides the overview of what happens in this function? It can be a reference to external documentation or what the implementation is based on, but this is pretty opaque and involves a lot of complicated functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in most recent commit.

Copy link
Collaborator

@PTNobel PTNobel left a comment

Choose a reason for hiding this comment

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

Last two comments!

is cubic in the number of distinct subscripts. We typically expect the greedy
search to produce the optimal path for most problems.
Here, einsum is implemented using the CVXPY sum, multiply, permute_dims, and reshape atoms.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't need to be in the doc comment! This is just for devs, so you can put it in a comment block below the doc comment!

input_subscripts, output_subscript = subscripts.split("->")
```
The rest is validation.
Copy link
Collaborator

Choose a reason for hiding this comment

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

There are empty spaces on this line.

"""Note for maintainers:
Here, einsum is implemented using the CVXPY sum, multiply, permute_dims, and reshape atoms.
The implementation proceeds as follows:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here.

@PTNobel PTNobel merged commit 0822817 into cvxpy:master Dec 22, 2025
42 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants