Coverage for gpkit/nomials/core.py: 94%
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"The shared non-mathematical backbone of all Nomials"
2from .data import NomialData
3from ..small_classes import Numbers, FixedScalar
4from ..repr_conventions import MUL, UNICODE_EXPONENTS
7def nomial_latex_helper(c, pos_vars, neg_vars):
8 """Combines (varlatex, exponent) tuples,
9 separated by positive vs negative exponent, into a single latex string."""
10 pvarstrs = ['%s^{%.2g}' % (varl, x) if "%.2g" % x != "1" else varl
11 for (varl, x) in pos_vars]
12 nvarstrs = ['%s^{%.2g}' % (varl, -x) if "%.2g" % -x != "1" else varl
13 for (varl, x) in neg_vars]
14 pvarstr = " ".join(sorted(pvarstrs))
15 nvarstr = " ".join(sorted(nvarstrs))
16 cstr = "%.2g" % c
17 if pos_vars and cstr in ["1", "-1"]:
18 cstr = cstr[:-1]
19 else:
20 cstr = "%.4g" % c
21 if "e" in cstr: # use exponential notation
22 idx = cstr.index("e")
23 cstr = "%s \\times 10^{%i}" % (cstr[:idx], int(cstr[idx+1:]))
25 if pos_vars and neg_vars:
26 return "%s\\frac{%s}{%s}" % (cstr, pvarstr, nvarstr)
27 if neg_vars and not pos_vars:
28 return "\\frac{%s}{%s}" % (cstr, nvarstr)
29 if pos_vars:
30 return "%s%s" % (cstr, pvarstr)
31 return "%s" % cstr
34class Nomial(NomialData):
35 "Shared non-mathematical properties of all nomials"
36 sub = None
38 def str_without(self, excluded=()):
39 "String representation, excluding fields ('units', varkey attributes)"
40 units = "" if "units" in excluded else self.unitstr(" [%s]")
41 if hasattr(self, "key"):
42 return self.key.str_without(excluded) + units # pylint: disable=no-member
43 if "ast" not in excluded and self.ast:
44 return self.parse_ast(excluded) + units
45 mstrs = []
46 for exp, c in self.hmap.items():
47 pvarstrs, nvarstrs = [], []
48 for (var, x) in sorted(exp.items(),
49 key=lambda vx: (vx[1], str(vx[0]))):
50 if not x:
51 continue
52 if x > 0:
53 varstrlist = pvarstrs
54 else:
55 x = -x
56 varstrlist = nvarstrs
57 varstr = var.str_without(excluded)
58 if UNICODE_EXPONENTS and int(x) == x and 2 <= x <= 9:
59 x = int(x)
60 if x in (2, 3):
61 varstr += chr(176+x)
62 elif x in (4, 5, 6, 7, 8, 9):
63 varstr += chr(8304+x)
64 elif x != 1:
65 varstr += "^%.2g" % x
66 varstrlist.append(varstr)
67 numerator_strings = pvarstrs
68 cstr = "%.3g" % c
69 if cstr == "-1":
70 cstr = "-"
71 if numerator_strings and cstr == "1":
72 mstr = MUL.join(pvarstrs)
73 else:
74 mstr = MUL.join([cstr] + pvarstrs)
75 if nvarstrs:
76 mstr = mstr + "/" + "/".join(nvarstrs)
77 mstrs.append(mstr)
78 return " + ".join(sorted(mstrs)) + units
80 def latex(self, excluded=()): # TODO: add ast parsing here
81 "Latex representation, parsing `excluded` just as .str_without does"
82 mstrs = []
83 for exp, c in self.hmap.items():
84 pos_vars, neg_vars = [], []
85 for var, x in exp.items():
86 if x > 0:
87 pos_vars.append((var.latex(excluded), x))
88 elif x < 0:
89 neg_vars.append((var.latex(excluded), x))
90 mstrs.append(nomial_latex_helper(c, pos_vars, neg_vars))
92 if "units" in excluded:
93 return " + ".join(sorted(mstrs))
94 units = self.unitstr(r"\mathrm{~\left[ %s \right]}", ":L~")
95 units_tf = units.replace("frac", "tfrac").replace(r"\cdot", r"\cdot ")
96 return " + ".join(sorted(mstrs)) + units_tf
98 @property
99 def value(self):
100 """Self, with values substituted for variables that have values
102 Returns
103 -------
104 float, if no symbolic variables remain after substitution
105 (Monomial, Posynomial, or Nomial), otherwise.
106 """
107 if isinstance(self, FixedScalar):
108 return self.cs[0]
109 p = self.sub({k: k.value for k in self.vks if "value" in k.descr}) # pylint: disable=not-callable
110 return p.cs[0] if isinstance(p, FixedScalar) else p
112 def __eq__(self, other):
113 "True if self and other are algebraically identical."
114 if isinstance(other, Numbers):
115 return isinstance(self, FixedScalar) and self.value == other
116 return super().__eq__(other)
118 __hash__ = NomialData.__hash__
119 # pylint: disable=multiple-statements
120 def __ne__(self, other): return not Nomial.__eq__(self, other)
121 def __radd__(self, other): return self.__add__(other, rev=True) # pylint: disable=no-member
122 def __rmul__(self, other): return self.__mul__(other, rev=True) # pylint: disable=no-member
124 def prod(self):
125 "Return self for compatibility with NomialArray"
126 return self
128 sum = prod