Skip to content

Xpress

What it is

FICO Xpress is a commercial linear, mixed-integer, and nonlinear programming solver. FlexTool writes each solve's model to an MPS file and runs the Xpress optimizer console (found on PATH or in ~/xpressmp/bin) on it in a separate process, giving every control as a setControl <NAME> <value> command. FlexTool never imports xpress directly.

FlexTool runs lpoptimize for a linear problem and mipoptimize for a solve with integer variables (integer investments, unit online variables). For a MIP, FlexTool reads how the search ended from the Xpress log, not from the print solution (which says "Optimal solution found" also after a search stopped by a limit):

  • *** Search completed ***: optimal.
  • STOPPING - MAXTIME limit reached / MAXNODE / MAXMIPSOL: the time, node or solution limit. A MIP with an integer solution keeps it with a warning naming the limit and the gap reached; without one the run stops (see Time and other limits).
  • Problem is integer infeasible: the run stops, "is infeasible".
  • Problem is unbounded: the run stops, "is unbounded" (the log also says *** Search completed ***, and may count heuristic solutions; FlexTool uses none of them).
  • A search that ends with no integer solution (Number of solutions found 0) stops the run: FlexTool never uses the LP relaxation Xpress writes then.

Any other stop (for example MAXSTALLTIME) ends as an unfinished search, which stops the run even with an integer solution.

FlexTool needs these log lines. OUTPUTLOG other than 1 or MIPLOG 0 leaves them out, so on a MIP FlexTool adds setControl OUTPUTLOG 1 / setControl MIPLOG 1 after your controls, with a printed line naming the value it replaced. Other MIPLOG values (2, 3, negative) are kept: they print the lines too. An LP keeps your values.

These log texts were checked with the xpress Python package's library; check them with your optimizer console on a small MIP before relying on a long run.

Official site: https://www.fico.com/en/products/fico-xpress-optimization

License options

  • Commercial. FICO sells perpetual and term licences directly and through partners.
  • Academic. Free academic licences for teaching and research; apply through the FICO Xpress academic partnership.
  • Community Edition. Free, no-registration size-limited build with a hard cap (historically 5000 variables / 5000 rows for LPs and MIPs; exact cap and small-print may change by release — confirm against the current FICO documentation). Useful for tutorials and small validation models, too small for typical FlexTool dispatch scenarios.

Licence and download portal: FICO's Xpress product page above.

Installation

Install the Python wrapper:

pip install xpress

The PyPI xpress wheel from FICO embeds the solver runtime, so no additional download is needed for the Community Edition.

For licensed users:

  1. Obtain xpauth.xpr from your FICO licence portal.
  2. Place it at one of the default locations searched by Xpress, or set the environment variable XPAUTH_PATH to point at it. Refer to the vendor's installation guide for the precise discovery order on your platform ([FIXME: confirm URL]).
  3. Floating-licence users point XPAUTH_PATH at the licence server's xpauth.xpr shim.

Unlike Gurobi/COPT, xpress.problem() does not currently accept a pre-constructed environment object, so the polar-high env= pass-through is accepted but unused for Xpress. Licence discovery is entirely vendor-side.

Verification

After installing the wrapper, run:

python -c "from polar_high.solvers import available_solvers; print(available_solvers)"

Expected: 'xpress' appears in the list.

['gurobi', 'cplex', 'xpress', 'copt', 'highs']

To verify the licence works (this also prints the Xpress banner with the licence type):

python -c "import xpress; xpress.problem()"

Community Edition users see a banner stating the size cap. If the call raises an exception mentioning license, oem, or no token, see "Common errors" below.

Common errors

The error messages below are what FlexTool surfaces as FlexToolUserError. Xpress does not expose a stable numeric error code on its Python exceptions, so polar-high classifies licence errors by message text rather than code; the keyword set is license, licence, oem, expired, no token.

  • No xpauth.xpr found. Xpress raises with a message containing "license" or "no token". FlexTool shows: "Solver 'xpress' is installed but its license check failed. Details: ...". Fix by placing xpauth.xpr or setting XPAUTH_PATH.
  • Community-Edition size cap exceeded. Xpress raises with a message containing "oem" or "exceeds the size of an OEM problem". FlexTool surfaces this as the licence-error family. The fix is either to shrink the model or to upgrade to a full licence — Community Edition is unsuitable for production FlexTool scenarios.
  • Unknown Xpress control. A setControl the console does not know is reported in the solver output; FlexTool does not check Xpress' names. The control names are in the Xpress Optimizer reference manual.
  • Time limit reached. An LP stopped at its time limit stops the run. See Time and other limits.
  • Objective values. MIPABSCUTOFF, MIPADDCUTOFF and MIPABSSTOP are written in unscaled currency; FlexTool scales them to the objective Xpress sees (see Time and other limits).

How to set it in FlexTool

On the solve entity:

solve_advanced.solver         = "xpress"
solve_advanced.solver_mip_gap = 0.005
solve_advanced.solver_arguments:
  defaultalg = 4
  presolve   = 1
flextool <input_db_url> --solver-time-limit 60

--solver-time-limit and --solver-mip-gap reach Xpress as MAXTIME (whole seconds, rounded up: MAXTIME 60 on an LP, MAXTIME -60 on a MIP, see below) and MIPRELSTOP (for a MIP), over the solve's solver_mip_gap, its solver_arguments and xpress.opt (precedence in Solver selection). Parameter names match without regard to case. --threads (Threads per run in the FlexTool window) sets THREADS; without it, THREADS in xpress.opt or solver_arguments applies. --highs-threads does not change it. MIPTHREADS, BARTHREADS and CONCURRENTTHREADS are used as given. The run prints what Xpress receives in a Solver args (xpress): line before each solve.

A positive MAXTIME stops a MIP only once Xpress has an integer solution; a negative one is a hard limit of its absolute value. FlexTool's own time limit (--solver-time-limit, FLEXTOOL_SOLVER_TIME_LIMIT, or the solve's time limit) is a hard limit, so on a MIP it reaches Xpress negated: --solver-time-limit 59.5 gives MAXTIME -60. The Solver args (xpress): line, the <solve>.opt record next to the MPS and the script Xpress gets all show -60. A MAXTIME you write in xpress.opt or solver_arguments (without the flag) is passed as written: a positive value there lets a MIP without an integer solution go on until FlexTool stops it (twice the limit plus 10 minutes), and the run stops.


Verified install on: [empty]