API reference
The supported way to call Quicopt is the official Python client:
pip install "quicopt[mathopt]" # or quicopt[pyomo]
This page describes it in full — Client, solve(), the Result it returns,
error handling, and the async job API for long solves. Package links:
PyPI ·
source & docs (Apache-2.0).
Client(base_url, api_key=None, *, timeout=60.0)
A connection to the Quicopt service. It holds your API key — and if you don't have one, your very first call sets one up automatically:
from quicopt import Client
client = Client("https://try.quicoptapi.pgi.fz-juelich.de")
| Parameter | Type | Meaning |
|---|---|---|
base_url | str | the service address |
api_key | str, optional | a key you already have; leave it out and the first call sets one up |
timeout | float, keyword-only | per-request timeout in seconds (default 60) |
After the first call the key is readable back from client.api_key — pass it
to a later Client(url, api_key=...) to keep solving as the same caller across
runs.
client.solve(model, *, gzip=False)
Solves a model synchronously and returns a Result. This
is the call you'll use most:
result = client.solve(model)
print(result.status, result.objective)
print(result.display) # the framed, ready-to-print summary
| Parameter | Type | Meaning |
|---|---|---|
model | Pyomo or MathOpt model | the model to solve, passed directly — the client converts it for you (see Modeling front-ends) |
gzip | bool, keyword-only | compress the request body — useful for large models |
If the service declines a request — for example a problem class that isn't
solved yet — solve() raises QuicoptError. A declined
request never returns a half-filled result.
The Result object
| Field | Type | Meaning |
|---|---|---|
status | str | optimal · heuristic · iteration_limit · infeasible · unbounded |
objective | float or None | objective value; None when there is no solution |
feasible | bool or None | whether the returned solution satisfies all constraints; None where that's undefined (e.g. an unconstrained heuristic) |
solution | dict[str, float] | variable name → value; empty for infeasible/unbounded |
model_class | str or None | how the service classified the model (lp, qp, milp, qubo, …) |
solve_time_seconds | float | solve wall time |
display | str | the framed console report — print it and you get the result view from the examples |
With the MathOpt front-end, solution keys are your variable names from the
model — name your variables and you can read the result without bookkeeping.
The Pyomo front-end currently returns generic x1, x2, … keys.
Status semantics
optimal— proven optimum (typical for LP/QP/MILP);feasible: True.heuristic— best solution found across several shots, optimality not proven (typical for QUBO);feasibleisNonewhen there are no constraints to check.iteration_limit— the solver stopped at its iteration cap and returns the best point found (can happen on hard NLPs); treat it likeheuristic.infeasible— no assignment satisfies the constraints;objectiveisNone,solutionis empty. This is a regular status, not an error — checkresult.statusrather than catching exceptions. There's a worked example.unbounded— the objective can be improved without limit; also a regular status.
Errors: QuicoptError
Anything the service declines raises QuicoptError with three useful fields:
from quicopt import Client, QuicoptError
try:
result = client.solve(model)
except QuicoptError as e:
print(e.reason) # stable code, e.g. "unsupported_model"
print(e.display) # the service's readable message, with a help contact
| Field | Meaning |
|---|---|
reason | a stable snake_case code, e.g. unsupported_model for a problem class that isn't solved yet |
display | the framed, human-readable message — including how to get in touch |
status_code | the HTTP status behind it |
Remember: infeasible and unbounded are results, not errors — you get a
normal Result for those.
Async jobs: client.submit()
For a long solve, don't block — submit the model and poll a job handle:
job = client.submit(model) # returns immediately
job.status() # {"status": "queued" | "running" | "done", ...}
result = job.result() # polls until done, returns the same Result as solve()
print(job.log()) # the solver log so far
job.delete() # remove the job and its stored result
| Method | Meaning |
|---|---|
job.status() | the job's state and a tail of its log |
job.result(wait=True, timeout=120.0, poll=0.5) | the finished Result; with wait=False it fetches once and raises if the job isn't done yet |
job.log() | the job's full plain-text log |
job.delete() | delete the job and its stored result on the server |
submit() takes the same models and the same gzip option as solve().
Beyond the free tier
The free tier is a one-time entry point to try the API. Questions about the client, or real models you want to try Quicopt on? Just ask:
Questions? Talk to us.
Whether something's unclear or you want to try Quicopt on your real models — tell us what you're optimizing.