Library / SDK
scipopt/PySCIPOpt avatar
scipopt/PySCIPOpt

PySCIPOpt: driving the SCIP solver from Python with Cython callbacks

Python interface for the SCIP Optimization Suite

999 stars284 forksCythonMIT

At a glance

What is it?
PySCIPOpt is the Python interface to the SCIP Optimization Suite, a Cython layer over the solver's C API that lets you build models, solve them and even write pricers and heuristics in Python. The install is one pip command, but the licensing picture changes at SCIP 8.0.3, and the project is run by volunteers looking for maintainers.
Who is it for?
PySCIPOpt is the right tool for a mixed Python and operations research team that needs a real MILP or nonlinear solver rather than an approximation, because it exposes the full SCIP C API and lets you write a pricer in Python when the default heuristics are not enough. It is the wrong choice if you want a pure Python solver with no native build step, or if you need the pre-8.0.3 SCIP licence terms and assume Apache 2.0 applies.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Cython, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Cython layer over the SCIP C API

PySCIPOpt does not reimplement a solver. It is an interface to the SCIP Optimization Suite, the C library that does the actual branch and bound work, and the project is written in Cython, which is how a Python object model can sit on top of a C API without paying the cost of a subprocess for every call.

The mechanics are simple enough to follow from the code. The Python side is generated from a Cython file named scip.pxi, and the methods it exposes are reached through a solver instance held in a variable called model. That file is the boundary: everything on the Python side of it is a wrapper, and everything on the C side is SCIP itself.

The build reflects the same arrangement. The pyproject.toml build system requires setuptools, cython of at least version 0.21 and numpy, and the runtime dependency is numpy of at least 1.16.0. The package supports Python 3.8 and later, and its classifiers call it a Beta release aimed at education and scientific research, which is an honest description of a binding whose main job is to expose someone else's solver.

From import to a solved model in five steps

The required steps are short, and the documentation gives them in order. You import the Model class.

python
from pyscipopt import Model

You create a solver instance, and the model name is optional.

python
model = Model("Example")  # model name is optional

Then you add variables, set an objective, add a constraint, solve and read the solution.

python
x = model.addVar("x")
y = model.addVar("y", vtype="INTEGER")
model.setObjective(x + y)
model.addCons(2*x - y*y >= 0)
model.optimize()
sol = model.getBestSol()
print(f"x: {sol[x]}")
print(f"y: {sol[y]}")

Two details in that snippet are worth pausing on. The variable type is given as a string, vtype equals INTEGER, so the interface is keyword driven rather than built from typed objects. And the constraint uses a nonlinear term, y*y, which tells you the interface is not limited to linear models.

The examples and tutorials in the repository are the intended entry point for more complicated code, and the recipes sub-package inside src/pyscipopt collects the common use cases.

SCIPOPTDIR decides where the solver library is found

Installing from PyPI is the recommended route, and it is one command.

bash
pip install pyscipopt

The documentation recommends a virtual environment, mainly to avoid interfering with system packages, and notes that some configurations require one.

bash
python3 -m venv venv     # creates a virtual environment called venv
source venv/bin/activate # activates the environment. On Windows use: venv\Scripts\activate
pip install pyscipopt

The part that needs attention is building from source, because the SCIP library has to be found on the machine. setup.py looks for an environment variable named SCIPOPTDIR, and if it is not set, the script tries to detect a conda environment through CONDA_PREFIX, and if that fails it assumes a global installation. The library name itself is platform dependent, since it is scip on Unix-like systems and libscip on Windows, and the include and library paths point into the conda prefix on macOS.

The wheel builds download a prebuilt SCIP archive from the scipoptsuite-deploy releases, with separate builds for x86_64 and aarch64 using manylinux_2_28 images, and PyPy is skipped because it does not work there.

The licence changes at SCIP 8.0.3

This is the detail most people miss, and it is worth reading before you deploy anything commercially. PySCIPOpt itself is MIT licensed. The solver underneath is not, at least not historically: starting from SCIP v8.0.3, SCIP uses the Apache 2.0 licence, and if you plan to use an earlier version of SCIP you are pointed to the licence restrictions on the SCIP website instead.

So the answer to a legal question about your project is not a single licence, it is a pair. The binding you write your model in is MIT, and the solver that computes the answer is Apache 2.0 from 8.0.3 onwards, with earlier SCIP releases carrying terms you have to check separately. Nothing here is legal advice, but the practical consequence is clear: pin the SCIP version you ship, and if it predates 8.0.3, read those restrictions before you distribute a commercial product that embeds it.

The repository also ships a CITATION.bib file and asks users to cite a paper on PySCIPOpt along with the corresponding SCIP Optimization Suite report, which is the scholarly counterpart of the same version pinning question.

