Skip to main content

AI agent that auto-tunes Gurobi MIP solver runs via parameter tuning + formulation rewriting, with a soft-prompt-specialized proposer trained on MIPLIB.

Project description

optimaze

Auto-tune Gurobi MIP solver runs with a multi-agent bandit + retrieval system.

PyPI Python License

What this is

optimaze is a multi-agent system that auto-tunes Gurobi MIP solver parameters on a per-instance basis. It combines a Thompson-sampling bandit over a 9-parameter config space, k-NN retrieval over a MIPLIB instance index (24-dimensional structural features), and an optional LLM proposer that injects creative out-of-distribution arms. Trials run in a pool of warm Gurobi worker subprocesses, and each run emits an auditable report explaining the winning config.

Compared to grbtune (Gurobi's built-in exhaustive tuner), optimaze reads the model: it uses constraint-graph features and historical priors from similar instances rather than starting from scratch.

Install

pip install optimaze

Optional extras:

pip install 'optimaze[hosted-llm]'   # Anthropic / OpenAI backends
pip install 'optimaze[train]'        # PEFT, datasets, accelerate (offline soft-prompt training)
pip install 'optimaze[dev]'          # pytest, ruff, mypy

You'll need a working Gurobi license on the machine that runs trials — Gurobi runs locally and stays under your license.

Quickstart

optimaze tune model.mps

Defaults: 600 s wall-clock budget, up to 50 trials, 4 parallel workers, output written to ./optimaze_out/. Use --no-llm for a pure-bandit run (no model download, no API key needed):

optimaze tune model.mps --no-llm --budget 60 --max-trials 10 --seed 42

Library use:

from pathlib import Path
from optimaze.config import OptimazeConfig
from optimaze.core.orchestrator import Orchestrator

orchestrator = Orchestrator(config=OptimazeConfig(output_dir=Path("./optimaze_out")))
result = orchestrator.tune(Path("model.mps"), budget_seconds=60, max_trials=10, seed=42)
print(f"best solve_time: {result.best_outcome.solve_time_s:.3f}s "
      f"({result.improvement_pct:.2f}% improvement)")

Example output

The following is the real output of a smoke-test run on the MIPLIB instance markshare_4_0 (dev-tier, 4-trial budget, no LLM, seed 42). Verbatim from optimaze_out/tuning_report.md:

# optimaze tuning report — markshare_4_0

- trials: 4
- baseline solve_time: 0.308s
- best solve_time: 0.236s
- improvement: 23.32%

## Best config
- `BranchDir` = 0
- `Cuts` = -1
- `Heuristics` = 0.6438651200806645
- `MIPFocus` = 1
- `Method` = 3
- `NodeMethod` = 1
- `Presolve` = 2
- `Symmetry` = 0
- `VarBranch` = 3

## Rationale
Best config was 1.19x faster than runner-up (0.24s vs 0.28s) because
Heuristics=0.6438651200806645 (vs 0.05), MIPFocus=1 (vs 0), Method=3 (vs -1),
Presolve=2 (vs -1), Symmetry=0 (vs -1), VarBranch=3 (vs -1).

## Trial log
1. 0.308s  status=2  Baseline: Gurobi default config (always tried first).
2. 0.236s  status=2  Thompson sample: arm pulled 0x, posterior Beta(α=1.00, β=1.00).
3. 0.281s  status=2  Thompson sample: arm pulled 1x, posterior Beta(α=1.20, β=1.80).
4. 0.421s  status=2  Thompson sample: arm pulled 0x, posterior Beta(α=1.00, β=1.00).

Headline: 23.32% wall-clock improvement on markshare_4_0 with 4 trials (0.308s → 0.236s). This is one instance, not a benchmark sweep; broader ML-eval numbers will land alongside the trained soft prefix in v0.4.1.

optimaze_out/ also contains:

  • best_config.json — the winning parameter set as JSON
  • trials.jsonl — one line per trial with config, hash, status, gap, nodes
  • logs/ — per-trial Gurobi logs

How it works

Online (optimaze tune)

user model (.mps / .mps.gz)
    │
    ▼
InstanceEmbedder ──► 24-d feature vector
    │
    ▼
InstanceIndex (faiss k-NN) ──► priors from similar historical instances
    │
    ▼
BanditProposer (Thompson sampling + optional LLM rationale)
    │
    ▼
TrialPool (warm Gurobi worker subprocesses)
    │
    ▼
PerfDiffer ──► updates bandit posterior, generates explanation
    │
    └──► loop until budget exhausted or 5 trials w/o improvement
    │
    ▼
Emit: best_config.json, tuning_report.md, trials.jsonl
Optional --repo: GitCommitter opens branch + PR

Per-arm posteriors are Beta over a normalized speedup r = clip(baseline_time / trial_time, 0, 5) / 5; the proposer Thompson-samples one θ per arm and picks the max. The default Gurobi config is always tried first as the baseline arm.

Offline (training pipeline, not run by users)

MIPLIB instances (240 catalogued; tiers: dev=10 / ci=50 / benchmark=180)
    │
    ▼
ActiveLearningHarness (Bayesian acquisition picks informative trials)
    │
    ├─► TrialPool ──► trial_outcomes.parquet
    └─► InstanceEmbedder ──► instance_index.faiss
            │
            ▼
        DatasetBuilder (outcomes → (features → config + rationale) pairs;
                         rationales labelled by Claude/GPT at training time)
            │
            ▼
        SoftPromptTrainer (PEFT prefix tuning over Qwen2.5-7B, ~20 tokens)
            │
            ▼
        optimaze_prefix.pt   (lands in v0.4.1)

The offline pipeline ships in the wheel under optimaze.harness and optimaze.training. Users can re-run it on their own trial data, but the shipped artifacts come from our training runs.

LLM backends

Backend Flag Soft prefix Network Notes
Qwen local --llm qwen-local (default) yes (when shipped) none Loads Qwen/Qwen2.5-7B-Instruct via transformers. CPU works; GPU recommended once the trained prefix lands.
Anthropic --llm anthropic no (hard-prompt) yes Requires ANTHROPIC_API_KEY. Install with pip install 'optimaze[hosted-llm]'.
OpenAI --llm openai no (hard-prompt) yes Requires OPENAI_API_KEY. Install with pip install 'optimaze[hosted-llm]'.
Pure bandit --no-llm n/a none No model load, no API key. The example above used this mode.

If an LLM backend fails to initialise (missing API key, no model cache, etc.), the CLI logs a warning and falls back to pure-bandit Thompson sampling. The bandit alone is enough to produce the 23.32% improvement shown above.

Differentiator vs grbtune

  • Reads the model. Structural features (sparsity, integrality, constraint graph) inform config proposals. grbtune is black-box exhaustive search.
  • Cold-start from neighbours. k-NN over the MIPLIB index reuses configs that worked on structurally similar instances rather than starting from the default every time.
  • Auditable. Every run emits a markdown report explaining the winning config relative to the baseline and the runner-up; optional --repo opens a PR with the diff.

Status / v0.4.0 notes

This is the first release of the v2 rewrite. Honest scope:

  • Bandit + retrieval pipeline: complete and shipping. The 23.32% number above used this path with the LLM disabled.
  • Hosted LLM backends (Anthropic, OpenAI): complete; use hard-prompt templates. Production-ready as creative proposers.
  • Trained soft-prompt artifact (optimaze_prefix.pt): not yet shipped. The training code (optimaze.training) is included but the artifact lands in v0.4.1. v0.4.0 ships with a hard-prompt fallback in BanditProposer and QwenLocalClient that works without a GPU and without the prefix file.
  • Formulation rewriting (.py input): formulation/rewriter.py is in-tree but the CLI path is param-only in v0.4.0. v0.5 is when the four rewrite types (aggregate constraints, eliminate redundant vars, symmetry-breaking, bound tightening) get plumbed through optimaze tune.

If you're evaluating optimaze against grbtune: the differentiator at this version is cold-start + retrieval + auditable rationales. Soft-prompt specialisation is the v0.4.1 differentiator.

Roadmap

See the full design spec at docs/superpowers/specs/2026-05-17-optimaze-v2-design.md, section 15 (out of scope for v1) and section 18 (build order).

  • v0.4.1 — Trained soft-prompt artifact (optimaze_prefix.pt) shipped in the wheel. ML-eval reports (≥60% of ci-tier instances ≥10% faster vs. default). Soft-prompt ablation numbers.
  • v0.5formulation_trial plumbed through CLI: four named rewrite types (aggregate constraints, eliminate redundant vars, symmetry-breaking, tighten bounds). Param interaction modelling.
  • Later — LoRA fine-tune swap-in once the harness has ≥1k labelled trials. HuggingFace Hub mirror of the prefix artifact. GNN constraint-graph embeddings.

Citation

If you use optimaze in academic work, please cite:

@software{puri_optimaze_2026,
  author  = {Puri, Daniel},
  title   = {optimaze: multi-agent auto-tuning for Gurobi MIP solvers},
  year    = {2026},
  version = {0.4.0},
  url     = {https://github.com/danielpuri/optimaze}
}

License

MIT. See LICENSE.

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

optimaze-0.4.0.tar.gz (124.9 kB view details)

Uploaded Source

Built Distribution

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

optimaze-0.4.0-py3-none-any.whl (73.8 kB view details)

Uploaded Python 3

File details

Details for the file optimaze-0.4.0.tar.gz.

File metadata

  • Download URL: optimaze-0.4.0.tar.gz
  • Upload date:
  • Size: 124.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for optimaze-0.4.0.tar.gz
Algorithm Hash digest
SHA256 901e3a5627ffabb953d4af0d0da1eac108c423de2636e788da521b2292ca9e98
MD5 18c260bda0da8ffbe1afdb7829d2dc59
BLAKE2b-256 f53c5d819a0fc13d70dcb2380dd3fa460914319b1c4203cd96451dacfb3be2e8

See more details on using hashes here.

File details

Details for the file optimaze-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: optimaze-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 73.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for optimaze-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f16a3ef2518219d8b788bd32f13856d6a9a20960bed988758c8d505a6d924c21
MD5 403f9f24154327140521cc0e830985c3
BLAKE2b-256 2938240607b24860b3799d32927a1c55633845f93eab0e6b3bc7a6b0cdd94982

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