Repository navigation
Local_Install
You can use the hosted web app at https://scen-opt.woodingben.com without installing anything. Run Scen-Opt on your own machine when:
- your problems take a long time to solve (on the hosted app, a solve that runs for more than 30 s shows a note that links to this page);
- your data must not leave your computer;
- you need solvers that are not installed on the server;
- you want to use the Python API.
There are two ways to run it locally:
- Option 1: Python, from a clone of the repository;
- Option 2: Docker, which needs no Python setup.
-
Python 3.10 or newer; 3.12 is recommended. The Docker image (
python:3.12-slim) and the CI test workflow both use 3.12. The examples on this wiki were also run with Python 3.10. -
gitandpip. - On minimal Linux systems, a compiler toolchain may be needed if a package has no prebuilt wheel for your platform. The Dockerfile installs
gcc,g++,gfortran,libopenblas-dev,gitandcmakefor this purpose.
Scen-Opt is not a pip-installable package. You clone the repository and run it from the cloned folder.
macOS / Linux:
git clone https://github.com/Kiguli/Scen-Opt.git
cd Scen-Opt
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txtWindows (PowerShell):
git clone https://github.com/Kiguli/Scen-Opt.git
cd Scen-Opt
py -3.12 -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txtrequirements.txt pins the exact versions it installs, including:
| Purpose | Packages |
|---|---|
| Optimization modelling | CVXPY 1.7.2 |
| Web server | Flask 3.1.3 |
| Risk-bound computation | JAX / jaxlib 0.6.2 |
| Numerics | NumPy 2.2.6, SciPy 1.15.3 |
| File formats | pandas, openpyxl (Excel), pyarrow (Parquet) |
| Solvers | CLARABEL, OSQP, SCS, and the MOSEK Python package (Mosek==11.0.28) |
The MOSEK package is installed by default, but MOSEK only works with a licence. See MOSEK licence below.
pip install -r requirements-solvers.txtThis installs further open-source solver packages (unpinned): cvxopt, ecos, piqp, proxsuite, highspy and daqp. The Docker image includes them. You can also install any other solver that CVXPY supports, following the CVXPY solver documentation.
To see which solvers CVXPY finds:
python -c "import cvxpy as cp; print(cp.installed_solvers())"With only requirements.txt installed, this prints ['CLARABEL', 'MOSEK', 'OSQP', 'SCIPY', 'SCS']. The web interface lists the same solvers, filtered by the active tab:
| Tab | Solvers offered (only requirements.txt installed) |
|---|---|
| LP | CLARABEL, MOSEK, SCIPY, SCS |
| QP | CLARABEL, MOSEK, OSQP, SCS |
| SDP | CLARABEL, MOSEK, SCS |
SCIPY solves LPs only and OSQP solves QPs only. Neither can handle the second-order or power cone that the regularization term adds for inf, both are offered. CLARABEL is the first entry and is selected by default. See Miscellaneous.py for how the list is built.
MOSEK is the recommended solver: it is the most stable for these problems, and all published results were computed with it. It is a commercial solver. Academic licences are free; see mosek.com/products/academic-licenses. There are three ways to give Scen-Opt a licence:
-
In the web interface. When MOSEK is selected and you press Solve, a MOSEK License Required dialog opens. It has two options:
-
Upload & Solve. Choose your
mosek.licfile. The server writes it to a temporary directory and runs the solve in a separate Python process that reads the licence from there. That process runs the same solve code as every other solve, so the results are reported in the same way. The directory is deleted afterwards. The browser keeps the licence in session storage, so later solves in the same session skip the dialog. While a licence is cached, a "mosek.lic cached" badge with a × Clear button appears under the solver menu. -
I have a local license. Nothing is uploaded. MOSEK looks for a licence in its usual places: the default location
~/mosek/mosek.lic, or the file named by theMOSEKLM_LICENSE_FILEenvironment variable of the process that started the server.
-
Upload & Solve. Choose your
-
From Python. MOSEK uses the same default location or
MOSEKLM_LICENSE_FILE. - With Docker. See Docker and MOSEK below.
If MOSEK cannot find a valid licence, the solve does not stop with a crash. Instead, the Error row of the results table shows MOSEK license cannot be located or is incorrect.
python app.pyThen open http://127.0.0.1:5000 in a browser.
- This command starts Flask's development server in debug mode. The server listens only on
127.0.0.1. - Stop it with
Ctrl+C.
To use a different port, run:
flask --app app run --port 5001Then open http://127.0.0.1:5001. With this command, debug mode is off.
macOS note. The AirPlay Receiver service also listens on port 5000. On a test machine,
http://localhost:5000reached AirPlay (HTTP 403 Forbidden) andhttp://127.0.0.1:5000reached Scen-Opt. If you see a 403 page, do one of the following:
- use
127.0.0.1instead oflocalhost;- start Scen-Opt on another port;
- turn off AirPlay Receiver in System Settings.
The development server is meant for one user on one machine. To serve Scen-Opt to other people, use a production WSGI server. The Docker image runs Gunicorn with the equivalent of the following command (install it first with pip install gunicorn):
gunicorn --bind 0.0.0.0:5000 --workers 2 --timeout 7200 app:appThe long timeout of 7200 s (two hours) is there because a single solve can take a long time.
From the repository root:
pip install pytest
python -m pytest tests/ -vpyproject.toml sets the test path and puts the repository root on the Python path. At the time of writing, the suite has 82 tests and took about 25 s on a laptop; most of that time is spent in the solvers. GitHub Actions runs the tests on Python 3.12 for every push and pull request.
Each folder under benchmarks/ has a run.py that solves the problem and prints the results. For example:
cd benchmarks/LP_half_width_2d
python run.py # solve with MOSEK (the default) and print the results
python run.py --solver CLARABEL # solve with another installed solver
python plot.py # draw the figure (needs matplotlib)-
Choosing the solver. Every
run.pytakes--solver(defaultMOSEK, which produced the published results). Without a MOSEK licence, pass another installed solver, e.g.--solver CLARABEL. With CLARABEL,LP_half_width_2d/run.pyreproduces the published numbers: half-width 0.498310,$k = 2$ , risk bounds [0.0000, 0.2085] at 99.9999% confidence. -
run.pyoverwrites the committed results. It writesresults/metrics.jsonandresults/solution.csv. -
Some scripts need extra packages that
requirements.txtdeliberately does not include. Each script names them in a comment at the top, with thepip installcommand:- every
plot.py,plot_data_only.pyandanimate.pyneedsmatplotlib; - the
generate.pyscripts of the Wine and Breast Cancer benchmarks (SDP_covariance_wine_15d,SDP_ellipsoid_enclosure_15d) needscikit-learn; - the Portfolio benchmark's
generate.pyneedsyfinance; - the Radiation Therapy benchmark's
generate.pyneedsmat73.
- every
You do not need to run the scripts to use a benchmark in the web interface. Each data/ folder has ready-to-upload program files; see First Example: Web Interface.
You need Docker installed.
docker run -p 5000:5000 ghcr.io/kiguli/scen-opt:latestThen open http://localhost:5000 (on macOS, http://127.0.0.1:5000; see the note above).
Image tags:
| Tag | Contents |
|---|---|
latest |
The current master branch |
v1.0, and so on |
One tag per release. Use a release tag for an exact, reproducible version, e.g. docker run -p 5000:5000 ghcr.io/kiguli/scen-opt:v1.0. |
Platform. The published image is built for both linux/amd64 (x86_64) and linux/arm64, so it runs natively on ARM machines such as Apple-silicon Macs. No --platform flag is needed.
What the image contains:
- the web app:
app.py,src/,templates/andstatic/; - the packages from
requirements.txtandrequirements-solvers.txt, plus Gunicorn.
It does not contain the benchmarks/ or tests/ folders. Download benchmark files from the repository to upload them.
docker run -p 8080:5000 ghcr.io/kiguli/scen-opt:latestThen open http://localhost:8080.
Mount your licence file at the default MOSEK location inside the container:
docker run -p 5000:5000 \
-v /path/to/mosek.lic:/home/appuser/mosek/mosek.lic:ro \
ghcr.io/kiguli/scen-opt:latestWhen the licence dialog appears, choose I have a local license. Alternatively, upload the licence through the dialog as described above.
The image starts Gunicorn with 2 workers, set through the environment variable GUNICORN_CMD_ARGS="--workers 2". To use more, override that variable:
docker run -p 5000:5000 -e GUNICORN_CMD_ARGS="--workers 4" ghcr.io/kiguli/scen-opt:latestgit clone https://github.com/Kiguli/Scen-Opt.git
cd Scen-Opt
docker build -t scen-opt .
docker run -p 5000:5000 scen-optAfter pulling new changes, run docker build -t scen-opt . again.
- First Example: Web Interface: solve a first problem in the browser.
- First Example: Python Calls: solve the same kind of problem from a Python script.