Python plugins are callback classes with a dictionary contract

The interface is not limited to describing models. The Python interface can be used to define custom plugins that extend the functionality of SCIP, and the documentation names three kinds: a pricer, a heuristic, and even a constraint handler. These are written in pure Python, and SCIP calls their methods through the callback system.

The structure is inheritance from a base class. Every available plugin has a base class that you extend, overwriting callbacks that are predefined but empty. Two simple examples are pointed out in the test suite, test_pricer.py and test_heur.py, which is where to start reading.

The subtlety is the return values. In most cases you need to use a dictionary to specify the return values needed by SCIP, so a plugin is not just a set of methods that happen to be called, it is a contract with a particular shape. That contract is where the friction lives, since the Python callback boundary is where you feel the C library underneath, and it is the part most likely to need experimentation before it behaves.

The old documentation is still the more complete API reference

The documentation situation has a wrinkle that the project is open about. There is an online documentation set at readthedocs, and the help function in Python or the question mark in IPython and Jupyter are both offered as ways to find out what a method does. But the older documentation, which the project says it is in the process of migrating from, is still more complete with respect to the API, and it is hosted separately.

That is a real cost for a binding. When the reference you are used to is the archived one, every lookup becomes a two source job, and the risk of writing against an API that has since shifted is real. The project counteracts that with a CHANGELOG.md that lists added, removed and fixed functionality, and with the stated goal of keeping PySCIPOpt coverage of the SCIP C API expanding.

The repository shows the effort behind that. There is a docs/ directory, a generate-docs.sh script, a stubs/ directory for type information, a mypy configuration in pyproject.toml with the deprecated error code enabled, a .readthedocs.yaml file, and an upgrade_scip.sh script for moving between SCIP versions.

Volunteer maintenance with a release planned per SCIP release

The project states plainly that it is sustained by volunteer effort, and that as it grows the team is inviting more contributors and maintainers. The core responsibilities are listed: going over the open issues regularly and visiting Stack Overflow and OR.SE, reviewing pull requests while making sure the changelog is updated and that added methods are tested, expanding coverage of the SCIP C API, keeping the documentation current with new tutorials and examples, and cutting a PySCIPOpt release for every SCIP release at a minimum.

That last item is the practical contract for anyone depending on the project, and the release history shows it being honoured. v6.2.0 landed on 2026-05-11, v6.2.1 on 2026-05-16, and v6.3.0 on 2026-10-11, with the last push to the repository on 2026-10-19. The changelog entry for v6.2.0 describes bugfixing, expression performance and new methods, which is the shape of a release that tracks solver changes rather than a major redesign.

For an adopter, the sensible reading is that PySCIPOpt tracks SCIP closely and that a solver upgrade is likely to pull a binding upgrade with it, so the SCIPOPTDIR path and the version pair belong in your dependency planning rather than in a one time setup step.

Editorial conclusion

PySCIPOpt is the right tool for a mixed Python and operations research team that needs a real MILP or nonlinear solver rather than an approximation, because it exposes the full SCIP C API and lets you write a pricer in Python when the default heuristics are not enough. It is the wrong choice if you want a pure Python solver with no native build step, or if you need the pre-8.0.3 SCIP licence terms and assume Apache 2.0 applies. Before you start, check the SCIP version your organisation will ship against, since SCIP switched to Apache 2.0 at v8.0.3 while PySCIPOpt itself stays MIT, and note that the older documentation set is still the more complete API reference.

Frequently asked questions

How do I install PySCIPOpt?

The recommended method is pip install pyscipopt, and the documentation suggests doing it inside a virtual environment with python3 -m venv venv followed by source venv/bin/activate. Building from source is covered in the online documentation, and setup.py locates the SCIP library through the SCIPOPTDIR environment variable.

What licence applies to PySCIPOpt and SCIP?

PySCIPOpt is MIT licensed. SCIP switched to Apache 2.0 starting from version 8.0.3, and if you plan to use an earlier version of SCIP you should review the licence restrictions linked from the SCIP website.

Can I write a custom solver plugin in Python with PySCIPOpt?

Yes. The interface can be used to define custom plugins to extend SCIP, and you can write a pricer, a heuristic or a constraint handler in pure Python, extending a base class and overwriting its empty callbacks. In most cases you need a dictionary to specify the return values SCIP needs.

How do I get help with PySCIPOpt?

The project points to the online documentation, the help function in Python and the question mark in IPython or Jupyter. Questions are also welcomed on the issue tracker, and the maintainers note that users also ask questions on Stack Overflow and OR.SE.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. scipopt/PySCIPOpt on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/scipopt-pyscipopt.svg)](https://hysenlabs.com/projects/scipopt-pyscipopt)

Was this useful?