This blog is part of the "Xpress Everywhere" series, showcasing how FICO® Xpress integrates with popular open-source optimization frameworks across different languages and modeling paradigms.
You've built your optimization model using Google OR-Tools. It works, but you're hitting walls: unsure how to handle multiple objectives, no way to warm-start your solve, and that nagging feeling that your model could be more readable and performant.
The recent Xpress integration in OR-Tools' MathOpt interface brings enterprise-grade features to the popular optimization toolkit. This post explores how indicator constraints, quadratic objectives, and other advanced capabilities transform the way you model real-world problems.
Note: We provide the full OR-tools/MathOpt C++ program, the corresponding model for Python/MathOpt and an equivalent version using the native Xpress C++ API in our new GitHub repository for third-party interface examples.
The data consists of:
Using the OR-tools MathOpt interface for C++, one can model decision variables as:
Interactive code: All code snippets are clickable — click to jump directly to the corresponding lines in our public GitHub repository !
To add a constraint, create a LinearExpression, sum the relevant variables, and call AddLinearConstraint method. For example, to add the customer demand satisfaction constraints (one linear expression per customer), we can do:
With this setup, let's see how Xpress-supported features transform the modeling experience through a series of natural extensions to this problem.
With the enhanced support for indicator constraints, you can express the logic directly by using the AddIndicatorConstraint method in case you decide not to compute a big-M yourself:
The Xpress solver handles the logical implication internally, choosing the most efficient representation. No M to tune, no numerical concerns, and often faster solves because the relaxation is tighter.
This naturally expresses the nonlinear relationship without approximation.
If you have a good feasible solution (from a previous solve, heuristic, or domain knowledge) and want to warm-start your solve, you can provide it as a hint to accelerate the search using the model-specific parameters. Hints can be complete or partial — specify values for just some variables (e.g., strategic decisions) and let the solver determine the rest:
The solver log confirms when your hint is accepted:
If a partial solution is passed (e.g. fixing only the warehouse opening variables), the solver log confirms when your partial solution hint is integrated by the solver:
The solver internally uses Xpress's delayed rows feature to defer enforcement until needed. This is more efficient than checking all constraints at every node, when many may never become binding.
But the Xpress support goes beyond the general OR-tools parameters. Any Xpress-specific controls can actually be set, such as the impactful heuristic emphasis or the recently added work limit control. WORKLIMIT counts deterministic "work units" rather than wall-clock time, ensuring identical behaviour regardless of machine speed:
Besides, you can set a message callback for real-time progress monitoring:
This declares an output callback function, called every time a text line relating to the given problem is output by the Optimizer. In this example, the new output line is printed after a "[Progress] " string.
The full program is available for download in the public GitHub repository.
pip install ortools
… or conda:
conda install conda-forge::ortools-python
The Python API follows Python conventions (snake_case methods, generator expressions, etc.) while maintaining feature parity with C++. Here are two representative examples:
Indicator Constraints:
Solver Parameters and Solve:
Output:
The result matches the C++ solution exactly. Xpress handles the quadratic congestion costs natively, selecting Warehouse_East (the large facility with the lowest congestion coefficient) as the optimal choice.
Note on Dynamic Callbacks: General callbacks for, e.g. dynamically adding lazy constraints during the solve are not yet supported for Xpress in MathOpt. However, static lazy constraint annotation (shown above) is fully supported in both C++ and Python.
If you've been working around solver limitations with big-M constraints or linearization tricks, it's time to let the solver do the heavy lifting. Your models will be cleaner, your solves faster, and your code more maintainable.
You've built your optimization model using Google OR-Tools. It works, but you're hitting walls: unsure how to handle multiple objectives, no way to warm-start your solve, and that nagging feeling that your model could be more readable and performant.
The recent Xpress integration in OR-Tools' MathOpt interface brings enterprise-grade features to the popular optimization toolkit. This post explores how indicator constraints, quadratic objectives, and other advanced capabilities transform the way you model real-world problems.
What Xpress Brings to OR-Tools
The enhanced Xpress integration in MathOpt (starting with version v9.15) delivers a comprehensive set of advanced features, available from both C++ and Python, amongst which:- Indicator constraints: Model conditional logic without big-M formulations
- Quadratic objectives and constraints: Native support for MIQP and MIQCQP problems
- Multi-objective optimization: apply a lexicographic approach to solve problems with multiple objectives
- Warm starts: Hint the solver with solutions you may have from a previous solve or heuristic
- Lazy constraints: Implement branch-and-cut algorithms with constraint generation for a pre-defined set of constraints
- Message callbacks: Monitor solver progress in real-time
- Full parameter control: Fine-tune solver behavior for your specific problem
Note: We provide the full OR-tools/MathOpt C++ program, the corresponding model for Python/MathOpt and an equivalent version using the native Xpress C++ API in our new GitHub repository for third-party interface examples.
A Capacitated Facility Location Model (C++)
Consider a classic logistics challenge: a company must decide which warehouses to open from a set of candidate locations, and how much product (can be fractional) to ship from each open warehouse to satisfy customer demands.The data consists of:
- A set of potential facility locations, each with a fixed opening cost, maximum capacity, and congestion characteristics
- A set of customers, each with a specific demand that must be satisfied
- Transportation costs between every facility-customer pair
- y: Binary variables indicating whether facility i is open (1) or closed (0)
- flow
: Continuous variables representing the flow (quantity shipped) from facility i to customer j
Using the OR-tools MathOpt interface for C++, one can model decision variables as:
Interactive code: All code snippets are clickable — click to jump directly to the corresponding lines in our public GitHub repository !
To add a constraint, create a LinearExpression, sum the relevant variables, and call AddLinearConstraint method. For example, to add the customer demand satisfaction constraints (one linear expression per customer), we can do:
With this setup, let's see how Xpress-supported features transform the modeling experience through a series of natural extensions to this problem.
Feature 1: Indicator Constraints — Alternative to Big-M
The classic challenge: "If this facility is closed, no shipments can leave it." The traditional approach uses big-M:With the enhanced support for indicator constraints, you can express the logic directly by using the AddIndicatorConstraint method in case you decide not to compute a big-M yourself:
The Xpress solver handles the logical implication internally, choosing the most efficient representation. No M to tune, no numerical concerns, and often faster solves because the relaxation is tighter.
Feature 2: Quadratic Constraints — Modeling Reality
The objective minimizes total cost: fixed costs for opening facilities, transportation costs for shipping products, plus congestion costs that increase quadratically with warehouse utilization. With the enhanced Xpress support, you can model these quadratic expressions directly:This naturally expresses the nonlinear relationship without approximation.
Feature 3: Multi-Objective Optimization
Real-world problems often have competing objectives. Beyond minimizing cost, you might want to minimize the number of open facilities for operational simplicity.
Important: multi-objective optimization with Xpress requires linear objectives. When combining quadratic costs with multi-objective, we use transfer variables to move quadratic terms into constraints:
OR-tools and Xpress will support lexicographic (priority-based) multi-objective optimization by using AddAuxiliaryObjective as follows:
The solver first optimizes the primary objective, then optimizes the secondary objective while maintaining the optimal primary value.
The log shows progress on each objective:
Note for Xpress wizards: The objective priority handling in OR-tools is the opposite of native Xpress, where higher priority values, in multi-objective context, mean higher importance. MathOpt inverts priorities internally when calling Xpress.
Feature 4: Solution Hints — Warm-Start Your Solve
MathOpt separates solver configuration into two classes: SolveParameters for solver behavior (time limits, tolerances, algorithm selection) and ModelSolveParameters for model-specific hints (warm starts, lazy constraints, branching priorities).If you have a good feasible solution (from a previous solve, heuristic, or domain knowledge) and want to warm-start your solve, you can provide it as a hint to accelerate the search using the model-specific parameters. Hints can be complete or partial — specify values for just some variables (e.g., strategic decisions) and let the solver determine the rest:
The solver log confirms when your hint is accepted:
If a partial solution is passed (e.g. fixing only the warehouse opening variables), the solver log confirms when your partial solution hint is integrated by the solver:
Feature 5: Lazy Constraints — Branch-and-Cut Made Simple
Some constraint families are large or rarely binding. For example, pairwise facility exclusion rules (certain facilities cannot both be open due to regulations) create many constraints. Lazy constraints are added to the model but only enforced when violated during branch-and-bound. Just as for warm start, you will need to use model parameters, in this case by inserting the intended linear constraints into the lazy_linear_constraints object of the model parameters:The solver internally uses Xpress's delayed rows feature to defer enforcement until needed. This is more efficient than checking all constraints at every node, when many may never become binding.
Feature 6: Solver Parameters and Message callback
Every problem has characteristics that can benefit from solver tuning. OR-tools exposes several global controls, such as time limit, optimality gap tolerance and logging enablement:But the Xpress support goes beyond the general OR-tools parameters. Any Xpress-specific controls can actually be set, such as the impactful heuristic emphasis or the recently added work limit control. WORKLIMIT counts deterministic "work units" rather than wall-clock time, ensuring identical behaviour regardless of machine speed:
Besides, you can set a message callback for real-time progress monitoring:
This declares an output callback function, called every time a text line relating to the given problem is output by the Optimizer. In this example, the new output line is printed after a "[Progress] " string.
Invoking Xpress and Solving
Initializing the solver and running the optimization is straightforward. Invoke the Solve function with SolverType::kXpress, after configuring all the solve and model parameters:Python Integration
The MathOpt Python API provides full feature parity with C++ — quadratic constraints/objectives, indicator constraints, multi-objective, and more. If you have a local Xpress installation (note that Xpress is not bundled with the OR-Tools package), you can use it directly from the “ortools” package available via pip:pip install ortools
… or conda:
conda install conda-forge::ortools-python
The Python API follows Python conventions (snake_case methods, generator expressions, etc.) while maintaining feature parity with C++. Here are two representative examples:
Indicator Constraints:
Solver Parameters and Solve:
Complete Python Example
For a complete working example demonstrating all features (indicator constraints, quadratic constraints, multi-objective, lazy constraints, solution hints, message callbacks, and solver parameters), check out the complete Python file.Output:
The result matches the C++ solution exactly. Xpress handles the quadratic congestion costs natively, selecting Warehouse_East (the large facility with the lowest congestion coefficient) as the optimal choice.
Note on Dynamic Callbacks: General callbacks for, e.g. dynamically adding lazy constraints during the solve are not yet supported for Xpress in MathOpt. However, static lazy constraint annotation (shown above) is fully supported in both C++ and Python.
Check out the equivalent example using the native Xpress C++ API
For comparison with the native FICO Xpress C++ API, check out the equivalent example file on GitHub. Besides being more readable and convenient for Xpress users, the native Xpress C++ API provides full access to Xpress capabilities like SOS constraints, full set of callbacks, and a built-in console handler.The Takeaway and What’s Next
The Xpress integration in OR-Tools bridges the gap between accessible modeling and enterprise-grade solving. Features like indicator constraints and quadratic objectives let you model problems naturally, while message callbacks and parameter control give you the visibility and solver tuning options that production systems demand.If you've been working around solver limitations with big-M constraints or linearization tricks, it's time to let the solver do the heavy lifting. Your models will be cleaner, your solves faster, and your code more maintainable.
Install the Xpress Solver and experiment yourself
Install OR-tools and sign up for a freeFICO® Xpress Community License, install Xpress and experiment with large-scale problems using OR-tools with Xpress for:- Academic research and teaching
- Commercial evaluation (30-day trial)
Next in the series: We explore Python's rich optimization ecosystem — Pyomo, CVXPY, PyOptInterface, and linopy — all powered by Xpress.
Have questions or feedback? Join the discussion on the FICO Community.
Updated 8 months ago
Version 4.0FICO
Community Manager
Joined July 21, 2025
FICO® Xpress Optimization Blog
Follow this blog board to get notified when there's new activity