Run a model¶
Five steps from pip install to an answer read back, on the dispatch model
of the home page: three generators meet a load over four
snapshots at least cost. What a spec may contain is
the language's
to say.
1. Install¶
That brings polars, HiGHS and the language.
2. Save the spec¶
Copy the YAML from the home page
into dispatch.yaml. It is also
examples/dispatch.yaml
in the repository.
3. Check the file¶
check reads the file against the language, and needs no data to do it. To
see it refuse one, take the sum out of power_balance: change its line to
expression: p == load, and check again:
DimensionError: Constraint 'power_balance': the expression carries dims ['generator'] that are not in its dims: ['snapshot'] — every stray dim multiplies the rows this constraint builds; add it to dims: if that is intended, or sum it out.
The message names the fix. Put sum(p, over=generator) back before the next
step.
4. Attach the numbers and solve¶
The file declares three parameters and two dimensions. sources supplies
each by name. A parameter over one dimension is a table with that dimension
and a value column; a bare sequence supplies a dimension's labels:
import polars as pl
generators = ['wind', 'solar', 'gas']
sources = {
'p_max': pl.DataFrame({'generator': generators, 'value': [80.0, 0.0, 200.0]}),
'cost': pl.DataFrame({'generator': generators, 'value': [10.0, 25.0, 50.0]}),
'load': pl.DataFrame({'snapshot': range(4), 'value': [60.0, 120.0, 180.0, 90.0]}),
'snapshot': range(4),
'generator': generators,
}
result = sps.solve('dispatch.yaml', sources)
print(result.objective) # 10500.0
Wind at 10 runs first, and gas at 50 covers what is left. Solar has no
capacity, so the where: "p_max > 0" on p built no column for it.
5. Read the answer back¶
print(result.primal('p')) # (snapshot, generator, value): eight rows, wind and gas at each snapshot
print(result.dual('power_balance')) # (snapshot, value): the price of one more unit of load
Each answer is a polars table keyed by the declaration's labels. The dual is the cost of the last generator on: 10 at snapshot 0, where wind alone covers the load, and 50 at the other three.
Where next¶
| Tables in, tables out | the next lesson: parquet in, tables out, and an archive to query |
| Preparing the data | from files to the tables above |
| The verbs · The data contract | what every call takes, returns and refuses |
| Choosing a solver | another solver, or a file for a tool specsolve has no solver for |
| Language reference · the limits of the language | what a file may contain, and where it stops |
| Debug a wrong answer | when it solves and the number is wrong, or it does not solve |
| Examples | every model in the repository |
| Roadmap | what is refused on purpose |