convexengineering / gpkit

Geometric programming for engineers
http://gpkit.readthedocs.org
MIT License
206 stars 40 forks source link

submodels with identical variable names not fully represented in model varkeys #1432

Closed whoburg closed 5 years ago

whoburg commented 5 years ago

This is best described by a MWE. As a user I want to be able to make a Model with multiple submodels (all instances of the same submodel class) and then pull out variables of those submodels using Model.varkeys and Model.variables_byname. Here's my MWE:

"""Fails on gpkit master commit 20d82e32a4198c79cfb5e8a0cc918b0f28015a4b"""
# (and also fails on the current master)
from gpkit import Variable, Model

class Sub(Model):
    "Submodel with mass"
    def setup(self):
        m = Variable("m", "lb", "mass")
        return []

class Widget(Model):
    "a thing with two Sub things"
    def setup(self):
        m_tot = Variable("m_{tot}", "lb", "total mass")
        self.subA = Sub()
        self.subB = Sub()
        return [self.subA, self.subB,
                m_tot >= self.subA["m"] + self.subB["m"]]

w = Widget()
print(w.variables_byname("m")) # [gpkit.Variable(Widget.Sub1.m [lb])]
# assert len(w.variables_byname("m")) == 2  # fails, length is 1
print(w.variables_byname("m")[0].key in w.varkeys)
assert w.subA["m"].key in w.varkeys
assert w.subB["m"].key in w.varkeys
m_vbn_keys = [v.key for v in w.variables_byname("m")]
# assert w.subA["m"].key in m_vbn_keys  # fails
assert w.subB["m"].key in m_vbn_keys    # passes
print(w.varkeys["m"]) # set([Widget.Sub1.m])
# note w.varkeys.keymap contains a stray u'Widget.Sub.m': set([Widget1.Sub1.m])
# (all other entries in w.varkeys.keymap refer to Widget1, not Widget)
bqpd commented 5 years ago

(copied over from the PR)

Note that the errors occur because of string access at the Widget level, which is not best practice - if this example emerged from your daily use of GPkit, I would encourage using docstring variable tables and/or method access (e.g. self.subA.m) instead!