Coverage for gpkit/varkey.py: 100%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Defines the VarKey class"""
2from .small_classes import Count, qty
3from .repr_conventions import ReprMixin
6class VarKey(ReprMixin): # pylint:disable=too-many-instance-attributes
7 """An object to correspond to each 'variable name'.
9 Arguments
10 ---------
11 name : str, VarKey, or Monomial
12 Name of this Variable, or object to derive this Variable from.
14 **descr :
15 Any additional attributes, which become the descr attribute (a dict).
17 Returns
18 -------
19 VarKey with the given name and descr.
20 """
21 unique_id = Count().next
22 subscripts = ("lineage", "idx")
24 def __init__(self, name=None, **descr):
25 # NOTE: Python arg handling guarantees 'name' won't appear in descr
26 self.descr = descr
27 self.descr["name"] = name or "\\fbox{%s}" % VarKey.unique_id()
28 unitrepr = self.unitrepr or self.units
29 if unitrepr in ["", "-", None]: # dimensionless
30 self.descr["units"] = None
31 self.descr["unitrepr"] = "-"
32 else:
33 self.descr["units"] = qty(unitrepr)
34 self.descr["unitrepr"] = unitrepr
36 self.key = self
37 fullstr = self.str_without(["modelnums", "vec"])
38 self.eqstr = fullstr + str(self.lineage) + self.unitrepr
39 self.hashvalue = hash(self.eqstr)
40 self.keys = set((self.name, fullstr))
42 if "idx" in self.descr:
43 if "veckey" not in self.descr:
44 vecdescr = self.descr.copy()
45 del vecdescr["idx"]
46 self.veckey = VarKey(**vecdescr)
47 else:
48 self.keys.add(self.veckey)
49 self.keys.add(self.str_without(["idx", "modelnums"]))
51 def __getstate__(self):
52 "Stores varkey as its metadata dictionary, removing functions"
53 state = self.descr.copy()
54 for key, value in state.items():
55 if getattr(value, "__call__", None):
56 state[key] = "unpickleable function %s" % value
57 return state
59 def __setstate__(self, state):
60 "Restores varkey from its metadata dictionary"
61 self.__init__(**state)
63 def str_without(self, excluded=()):
64 "Returns string without certain fields (such as 'lineage')."
65 name = self.name
66 if "lineage" not in excluded and self.lineage:
67 namespace = self.lineagestr("modelnums" not in excluded).split(".")
68 for ex in excluded:
69 if ex[0:7] == ":MAGIC:":
70 to_replace = ex[7:]
71 if not to_replace:
72 continue
73 to_replace = to_replace.split(".")
74 replaced = 0
75 for modelname in to_replace:
76 if not namespace or namespace[0] != modelname:
77 break
78 replaced += 1
79 namespace = namespace[1:]
80 if len(to_replace) > replaced:
81 namespace.insert(0, "."*(len(to_replace)-replaced))
82 necessarylineage = self.necessarylineage
83 if necessarylineage is None and self.veckey:
84 necessarylineage = self.veckey.necessarylineage
85 if necessarylineage is not None:
86 if necessarylineage > 0:
87 namespace = namespace[-necessarylineage:]
88 else:
89 namespace = None
90 if namespace:
91 name = ".".join(namespace) + "." + name
92 if "idx" not in excluded:
93 if self.idx:
94 name += "[%s]" % ",".join(map(str, self.idx))
95 elif "vec" not in excluded and self.shape:
96 name += "[:]"
97 return name
99 __repr__ = str_without
101 # pylint: disable=multiple-statements
102 def __hash__(self): return self.hashvalue
103 def __getattr__(self, attr): return self.descr.get(attr, None)
105 @property
106 def models(self):
107 "Returns a tuple of just the names of models in self.lineage"
108 return list(zip(*self.lineage))[0]
110 def latex(self, excluded=()):
111 "Returns latex representation."
112 name = self.name
113 if "vec" not in excluded and "idx" not in excluded and self.shape:
114 name = "\\vec{%s}" % name
115 if "idx" not in excluded and self.idx:
116 name = "{%s}_{%s}" % (name, ",".join(map(str, self.idx)))
117 if "lineage" not in excluded and self.lineage:
118 name = "{%s}_{%s}" % (name,
119 self.lineagestr("modelnums" not in excluded))
120 return name
122 def __eq__(self, other):
123 if not hasattr(other, "descr"):
124 return False
125 return self.eqstr == other.eqstr