Core package badges:
Quality and tooling:
Project/community:
Docs:
pyopl is a Python library for parsing and solving OPL-like [1] mathematical programming models using either Gurobi or the open-source SciPy (HiGHS) solver. PyOPL supports a rich subset of Optimisation Programming Language (OPL) syntax for linear and mixed-integer programming.
[1] Van Hentenryck, P. (1999). The OPL optimization programming language. London, England: MIT Press.
The GitHub project and importable compiler package are named pyopl; the published PyPI distribution is named rhetor.
Install via pip (recommended):
pip install rhetor
Or clone the repository and install locally:
git clone https://github.com/gwr3n/pyopl.git
cd pyopl
pip install .
Dependencies are managed via pyproject.toml and are listed in requirements.txt
PyOPL requires Python 3.10+
You can use either Gurobi or SciPy/HiGHS as the solver. Both solvers are selectable in the API and the Rhetor IME. PyOPL provides robust support for tuple/nested tuple data, advanced boolean logic, implication, and field access in both models and data files.
You can use the solve function to load and solve an OPL model (and optional data file). Choose the solver with the solver argument:
from pyopl import solve
results = solve('model.mod', 'data.dat', solver='gurobi') # Use Gurobi (default)
results = solve('model.mod', 'data.dat', solver='scipy') # Use SciPy/HiGHSSuppose you have the following files:
knapsack.mod(your OPL model)knapsack.dat(your data file)
You can solve the model as follows:
from pyopl import solve
model = "knapsack.mod"
data = "knapsack.dat"
results = solve(model, data)
print(results)This will print the parsed AST, the generated solver code, and the solution output from the selected solver. The solve function returns a dictionary with the following keys:
status: The status of the optimization (e.g., 'OPTIMAL', 'INFEASIBLE', etc.)solution: A dictionary of variable names and their values (if optimal)objective_value: The value of the objective function (if optimal)stats: Additional statistics (e.g., MIPGap, Runtime, NodeCount, IterCount)message: Any error or status messages
Below, we provide model and data file for our knapsack example.
Example contents for knapsack.mod:
// knapsack.mod
int+ n = ...; // non-negative integer parameter
float+ c = ...; // non-negative float parameter
float+ w[1..n] = ...; // indexed parameter
float+ v[1..n] = ...;
dvar boolean x[1..n];
maximize sum(i in 1..n) v[i] * x[i];
subject to {
sum(i in 1..n) w[i] * x[i] <= c;
forall(i in 1..n) x[i] >= 0;
}
Example contents for knapsack.dat:
// knapsack.dat
n = 4;
c = 10;
w = [2, 3, 4, 5];
v = [3, 4, 5, 6];
See tools/examples.py for a repository of examples.
PyOPL includes Rhetor, a GenAI-first integrated modelling environment (IME) for creating, revising, solving, exporting, and versioning OPL models and data files.
The IME features:
- GenAI-first modelling workflows for generating models, revising existing model/data pairs, asking questions about a formulation, and explaining solutions with OpenAI, Google/Gemini, or Ollama models when configured
- Optional visual prompt attachments for supported GenAI workflows, including images and short PDFs
- Session-based model version tracking: each run/request can keep a timestamped snapshot that can be previewed, diffed against the current editors, restored, renamed, or deleted
- Output and session panels for reviewing recent runs, generated artifacts, model/data snapshots, and GenAI interactions
- Syntax-highlighted model and data editors with open, save, save-as, undo, redo, find, and replace
- Integrated solve workflow with Gurobi or SciPy/HiGHS selection, solver logs, elapsed-time status, and optional solver-progress display
- Export support for compiled Python, LP, and MPS artifacts where supported by the selected backend
- Light/dark themes and configurable editor font sizes, with settings saved between sessions
Running PyOPL with no subcommand launches the IME:
python -m pyoplIf installed as a package, the pyopl console command can be used in place of python -m pyopl.
This opens the Rhetor IME window. You can open .mod model files and optional .dat data files, generate or revise formulations with GenAI assistance, edit them directly, solve them from the interface, export generated artifacts, and choose either Gurobi or SciPy/HiGHS from the Solve menu.
Rhetor keeps an IME session history in a .pyopl_session file in the current working directory. Session entries preserve output history and associated model/data snapshots, so you can track how a model changes over an interactive, GenAI-assisted modelling session. From the session list, use the context menu to preview a saved snapshot, diff it against the current editors, restore it into the editors, rename the session entry, or delete it.
PyOPL also includes a command-line interface for solving models, exporting generated artifacts, and using GenAI helpers from scripts or terminals.
Basic usage:
python -m pyopl solve model.mod data.dat --solver highs --out jsonThe CLI supports:
python -m pyopl solve <model.mod> [data.dat]to compile and solve a model--solver highs|gurobito choose the backend solver--out json|py|lp|mpsto print results, export generated Python, or write LP/MPS solver files--out-file <path>to write output to a file
Examples:
python -m pyopl solve knapsack.mod knapsack.dat --solver highs --out json
python -m pyopl solve knapsack.mod knapsack.dat --solver highs --out lp --out-file knapsack.lp
python -m pyopl solve knapsack.mod knapsack.dat --solver highs --out mps --out-file knapsack.mpsPyOPL MCP exposes core PyOPL compiler/solver functionality as MCP tools so external clients (IDEs, editors, automation) can call compile, solve, export, and compare operations over stdio-based MCP servers.
- Purpose: Provide programmatic access to compilation, solving, Python code export, and model equivalence comparison for OPL models using in-memory model/data strings.
- Exposed tools:
- read_pyopl_grammar_tool: Return the bundled grammar text.
- solve_strings_tool: Compile and solve a model from
model_textand optionaldata_text. - export_py_strings_tool: Compile
model_textand optionaldata_textto generated Python source and return it as a string. - compare_model_strings_tool: Compare two OPL models from strings using the same MILP equivalence engine as the IDE's Compare models workflow. Returns
status,equivalent,level,reason,proof_steps, andcounterexample.
- Not exposed as MCP tools: File-path helpers such as
solve_files_toolandexport_py_files_toolare retained in the Python module for trusted local/internal use, but are not registered as MCP tools by default for security reasons. - Solver mapping: Default solver alias
highs→ SciPy/HiGHS;gurobi→ Gurobi. See the toolsolverparameter for selection. - Quick start (VS Code MCP example - .vscode/mcp.json):
{
"servers": {
"PyOPL MCP": {
"type": "stdio",
"command": "${workspaceFolder}/venv/bin/python",
"args": ["-m", "pyopl.pyopl_mcp"]
}
}
}- Run locally:
python -m pyopl.pyopl_mcp- Files: Implementation and tool list in pyopl_mcp.py.
- Notes: Errors from the compiler/solver/comparison engine are propagated to the caller; generated Python code is returned (not written) so the client can persist it as desired.
A comprehensive User Guide is available in the docs folder of the repository.
Rossi, R. & Prestwich, S. D. (2026).
Grammar-Aware Literate Generative Mathematical Programming with Compiler-in-the-Loop.
arXiv:2601.17670 [cs.PL]
@misc{rossi2026grammar,
title={Grammar-Aware Literate Generative Mathematical Programming with Compiler-in-the-Loop},
author={Roberto Rossi and Steven D. Prestwich},
year={2026},
eprint={2601.17670},
archivePrefix={arXiv},
primaryClass={cs.PL},
url={https://arxiv.org/abs/2601.17670},
}