oxfordcontrol / Clarabel.rs

Clarabel.rs: Interior-point solver for convex conic optimisation problems in Rust.
Apache License 2.0
314 stars 24 forks source link

PanicException: assertion `left == right` failed #127

Open stephane-caron opened 1 month ago

stephane-caron commented 1 month ago

Hi and thanks again for maintaining this open source solver :smiley: I noticed the following exception thrown by Clarabel on the QUADCMPC1 problem of the free-for-all QP test set:

$ python free_for_all.py run --solver clarabel --problem QUADCMPC1
results_file='src/free_for_all_qpbenchmark/results/free_for_all.csv'
[2024-07-31 14:30:39,925] [info] Loading existing results from src/free_for_all_qpbenchmark/results/free_for_all.csv (results.py:78)
[2024-07-31 14:30:39,953] [info] Solving QUADCMPC1 by clarabel with default settings... (run.py:108)
thread '<unnamed>' panicked at src/solver/implementations/default/solver.rs:56:9:
assertion `left == right` failed
  left: 1536
 right: 1408
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "src/free_for_all_qpbenchmark/free_for_all.py", line 231, in <module>
    main(test_set_path=os.path.abspath(__file__))
  File ".micromamba/envs/qpbenchmark/lib/python3.12/site-packages/qpbenchmark/benchmark.py", line 268, in main
    run(
  File ".micromamba/envs/qpbenchmark/lib/python3.12/site-packages/qpbenchmark/run.py", line 113, in run
    solution, runtime = time_solve_problem(
                        ^^^^^^^^^^^^^^^^^^^
  File ".micromamba/envs/qpbenchmark/lib/python3.12/site-packages/qpbenchmark/utils.py", line 129, in time_solve_problem
    solution = qpsolvers.solve_problem(problem, solver=solver, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".micromamba/envs/qpbenchmark/lib/python3.12/site-packages/qpsolvers/solve_problem.py", line 81, in solve_problem
    return solve_function[solver](problem, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".micromamba/envs/qpbenchmark/lib/python3.12/site-packages/qpsolvers/solvers/clarabel_.py", line 118, in clarabel_solve_problem
    solver = clarabel.DefaultSolver(P, q, A_stack, b_stack, cones, settings)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pyo3_runtime.PanicException: assertion `left == right` failed

I checked quickly that A_stack.shape=(2432, 768) and b_stack.shape=(2432,) (could be "left" and "right"?). Other solvers like OSQP solve the problem successfully.

Sorry I don't have the time right now to make a reproducer that does not depend on the benchmarking library, but the exception should be reproducible (after conda/PyPI installing qpbenchmark) by:

$ python free_for_all.py run --solver clarabel --problem QUADCMPC1

Finally I noticed that Clarabel 0.7.0 does not raise the exception, while Clarabel 0.8.0 does.

Hoping this helps!

goulart-paul commented 1 month ago

It looks like that error is thrown when there is a mismatch between the dimension of b and the total of the dimensions in the cones that is passed to the solver. What does cones look like?

Edit: even if the above is the issue, please leave this open since that is not a nice way for the solver to fail. Probably better for us rewrite some of these input checking assertions so that they return clearer error to the user on solver initialisation.

stephane-caron commented 1 month ago

The cones look like this:

A.shape=(384, 768)
G.shape=(2048, 768)
A_stack.shape=(2432, 768)
b_stack.shape=(2432,)
cones=[ZeroConeT(384), NonnegativeConeT(2048)]

Here is the context for reference.

goulart-paul commented 1 month ago

The cones appear to be compatible, although the total dimension (2432) is lower than both sides of the assertion that failed.

In version 0.8.0 we reimplemented the preprocessing step that eliminates infinite bounds, so perhaps an error was introduced there. Does b_stack have a lot of very large entries. Specifically, does it have 1000 entries with values >= 1e20?

stephane-caron commented 1 month ago

Yes it does :dart:

In [3]: (b_stack >= 1e20).sum()
Out[3]: 1024
goulart-paul commented 1 month ago

OK, thank you for confirming. I think this must be a bug introduced in the v0.8 version of the presolve. I will make a fix and release patched version as soon as I can, but probably not for a week or two.