From 23a3edfbf200026a494823c7d7cdb96f3db7ed9d Mon Sep 17 00:00:00 2001 From: Gleb Belov Date: Thu, 21 Mar 2024 20:22:21 +1100 Subject: [PATCH] ModelExplorer doc #232 --- doc/source/conf.py | 4 +- doc/source/images/ref_explore.png | Bin 0 -> 36452 bytes doc/source/index.rst | 4 + doc/source/modeling-tools.rst | 149 +++++++++++++++++- doc/source/requirements.txt | 3 +- .../scripts/python/modelreader.py | 2 - 6 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 doc/source/images/ref_explore.png diff --git a/doc/source/conf.py b/doc/source/conf.py index f4a901dc9..e2482f1b1 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -15,7 +15,9 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ["breathe", "sphinx.ext.mathjax", "sphinx.ext.graphviz"] +extensions = ["breathe", + "sphinx.ext.mathjax", "sphinx.ext.graphviz", + "sphinx_tabs.tabs"] # Configure Breathe. # When building with CMake, the path to doxyxml is passed via the command line. diff --git a/doc/source/images/ref_explore.png b/doc/source/images/ref_explore.png new file mode 100644 index 0000000000000000000000000000000000000000..df4201ad718883b40cf89f74a56052f08c8cb05a GIT binary patch literal 36452 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
WJ73c2nN4XZLSCp`)iCY%eF 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 YvA--1rFK{vZwE#~`. + Moreover, MP library provides a :ref:`lightweight NL writer `. diff --git a/doc/source/modeling-tools.rst b/doc/source/modeling-tools.rst index ab8a3b417..ad65eef58 100644 --- a/doc/source/modeling-tools.rst +++ b/doc/source/modeling-tools.rst @@ -59,7 +59,7 @@ the following ways. .. _explore-final-model: -Explore the final model +Export the solver model ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To explore the model received by the solver, @@ -81,16 +81,151 @@ Some solvers can export their presolved model: .. _reformulation-graph: -Reformulation graph +Reformulation explorer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The flattening and reformulation graph can be exported -by the ``cvt:writegraph`` option (WIP). +MP provides a tool to explore and compare the model +provided to an MP solver driver in the NL file, and the final model +sent to the underlying solver. -At the moment only arcs are exported. Terminal nodes (variables, constraints, -objectives) can be seen in the NL model (ampl: ``expand``) and the -final flat model (gurobi: option ``tech:writeprob``). +.. image:: images/ref_explore.png + :width: 400 + :align: center + :alt: Reformulation explorer interface +Tool invocation +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use the reformulation explorer online, go to http://ampl.com/streamlit. + +To run locally, download the `MP repository `_. +In subfolder `support/modelexplore`, run the command:: + + streamlit run modelexplore.py + + +Using the explorer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To produce the input data for the tool, containing the reformulations, +run an MP solver with the `writegraph` option, as follows. + +.. tabs:: + + .. tab:: AMPL + + .. code-block:: ampl + + ampl: option solver gurobi; # select solver + ampl: option gurobi_auxfiles rc; # write var/con names + ampl: option gurobi_options 'writegraph=model.jsonl lim:time=0'; + ampl: solve; # solve the problem + + .. tab:: Python + + How to install using `amplpy `_: + + .. code-block:: bash + + # Install Python API for AMPL: + $ python -m pip install amplpy --upgrade + + # Install AMPL & solver modules: + $ python -m amplpy.modules install gurobi # install Gurobi + + # Activate your license (e.g., free ampl.com/ce or ampl.com/courses licenses): + $ python -m amplpy.modules activate + + How to use: + + .. code-block:: python + + from amplpy import AMPL + ampl = AMPL() + ... + ampl.set_option("gurobi_auxfiles", "rc") + ampl.solve(solver="gurobi", gurobi_options="writegraph=graph.jsonl") + + Learn more about what we have to offer to implement and deploy `Optimization in Python `_. + + .. tab:: Other APIs + + `AMPL APIs `_ are interfaces + that allow developers to access the features of the AMPL interpreter + from within a programming language. We have APIs available for: + + - `Python `_ + - `R `_ + - `C++ `_ + - `C#/.NET `_ + - `Java `_ + - `MATLAB `_ + + .. tab:: Command line + + .. code-block:: bash + + auxfiles=rc ampl -obmodel model.mod data.dat + gurobi model.nl writegraph=reformulations.jsonl lim:time=0 + + +In the Explorer, upload the JSONL file. The NL (source) and solver's +(destination) models are displayed. + +.. note:: + The NL model displayed in most cases coincides + with the output of AMPL's `solexpand` command. + + The solver model is equivalent to the solver's exported model + via the `tech:writeprob` option. + +The following operations are possible: + +- *Search for a text pattern*. To display the subsets of the models + containing a certain name, enter that in the 'Search pattern' field. + +- *Download (subsets of) the models*. To download currently + displayed (sub)models, use the download buttons. + + +Example +~~~~~~~~~~~~~~~~~~~~~ + +Consider the following AMPL model. + +.. code-block:: ampl + + var x binary; + var y binary; + var z binary; + minimize TotalSum: z + 1; + subj to C1: x+y >= 1; + subj to C2: x^2+y^2+(z-0.7)^2 <= 1.83; + subj to C3: z==1 ==> x-y <= 2; + +To see the reformulations applied to constraint `C3`, +download the corresponding JSONL file in the Explorer +and enter `C3` in the 'Search pattern' field. For Gurobi, +the resulting subset of the Solver model can be as follows: + +.. code-block:: ampl + + ## Variables (3) + var C3 binary; + var C3_3_ binary; + var C3_5_ = 1; + + ## Constraints '_indle' (1) + C3_4_: C3_3_==1 ==> (1*x - 1*y <= 2); + + ## Constraints '_lineq' (1) + C3_2_: 1*z - 1*C3 == -1; + + ## Constraints '_or' (1) + C3_6_: C3_5_ == OrConstraint([C3, C3_3_], []); + +The constraint types (`_indle`, `_or`, etc.) are as explained +in :ref:`supported-constraints`. .. _solution-check: diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt index 188f51e62..5a43efe0f 100644 --- a/doc/source/requirements.txt +++ b/doc/source/requirements.txt @@ -1 +1,2 @@ -breathe \ No newline at end of file +breathe +sphinx-tabs diff --git a/support/modelexplore/scripts/python/modelreader.py b/support/modelexplore/scripts/python/modelreader.py index 6cb86da44..985b1c352 100644 --- a/support/modelexplore/scripts/python/modelreader.py +++ b/support/modelexplore/scripts/python/modelreader.py @@ -3,8 +3,6 @@ # if __name__ == "__main__": # pass -import streamlit as st - import json from scripts.python.model import Model