Auto-breakdowns
See original GitHub issueA feature I discussed with @mtwichan.
Anecdotally, a lot of GP(kit) constraints take the form y > x1 + x2 + x3 + ... + xn
(e.g. mass rollup, cost rollup, energy rollup etc.). What’s more, those x1
, x2
etc. are often themselves constrained by rollups.
I often want to see/understand/plot/fetch the values of the constituent parts that make up y, i.e. the values of x1...n
.
To do this in a semi-automatic way, I currently access the (known) constraint’s varkeys, with something like:
mass_rollup = constraints[4]
masses = mass_rollup.right.varkeys
some_plotting_function(sol, masses)
However, given that the pattern is relatively prevalent and that it would be nice to be able to visualize any arbitrary rollup, I think it could be useful (and not too tricky) to have a native breakdown generator built into GPkit that takes a model (or a solution!) and a variable (in this case y
) as an input and returns the rollup.
I think there are ~three~ four possible tiers of functionality, maybe implementation stepping stones.
Bronze
Returns a list of varkeys given an input varkey
# for the constraint y >= x1 + x2 + x3
m.breakdown_search("y") --> [x1, x2, x3]
Silver
Returns a dict of lists given an input varkey
# y >= x1 + x2 + x3
# x1 >= v1 + v2
# x2 >= v3
# x3 >= b*t**3 + a*t**2
m.breakdown_search("y") --> {x1: [v1, v2], x2: [v3], x3: x3}
Gold
Returns a nested dict of dicts for a SolutionArray given an input varkey. This is particularly appealing because I often want to dig into a solution without needing to re-generate the model object from which to derive the rollup (which breaks if the model has rollup has diverged from the rollup used to generate the solution).
# y >= x1 + x2 + x3
# x1 >= v1 + v2 # v2 has optimal value 5
# v1 >= u2 + u2 # u1 has optimal value 1, u2 has optimal value 2
# x2 >= v3 + v4 # v3 has optimal value 2, v4 has optimal value 1
# x3 >= b*t**3 + a*t**2 # x3 has optimal value 10
sol.breakdown("y") --> {x1: {v1: {u1: 1, u2: 2}, v2: 5},
x2: {v3: 2, v4: 1},
x3: 10}
Platinum
Returns a JSON string for creating an icicle plot (the D3 syntax is just one option – I’m biased because it’s the one I use)
# y >= x1 + x2 + x3
# x1 >= v1 + v2 # v2 has optimal value 5
# v1 >= u2 + u2 # u1 has optimal value 1, u2 has optimal value 2
# x2 >= v3 + v4 # v3 has optimal value 2, v4 has optimal value 1
# x3 >= b*t**3 + a*t**2 # x3 has optimal value 10
sol.breakdown("y", units="MUSD") -->
"""
{"name": "y",
"children": [
{"name": "x1",
"children": [
{"name": "v1":
"children": [
{"name": "u1",
"size": 1,
"label": "1 MUSD",
},
{"name": "u2",
"size": 2,
"label": "0.002 MUSD",
},
},
{"name": v2"
"size": 5,
"label": "5 MUSD",
},
]
},
{"name": x2",
"children": [
{"name": "v3",
"size": 2,
"label": "2 MUSD",
},
{"name": v4,
"size": 1,
"label": "1 MUSD",
},
],
},
{"name": "x3",
"size": 10,
"label": "0.01 MUSD",
},
]
} # I'm sure I made some mistake but you get the point
"""
@bqpd what do you think about these various proposals?
Issue Analytics
- State:
- Created 3 years ago
- Comments:15 (14 by maintainers)
Top GitHub Comments
yup, nesting would still be implicit!
Breakdown
is a great name.related to #507, #522