# Coverage for gpkit/nomials/core.py: 91%

## 93 statements

, created at 2023-09-23 21:28 -0400

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)