Supporting OPL Models in Python

This tutorial is intended for users who want to integrate OPL models into their Python-based optimization workflows using docplex.mp (for CPLEX Mathematical Programming) and docplex.cp (for CP Optimizer Constraint Programming). It explains how the extended APIs enable native support for OPL models within Python applications.

Through this API, users can build, load, and solve OPL models directly from Python. The tutorial demonstrates how OPL models can interact seamlessly with Python data structures—such as dictionaries, lists, and pandas DataFrames—thereby eliminating the need to manage external .dat files. It also shows how to extract OPL decision variables and solution results in structured, Python-friendly formats for analysis and integration into downstream applications.

By following this tutorial, users will learn a flexible, automated, and efficient approach to executing and managing OPL models programmatically. The subsequent sections provide a step-by-step guide to creating and running CPLEX or CP Optimizer models using OPL models with data supplied directly from Python.

1. What is OPL .mod and .dat?

OPL (Optimization Programming Language) is a high-level modeling language used with IBM CPLEX and CP Optimizer to describe and solve optimization problems.

  1. .mod File: Contains the mathematical formulation of the problem, including decision variables, constraints, and the objective function.

Example:

int MAXVAL = ...;
int LIMIT  = ...;
dvar int x in 0..MAXVAL;
maximize x + y;
subject to { x + y <= LIMIT; }
  1. .dat File: Provides data values used by the model, such as parameters, sets, or arrays.

Example:

MAXVAL = 10;
LIMIT = 12

2. Creating a CPO or CPLEX Model from OPL

User can create a CPO or CPLEX model directly from OPL .mod and .dat content using docplex. The API provides flexible options for supplying data from Python.

2.1. Creating a CPO Model

from docplex.cp.model import CpoModel

mdl = CpoModel()
mdl.build_opl_model(mod, data=None, Var1=None, Var2=None, ...)

Parameters:

  1. mod (required): The OPL model, either as a .mod file path or a string containing the model content.

  2. data (optional): Can be provided in any of the following forms:

    • A dictionary of variable–value pairs

    • A .dat file path

    • .dat file content as a string

  3. Var1, Var2, … (optional): Individual data variables passed as keyword arguments.

Data Flexibility: Users can supply -

  • Only data,

  • Only individual variables, or

  • A mix of both; the function will merge them automatically.

Example:

from docplex.cp.model import CpoModel

mdl = CpoModel()
mdl.build_opl_model(mod = './problem.mod',data = {'LIMIT'  : 12}, MAXVAL = 10)

2.2. Creating a CPLEX Model

For CPLEX mathematical programming models, the API provides:

from docplex.mp.model_reader import ModelReader

mdl = ModelReader.build_opl_model(mod, data)

Note: The parameters for building a CPLEX model are the same as those for a CPO model, allowing the same flexibility in providing .dat files, Python dictionaries, or individual variables.

3. Creating OPL Data Using Python Data Structures

When building OPL models from Python, the data provided must be compatible with the variable declarations in the .mod file. The build_opl_model API automatically translates Python data types to OPL data types, so the data supplied must follow specific rules to ensure compatibility with the corresponding OPL types.

Sl NoOPL Datatypemod declarationPython dataRemarks
1intint var = ...; var = 3Simple integer mapping
2floatfloat var = ...; var = 3.35Simple float mapping
3setset of strings:
{string} var = ...;
var = OrderedSet(["P1","P2","P3"])Use OrderedSet instead of standard set {} to preserve order
4arrayExample 1:
int a[1..2][1..3] = ...;
by listing values:
a = HashableList([ [10, 20, 30], [40, 50, 60] ])
or
a = [[10, 20, 30], [40, 50, 60]]
can use either HashableList (hashable & frozen) or standard list [] (forzen)

