Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace OSQP with a hybrid HIGHS/OSQP solver interface #256

Merged
merged 24 commits into from
Oct 23, 2023

Conversation

cdiener
Copy link
Member

@cdiener cdiener commented Sep 14, 2023

  • description of feature/fix
  • tests added/passed
  • add an entry to the next release

This is a proposal for a new interface that leverages the matrix interface to combine HIGHS and OSQP in a general purpose large problem solver. This was designed with MICOM in mind, so I am not completely sure whether it's in scope here (see pro-con below). It passes all the generic tests in optlang and also the full COBRAPY suite.

Pro

  • this is a full open source LP/MILP/QP interface
  • efficient and good accuracy LP and QP solvers that work with huge problems (100K+ vars/cons)
  • MIP solver is faster and more accurate than GLPK
  • relatively simple codebase
  • allows warm start of OSQP with a HIGHS solution, OSQP and HIGHS will both reuse prior solutions/bases
  • fairly little code to add compared to full new interface

Cons

  • because it uses the matrix interface it is not as efficient as possible (gets the full solution [primals+duals] at every solve, which makes it slower)
  • we should probably have a separate HIGHS interface that makes use of all the features (and allows lean solution access)
  • HIGHS already includes a QP solver (that does not work for large problems though)
  • MIP solver is much slower than CPLEX and Gurobi (up to 10-100x depending on the problem)

So let me know what you think.

COBRAPY tests and benchmarks

==================================================================== test session starts ====================================================================
platform linux -- Python 3.11.5, pytest-7.3.0, pluggy-1.0.0
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/cdiener/code/cobrapy
configfile: tox.ini
testpaths: tests
plugins: cov-4.0.0, mock-3.10.0, anyio-3.6.2, benchmark-4.0.0
collected 670 items                                                                                                                                         

