Hide keyboard shortcuts

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"Repository for representation standards" 

2import sys 

3import re 

4import numpy as np 

5from .small_classes import Quantity, Numbers 

6from .small_scripts import try_str_without 

7 

8INSIDE_PARENS = re.compile(r"\(.*\)") 

9 

10if sys.platform[:3] == "win": # pragma: no cover 

11 MUL = "*" 

12 PI_STR = "PI" 

13 UNICODE_EXPONENTS = False 

14 UNIT_FORMATTING = ":~" 

15else: # pragma: no cover 

16 MUL = "·" 

17 PI_STR = "π" 

18 UNICODE_EXPONENTS = True 

19 UNIT_FORMATTING = ":P~" 

20 

21def lineagestr(lineage, modelnums=True): 

22 "Returns properly formatted lineage string" 

23 if not isinstance(lineage, tuple): 

24 lineage = getattr(lineage, "lineage", None) 

25 return ".".join(["%s%i" % (name, num) if (num and modelnums) else name 

26 for name, num in lineage]) if lineage else "" 

27 

28 

29def unitstr(units, into="%s", options=UNIT_FORMATTING, dimless=""): 

30 "Returns the string corresponding to an object's units." 

31 if hasattr(units, "units") and isinstance(units.units, Quantity): 

32 units = units.units 

33 if not isinstance(units, Quantity): 

34 return dimless 

35 if options == ":~" and "ohm" in str(units.units): # pragma: no cover 

36 rawstr = str(units.units) # otherwise it'll be a capital Omega 

37 else: 

38 rawstr = ("{%s}" % options).format(units.units) 

39 units = rawstr.replace(" ", "").replace("dimensionless", dimless) 

40 return into % units or dimless 

41 

42def latex_unitstr(units): 

43 "Returns latex unitstr" 

44 us = unitstr(units, r"~\mathrm{%s}", ":L~") 

45 utf = us.replace("frac", "tfrac").replace(r"\cdot", r"\cdot ") 

46 return utf if utf != r"~\mathrm{-}" else "" 

47 

48 

49def strify(val, excluded): 

50 "Turns a value into as pretty a string as possible." 

51 if isinstance(val, Numbers): 

52 isqty = hasattr(val, "magnitude") 

53 if isqty: 

54 units = val 

55 val = val.magnitude 

56 if np.pi/12 < val < 100*np.pi and abs(12*val/np.pi % 1) <= 1e-2: 

57 # val is in bounds and a clean multiple of PI! 

58 if val > 3.1: # product of PI 

59 val = "%.3g%s" % (val/np.pi, PI_STR) 

60 if val == "1%s" % PI_STR: 

61 val = PI_STR 

62 else: # division of PI 

63 val = "(%s/%.3g)" % (PI_STR, np.pi/val) 

64 else: 

65 val = "%.3g" % val 

66 if isqty: 

67 val += unitstr(units, " [%s]") 

68 else: 

69 val = try_str_without(val, excluded) 

70 return val 

71 

72 

73def parenthesize(string, addi=True, mult=True): 

74 "Parenthesizes a string if it needs it and isn't already." 

75 parensless = string if "(" not in string else INSIDE_PARENS.sub("", string) 

76 bare_addi = (" + " in parensless or " - " in parensless) 

77 bare_mult = ("·" in parensless or "/" in parensless) 

78 if parensless and (addi and bare_addi) or (mult and bare_mult): 

79 return "(%s)" % string 

80 return string 

81 

82 

83class ReprMixin: 

84 "This class combines various printing methods for easier adoption." 

85 lineagestr = lineagestr 

86 unitstr = unitstr 

87 latex_unitstr = latex_unitstr 

88 

89 cached_strs = None 

90 ast = None 

91 # pylint: disable=too-many-branches, too-many-statements 

92 def parse_ast(self, excluded=("units")): 

93 "Turns the AST of this object's construction into a faithful string" 

94 if self.cached_strs is None: 

95 self.cached_strs = {} 

