Skip to main content

Drop-in gurobipy wrapper backed by the HiGHS solver

Project description

grbcompat

PyPI CI License: MIT

A Python package that lets you run gurobipy-based optimization models on the free, open-source HiGHS solver — with no changes to your existing code.

Why

Gurobi is a best-in-class commercial solver, but it requires a licence. HiGHS is a high-quality open-source LP/MIP solver. This wrapper translates the gurobipy API into HiGHS calls at runtime, so you can:

  • Run models on HiGHS during development without a Gurobi licence.
  • Switch freely between solvers to compare results or costs.
  • Keep a single codebase that works with either solver.

Requirements

  • Python ≥ 3.11
  • highspy ≥ 1.7 (installed automatically)
  • A Gurobi licence is not required to use this wrapper.

Installation

pip install grbcompat

Or, to work from source:

git clone <repo-url>
cd grbcompat
uv sync --dev

Usage

Pattern A — Drop-in replacement (one extra line)

Add a single install() call before any import gurobipy statement. Every subsequent import gurobipy in that process resolves to the HiGHS-backed wrapper. Your existing code stays untouched.

import grbcompat
grbcompat.install()          # ← the only change

import gurobipy as gp                # now backed by HiGHS
from gurobipy import GRB

m = gp.Model("my_model")
x = m.addVar(lb=0, name="x")
y = m.addVar(lb=0, name="y")

m.setObjective(x + 2 * y, GRB.MINIMIZE)
m.addConstr(x + y >= 1, "demand")
m.optimize()

print(f"x={x.X:.4f}  y={y.X:.4f}  obj={m.ObjVal:.4f}")

Pattern B — Side-by-side solvers

Import the wrapper directly under its own name. Both solver namespaces are fully independent and can be used in the same script simultaneously.

import grbcompat as highs    # backed by HiGHS (free)
import gurobipy as gp                # backed by Gurobi (licensed)

from grbcompat import GRB as HGRB

# Build the same LP with both solvers
def build(Mod, G):
    m = Mod()
    x = m.addVar(lb=0.0, name="x")
    y = m.addVar(lb=0.0, name="y")
    m.addConstr(x + y >= 4, "demand")
    m.setObjective(2 * x + 3 * y, G.MINIMIZE)
    m.optimize()
    return m, x, y

m_h, x_h, y_h = build(highs.Model, HGRB)
m_g, x_g, y_g = build(gp.Model, gp.GRB)

print(f"HiGHS:  obj={m_h.ObjVal:.4f}  x={x_h.X:.4f}  y={y_h.X:.4f}")
print(f"Gurobi: obj={m_g.ObjVal:.4f}  x={x_g.X:.4f}  y={y_g.X:.4f}")

Supported gurobipy API

Model

Method / Property Notes
addVar(lb, ub, obj, vtype, name) All types: CONTINUOUS, INTEGER, BINARY
addVars(*indices, lb, ub, obj, vtype, name) Scalar, list, range, or cartesian-product indices; lb/ub can be dicts
addConstr(lhs, sense, rhs, name) TempConstr from <=/>=/==, or explicit sense/rhs
addConstrs(generator, name) Returns a tupledict
addLConstr(...) Alias for addConstr
setObjective(expr, sense) GRB.MINIMIZE / GRB.MAXIMIZE
optimize()
update() No-op (changes applied immediately)
reset() Clears solution without rebuilding the model
write(filename) Writes .lp, .mps, or other HiGHS-supported formats
setParam(name, value) Alias for model.Params.<name> = value
setAttr(attr, value) Supports ModelSense, ObjCon
getAttr(attr, objects) Batch-reads X, Pi, Slack, RC, LB, UB, …
getVars() / getConstrs()
getVarByName(name) / getConstrByName(name)
ObjVal, ObjBound, MIPGap After optimize()
Status, Runtime
NumVars, NumConstrs
ModelName, ModelSense Readable and writable
Context manager (with Model() as m)

Var

Attribute / Property Notes
X Primal value (after optimize())
RC Reduced cost
LB, UB, Obj, VType, VarName Readable and writable; changes take effect immediately
+, -, *, /, unary - Returns LinExpr
<=, >=, == Returns TempConstr for use in addConstr

Constr

Attribute / Property Notes
Pi Dual value / shadow price (after optimize())
Slack Constraint slack (after optimize())
ConstrName, Sense, RHS RHS is writable; change takes effect at next optimize()

LinExpr

Full arithmetic support: +, -, *, /, unary -, sum() built-in, ==/<=/>= to produce constraints.
Methods: size(), getCoeff(i), getVar(i), getConstant(), add(), addTerms(), getValue().

tupledict

Returned by addVars and addConstrs. Supports select(*pattern), sum(*pattern), prod(coeff_dict, *pattern).

GRB constants

