Skip to main content

optimaze

A multi-agent system that auto-tunes Gurobi MIP solver runs. A central orchestrator runs the optimization loop, coordinating specialized agents that propose a solver config, run it, and diff the result — converging on a faster Gurobi configuration for each model.

PyPI Python License

What this is

optimaze wraps Gurobi in an agentic tuning loop. A central orchestrator runs the optimization loop and coordinates three specialized agents:

  • Proposer (tuning-strategy) — decides the next solver config to try. It runs a Thompson-sampling bandit over a 9-parameter space (MIPFocus, presolve, cuts, symmetry breaking, and more), seeded by k-NN retrieval over structurally similar MIPLIB instances, with an optional LLM that injects creative out-of-distribution configs.
  • Solver runner — executes each proposed config against the model in a pool of warm Gurobi worker subprocesses and records the outcome: solve time, optimality gap, and branch-and-bound nodes.
  • Performance differ — compares every run to the default-config baseline, updates the proposer's beliefs, and writes an auditable report explaining why the winning config won.

The orchestrator loops until the time budget is spent or progress stalls. An automated eval harness scores runs against the MIPLIB benchmark suite, and every run emits structured logs plus a markdown report from day one — so you can always see what each agent did and why.

Compared to grbtune (Gurobi's built-in exhaustive tuner), optimaze reads the model: it uses constraint-graph features and priors from structurally 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.2.

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.2)

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.2. 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.2 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.2 — 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.5 — formulation_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.1},
  url     = {https://github.com/danielpuri1901/optimaze-agent}
}

License

MIT. See LICENSE.

Metadata

Release files for optimaze 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for optimaze 0.4.1
File Size Uploaded Provenance
optimaze-0.4.1.tar.gz 131.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for optimaze 0.4.1
File Interpreter ABI Platform
optimaze-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 208.7 kB

Release files / optimaze-0.4.1.tar.gz

Download URL optimaze-0.4.1.tar.gz
Size 131.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e0fe515baa86ba8067e53cf2bb5c2e21081c6322e129bb89fb76640f527bebe7
BLAKE2b-256 checksum
How to use checksums
73948ce058484387247ff34493079048fc5d1117b3e5b0cf420554f77cc622e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release files / optimaze-0.4.1-py3-none-any.whl

Download URL optimaze-0.4.1-py3-none-any.whl
Size 77.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3f3e66eb6ad3d6b62fa4aeec6011a97ac927fbe829f3ce7d593a2d7c451d9efb
BLAKE2b-256 checksum
How to use checksums
189378412f1bd0df3497258ed0bd32adfc5579e3ed7bccbf3de9a9c7a50ab730
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Security for optimaze 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page