tests/test_core/test_configuration.py ......                                                                                                          [  0%]
tests/test_core/test_core_reaction.py ...........s.........................................x.......                                                   [ 10%]
tests/test_core/test_dictlist.py ......................                                                                                               [ 13%]
tests/test_core/test_formula.py .....                                                                                                                 [ 14%]
tests/test_core/test_gene.py .                                                                                                                        [ 14%]
tests/test_core/test_gpr.py .....................x..x.............................................                                                    [ 24%]
tests/test_core/test_group.py ..                                                                                                                      [ 24%]
tests/test_core/test_metabolite.py ....s..s.                                                                                                          [ 26%]
tests/test_core/test_model.py ...............................................................s.                                                       [ 35%]
tests/test_core/test_solution.py ..s                                                                                                                  [ 36%]
tests/test_flux_analysis/test_deletion.py ....s.....                                                                                                  [ 37%]
tests/test_flux_analysis/test_fastcc.py ....                                                                                                          [ 38%]
tests/test_flux_analysis/test_geometric.py ..                                                                                                         [ 38%]
tests/test_flux_analysis/test_moma.py .                                                                                                               [ 38%]
tests/test_flux_analysis/test_parsimonious.py ..                                                                                                      [ 39%]
tests/test_flux_analysis/test_reaction.py .                                                                                                           [ 39%]
tests/test_flux_analysis/test_room.py ....                                                                                                            [ 40%]
tests/test_flux_analysis/test_variability.py .......                                                                                                  [ 41%]
tests/test_flux_analysis/test_deletion.py ..........                                                                                                  [ 42%]
tests/test_flux_analysis/test_fastcc.py ....                                                                                                          [ 43%]
tests/test_flux_analysis/test_geometric.py ..                                                                                                         [ 43%]
tests/test_flux_analysis/test_moma.py .                                                                                                               [ 43%]
tests/test_flux_analysis/test_parsimonious.py ..                                                                                                      [ 43%]
tests/test_flux_analysis/test_reaction.py .                                                                                                           [ 44%]
tests/test_flux_analysis/test_room.py ....                                                                                                            [ 44%]
tests/test_flux_analysis/test_variability.py .......                                                                                                  [ 45%]
tests/test_flux_analysis/test_deletion.py ..........                                                                                                  [ 47%]
tests/test_flux_analysis/test_fastcc.py ....                                                                                                          [ 47%]
tests/test_flux_analysis/test_geometric.py ..                                                                                                         [ 48%]
tests/test_flux_analysis/test_moma.py .                                                                                                               [ 48%]
tests/test_flux_analysis/test_parsimonious.py ..                                                                                                      [ 48%]
tests/test_flux_analysis/test_reaction.py .                                                                                                           [ 48%]
tests/test_flux_analysis/test_room.py ....                                                                                                            [ 49%]
tests/test_flux_analysis/test_variability.py .......                                                                                                  [ 50%]
tests/test_flux_analysis/test_deletion.py ...                                                                                                         [ 50%]
tests/test_flux_analysis/test_moma.py .                                                                                                               [ 50%]
tests/test_flux_analysis/test_deletion.py ...                                                                                                         [ 51%]
tests/test_flux_analysis/test_moma.py .                                                                                                               [ 51%]
tests/test_flux_analysis/test_deletion.py ......                                                                                                      [ 52%]
tests/test_flux_analysis/test_gapfilling.py .                                                                                                         [ 52%]
tests/test_flux_analysis/test_helpers.py ...                                                                                                          [ 52%]
tests/test_flux_analysis/test_loopless.py .......                                                                                                     [ 54%]
tests/test_flux_analysis/test_phenotype_phase_plane.py ......                                                                                         [ 54%]
tests/test_flux_analysis/test_variability.py .......                                                                                                  [ 55%]
tests/test_io/test_annotation.py ..                                                                                                                   [ 56%]
tests/test_io/test_annotation_format.py ..                                                                                                            [ 56%]
tests/test_io/test_io_order.py ...........................                                                                                            [ 60%]
tests/test_io/test_json.py ....                                                                                                                       [ 61%]
tests/test_io/test_mat.py ...............                                                                                                             [ 63%]
tests/test_io/test_notes.py .                                                                                                                         [ 63%]
tests/test_io/test_pickle.py ..                                                                                                                       [ 63%]
tests/test_io/test_sbml.py .ssss............xxxx.x.x..s.............                                                                                  [ 70%]
tests/test_io/test_yaml.py .x                                                                                                                         [ 70%]
tests/test_io/test_web/test_load.py .......                                                                                                           [ 71%]
tests/test_manipulation/test_annotate.py .                                                                                                            [ 71%]
tests/test_manipulation/test_delete.py .......                                                                                                        [ 72%]
tests/test_manipulation/test_modify.py ...                                                                                                            [ 72%]
tests/test_manipulation/test_validate.py ..                                                                                                           [ 73%]
tests/test_medium/test_boundary_types.py .........                                                                                                    [ 74%]
tests/test_medium/test_minimal_medium.py ..........                                                                                                   [ 76%]
tests/test_sampling/test_achr.py ......                                                                                                               [ 77%]
tests/test_sampling/test_optgp.py ......                                                                                                              [ 77%]
tests/test_sampling/test_sampling.py ..........                                                                                                       [ 79%]
tests/test_summary/test_metabolite_summary.py .................                                                                                       [ 81%]
tests/test_summary/test_model_summary.py ...............                                                                                              [ 84%]
tests/test_summary/test_reaction_summary.py ...........                                                                                               [ 85%]
tests/test_summary/test_metabolite_summary.py .................                                                                                       [ 88%]
tests/test_summary/test_model_summary.py ...............                                                                                              [ 90%]
tests/test_summary/test_reaction_summary.py ....................                                                                                      [ 93%]
tests/test_util/test_array.py ..                                                                                                                      [ 93%]
tests/test_util/test_context.py ...                                                                                                                   [ 94%]
tests/test_util/test_process_pool.py ...............                                                                                                  [ 96%]
tests/test_util/test_solver.py ...................                                                                                                    [ 99%]
tests/test_util/test_util.py ....                                                                                                                     [100%]

