Hot-keys on this page
r m x p 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 HashVector, 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 vars_of_a_name = {}
23 subscripts = ("lineage", "idx")
25 def __init__(self, name=None, **descr):
26 # NOTE: Python arg handling guarantees 'name' won't appear in descr
27 self.descr = descr
28 self.descr["name"] = name or "\\fbox{%s}" % VarKey.unique_id()
29 unitrepr = self.unitrepr or self.units
30 if unitrepr in ["", "-", None]: # dimensionless
31 self.descr["units"] = None
32 self.descr["unitrepr"] = "-"
33 else:
34 self.descr["units"] = qty(unitrepr)
35 self.descr["unitrepr"] = unitrepr
37 self.key = self
38 fullstr = self.str_without(["modelnums", "vec"])
39 self.eqstr = fullstr + str(self.lineage) + self.unitrepr
40 self.hashvalue = hash(self.eqstr)
41 self.keys = set((self.name, fullstr))
42 self.hmap = NomialMap({HashVector({self: 1}): 1.0})
43 self.hmap.units = self.units
45 if "idx" in self.descr:
46 if "veckey" not in self.descr:
47 vecdescr = self.descr.copy()
48 del vecdescr["idx"]
49 self.veckey = VarKey(**vecdescr)
50 else:
51 self.keys.add(self.veckey)
52 self.keys.add(self.str_without(["idx", "modelnums"]))
54 def __getstate__(self):
55 "Stores varkey as its metadata dictionary, removing functions"
56 state = self.descr.copy()
57 for key, value in state.items():
58 if getattr(value, "__call__", None):
59 state[key] = "unpickleable function %s" % value
60 return state
62 def __setstate__(self, state):
63 "Restores varkey from its metadata dictionary"
64 self.__init__(**state)
66 def str_without(self, excluded=()):
67 "Returns string without certain fields (such as 'lineage')."
68 name = self.name
69 if ("lineage" not in excluded and self.lineage
70 and ("unnecessary lineage" not in excluded
71 or self.necessarylineage)):
72 name = self.lineagestr("modelnums" not in excluded) + "." + name
73 if "idx" not in excluded:
74 if self.idx:
75 name += "[%s]" % ",".join(map(str, self.idx))
76 elif "vec" not in excluded and self.shape:
77 name += "[:]"
78 return name
80 __repr__ = str_without
82 # pylint: disable=multiple-statements
83 def __hash__(self): return self.hashvalue
84 def __getattr__(self, attr): return self.descr.get(attr, None)
86 @property
87 def models(self):
88 "Returns a tuple of just the names of models in self.lineage"
89 return list(zip(*self.lineage))[0]
91 def latex(self, excluded=()):
92 "Returns latex representation."
93 name = self.name
94 if "vec" not in excluded and "idx" not in excluded and self.shape:
95 name = "\\vec{%s}" % name
96 if "idx" not in excluded and self.idx:
97 name = "{%s}_{%s}" % (name, ",".join(map(str, self.idx)))
98 if ("lineage" not in excluded and self.lineage
99 and ("unnecessary lineage" not in excluded
100 or self.necessarylineage)):
101 name = "{%s}_{%s}" % (name,
102 self.lineagestr("modelnums" not in excluded))
103 return name
105 def __eq__(self, other):
106 if not hasattr(other, "descr"):
107 return False
108 return self.eqstr == other.eqstr
110from .nomials import NomialMap # pylint: disable=wrong-import-position