Glossary¶
The one definition of each name this project uses. The rest hang off one distinction:
A spec is what you write: the math, with no data. A model is a spec with your data attached, a
Modelin Python. A result is one answer read back.
spec ──▶ build ──▶ Model ──▶ solve ──▶ Result
│ (+data) (one answer)
└─────▶ check ──▶ Program
(the plan, for reading)
The chain¶
- Spec
- Short for specification. The math before any data: a YAML file, a
mapping, or a
Specfrommathspec.to_spec. It carries no numbers, and every verb takes it first. ASpeccarries its own program, so one handed back to a verb is not read again. What it may contain is the language. - Program
- The spec lowered to the plan a build reads its rows off: what
checkreturns, still with no data, for reading the plan. No verb takes one back: lowering has no inverse, so keep theSpec(the spec argument). The two states are the language's (SpecandProgram). - Formulation
- A block that states rows nothing lowers,
piecewise:today. Every verb refuses a spec still carrying one;to_spec(spec).expand('piecewise')or.expand()writes it out first (the spec argument). - Model
- A spec with data attached, the language's own meaning of the word
(glossary).
These docs use it in no other sense.
specsolve.Model, whatbuildreturns, is one. OneModelfeeds any sink throughsolve()orwrite(path);row(...)anddiagnostics()read it without solving.update(...)puts new numbers on it in place. - Result
- One answer read back from a solve:
objective,primal(name),dual(name),evaluate(expression)and the rest of reading a result. It owns its tables, so it outlives its model. - Answer
- What came back, whichever verb asked: a
Resultfor one solve, aSweepfor a sweep.savewrites one as a directory —record.parquetfor how it terminated, thenprimal/,dual/,activity/andexpression/— and an archive holds that directory asanswer/. - Archive
- A spec, the data it was solved with and what came back, written together as
one zip or one directory by
archive=(archiving). It reads back as aSolveArchive, or aSweepArchivewhere the sources were cut. Itsrunis the archive's own name, stamped into the answer when it is written. Never "artifact". - Digest
- A hash that says whether two things are the same input.
spec_digestnames the document an answer came from, and an archive whose answer names another is refused;archive.source_digestsnames each data member, so two archives of one spec say which input moved.
The verbs¶
- check · build · solve · write
check(spec)validates and lowers;check(spec, sink)also asks whether that sink takes it.build(spec, sources)returns a Model.solveandwritebuild and then solve or stream in one call. There is no Python API for constructing a spec.- evaluate
evaluate(spec, sources, expression)values one expression of a spec that declares no variables: arithmetic on the attached data, no solver.result.evaluate(expression)is the same read at a solution.- update
model.update(sources)puts new numbers on a built model in place, naming only what changed. A change that moves a mask rebuilds and solves cold.- load · scan
- The two ways a saved answer is read back.
load_result,load_sweepandload_archiveread whole, so the directory is free afterwards.scan_result,scan_sweepandscan_archiveread each frame at the call that asks for it, so the files have to outlive the value (loading or scanning). Never "open". - Buildable
- The type alias for a spec argument:
str | Path | Mapping | Spec. The loweredProgramthatcheckreturns is not one. - Source
- The type alias for one value of
sources. The shapes it covers are the data contract. - Label
- One member of a dimension,
windsay, and its type alias:int | float | str | datetime. A sweep's slice key is a label too, andEachCoordinate(dim)slices on one label ofdimat a time.
The data¶
- Index
- A dimension's labels in order, supplied under the dimension's own key in
sources.shiftreads that order positionally (the data contract). - Coordinate
- One point of a declaration's dimensions: one snapshot for one generator. A parameter has a value at each coordinate it covers, or no row there. The language calls the dimensions themselves the declaration's frame (named expressions).
- Table
- A polars
DataFramewith one column per dimension, avaluecolumn and one row per coordinate: what a parameter arrives as, and whatprimalhands back. A relation's table is the exception, one column per column it declares. The code calls one a frame and means the same thing. - Relation
- A named map between dimensions, supplied under its own key as a table of the rows it has. A keyed relation declares key columns and value columns and holds one row per key; a bare one holds each row at most once (the data contract).
- Assumption
- An
assumptions:entry: a predicate on the data that only the numbers can answer, checked when data attaches and refused as aDataErrorwhere it fails. The conditions apiecewise:method puts on its breakpoints arrive the same way. - Mask
- The
where:on a declaration. What an excluded coordinate means is absence.
How it runs¶
- Lane
- A way a spec is executed. specsolve's is the relational lane: it
validates at load time, lowers to the plan and streams on polars. The test
suite's linopy lane builds the same spec as a
linopy.Model, as the oracle the relational lane is checked against (relationship to linopy). - Engine
- The relational lane's builder: it fills the model's tables from the attached data and hands them to a sink.
- Sink
- Where the handoff lands: a solver (
highs,gurobi,xpress) or a file writer (.lp,.mps).linopyis a lane, not a sink. What a sink can ingest is its capability: a special-ordered set is one, and a sink without it refuses a model carrying a set rather than rewriting it (what each sink takes). - Sources
- The data you attach: parameter, dimension and relation names to tables, and dimension names to their labels.
- attach
- Fitting sources onto a spec to make a Model; what
builddoes andupdatedoes again. Never "bind", so thatboundmeans one thing.
The built form¶
- Handoff
- The built model as a sink sees it, and all a sink sees:
cols(bounds, type),obj,rows,matrix(CSR),quad(the objective's quadratic part),qmatrix(the constraints') andsos. Handing it over is the phase the metrics clock ashandoff_seconds. - keep
- How much of a session
model.solvecarries to the next solve:solver(default),progress(its work too) ornothing(the verbs).
Sweeps¶
- solve_over (a sweep)
- Solve one spec once per slice of an axis and fold the answers into a
Sweep, releasing each slice's model as it goes. A sweep, never a "study" (sweeps). - Axis · slice · key
- An axis says how the sources split:
EachCoordinate(dim), one slice per label;EachWindow(dim, ...), one per window of consecutive labels; or a hand-built list of(key, sources)pairs. A slice is one set of sources, solved as one model, and its key is the label its rows are prefixed with in every table the sweep hands back. - Sweep
- A sweep's answer:
Result's readers one dimension wider, the key column first.original_index=Truereads a table back over the sliced dimension's own labels. - carry
carry={parameter: variable}hands one slice's solution to the next as data, in slice order.- held · spilled
- Where a sweep's frames are. A held sweep carries them in memory, and
sweep.primal(name)and the exports — the frame readers, the ones that hand back a table — answer off them. A spilled sweep left them in a directory, which is whatspill_to=writes and whatscan_sweepreads: theresweep.scan(name)is the reader and the frame readers refuse (spilling).
Row types¶
- Record · Metrics · SliceMetrics
- The three saved rows, each a
NamedTuplethat names its own columns. Where a column is nullable, the type also derives the schema it is written with, so an all-null column keeps its own type instead of the one a single row infers. Record is how a solve terminated, one per solve, and whatresult.recordhands back. Metrics is what it took — the sizes, what the sink added to them, the counters and the clocks, every clock naming its unit — and is whatarchive.metricshands back (the attributes). SliceMetrics is one slice of a sweep's share of that, in its own columns, and is the row behindsweep.metrics.
A row is a value and gets a type; a table stays a
Table. So a result hands back its one Record, while
Record and SliceMetrics are the rows behind sweep.record and
sweep.metrics rather than what those hand back, and a reader that wants
one row of a table asks the frame for it.
bound means one thing¶
- bound
- A lower or upper limit on a variable or a constraint row: the
bounds:of a declaration, theBOUNDSsection of an.mpsfile, an absent bound the solver reads as infinity. Nothing else; data is attached, never bound.