===================================================================== warnings summary ======================================================================
../optlang/src/optlang/matrix_interface.py:60
  /home/cdiener/code/optlang/src/optlang/matrix_interface.py:60: DeprecationWarning: invalid escape sequence '\m'
    """A representation of the convex optimizatgion problem in standard form.

tests/test_core/test_gpr.py::test_and_gpr[a AND b-2-gpr_genes2-a and b]
tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_and_b_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists0]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists1]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists2]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists3]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'a AND b'.
    warn(

tests/test_core/test_gpr.py::test_or_gpr[a OR b-2-gpr_genes2-a or b]
tests/test_core/test_gpr.py::test_gpr_as_symbolic_boolean[a OR b-symbolic_gpr2]
tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_or_b_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists0]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists4]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists5]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists6]
tests/test_core/test_gpr.py::test_gpr_from_symbolic[a OR b-symbolic_gpr5]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'a OR b'.
    warn(

tests/test_core/test_gpr.py::test_complicated_gpr[(a OR b) AND c]
tests/test_core/test_gpr.py::test_gpr_as_symbolic_boolean[(a OR b) AND c-symbolic_gpr6]
tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_b_c_or_and_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists3]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists6]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists8]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists9]
tests/test_core/test_gpr.py::test_gpr_from_symbolic[(a OR b) AND c-symbolic_gpr9]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule '(a OR b) AND c'.
    warn(

tests/test_core/test_gpr.py::test_gpr_that_needs_two_replacements
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule '(591001.3.peg.1891 AND 591001.3.peg.1892 AND 591001.3.peg.1893)'.
    warn(

tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_and_b_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists0]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists1]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists2]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists3]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'b AND a'.
    warn(

tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_or_b_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists0]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists4]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists5]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists6]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'b OR a'.
    warn(

tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_b_c_or_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists1]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists4]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists7]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists8]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'a OR b or c'.
    warn(

tests/test_core/test_gpr.py::test_gpr_equality_with_bolean_logic[a_b_c_and_strs]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists2]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists5]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists7]
tests/test_core/test_gpr.py::test_gpr_inequality_boolean[gpr_lists9]
  /home/cdiener/code/cobrapy/src/cobra/core/gene.py:358: SyntaxWarning: Uppercase AND/OR found in rule 'a AND b and c'.
    warn(

tests/test_core/test_model.py::test_reaction_delete
tests/test_core/test_model.py::test_reaction_delete
  /home/cdiener/code/cobrapy/src/cobra/core/reaction.py:879: DeprecationWarning: delete is deprecated. Use reaction.remove_from_model instead
    warn(

tests/test_core/test_model.py::test_group_loss_of_elements
tests/test_flux_analysis/test_gapfilling.py::test_gapfilling
  /home/cdiener/code/cobrapy/src/cobra/core/group.py:147: UserWarning: need to pass in a list
    warn("need to pass in a list")

tests/test_core/test_model.py::test_change_objective
tests/test_core/test_model.py::test_change_objective
tests/test_core/test_model.py::test_change_objective
  /home/cdiener/code/cobrapy/src/cobra/core/reaction.py:761: DeprecationWarning: Please use reaction.flux instead.
    warn("Please use reaction.flux instead.", DeprecationWarning)

tests/test_io/test_json.py: 6 warnings
tests/test_io/test_mat.py: 14 warnings
tests/test_io/test_pickle.py: 2 warnings
tests/test_io/test_sbml.py: 18 warnings
tests/test_io/test_yaml.py: 2 warnings
  /home/cdiener/code/cobrapy/src/cobra/util/solver.py:554: UserWarning: Solver status is 'infeasible'.
    warn(f"Solver status is '{status}'.", UserWarning)

tests/test_medium/test_minimal_medium.py: 338 warnings
  /home/cdiener/code/cobrapy/src/cobra/medium/minimal_medium.py:112: FutureWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
    medium = pd.Series()

tests/test_util/test_process_pool.py::test_with_context
  /home/cdiener/code/cobrapy/src/cobra/util/process_pool.py:72: PytestMockWarning: Mocks returned by pytest-mock do not need to be used as context managers. The mocker fixture automatically undoes mocking at the end of a test. This warning can be ignored if it was triggered by mocking a context manager. https://pytest-mock.readthedocs.io/en/latest/remarks.html#usage-as-context-manager
    self._pool.__enter__()

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

------------------------------------------------------------------------------------------------------------------------------ benchmark: 56 tests -------------------------------------------------------------------------------------------------------------------------------
Name (time in us)                                                       Min                        Max                       Mean                     StdDev                     Median                        IQR            Outliers           OPS            Rounds  Iterations
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_subtract_metabolite_benchmark[glpk]                             2.2940 (1.0)              41.6790 (1.75)              2.7088 (1.0)               1.6004 (1.36)              2.5470 (1.0)               0.2420 (1.0)        62;217  369,171.1731 (1.0)        5147           1
test_subtract_metabolite_benchmark[gurobi]                           2.3040 (1.00)             23.8300 (1.0)               3.1370 (1.16)              1.2766 (1.08)              2.7490 (1.08)              0.3728 (1.54)      547;745  318,776.9995 (0.86)       5171           1
test_subtract_metabolite_benchmark[cplex]                            2.3270 (1.01)             29.6590 (1.24)              3.0719 (1.13)              1.1784 (1.0)               2.8710 (1.13)              0.4440 (1.83)      161;264  325,527.3538 (0.88)       4861           1
test_change_objective_benchmark[optlang-glpk]                       93.7590 (40.87)         1,045.8220 (43.89)           115.6829 (42.71)            40.7843 (34.61)           105.6195 (41.47)            17.7575 (73.38)     393;602    8,644.3185 (0.02)       6488           1
test_change_objective_benchmark[optlang-cplex]                     167.4180 (72.98)           664.0410 (27.87)           198.0228 (73.10)            68.6797 (58.28)           172.5510 (67.75)            31.7868 (131.35)        5;7    5,049.9224 (0.01)         71           1
test_achr_sample_benchmark                                         285.6440 (124.52)       12,066.5810 (506.36)          613.6580 (226.54)        1,518.5459 (>1000.0)         417.2535 (163.82)          136.0595 (562.23)        8;9    1,629.5722 (0.00)        336           1
test_optgp_sample_benchmark                                        318.7220 (138.94)        1,453.9940 (61.02)           439.3567 (162.20)          123.3586 (104.68)          380.6855 (149.46)          252.9545 (>1000.0)     292;1    2,276.0552 (0.01)       1028           1
test_loopless_benchmark_after                                      856.9130 (373.55)        1,914.0690 (80.32)           932.6770 (344.32)           89.8059 (76.21)           912.2280 (358.16)           57.6123 (238.07)      48;42    1,072.1825 (0.00)        835           1
test_loopless_benchmark_before                                     982.1810 (428.15)        2,895.7210 (121.52)        1,125.2880 (415.42)          148.0538 (125.64)        1,084.9300 (425.96)           71.4895 (295.41)      46;50      888.6614 (0.00)        543           1
test_minimal_medium_mip_benchmark                                5,000.9720 (>1000.0)      11,344.0710 (476.04)        5,979.3052 (>1000.0)       1,010.8075 (857.75)        5,577.5295 (>1000.0)         605.6295 (>1000.0)     16;16      167.2435 (0.00)        152           1
test_minimal_medium_linear_benchmark                             5,014.5100 (>1000.0)      13,586.2740 (570.13)        6,196.1172 (>1000.0)       1,249.0836 (>1000.0)       5,673.4300 (>1000.0)       1,269.3137 (>1000.0)     22;10      161.3914 (0.00)        171           1
test_copy_benchmark[optlang-glpk]                                7,775.1690 (>1000.0)     233,973.5810 (>1000.0)      12,314.2383 (>1000.0)      22,097.1067 (>1000.0)      10,021.4950 (>1000.0)       1,900.2120 (>1000.0)       1;1       81.2068 (0.00)        103           1
test_copy_benchmark[optlang-cplex]                               8,192.3830 (>1000.0)     188,663.0290 (>1000.0)      14,563.4414 (>1000.0)      27,913.1416 (>1000.0)      10,097.4170 (>1000.0)       1,617.4582 (>1000.0)       1;3       68.6651 (0.00)         41           1
test_deepcopy_benchmark                                         14,818.1790 (>1000.0)     341,512.8770 (>1000.0)      22,460.2896 (>1000.0)      40,571.6102 (>1000.0)      17,043.4845 (>1000.0)       1,779.8940 (>1000.0)       1;5       44.5230 (0.00)         64           1
test_gpr_equality_benchmark                                     19,512.2750 (>1000.0)      27,561.2190 (>1000.0)      20,760.3585 (>1000.0)       1,596.3958 (>1000.0)      20,329.4905 (>1000.0)       1,003.6905 (>1000.0)       5;5       48.1687 (0.00)         44           1
test_single_reaction_deletion_benchmark[glpk]                   24,949.6810 (>1000.0)      39,783.2670 (>1000.0)      28,757.6977 (>1000.0)       4,220.5987 (>1000.0)      26,283.3280 (>1000.0)       6,584.3122 (>1000.0)       7;0       34.7733 (0.00)         35           1
test_fastcc_benchmark[cplex]                                    26,375.8290 (>1000.0)      29,994.9120 (>1000.0)      27,830.2230 (>1000.0)         960.0516 (814.68)       27,425.7610 (>1000.0)       1,428.6313 (>1000.0)       8;0       35.9322 (0.00)         31           1
test_fastcc_benchmark[glpk]                                     27,192.8950 (>1000.0)      36,070.9660 (>1000.0)      30,657.0597 (>1000.0)       2,188.4312 (>1000.0)      30,429.1620 (>1000.0)       3,345.3580 (>1000.0)      13;0       32.6189 (0.00)         32           1
test_single_gene_deletion_moma_benchmark[cplex]                 27,316.7860 (>1000.0)      40,653.3360 (>1000.0)      29,405.6284 (>1000.0)       2,388.0167 (>1000.0)      28,958.4930 (>1000.0)       1,984.2020 (>1000.0)       2;1       34.0071 (0.00)         32           1
test_single_gene_deletion_linear_moma_benchmark[glpk]           29,020.0350 (>1000.0)      42,259.8270 (>1000.0)      32,428.5570 (>1000.0)       2,789.7775 (>1000.0)      31,926.0450 (>1000.0)       3,058.6935 (>1000.0)       9;1       30.8370 (0.00)         29           1
test_single_gene_deletion_linear_room_benchmark[cplex]          29,797.8000 (>1000.0)      36,418.9160 (>1000.0)      31,571.9718 (>1000.0)       1,871.9644 (>1000.0)      30,884.4510 (>1000.0)       1,969.3680 (>1000.0)       4;2       31.6737 (0.00)         26           1
test_single_gene_deletion_linear_room_benchmark[glpk]           30,084.9770 (>1000.0)      40,439.0320 (>1000.0)      31,899.7990 (>1000.0)       2,381.5916 (>1000.0)      31,442.5100 (>1000.0)       1,983.5260 (>1000.0)       2;2       31.3482 (0.00)         34           1
test_single_gene_deletion_linear_moma_benchmark[cplex]          30,318.9700 (>1000.0)      47,109.7660 (>1000.0)      34,200.8932 (>1000.0)       4,610.8317 (>1000.0)      32,318.3530 (>1000.0)       4,807.6578 (>1000.0)       2;2       29.2390 (0.00)         25           1
test_single_reaction_deletion_benchmark[cplex]                  39,403.7990 (>1000.0)      42,882.9550 (>1000.0)      40,963.0930 (>1000.0)         860.1422 (729.90)       40,812.3240 (>1000.0)         989.7122 (>1000.0)       5;0       24.4122 (0.00)         23           1
test_fastcc_benchmark[hybrid]                                   45,097.8010 (>1000.0)      48,174.6180 (>1000.0)      46,268.7677 (>1000.0)         844.4191 (716.55)       46,235.3120 (>1000.0)       1,249.0205 (>1000.0)       7;0       21.6129 (0.00)         19           1
test_add_metabolite_benchmark[glpk]                             47,883.7340 (>1000.0)      52,183.0690 (>1000.0)      49,432.3566 (>1000.0)       1,124.5969 (954.31)       49,502.9490 (>1000.0)       1,613.4523 (>1000.0)       8;0       20.2297 (0.00)         21           1
test_add_metabolite_benchmark[cplex]                            47,917.3350 (>1000.0)      54,370.6840 (>1000.0)      49,333.9763 (>1000.0)       1,511.0800 (>1000.0)      48,942.5195 (>1000.0)         969.4290 (>1000.0)       2;2       20.2700 (0.00)         18           1
test_add_metabolite_benchmark[gurobi]                           48,237.0580 (>1000.0)      52,046.7320 (>1000.0)      49,559.0800 (>1000.0)       1,070.3856 (908.30)       49,126.7300 (>1000.0)       1,229.6935 (>1000.0)       5;1       20.1779 (0.00)         20           1
test_flux_variability_benchmark[cplex]                          62,572.2430 (>1000.0)      67,038.3950 (>1000.0)      63,772.4243 (>1000.0)       1,536.4200 (>1000.0)      63,433.0310 (>1000.0)       1,197.2452 (>1000.0)       1;1       15.6808 (0.00)          7           1
test_pfba_benchmark[cplex]                                      69,373.4100 (>1000.0)      72,500.4950 (>1000.0)      70,726.8981 (>1000.0)       1,150.6451 (976.41)       70,255.0820 (>1000.0)       1,765.2030 (>1000.0)       3;0       14.1389 (0.00)          7           1
test_single_gene_deletion_fba_benchmark[glpk]                   71,984.7330 (>1000.0)     101,895.6180 (>1000.0)      84,120.6408 (>1000.0)      10,542.5950 (>1000.0)      81,724.0980 (>1000.0)      17,880.6290 (>1000.0)       5;0       11.8877 (0.00)         13           1
test_flux_variability_loopless_benchmark[glpk]                  87,341.3150 (>1000.0)      98,250.1150 (>1000.0)      92,035.9655 (>1000.0)       3,734.7568 (>1000.0)      92,681.6800 (>1000.0)       6,607.9350 (>1000.0)       4;0       10.8653 (0.00)         10           1
test_single_gene_deletion_linear_moma_benchmark[hybrid]         89,488.5290 (>1000.0)      98,569.1990 (>1000.0)      93,464.3613 (>1000.0)       3,368.9686 (>1000.0)      92,577.7580 (>1000.0)       6,140.8090 (>1000.0)       4;0       10.6993 (0.00)         10           1
test_single_gene_deletion_linear_room_benchmark[hybrid]         89,873.4130 (>1000.0)     111,261.5240 (>1000.0)      99,264.7753 (>1000.0)       7,729.0775 (>1000.0)      96,084.0400 (>1000.0)      11,888.2920 (>1000.0)       3;0       10.0741 (0.00)          9           1
test_single_gene_deletion_fba_benchmark[cplex]                  94,007.7240 (>1000.0)     125,803.0550 (>1000.0)     109,609.7511 (>1000.0)       9,708.6572 (>1000.0)     109,267.7025 (>1000.0)      10,994.1460 (>1000.0)       4;0        9.1233 (0.00)         10           1
test_flux_variability_loopless_benchmark[cplex]                101,279.8200 (>1000.0)     127,426.1190 (>1000.0)     115,119.6169 (>1000.0)       8,934.3517 (>1000.0)     115,994.7180 (>1000.0)      15,209.3568 (>1000.0)       5;0        8.6866 (0.00)         11           1
test_single_gene_deletion_fba_benchmark[hybrid]                108,592.5740 (>1000.0)     128,052.1530 (>1000.0)     114,276.8117 (>1000.0)       6,564.1222 (>1000.0)     112,137.3330 (>1000.0)       6,858.0570 (>1000.0)       2;1        8.7507 (0.00)          9           1
test_achr_init_benchmark                                       111,644.4430 (>1000.0)     259,542.5750 (>1000.0)     189,091.9971 (>1000.0)      40,641.7804 (>1000.0)     188,813.5120 (>1000.0)      28,185.8560 (>1000.0)       3;2        5.2884 (0.00)         10           1
test_flux_variability_loopless_benchmark[hybrid]               137,303.4070 (>1000.0)     172,634.0580 (>1000.0)     144,482.7328 (>1000.0)      11,939.1357 (>1000.0)     138,924.5685 (>1000.0)       7,516.0970 (>1000.0)       1;1        6.9212 (0.00)          8           1
test_geometric_fba_benchmark[cplex]                            159,985.5510 (>1000.0)     177,495.7960 (>1000.0)     164,643.3833 (>1000.0)       6,773.4833 (>1000.0)     162,194.5010 (>1000.0)       5,778.3530 (>1000.0)       1;1        6.0737 (0.00)          6           1
test_gpr_symbolism_benchmark                                   160,644.6840 (>1000.0)     167,942.6390 (>1000.0)     164,815.3687 (>1000.0)       2,588.9621 (>1000.0)     164,865.6390 (>1000.0)       3,398.7670 (>1000.0)       2;0        6.0674 (0.00)          6           1
test_double_gene_deletion_benchmark                            167,696.1570 (>1000.0)     175,797.2720 (>1000.0)     172,594.0390 (>1000.0)       3,088.6810 (>1000.0)     173,200.2620 (>1000.0)       3,847.0258 (>1000.0)       2;0        5.7939 (0.00)          5           1
test_pfba_benchmark[glpk]                                      172,922.4480 (>1000.0)     183,506.8040 (>1000.0)     178,845.3286 (>1000.0)       3,971.8920 (>1000.0)     179,071.5260 (>1000.0)       5,179.9003 (>1000.0)       2;0        5.5914 (0.00)          5           1
test_optgp_init_benchmark                                      181,274.1330 (>1000.0)     295,439.2900 (>1000.0)     248,008.1180 (>1000.0)      47,964.6059 (>1000.0)     257,072.5880 (>1000.0)      80,119.2250 (>1000.0)       1;0        4.0321 (0.00)          5           1
test_geometric_fba_benchmark[glpk]                             190,243.9940 (>1000.0)     205,950.4770 (>1000.0)     198,127.5766 (>1000.0)       7,351.6281 (>1000.0)     199,338.0600 (>1000.0)      14,028.5838 (>1000.0)       2;0        5.0473 (0.00)          5           1
test_copy_benchmark_large_model[optlang-cplex]                 200,014.1030 (>1000.0)     479,692.8340 (>1000.0)     260,174.3876 (>1000.0)     122,820.0532 (>1000.0)     209,061.5160 (>1000.0)      78,163.3175 (>1000.0)       1;1        3.8436 (0.00)          5           1
test_copy_benchmark_large_model[optlang-glpk]                  201,319.6950 (>1000.0)     431,441.0280 (>1000.0)     261,893.3830 (>1000.0)      96,839.3568 (>1000.0)     217,140.3780 (>1000.0)      91,585.1513 (>1000.0)       1;0        3.8183 (0.00)          5           1
test_pfba_benchmark[hybrid]                                    203,952.2130 (>1000.0)     569,494.7990 (>1000.0)     288,143.9220 (>1000.0)     157,503.4885 (>1000.0)     223,132.0900 (>1000.0)      96,671.7515 (>1000.0)       1;1        3.4705 (0.00)          5           1
test_single_reaction_deletion_benchmark[hybrid]                221,182.8530 (>1000.0)     244,393.6030 (>1000.0)     230,863.3204 (>1000.0)       8,749.2173 (>1000.0)     231,146.5540 (>1000.0)      10,639.3385 (>1000.0)       2;0        4.3316 (0.00)          5           1
test_single_gene_deletion_moma_benchmark[hybrid]               299,807.7240 (>1000.0)     307,206.4760 (>1000.0)     303,496.1998 (>1000.0)       2,679.2733 (>1000.0)     303,887.6140 (>1000.0)       2,964.3612 (>1000.0)       2;0        3.2949 (0.00)          5           1
test_flux_variability_benchmark[glpk]                          346,637.4510 (>1000.0)     362,749.8540 (>1000.0)     356,306.9624 (>1000.0)       6,185.9668 (>1000.0)     356,477.0300 (>1000.0)       7,904.1225 (>1000.0)       2;0        2.8066 (0.00)          5           1
test_double_reaction_deletion_benchmark                        539,117.0300 (>1000.0)     560,762.3910 (>1000.0)     550,230.1016 (>1000.0)       8,060.1946 (>1000.0)     551,997.7410 (>1000.0)      10,341.8253 (>1000.0)       2;0        1.8174 (0.00)          5           1
test_geometric_fba_benchmark[hybrid]                         1,105,175.6980 (>1000.0)   1,346,059.5970 (>1000.0)   1,254,707.5488 (>1000.0)      93,848.3047 (>1000.0)   1,252,914.2670 (>1000.0)     115,573.2593 (>1000.0)       1;0        0.7970 (0.00)          5           1
test_flux_variability_benchmark[hybrid]                      4,693,848.6870 (>1000.0)   5,364,513.7700 (>1000.0)   5,148,930.4578 (>1000.0)     280,675.3526 (>1000.0)   5,292,484.2370 (>1000.0)     369,828.9155 (>1000.0)       1;0        0.1942 (0.00)          5           1
test_single_gene_deletion_room_benchmark[cplex]              7,970,187.0850 (>1000.0)   8,966,477.0290 (>1000.0)   8,280,201.4938 (>1000.0)     422,268.7731 (>1000.0)   8,078,233.4040 (>1000.0)     567,589.4288 (>1000.0)       1;0        0.1208 (0.00)          5           1
test_single_gene_deletion_room_benchmark[hybrid]            39,582,174.2460 (>1000.0)  95,114,824.2720 (>1000.0)  69,713,440.2258 (>1000.0)  20,431,416.8946 (>1000.0)  73,131,111.6930 (>1000.0)  24,705,340.6650 (>1000.0)       2;0        0.0143 (0.00)          5           1
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
=========================================== 649 passed, 11 skipped, 10 xfailed, 432 warnings in 699.26s (0:11:39) ===========================================

@Midnighter
Copy link
Member

Could you elaborate a little on the pros/cons of creating a separate HIGHS interface compared to a combined one? I don't find the fact that it is not suitable for very large problems concerning, since presumably MICOM users would know to use the OSQP interface?

I don't think that the fact that this interface is slower than CPLEX & Gurobi is a problem. It would still be the only open source MILP solver that we have available in optlang. This would be extremely helpful for the memote webservice, for example, where we had to disable the MILPs.

In summary, I'm not sure about splitting the interfaces but I definitely would like to have them ❤️.

@cdiener
Copy link
Member Author

cdiener commented Sep 15, 2023

Could you elaborate a little on the pros/cons of creating a separate HIGHS interface compared to a combined one? I don't find the fact that it is not suitable for very large problems concerning, since presumably MICOM users would know to use the OSQP interface?

Sorry I wasn't clear here. I think there should be a HIGHS interface in optlang regardless. HIGHS is a great solver and it has another API (somewhat reminiscent of the GLPK API) that would fit well with optlang and be more efficient in terms of basis reuse and getting solution values. The QP solver in HIGHS is also pretty good for decent size problem (thousands of vars).

OSQP is great for QPs but can't solve LPs well, which leads to issues in settings where you need to do both within the same interface. That applies to MICOM but also other examples (MOMA in COBRAPY is another example). So this combines OSQP with HIGHS to cover all bases. Maybe it should even replace the OSQP interface since it would still retain all functionality but would provide an excellent LP/MILP fallback in the same interface as well... 🤔 If that is not a good fit I cold also just add it to MICOM though.

I don't think that the fact that this interface is slower than CPLEX & Gurobi is a problem. It would still be the only open source MILP solver that we have available in optlang. This would be extremely helpful for the memote webservice, for example, where we had to disable the MILPs.

I mean GLPK has a MILP solver, it just struggles with certain types of problems. Which specific MILPs are you running in MEMOTE? I could benchmark some with my COBRAPY branch that has the interface enabled to see if it would be helpful there.

In summary, I'm not sure about splitting the interfaces but I definitely would like to have them ❤️.

Yeah they will definitely both be in optlang eventually. I do want to get on the HIGHS interface as well but it might take a bit longer since it would have to be coded from the ground up and there are more methods to overwrite.

@Midnighter
Copy link
Member

Okay, from my understanding of your description, it sounds like it might be best to have one combined HIGHS-OSQP interface and a separate HIGHS interface.

With regard to MEMOTE, there are a couple of MILP in the test_stoichiometry module. There is also the paper reference in the docstrings if you want to read the source. GLPK does very poorly at those. Can easily take hours whereas CPLEX/Gurobi finish in about a minute.

@cdiener
Copy link
Member Author

cdiener commented Sep 15, 2023

Okay perfect, I'll change it into that then.

@cdiener
Copy link
Member Author

cdiener commented Sep 15, 2023

The only MIPs I found in memote for now where find_unconserved_metabolites and find_inconsistent_min_stoichiometry. Running those on iJO1366 cplex and highs were pretty much equally fast. Though, all returned empty sets so maybe should be benchmarked with a problem that has some inconsistencies.

In [10]: mod = load_model("iJO1366")

In [11]: modhy = mod.copy()

In [12]: modhy.solver.configuration.qp_method = "auto"

In [13]: modhy.solver.configuration.lp_method = "auto"

In [14]: modhy.solver = "hybrid"

In [15]: %time find_unconserved_metabolites(mod)
CPU times: user 2.06 s, sys: 6.33 ms, total: 2.06 s
Wall time: 1.99 s
Out[15]: set()

In [16]: %time find_unconserved_metabolites(modhy)
CPU times: user 2.24 s, sys: 7.73 ms, total: 2.25 s
Wall time: 2.25 s
Out[16]: set()

In [17]: from memote.support.consistency import *

In [18]: %time find_inconsistent_min_stoichiometry(mod)
CPU times: user 1.81 s, sys: 0 ns, total: 1.81 s
Wall time: 1.81 s
Out[18]: set()

In [19]: %time find_inconsistent_min_stoichiometry(modhy)
CPU times: user 1.65 s, sys: 3.24 ms, total: 1.65 s
Wall time: 1.65 s
Out[19]: set()

@Midnighter
Copy link
Member

Something like Recon3D is probably the biggest that we have. Super cool to hear about the comparable speed ✌🏼

@cdiener
Copy link
Member Author

cdiener commented Sep 18, 2023

Something like Recon3D is probably the biggest that we have. Super cool to hear about the comparable speed ✌🏼

Same for Recon3, just takes around 9s for either, but again there are no violations, so I could imagine that it is different for models with actual inconsistencies.

@cdiener cdiener changed the title [proposal] add a hybrid HIGHS/OSQP solver interface Replace OSQP with a hybrid HIGHS/OSQP solver interface Sep 18, 2023
@Midnighter
Copy link
Member

Oh yeah, if there are none, then it is a very fast MILP.

@cdiener
Copy link
Member Author

cdiener commented Oct 20, 2023

I would probably be inclined to pull this by November 14 (2 month wait) if I get no reviews because it is high priority for us. It is tested pretty extensively now and avoids returning astonishingly wrong/non-optimal LP solutions in the OSQP interface.

@Midnighter
Copy link
Member

By pull, you mean merge? I'm sorry, I didn't realize you were waiting on me. I thought you were still making modifications.

@cdiener
Copy link
Member Author

cdiener commented Oct 21, 2023

Yep I meant merge. It has been done for a while. I fixed some edge cases that came up testing some larger models, but it has been done for a while .

Copy link
Member

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

The logger knows how to format tracebacks if you pass it an exception instance. Otherwise looks good to me!

src/optlang/__init__.py Outdated Show resolved Hide resolved
@cdiener
Copy link
Member Author

cdiener commented Oct 23, 2023

Thank you!

@cdiener cdiener merged commit f934e6f into opencobra:master Oct 23, 2023
13 checks passed
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