Compare two specs#
This guide shows how to diff two specification files (specs) so that the diff contains only what the two specs state differently. You need mathspec installed and two spec files that load.
Write a spec in the canonical form#
Write one spec in one fixed layout for a spec
(the canonical form), to standard
output (stdout), or to a file with -o canonical.yaml. Here
spec.yaml is the base spec on
composing specs, a least-cost dispatch
spec:
version: 0
dimensions:
generator: {}
snapshot: {dtype: int}
parameters:
capacity: {dims: [generator]}
cost: {dims: [generator]}
load: {dims: [snapshot]}
variables:
dispatch:
dims: [generator, snapshot]
bounds: {lower: 0.0, upper: capacity}
objective:
expression: sum(cost * dispatch)
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
The sections come in a fixed order, and the names within a section and the
dims of dispatch are sorted. A field at its default, such as dtype: str or
sense: minimize, is left out. The objective is sum(cost * dispatch), although the file has
sum(dispatch * cost), because mathspec writes the factors of a product in a
fixed order.
Keep this Python session open, because later steps use ms.
Diff two files#
Write both specs in the canonical form, and diff the two. Here before.yaml
is the spec.yaml above, and in after.yaml the objective has twice the
cost:
--- before.yaml
+++ after.yaml
@@ -11,7 +11,7 @@
dims: [generator, snapshot]
bounds: {lower: 0.0, upper: capacity}
objective:
- expression: sum(cost * dispatch)
+ expression: sum((2 * cost) * dispatch)
constraints:
power_balance:
dims: [snapshot]
The one changed line is the objective, with the factor 2 in brackets. When
the specs differ, the command exits with status 1, and the
command line reference lists every exit status. In
Python, where the specs differ, before == after is False.
Make git diff show the canonical form#
-
Tell git which files are specs, and which command writes them out:
-
Run
git diffas usual.git diffnow shows no difference for a change that writessum(dispatch * cost)assum(cost * dispatch), and one line for a change that doubles a coefficient. After the header lines,git diffprints:
The files in the repository stay as you wrote them, with their comments, and only the diff changes.
Warning
Match only spec files in .gitattributes, because git runs the command on
every file that the pattern matches. mathspec refuses a YAML file that is
not a spec, so git diff shows the refusal for that file.
Check in CI that a change leaves the spec the same#
To check that a change only moves declarations or reorders the terms of a sum, run a continuous integration (CI) job. In the job, write out the file on the main branch and compare that file with the file in the change:
The job fails when the two specs differ, and the log of the job lists the lines that changed.
See also
canonical, for the options of the command.diff, for the options and exit status of the command.- Comparing two specs, for what mathspec sorts when it writes the canonical form.