Blog Post

FICO® Xpress Optimization Blog
7 MIN READ

Introducing MoselPy: A Python Interface for FICO® Xpress Mosel

FICO's avatar
FICO
Community Manager
4 months ago
MoselPy is a new Python package that provides bindings to FICO® Xpress Mosel, enabling Python applications to compile and run Mosel models and to exchange data with them directly. Data can be passed in memory through the moselpy I/O driver, and Mosel models can equally read from and write to external sources such as files and databases.

MoselPy is aimed at workflows where the optimization model is written in Mosel and Python is used to drive execution, manage data, and integrate results into a wider application or pipeline implemented with Python. It works alongside the existing Mosel toolchain: models designed for MoselPy still run standalone, so you can adopt it incrementally without disrupting existing workflows.

A typical workflow is straightforward: prepare input data in Python, pass it to a Mosel model for optimization, and retrieve the results back in Python to leverage Python pipelines and visualization packages. Alternatively, the Mosel model can read data directly from external sources such as databases, leaving Python to drive execution and post-process results. Data-structure conversions between Python and Mosel are handled automatically by the driver, covering a collection of scalars, arrays, sets, lists, and Pandas objects. This post covers the main features and workflows, and points to the documentation and notebook examples to help you get started.

Installing MoselPy and User Guide

MoselPy is available on PyPI:

pip install moselpy

The Mosel runtime (mosellibs) and FICO® Xpress solver libraries (xpresslibs) are also published on PyPI as separate packages. MoselPy does not require them: if mosellibs is installed it is used automatically, otherwise MoselPy falls back to a local Xpress installation found via XPRESSDIR. This means a local installation is not required to run MoselPy models, including solver-based ones, as long as mosellibs (and xpresslibs for solver access) are installed alongside it:

pip install moselpy mosellibs xpresslibs

A local Xpress installation is still recommended for access to the full toolchain, including the complete examples library and the solver documentation.

The MoselPy User Guide and Reference Manual covers installation, the three-step workflow, and the full API reference. It is also included in the FICO Xpress 9.9 installation under the docs/mosel subdirectory of the Xpress installation directory (XPRESSDIR), available as both PDF and Markdown.

Jupyter Notebooks Examples on GitHub

Working examples for all features described in this post are available in the fico-xpress/python-notebooks repository on GitHub. The MoselPy notebooks are based on examples from the book Applications of Optimization with Xpress-MP (Dash Associates, 2002), a rich library of optimization model formulations spanning 11 topic areas such as production planning, scheduling and sequencing, transport, and finance, among others. The original Mosel models for all examples are available at examples.xpress.fico.com and are also included in Xpress distributions.

The notebooks run without a local Xpress installation and can be launched directly in GitHub Codespaces with no local setup. Throughout this post, each code snippet includes a Source link pointing to the notebook where that feature is demonstrated in a full working context.

The Three-Step Workflow

The standard Mosel workflow consists of three steps: compile the Mosel source to binary form, load it into memory, and run it.

compile_model() invokes the Mosel compiler and produces a .bim file from a Mosel source file (.mos). The .bim format is platform-independent and can be loaded without recompilation on any subsequent run, which avoids compilation overhead when running the same model repeatedly. It also allows a model to be distributed without the Mosel source, thus protecting the intellectual property in the model formulation.

load_model() loads the compiled binary into the Mosel instance and returns a Model object. The model stays resident in memory across multiple run() calls; there is no need to reload between solves. A context manager form (with mp.load_model(...) as model:) is also an option for automatic cleanup once the model is no longer required.

model.run() executes the model. It accepts input data via input_data and model parameters via exec_params, and returns a dictionary of all identifiers exported by the model.

Source:intro.ipynb
The function execute_model() is also available as a shorthand that compiles, loads, and runs in a single call, returning (model, output) as a tuple. It is convenient for quick execution, and since the loaded Model instance is returned, it can still be run again afterwards.

Data Exchange

On the Mosel side, initializations from "moselpy:" reads input data passed from Python, and initializations to "moselpy:" writes output data back to the Python program. From Python, input is provided as a dictionary to input_data, and run() returns a dictionary of all exported identifiers.
Scalars, arrays, sets, and lists are all supported:

Source:intro.ipynb
Pandas Series and DataFrames are also accepted directly as input. The index is mapped to the Mosel set dimension automatically, with no manual reshaping required. On output, find_identifier() with use_pandas=True returns a Series or MultiIndex Series, which can be unstacked into a DataFrame:

