See what a curve or a set expands to#
A piecewise: block and a sos: block
each stand for plain variables and constraints. Write them out to review a
formulation, to teach one, or to hand the model to an engine that has no
concept of a set.
1. Write the formulation out#
expand() returns the same math with its formulations stated as plain
declarations. to_yaml() prints the result as a file.
The command line prints the expansion as math rather than as YAML. Pass
'piecewise' or 'sos' to write out one kind and keep the other.
2. Read a set#
The sos: block below says that at most one p is nonzero. Its expansion
adds one binary per member, a row that picks at most one binary, and a row that
holds an unpicked member at zero. The coefficient 10.0 is the upper bound of
p.
dimensions:
g: { dtype: str }
variables:
p:
dims: [g]
bounds: { lower: 0, upper: 10 }
pick_seg:
dims: [g]
domain: binary
description: a binary per member, 1 where that member may be nonzero
constraints:
pick_pick:
dims: []
expression: sum(pick_seg, over=g) <= 1
pick_nonzero:
dims: [g]
expression: p <= 10.0 * (pick_seg)
Subject to
pick_pick
pick_nonzero
Variable domains
p
pick_seg
Every name the expansion adds starts with the name of the block, so pick_seg
is the binary of the set pick.
3. Read a curve#
The piecewise: block below ties x and y to a curve through the
breakpoints in x_bp and y_bp. A method: sos2 curve states a set, so it
writes out in two steps. Compare the tabs from left to right:
expand('piecewise')writes the curve out and leaves its set. It adds a weight per breakpoint and one link row per tied variable. Ansos:block over the weights keeps at most two neighbouring weights nonzero.expand()writes the set out too. Thesos:block becomes one binary per segment and the rows that keep the two nonzero weights next to each other.
Subject to
curve
Variable domains
x
y
Assumptions
curve_complete
dimensions:
bp: { dtype: int }
parameters:
x_bp: { dims: [bp] }
y_bp: { dims: [bp] }
variables:
x: { dims: [], bounds: { lower: 0 } }
y: { dims: [], bounds: { lower: 0 } }
curve_lam:
dims: [bp]
bounds: { lower: 0, upper: 1 }
description: convex-combination weight on a breakpoint
constraints:
curve_convexity:
dims: []
expression: sum(curve_lam, over=bp) == 1
curve_link0:
dims: []
expression: (x) == sum(curve_lam * x_bp, over=bp)
curve_link1:
dims: []
expression: (y) == sum(curve_lam * y_bp, over=bp)
sos:
curve:
variable: curve_lam
along: bp
type: 2
assumptions:
curve_complete:
holds: x_bp AND y_bp
description: >-
piecewise 'curve': every breakpoint the curve runs through needs a row in
'x_bp', 'y_bp' — a missing row is read as a zero rather than as a shorter
curve, so it sits the curve on the origin. Bind the rows, or declare
points: to say how far the curve runs.
Subject to
curve_convexity
curve_link0
curve_link1
Variable domains
x
y
curve_lam
curve
Assumptions
curve_complete
dimensions:
bp: { dtype: int }
parameters:
x_bp: { dims: [bp] }
y_bp: { dims: [bp] }
variables:
x: { dims: [], bounds: { lower: 0 } }
y: { dims: [], bounds: { lower: 0 } }
curve_lam:
dims: [bp]
bounds: { lower: 0, upper: 1 }
description: convex-combination weight on a breakpoint
curve_seg:
dims: [bp]
domain: binary
description: a binary per segment, 1 where the two members it spans may be nonzero
constraints:
curve_convexity:
dims: []
expression: sum(curve_lam, over=bp) == 1
curve_link0:
dims: []
expression: (x) == sum(curve_lam * x_bp, over=bp)
curve_link1:
dims: []
expression: (y) == sum(curve_lam * y_bp, over=bp)
curve_pick:
dims: []
expression: sum(curve_seg, over=bp) <= 1
curve_adjacency:
dims: [bp]
expression: curve_lam <= (curve_seg + shift(curve_seg, along=bp, offset=1, edge=0))
assumptions:
curve_complete:
holds: x_bp AND y_bp
description: >-
piecewise 'curve': every breakpoint the curve runs through needs a row in
'x_bp', 'y_bp' — a missing row is read as a zero rather than as a shorter
curve, so it sits the curve on the origin. Bind the rows, or declare
points: to say how far the curve runs.
Subject to
curve_convexity
curve_link0
curve_link1
curve_pick
curve_adjacency
Variable domains
x
y
curve_lam
curve_seg
Assumptions
curve_complete
The assumptions: rows state what
the curve needs of its data. What
expand() accepts, and what each method: emits, is under
piecewise curves and SOS.