96 elif frozenset(excluded) in self.cached_strs: 

97 return self.cached_strs[frozenset(excluded)] 

98 aststr = None 

99 oper, values = self.ast # pylint: disable=unpacking-non-sequence 

100 excluded = set(excluded) 

101 excluded.add("units") 

102 if oper == "add": 

103 left = strify(values[0], excluded) 

104 right = strify(values[1], excluded) 

105 if right[0] == "-": 

106 aststr = "%s - %s" % (left, right[1:]) 

107 else: 

108 aststr = "%s + %s" % (left, right) 

109 elif oper == "mul": 

110 left = parenthesize(strify(values[0], excluded), mult=False) 

111 right = parenthesize(strify(values[1], excluded), mult=False) 

112 if left == "1": 

113 aststr = right 

114 elif right == "1": 

115 aststr = left 

116 else: 

117 aststr = "%s%s%s" % (left, MUL, right) 

118 elif oper == "div": 

119 left = parenthesize(strify(values[0], excluded), mult=False) 

120 right = parenthesize(strify(values[1], excluded)) 

121 if right == "1": 

122 aststr = left 

123 else: 

124 aststr = "%s/%s" % (left, right) 

125 elif oper == "neg": 

126 aststr = "-%s" % parenthesize(strify(values, excluded), mult=False) 

127 elif oper == "pow": 

128 left = parenthesize(strify(values[0], excluded)) 

129 x = values[1] 

130 if left == "1": 

131 aststr = "1" 

132 elif (UNICODE_EXPONENTS and not getattr(x, "shape", None) 

133 and int(x) == x and 2 <= x <= 9): 

134 x = int(x) 

135 if x in (2, 3): 

136 aststr = "%s%s" % (left, chr(176+x)) 

137 elif x in (4, 5, 6, 7, 8, 9): 

138 aststr = "%s%s" % (left, chr(8304+x)) 

139 else: 

140 aststr = "%s^%s" % (left, x) 

141 elif oper == "prod": # TODO: only do if it makes a shorter string 

142 aststr = "%s.prod()" % parenthesize(strify(values[0], excluded)) 

143 elif oper == "sum": # TODO: only do if it makes a shorter string 

144 aststr = "%s.sum()" % parenthesize(strify(values[0], excluded)) 

145 elif oper == "index": # TODO: label vectorization idxs 

146 left = parenthesize(strify(values[0], excluded)) 

147 idx = values[1] 

148 if left[-3:] == "[:]": # pure variable access 

149 left = left[:-3] 

150 if isinstance(idx, tuple): 

151 elstrs = [] 

152 for el in idx: 

153 if isinstance(el, slice): 

154 start = el.start or "" 

155 stop = (el.stop if el.stop and el.stop < sys.maxsize 

156 else "") 

157 step = ":%s" % el.step if el.step is not None else "" 

158 elstrs.append("%s:%s%s" % (start, stop, step)) 

159 elif isinstance(el, Numbers): 

160 elstrs.append("%s" % el) 

161 idx = ",".join(elstrs) 

162 elif isinstance(idx, slice): 

163 start = idx.start or "" 

164 stop = idx.stop if idx.stop and idx.stop < 1e6 else "" 

165 step = ":%s" % idx.step if idx.step is not None else "" 

166 idx = "%s:%s%s" % (start, stop, step) 

167 aststr = "%s[%s]" % (left, idx) 

168 else: 

169 raise ValueError(oper) 

170 self.cached_strs[frozenset(excluded)] = aststr 

171 return aststr 

172 

173 def __repr__(self): 

174 "Returns namespaced string." 

175 return "gpkit.%s(%s)" % (self.__class__.__name__, self) 

176 

177 def __str__(self): 

178 "Returns default string." 

179 return self.str_without() # pylint: disable=no-member 

180 

181 def _repr_latex_(self): 

182 "Returns default latex for automatic iPython Notebook rendering." 

183 return "$$"+self.latex()+"$$" # pylint: disable=no-member