Source:production_planning.ipynb
Since results are returned as native Python objects or Pandas DataFrames, they can be passed directly to visualization libraries such as matplotlib, seaborn, or Plotly. The chart below is generated from the optimization output with a few lines of standard Python, with no data export or format conversion needed.


The full type mapping, including NumPy and sparse array support, is documented in the Data Exchange and I/O Driver sections of the MoselPy User Guide.

Runtime Parameters

Mosel models may define a parameters block with default values. These can be overridden at execution time via exec_params. This is the standard pattern for running the same compiled model under different configurations:

Iterative Solving

A loaded model can be run multiple times without recompilation or reloading; run() resets the model state automatically between calls. This supports iterative workflows where Python logic controls the sequence of solves:


Source:scheduling_sequencing.ipynb

For independent scenario branches, copy.deepcopy(model) produces separate model instances from a single loaded binary, without recompilation.

Preprocessing Data in Python: A Warm-Start Example

A common pattern is to preprocess data in Python before handing it to the optimization model. A practical instance of this is computing a warm-start solution: Python builds a quick heuristic solution, and MoselPy passes it to the Mosel model via input_data, which then forwards it to the MIP solver as an initial integer solution before branch-and-bound begins.

The following example applies an LPT (Longest Processing Time) heuristic to a wagon-loading problem, then passes the assignment to the solver as a starting point:


Source:loading_cutting_stock.ipynb

Output Capture and Stream Control

Mosel output streams can be redirected per-model using set_default_stream(). Output can be suppressed, written to a file, or captured into a Python buffer:

Routing the output and error streams explicitly is recommended good practice: it lets you keep a record of solver logs, surface errors to the calling application, and integrate Mosel output cleanly into a larger Python program's logging.

Getting Started

  1. Install:pip install moselpy mosellibs xpresslibs (or just pip install moselpy to use a local Xpress installation via XPRESSDIR)
  2. User Guide and Reference Manual: The MoselPy User Guide and Reference Manual covers installation, the three-step workflow, and the full API reference
  3. Notebooks: Clone or open the python-notebooks repository and run the introductory notebook, or launch it directly in GitHub Codespaces
The Mosel runtime itself is not licensed; a license is only required to run the Xpress solvers. For licensing information, see the FICO Xpress trial and licensing options page. New users can also get started for free with the FICO Xpress Community License, which provides a size-limited version of the optimizer.

Developing Mosel Models with the VS Code Extension

When working with MoselPy, the Mosel models themselves are written in .mos files. The FICO® Xpress Mosel extension for VS Code (currently in beta) provides comprehensive language support for Mosel directly inside Visual Studio Code, covering the full development cycle from writing to debugging:
  • Syntax highlighting, code folding, and formatting for .mos files
  • Code completion and inline documentation, including across files
  • Jump to definition and hover documentation, also across files
  • Real-time diagnostics from the Mosel parser, without triggering a full compile
  • Compile, run, and debug commands, with full VS Code debugger integration including breakpoints, variable inspection, and a debug console

For users building MoselPy workflows, the extension is a natural complement: edit and debug your Mosel model in VS Code, compile it to a .bim with MoselPy, and drive execution from Python. With the extension installed, VS Code becomes a single development environment for the whole workflow, covering Mosel through the new extension, Python, and Jupyter notebooks side by side. The extension can also be installed in a browser-based VS Code session, so the same language support is available when editing Mosel models online or running notebooks in environments such as GitHub Codespaces. For more details, see the blog post introducing the extension.

Conclusion

MoselPy brings Mosel models directly into Python applications and data pipelines, with in-memory data exchange, native Pandas support, and a clean separation between optimization logic and application code. Because models designed for MoselPy still run standalone, the same model can be developed and debugged on its own before being driven from Python, keeping the two concerns independent. In deployment, applications typically work with precompiled Mosel models, which protects the model IP and prevents unwanted edits by end-users. Whether you are integrating an existing model, running scenario analyses from a notebook, or deploying optimization as part of a Python pipeline, MoselPy is designed to help you.

Try it yourself: install the package with pip install moselpy and run the introductory notebook from the python-notebooks repository. As this is a beta release, your feedback is valuable; share your thoughts or report issues in the comments below.

Subscribe to the FICO Xpress Optimization Blog for more content on Mosel, optimization, and the latest Xpress features.
Updated 4 months ago
Version 3.0
No CommentsBe the first to comment