Skip to content

Instantly share code, notes, and snippets.

@mvernacc
Last active March 26, 2019 15:30
Show Gist options
  • Save mvernacc/5505ea8278f8cacff9ce0b2d447ccf1c to your computer and use it in GitHub Desktop.
Save mvernacc/5505ea8278f8cacff9ce0b2d447ccf1c to your computer and use it in GitHub Desktop.
Minimum working example of Issue 1390 from gpkit
"""Minimum working example of Issue 1390
See https://github.com/convexengineering/gpkit/issues/1390
"""
import traceback
from gpkit import Model, Variable, units, DimensionalityError
from gpkit.constraints.tight import Tight
class DummyModelRad(Model):
"""This one replicates the original error."""
def setup(self):
x = Variable('x', 'radian', '')
constraints = [
x >= 1. * units('radian'),
Tight([x <= 2.]),
]
return constraints
class DummyModelMeter(Model):
"""This one raises a different error."""
def setup(self):
x = Variable('x', 'meter', '')
constraints = [
x >= 1. * units('meter'),
Tight([x <= 2.]),
]
return constraints
class DummyModelDimless(Model):
"""This one works."""
def setup(self):
x = Variable('x', '', '')
constraints = [
x >= 1. * units(''),
Tight([x <= 2.]),
]
return constraints
def main():
"""The optimization problem is:
min x
s.t. x >= 1
x <= 2
The optimal cost is `1` with `x = 1`. At the optimum, `x = 1 < 2`,
so the second constraint is not tight. Because the second constraint
was wrapped with Tight(), this enters the if clause on line 44
of tight.py. On line 54, the lefthand side will have a `magnitude`
attr, because `x` is a pint variable (with units of rad). However
the righthand side is simply a float, so calling `rightsubbed.to()`
on line 55 will fail.
"""
print('**This one raises an AttributeError, like the original bug**')
m1 = DummyModelRad()
m1.cost = m1['x']
try:
# This replicates the original error.
sol = m1.solve()
except AttributeError:
print(traceback.format_exc())
"""This is the same optimization problem, but with `x` having units of
meter instead of radian. In this case, we do not see the error in tight.py.
Instead, we get are not allowed to create a constraint comparing `x`
(with units of meters) to `2.` (with no units).
"""
print('\n\n**This one raises an DimensionalityError on initialization**')
try:
# This creates a different error.
m2 = DummyModelMeter()
except DimensionalityError:
print(traceback.format_exc())
"""This example uses the same optimization problem, but with `x` being dimensionless.
In this case the `leftsubbed` in `tight.py` does not have a `magnitude` attr,
and so the if clause on line 54 is not entered.
"""
print('\n\n**This one works**')
m3 = DummyModelDimless()
m3.cost = m3['x']
sol = m3.solve()
print(sol.table())
"""These examples illustrate that the bug only occurs in a weird edge
case where we compare a pint variable with units of radians to a non-pint
(e.g. float) variable. This comparison is allowed by pint (because radian
is vaguely equivalent to being dimensionless) but is not handled by `tight.py`.
"""
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment