quicopt.ir¶
ir ¶
quicopt.ir — a model as plain data.
The name is short for intermediate representation: the form a model takes
between the library that wrote it and the service that solves it. A Program
is exactly that form — variables, expressions and constraints, with no trace of
the library it came from. An importer (quicopt.pyomo, quicopt.mathopt,
quicopt.pulp) builds one; quicopt.wire encodes it to the bytes the
service reads. The shape of a Program is the service's published contract — these types track
it, they never fork it. An index tuple entry is either an int, a concrete
coordinate, or a str, the name of an index to bind.
Example
Maximize 3x + 5y subject to x + 2y ≤ 5, with 0 ≤ x ≤ 4 and y
binary — written directly, with no modeling library in sight:
from quicopt import Client
from quicopt.ir import (Program, VarDecl, Constraint, Nonneg,
Var, Const, Apply, CONTINUOUS, BINARY)
p = Program(
vars=[VarDecl("x", [], CONTINUOUS, 0.0, 4.0, 0.0),
VarDecl("y", [], BINARY, 0.0, 1.0, 0.0)],
objective=Apply("+", [Apply("*", [Const(3.0), Var("x")]),
Apply("*", [Const(5.0), Var("y")])]),
sense="max",
constraints=[Constraint(
f=Apply("-", [Const(5.0),
Apply("+", [Var("x"),
Apply("*", [Const(2.0), Var("y")])])]),
set=Nonneg())],
)
result = Client().solve(p) # a Program solves like a model
print(result.status, result.objective) # optimal 14.0
print(result.solution) # {'x': 3.0, 'y': 1.0}
A constraint is a set membership: the expression f must land in set,
so x + 2y ≤ 5 is written as 5 − (x + 2y) ∈ Nonneg — one sign
convention rather than two.
This is byte-for-byte the Program that quicopt.pulp builds from the
same model written in PuLP, and it solves to the same answer. So writing a
Program by hand is a real option — for a model no front-end expresses, or
for generating one programmatically.
Domain ¶
Bases: IntEnum
The domain a variable ranges over. Values are the codes the service reads.
Expression ¶
Base of the expression grammar.
Param
dataclass
¶
Bases: Expression
A reference to a parameter-table entry — data bound at instance time, by
name and an index tuple (() for a scalar).
Var
dataclass
¶
Apply
dataclass
¶
SetRef
dataclass
¶
A reference to an index set: args=() is the flat set; args=("i",)
references the set indexed by enclosing bound indices.
Reduce
dataclass
¶
Reduce(
op: str,
idx: str,
over: SetRef,
body: Expression,
cond: "Expression | None" = None,
)
Bases: Expression
A fold of body over idx ranging across over — e.g. a Σ or Π —
keeping a term only where cond is non-zero (None ⇒ keep every term).
SourceRef
dataclass
¶
Bases: Expression
A reference to a random variable declared in Program.sources.
Identity lives in the name: every SourceRef("demand") denotes the same
draw, however many times the subtree containing it is copied, so a model's
correlation structure survives substitution and tree copying. Two independent
random variables are two declarations under two names.
Indicator
dataclass
¶
Indicator(bin: Var, inner: object)
bin active (= 1) implies the body satisfies the inner ConSet.
Parametric
dataclass
¶
A random variable drawn from a distribution head with params.
head is a catalog operator ("normal", …) and each parameter is an
ordinary deterministic expression — so a distribution whose mean is itself a
decision (an endogenous distribution) needs nothing the grammar does not
already have. A parameter containing a SourceRef is rejected by the
service: a distribution's parameters are data, not draws.
Empirical
dataclass
¶
A random variable given as a fixed scenario column of data.
Exactly Program.scenarios values, one per scenario. Several empirical
columns are read at the same scenario index, so columns drawn jointly stay
correlated — which is how a joint distribution is expressed.
VarDecl
dataclass
¶
VarDecl(
name: str,
axes: list,
domain: Domain,
lower: object,
upper: object,
start: float,
)
A variable declaration: name over the product of the index sets in
axes ([] ⇒ scalar), ranging over domain, with lower/upper
bounds and an initial start. A bound is a float, or the str name of a
Param table when it varies by index.
IndexSet
dataclass
¶
A named index set with concrete elements (each int or str).
Constraint
dataclass
¶
Constraint(f: Expression, set: object, over: list = list())
A constraint row: the expression f lies in the ConSet set, for every
binding in over ([(dummy, SetRef)]; empty ⇒ a single scalar row).
Program
dataclass
¶
Program(
sets: list = list(),
indexed_sets: dict = dict(),
params: dict = dict(),
vars: list = list(),
objective: Expression = None,
sense: str = "min",
constraints: list = list(),
fix: dict = dict(),
scenarios: int = 1,
scenario_seed: int = 1,
sources: dict = dict(),
)
A complete optimization model: index sets and data tables, variable
declarations, the objective and its sense, the constraint rows, and any
per-index variable pins (fix).
A model under uncertainty adds three more: the random variables it draws
(sources), how many scenarios are drawn (scenarios) and the seed they
are drawn from (scenario_seed). The last two are model data — they pin
the sampled instance, so the same Program always sees the same draws. Left at
their defaults they say nothing, and the encoded bytes are those of a
deterministic model.