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")
ParameterTypeMeaning
base_urlstrthe service address
api_keystr, optionala key you already have; leave it out and the first call sets one up
timeoutfloat, keyword-onlyper-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
ParameterTypeMeaning
modelPyomo or MathOpt modelthe model to solve, passed directly — the client converts it for you (see Modeling front-ends)
gzipbool, keyword-onlycompress 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

FieldTypeMeaning
statusstroptimal · heuristic · iteration_limit · infeasible · unbounded
objectivefloat or Noneobjective value; None when there is no solution
feasiblebool or Nonewhether the returned solution satisfies all constraints; None where that's undefined (e.g. an unconstrained heuristic)
solutiondict[str, float]variable name → value; empty for infeasible/unbounded
model_classstr or Nonehow the service classified the model (lp, qp, milp, qubo, …)
solve_time_secondsfloatsolve wall time
displaystrthe 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); feasible is None when 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 like heuristic.
  • infeasible — no assignment satisfies the constraints; objective is None, solution is empty. This is a regular status, not an error — check result.status rather 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
FieldMeaning
reasona stable snake_case code, e.g. unsupported_model for a problem class that isn't solved yet
displaythe framed, human-readable message — including how to get in touch
status_codethe 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
MethodMeaning
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.

Talk to us →