Skip to content

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.

Const dataclass

Const(value: float)

Bases: Expression

A literal numeric constant.

Param dataclass

Param(name: str, index: tuple = ())

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

Var(name: str, index: tuple = ())

Bases: Expression

A reference to a decision variable, by name and an index tuple (() for a scalar).

Apply dataclass

Apply(op: str, args: list)

Bases: Expression

A catalog operator op applied to its argument subexpressions.

SetRef dataclass

SetRef(name: str, args: tuple = ())

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

SourceRef(name: str)

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.

Zero dataclass

Zero()

f = 0

Nonneg dataclass

Nonneg()

f ≥ 0

Indicator dataclass

Indicator(bin: Var, inner: object)

bin active (= 1) implies the body satisfies the inner ConSet.

Parametric dataclass

Parametric(head: str, params: list)

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

Empirical(data: list)

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

IndexSet(name: str, elements: list)

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.