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 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:].split(".")
71 replaced = 0
72 for modelname in to_replace:
73 if not namespace or namespace[0] != modelname:
74 break
75 replaced += 1
76 namespace = namespace[1:]
77 if len(to_replace) > replaced:
78 namespace.insert(0, "."*(len(to_replace)-replaced))
79 if "unnecessary lineage" in excluded:
80 if self.necessarylineage:
81 namespace = namespace[-self.necessarylineage:]
82 else:
83 namespace = None
84 if namespace:
85 name = ".".join(namespace) + "." + name
86 if "idx" not in excluded:
87 if self.idx:
88 name += "[%s]" % ",".join(map(str, self.idx))
89 elif "vec" not in excluded and self.shape:
90 name += "[:]"
91 return name
93 __repr__ = str_without
95 # pylint: disable=multiple-statements
96 def __hash__(self): return self.hashvalue
97 def __getattr__(self, attr): return self.descr.get(attr, None)
99 @property
100 def models(self):
101 "Returns a tuple of just the names of models in self.lineage"
102 return list(zip(*self.lineage))[0]
104 def latex(self, excluded=()):
105 "Returns latex representation."
106 name = self.name
107 if "vec" not in excluded and "idx" not in excluded and self.shape:
108 name = "\\vec{%s}" % name
109 if "idx" not in excluded and self.idx:
110 name = "{%s}_{%s}" % (name, ",".join(map(str, self.idx)))
111 if ("lineage" not in excluded and self.lineage
112 and ("unnecessary lineage" not in excluded
113 or self.necessarylineage)):
114 name = "{%s}_{%s}" % (name,
115 self.lineagestr("modelnums" not in excluded))
116 return name
118 def __eq__(self, other):
119 if not hasattr(other, "descr"):
120 return False
121 return self.eqstr == other.eqstr