GRB.MINIMIZE / GRB.MAXIMIZE
GRB.CONTINUOUS / GRB.INTEGER / GRB.BINARY / GRB.SEMICONT / GRB.SEMIINT
GRB.LESS_EQUAL / GRB.GREATER_EQUAL / GRB.EQUAL
GRB.INFINITY
GRB.OPTIMAL / GRB.INFEASIBLE / GRB.UNBOUNDED / GRB.INF_OR_UNBD
GRB.TIME_LIMIT / GRB.ITERATION_LIMIT / GRB.SOLUTION_LIMIT / 
GRB.Status.*   # mirrors the top-level codes
GRB.Attr.*     # attribute name strings

Params

Set solver parameters via attribute assignment. gurobipy names are translated to their HiGHS equivalents automatically.

gurobipy name HiGHS option Type
TimeLimit time_limit float
MIPGap mip_rel_gap float
MIPGapAbs mip_abs_gap float
FeasibilityTol primal_feasibility_tolerance float
OptimalityTol dual_feasibility_tolerance float
IntFeasTol mip_feasibility_tolerance float
OutputFlag output_flag bool
Threads threads int
Seed random_seed int
NodeLimit mip_max_nodes int
IterationLimit simplex_iteration_limit int

Unknown parameter names are forwarded directly to HiGHS.

Compatibility stubs

GurobiError, Env, disposeDefaultEnv — accepted and silently ignored so that licence-management code in existing scripts does not break.

Module-level functions

grbcompat.quicksum(iterable)      # → LinExpr
grbcompat.multidict(data)         # → [keys, dict1, dict2, …]
grbcompat.install()               # patches sys.modules['gurobipy']

Running the tests

uv sync --dev
uv run pytest

The test suite has 388 tests across 10 files:

File Tests Coverage
test_constants.py 28 All GRB constants and status codes
test_expr.py 47 LinExpr arithmetic, merging, TempConstr
test_var.py 52 All Var properties, setters, operators
test_constr.py 22 Constr metadata, duals, slacks, RHS setter
test_tupledict.py 31 select, sum, prod, addVars integration
test_params.py 16 All mapped params, unknown-param error
test_model_core.py 81 addVar/Vars, addConstr/Constrs, setObjective, I/O
test_model_lp.py 32 LP correctness, duals, re-optimization
test_model_mip.py 15 Binary, integer, mixed-integer programs
test_api_compat.py 55 install() isolation, gurobipy usage patterns
test_gurobi_comparison.py 29 Cross-solver comparison (skipped without Gurobi licence)

Cross-solver comparison tests

If you have a valid Gurobi licence, the comparison tests run automatically and verify that HiGHS and Gurobi produce identical results (within 1e-4 tolerance) for LP objectives, primal values, dual values, slacks, solve status, and MIP objectives:

pytest tests/test_gurobi_comparison.py -v

Without a licence they are skipped with a clear message — no configuration needed.


Limitations

  • Quadratic objectives and constraints (QuadExpr, QConstr) are not supported. HiGHS does support QP but the translation layer is not yet implemented.
  • Model.remove() (removing individual variables or constraints) is not implemented.
  • Callbacks (Model.optimize(callback)) are not supported.
  • Multi-objective and scenario features are not supported.
  • HiGHS and Gurobi may return different optimal bases for degenerate problems; primal solution values can differ while objective values agree.

How it works

When you call install(), the package registers itself under sys.modules['gurobipy']. Subsequent import gurobipy statements in the same process return the wrapper instead of the real package.

Internally, each Model creates a highspy.Highs instance. Variable and constraint operations translate directly to HiGHS column/row operations applied immediately (no lazy batching). model.update() is a no-op.

The solver-status integer codes (GRB.OPTIMAL = 2, etc.) match gurobipy's values exactly, so any code that branches on model.Status works correctly with either solver.


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grbcompat-0.1.2.tar.gz (90.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grbcompat-0.1.2-py3-none-any.whl (31.5 kB view details)

Uploaded Python 3

File details

Details for the file grbcompat-0.1.2.tar.gz.

File metadata

  • Download URL: grbcompat-0.1.2.tar.gz
  • Upload date:
  • Size: 90.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for grbcompat-0.1.2.tar.gz
Algorithm Hash digest
SHA256 2e04cd3392bbf4b3f10a10acf2f64681738ba66e198ec42406afb5858c5ccfb8
MD5 01b005cbf7f260926f39f5bfb83a2922
BLAKE2b-256 7f34b964edab987010522340dc59ee8d0f056411f08f35d709a9ec7553850c06

See more details on using hashes here.

File details

Details for the file grbcompat-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: grbcompat-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 31.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for grbcompat-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d4f0f449ec926b18da7112f749e02293d6a7f50eafc68d7dc3713e68ffac168d
MD5 5c7535ff87806c909ac2c5a77bf3574c
BLAKE2b-256 f48c2043ef50fab04780fda1b7e8097f59e120442448dde52774b444f89aee3b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page