Note: Use HashableList whenever a list is placed inside a set to maintain hashability.
Example 2:
{string} Days = {"M","T","W"};
int a[Days] = ...;
by specifying as key-value pairs:
a = { "M" : 10, "T" : 20, "W" : 30 }
Example 3:
int a[1..2][1..3] = ...;
two forms combined:
a = { 2: [40, 50, 60], 1: [10, 20, 30] }
5tupleExample 1:
tuple point { int x; int y; } point p=...;
tuple of integers:
p = (1,2)
Example 2:
tuple Resource { string name; float capacity; } {Resource} Resources = ...;
set of tuple:
Resources = OrderedSet([ ("Labor",1000.0), ("Machine", 500.0) ])

The user can either create a Python dictionary named data, where the keys are OPL variable names and the values are their corresponding data, or pass the variables and their values directly as arguments to build_opl_model.

Example:

mdl.build_opl_model(mod='./problem.mod', data={'LIMIT': 12}, MAXVAL=10)

In this example, the dictionary data includes the variable LIMIT with the value 12, and the variable MAXVAL is passed separately with the value 10. The build_opl_model function combines these variables and supplies them for creating the CPLEX/CPO model.

Note: When passing data as variables, use the format variable = value, not just the variable name.

✔️

mdl.build_opl_model(mod='./problem.mod', MAXVAL=10)
# or
MAXVAL = 10
mdl.build_opl_model(mod='./problem.mod', MAXVAL=MAXVAL)

✖️ mdl.build_opl_model(mod='./problem.mod', MAXVAL)

This ensures OPL variables and their values are correctly mapped for model creation.

4. Exporting Data to a .dat File

After building an OPL model in docplex, you can export the associated data to a .dat file for reuse or sharing. This is particularly useful when you have provided data as Python dictionaries or variables and want to generate a standard OPL .dat file.

Example:

mdl.export_dat('./file.dat') # Export the data used in the model to a .dat file

mdl.export_dat() # Print the generated .dat content to the console

Key Points:

  • The exported file contains all the data used in the model in OPL .dat format.

  • This allows the same data to be reused with OPL models outside Python or shared with other users.

  • Works for both CPO (CpoModel) and CPLEX (ModelReader) models built from Python data structures.

5. Solving the Model

Once the OPL model is built, users can solve it directly from Python. To solve the model, simply call the solve() method:

sol = mdl.solve()

This executes the OPL model and returns a solution object sol that can be used for further analysis.

6. Extracting Model Variables

User can extract all OPL variables defined in the model using:

all_Var = mdl.get_opl_var()

The all_Var object contains structured access to all OPL variables and their data.

all_Var.variable_names     # returns list of variable names
# example output-> [var1, var2, var3]

all_Var.var1
# example output ->
# {
#      5: {
#         6: <docplex.cp.expression.CpoIntervalVar at 0x127108820>,
#         5: <docplex.cp.expression.CpoIntervalVar at 0x12710b450>,
#         4: <docplex.cp.expression.CpoIntervalVar at 0x12710b370>
#      },
#      ...
# }

#can extract each variable using proper indexing:
all_Var.var1[5][6]
# -> <docplex.cp.expression.CpoIntervalVar at 0x127108820>

7. Extracting Variable Solutions

Once the model is solved, you can map the variable objects to their corresponding solution values by passing the solution object sol to from_solution():

all_Var_sol = all_Var.from_solution(sol)

This creates a structured solution mapping between model variables and their solved values.

all_Var_sol.variable_names   # list variable names
# example output-> [var1, var2, var3]

all_Var_sol.var1
# example output ->
# {
#      5: {
#         6: IntervalVarValue(start=101, end=110, size=9),
#         5: IntervalVarValue(start=86, end=98, size=12),
#         4: IntervalVarValue(start=65, end=71, size=6)
#      },
#      ...
# }

#can extract each variable solution using proper indexing:
all_Var_sol.var1[5][6]
# output -> IntervalVarValue(start=101, end=110, size=9)

8. Downloading the Examples

The examples can be downloaded from GitHub: docplex_examples