Skip to content

Local_Install

Kiguli edited this page Oct 6, 2026 · 4 revisions

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

Requirements

  • 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.
  • git and pip.
  • 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, git and cmake for this purpose.

Scen-Opt is not a pip-installable package. You clone the repository and run it from the cloned folder.

Install

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.txt

Windows (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.txt

requirements.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.

Optional solvers

pip install -r requirements-solvers.txt

This 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 $p \ne 1, \infty$ (including the default $p = 2$). The web interface then hides OSQP on the QP tab and SCIPY on the LP tab; with $p = 1$ or inf, both are offered. CLARABEL is the first entry and is selected by default. See Miscellaneous.py for how the list is built.

MOSEK licence

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.lic file. 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 the MOSEKLM_LICENSE_FILE environment variable of the process that started the server.
  • 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.

Start the web app

python app.py

Then 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 5001

Then 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:5000 reached AirPlay (HTTP 403 Forbidden) and http://127.0.0.1:5000 reached Scen-Opt. If you see a 403 page, do one of the following:

  • use 127.0.0.1 instead of localhost;
  • 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:app

The long timeout of 7200 s (two hours) is there because a single solve can take a long time.

Run the tests

From the repository root:

pip install pytest
python -m pytest tests/ -v

pyproject.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.

Run the benchmark scripts

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.py takes --solver (default MOSEK, which produced the published results). Without a MOSEK licence, pass another installed solver, e.g. --solver CLARABEL. With CLARABEL, LP_half_width_2d/run.py reproduces the published numbers: half-width 0.498310, $k = 2$, risk bounds [0.0000, 0.2085] at 99.9999% confidence.
  • run.py overwrites the committed results. It writes results/metrics.json and results/solution.csv.
  • Some scripts need extra packages that requirements.txt deliberately does not include. Each script names them in a comment at the top, with the pip install command:
    • every plot.py, plot_data_only.py and animate.py needs matplotlib;
    • the generate.py scripts of the Wine and Breast Cancer benchmarks (SDP_covariance_wine_15d, SDP_ellipsoid_enclosure_15d) need scikit-learn;
    • the Portfolio benchmark's generate.py needs yfinance;
    • the Radiation Therapy benchmark's generate.py needs mat73.

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.

Option 2: Docker

You need Docker installed.

Run the published image

docker run -p 5000:5000 ghcr.io/kiguli/scen-opt:latest

Then 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/ and static/;
  • the packages from requirements.txt and requirements-solvers.txt, plus Gunicorn.

It does not contain the benchmarks/ or tests/ folders. Download benchmark files from the repository to upload them.

Change the port

docker run -p 8080:5000 ghcr.io/kiguli/scen-opt:latest

Then open http://localhost:8080.

MOSEK licence in Docker

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:latest

When the licence dialog appears, choose I have a local license. Alternatively, upload the licence through the dialog as described above.

More Gunicorn workers

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:latest

Build the image yourself

git clone https://github.com/Kiguli/Scen-Opt.git
cd Scen-Opt
docker build -t scen-opt .
docker run -p 5000:5000 scen-opt

After pulling new changes, run docker build -t scen-opt . again.

Next steps

Using The Tool

Home

Starting Up

Convex Optimization

Graphical Results

Getting into the Weeds

Scenario Theory

Implementation Details

Clone this wiki locally