Skip to content

Releases: fluxopt/specsolve

0.7.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 10:16
5adfc58

specsolve now requires polars 2.0. An environment that must stay on polars 1.x
keeps 0.6.2.

  • feat(deps): specsolve runs on polars 2.0 and requires it (#1857)

0.6.2

Choose a tag to compare

@github-actions github-actions released this 07 Oct 06:33
9e47978
  • fix(archive): a sweep being archived is invisible to a reader of its directory until it lands (#1873)
  • docs(benchmarks): the benchmark page is one page in the site's theme, built on a published table of measurements (#1851, #1855, #1860, #1862)

0.6.1

Choose a tag to compare

@github-actions github-actions released this 06 Oct 15:51
79258b1

specsolve now requires polars below 2.0. On polars 2.0.0, a row's dual can come
back empty, and a model can take about nine times the memory. Nothing else
changes.

  • fix(deps): specsolve installs a polars older than 2.0, on which a row's dual can come back empty and a model can take nine times the memory (#1852)
  • docs: the published benchmarks are re-measured on specsolve 0.6.0 (#1850)

0.6.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 10:48
aa90239

Breaks:

  • An archive, spill or saved result written by 0.5.0 is refused: the layout is 3.
  • catalog.parquet has no dim_position.
  • owned.parquet is at answer/windows/, and only with keep_windows=True.

The pull requests since 0.5.0:

  • fix(data): a datetime label is held in microseconds whatever unit it arrives in (#1839)
  • feat(archive): an archive writes every column as a type that parquet readers agree on (#1835)
  • fix(archive): an archive's catalog describes each file as it is written, and kept windows have a catalog of their own (#1838)
  • fix(sweep): a sweep over a datetime axis in nanoseconds or milliseconds solves rather than crashing in its first slice (#1848)

0.5.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 14:31
44fe66e

The top level of specsolve now holds only what you call. What a call returns
is in specsolve.types, and what it raises is in specsolve.errors. Any other
name under specsolve. is internal. A spilled sweep now reads like one held in
memory. This release breaks imports, one class name, one attribute and one
method. Nothing on disk changed: archives, spills and saved results written by
0.4.0 read back.

Breaks:

  • Model, Result, Sweep, ResultArchive and SweepArchive are imported
    from specsolve.types, and so are the rows they hold: Record,
    Provenance, Metrics, Diagnostics and ConstraintRow. Write
    sps.types.Result for sps.Result. specsolve.relational.parquet is
    removed.
  • Every error and SpecsolveWarning is imported from specsolve.errors.
    Write sps.errors.DataError for sps.DataError.
  • SolveArchive is now ResultArchive. What an archive holds is
    archive.result for one solve and archive.sweep for a sweep; .answer is
    removed.
  • Model.evaluator is private. An archive and a sweep still evaluate an
    expression the file never named.

New:

  • On a spilled or scanned sweep, primal, dual, evaluate, to_pandas,
    to_dataarray, to_dataset and save read the name they are asked for
    instead of refusing. sweep.scan(name) returns the same frame, not yet read.
  • The reference has an internal glossary: the names the code uses for its own
    parts, for anyone reading src/.

The pull requests since 0.4.0:

  • refactor(archive): Record, Metrics and Provenance are imported from specsolve.relational.answer_layout, which an archive's own layout nests (#1823)
  • refactor(archive): an archive of one solve is a ResultArchive read through .result, and a sweep archive is read through .sweep (#1828)
  • feat(sweep): a spilled or scanned sweep's readers read the name they are asked for instead of refusing (#1830)
  • refactor(api): what a call returns is imported from specsolve.types, and what it raises from specsolve.errors (#1833)

0.4.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 08:43
cbd485d

An archive now says what produced it, and a directory of archives reads as one
table per file. This release breaks archives, spills and saved results from
0.3.0, a model file that uses a reserved name, one import and one keyword.

Breaks:

  • An archive, a sweep spill or a saved result written by 0.3.0 is refused by
    name. Its format.json names the specsolve that wrote it: read it with that
    release.
  • A spec that declares a name starting with specsolve_, in any letter case,
    is refused. Rename the name. The prefix is reserved for the columns
    specsolve adds.
  • The readers of a sweep return the answer. An EachWindow sweep comes back
    over the model's own coordinates, and the lookahead rows are dropped.
    original_index= is removed. To get the frames of each window, pass
    per_window=True.
  • A sweep archive holds the answer. To archive the frames of each window too,
    pass keep_windows=True to solve_over.
  • SliceMetrics is removed. A row of sweep.metrics is a Metrics row, and
    loaded is now loads, which is 0 or 1.
  • The run column of record and metrics is now specsolve_run.

New:

  • Every table in an archive carries specsolve_run, the archive's own name.
    record.parquet and metrics.parquet have the same columns for a solve and
    for every kind of sweep. A sweep names each slice in slice_axis and
    slice.
  • catalog.parquet lists each file an archive holds, with its kind,
    description and dimensions.
  • An archive holds each source as the tidy table that the solve read.
    sps.tidy(spec, sources) returns those tables.
  • The record names the solver, its version, its options, and the specsolve
    and mathspec versions. The options are a JSON string. To record more
    options than the solver's list, pass record_options=.
  • specsolve requires mathspec>=0.2.1,<0.3, so a release installed later
    gets the mathspec it was released with.

Fixes:

  • A sweep key named like a metrics column, such as loads, is refused before a
    slice is solved.
  • A sweep over an index given as an iterator reads it once, and every slice
    and the archive see the same labels.

The pull requests since 0.3.0:

  • fix(deps): an installed specsolve release keeps the mathspec minor version it was released against (#1816)
  • feat(archive): every archived table carries the run it came from as specsolve_run, and names starting with specsolve_ are reserved (#1809)
  • feat(archive): an archive's record and metrics have the same columns for a solve and for every kind of sweep (#1810)
  • feat(archive): an archive lists every name it holds, its kind, description and dimensions in catalog.parquet (#1812)
  • feat(sweep): a sweep reads and archives its answer over the model's own coordinates by default, and keeps the per-window frames only on request (#1811)
  • feat(data): an archive holds each source as the tidy table the solve read, and tidy() returns those tables (#1813)
  • fix(sweep): a sweep key named like a metrics column is refused before a slice is solved (#1820)
  • feat(archive): an archived answer names the solver, its options and the specsolve and mathspec versions that produced it (#1817)
  • feat(api): a caller can name more solver options whose value the record keeps (#1818)

0.3.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 10:53
3ff0e3e

specsolve now requires mathspec 0.2.1. This release breaks one import.

  • check(spec, sink=...) is removed. To ask a sink without a solve, call
    build(spec, sources).check(sink). A sink refuses only what the built model
    asks of it.

With mathspec 0.2.1:

  • A divisor, a power's base or an exponent may add over parameters, such as
    x / (1 - cost) or (1 + rate) ** years.
  • A spec composed from several files with mathspec.merge builds. A fragment
    is refused by name.

Fixes:

  • A constant sum that no member reaches at a coordinate adds zero there.
  • A cases: region whose value is 0, read through a relation, no longer
    makes the build refuse its rows.

The pull requests since 0.2.1:

  • feat(sinks): a built model checks whether a sink takes it without a solve, and check no longer takes a sink (#1806)
  • feat: specsolve requires mathspec 0.2.1, where a divisor or a power over parameters may add and a spec may be composed from several files (#1800)
  • fix(engine): a constant sum that no member reaches at a coordinate adds zero there rather than leaving a gap (#1801)
  • fix(engine): a cased quantity whose otherwise is zero no longer reads as short where it is read through a relation (#1804)
  • docs: the tutorials teach in the order a new user needs them, and warm-starting a re-solve has its own how-to guide (#1788)
  • docs: a how-to guide chooses a solver or writes the model to a file, and lists the solvers this build has (#1790)
  • docs: a how-to guide reads an answer into pandas or xarray (#1789)

0.2.1

Choose a tag to compare

@github-actions github-actions released this 29 Sep 13:17
5ced980

This release fixes three wrong answers. None of them raised an error. A model
that meets one builds a different row, or reads a different value, in 0.2.1.
No file, archive or import breaks.

  • A sum over a variable with a where:, beside a parameter over fewer
    dimensions, such as sum(y + w, over=f) with w over f alone. The
    parameter now drops out where the variable is absent, in the constraint row
    and in evaluate. Before, it stayed in, so the row had a wrong right-hand
    side.
  • A divisor, a power's base or an exponent that is a sum(...). It is now
    taken as its total, in a build and in a read. Before, it was taken summand by
    summand.
  • A reported quotient whose divisor is absent or zero. It now has no value at
    that coordinate. Before, it read inf or raised a DataError.

Result.dual now states the sign of a dual: the rate at which the optimal
objective rises with the row's right side, for every comparator, under either
sense and on every solver. No value changes. mathspec's reference now defines
dual(c) the same way
(energy-models/mathspec#751).

The pull requests since 0.2.0:

  • fix(engine): a sum leaves out a parameter where a variable added to it is absent, in the model and in a read (#1784)
  • fix(engine): a divisor, a power's base or an exponent that is a sum is taken as its total rather than summand by summand (#1779)
  • fix(api): a reported quotient is absent where its divisor is absent or zero (#1776)
  • docs(api): a dual is the rate at which the optimal objective rises with its row's right side, on every sink (#1774)

0.2.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 16:48
300fc71

A saved answer now records which layout it was written in and which specsolve
wrote it, so a later release can name an answer it no longer reads. The Python
API reference is now rendered from the docstrings.

This release breaks one thing:

  • An answer or an archive that 0.1.0 or earlier wrote is refused with a
    LayoutError that says to solve the model again and save it. Its
    format.json reads {"answer": 0}; 0.2.0 writes
    {"layout": 1, "specsolve": "0.2.0"}. An archive still holds the spec and
    the data it was solved with, under spec.yaml and sources/.

The pull requests since 0.1.0:

  • feat(api)!: a saved answer is stamped with layout 1 and the specsolve version that wrote it, and one written by 0.1.0 or earlier is refused by name (#1765)
  • docs: each fact about the Python API is stated once, in the docstring of the name it belongs to (#1769)
  • docs: the Python API page renders every public name from its docstring (#1766)
  • docs(sweeps): the sweep reference says how many sessions a sweep opens on a remote Gurobi (#1771)

0.1.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 16:16
40193d0

🎉 specsolve is officially on PyPI!

pip install specsolve

specsolve 0.1.0 requires mathspec 0.2.0 and uses its words. A spec is the
problem a file states, with no data. A model is a spec with data attached,
which build returns as a Model
(glossary).
The messages and the docs use the two words in these senses.

Since 0.1.0rc1, this release breaks three things:

  • An archive holds its spec as spec.yaml, not model.yaml. An archive that
    0.1.0rc1 wrote is refused with a LayoutError. To read one, rename its
    model.yaml member to spec.yaml.
  • specsolve requires mathspec 0.2.0. There, the first parameter of to_spec,
    advice and the typesetting functions is spec, not model, and the module
    mathspec.model is mathspec.spec. A call that passes model= by keyword
    fails. A positional call works as before.
  • Messages say "spec" where they said "model" for the file. A test that
    matches the old text fails.

The pull requests since 0.1.0rc1:

  • docs: the site follows the reader's light or dark setting in its own violet colour, with code, diagrams and footnotes readable in both (#1767)
  • feat!: specsolve requires mathspec 0.2.0 and uses its words spec and model, so an archive holds its spec as spec.yaml (#1768)
  • docs: every link to the language's documentation points at mathspec.readthedocs.io (#1764)
  • fix: the PyPI page links the docs, issues and changelog, and a stale saved answer says the layout moves before 1.0 (#1763)