Parser of berki style problems and generator of latex file
Samo Penic
2018-11-07 5bc997a926697e4ba120605a0f865284b5fbb27f
commit | author | age
91fb15 1 from . import Exceptions
5288d6 2 from math import floor, log10
d89217 3
7b5760 4 STRING = 1
SP 5 FLOAT = 2
6
7
8 class Variable:
7e7033 9     def __init__(self, value=None, formatting=None):
993a25 10         self.formatted_value = None
7b5760 11         try:
SP 12             self.value = float(value)
7e7033 13             self.type = FLOAT
7b5760 14         except (ValueError, TypeError):
SP 15             self.type = STRING
08b2a2 16             self.value = value
SP 17             self.formatted_value = value
7b5760 18         if formatting is not None:
33c054 19             self.format_float(formatting)
7b5760 20         self.formatting = formatting
08b2a2 21
SP 22     def is_float(self):
ce4fc9 23         if self.type == FLOAT:
08b2a2 24             return True
SP 25         else:
26             return False
7b5760 27
33c054 28     def format_float(self, formatting=None):
993a25 29         if formatting is None:
SP 30             formatting = self.formatting
31         formatter = FormatterFactory.get_formatter(formatting)
32         self.formatted_value = formatter.getValue(self.value)
7b5760 33
04ee9d 34     def format_as_tex(self, formatting=None, glyph=None, unit=None):
993a25 35         if formatting is None:
SP 36             formatting = self.formatting
04ee9d 37         formatter = FormatterFactory.get_formatter(formatting)
5bc997 38         if formatting == "str" or formatting == "string":
04ee9d 39             return formatter.toFormat(self.value)
08b2a2 40         elif glyph is None and unit is None:
04ee9d 41             return ("${}$").format(formatter.toFormat(self.value))
08b2a2 42         elif glyph is None and unit is not None:
SP 43             return ("${}~\mathrm{{{}}}$").format(formatter.toFormat(self.value), unit)
44         elif glyph is not None and unit is None:
45             return ("${}={}$").format(glyph, formatter.toFormat(self.value))
04ee9d 46         else:
08b2a2 47             return ("${}={}~\mathrm{{{}}}$").format(
SP 48                 glyph, formatter.toFormat(self.value), unit
49             )
7b5760 50
04ee9d 51     def format_without_dollar(self, formatting=None):
SP 52         if formatting is None:
53             formatting = self.formatting
993a25 54         formatter = FormatterFactory.get_formatter(formatting)
SP 55         return formatter.toFormat(self.value)
7b5760 56
SP 57     def get_formatted_value(self):
993a25 58         return self.formatted_value
08b2a2 59         # if self.type != STRING else self.value
7b5760 60
ef19a9 61     def __str__(self):
SP 62         return str(self.format_as_tex())
63
78d798 64     def __repr__(self):
SP 65         return self.__str__()
66
7b5760 67
d89217 68 class FormatterFactory:
404823 69     @staticmethod
SP 70     def get_formatter(formatstring):
71         spl = formatstring.split()
72         type = spl[0]
73         arglist = spl[1:]
74
5bc997 75         if type == "sci" or type == "scientific":
d89217 76             return SciFloatFormatter(arglist)
5bc997 77         elif type == "str" or type == "string":
993a25 78             return StringFormatter()
5bc997 79         elif type == "eng" or type == "engineering":
993a25 80             return EngFloatFormatter(arglist)
5bc997 81         elif type == "prefix":
SP 82             return PrefixFloatFormatter(arglist)
83         elif type == "dec" or type == "decimal":
84             return EngFloatFormatter(arglist) #fallback to engineering
404823 85         else:
SP 86             return None
5288d6 87
SP 88     @staticmethod
89     def fexp(f):
90         return int(floor(log10(abs(f)))) if f != 0 else 0
91
92     @staticmethod
93     def fman(f):
7b5760 94         return f / 10 ** FormatterFactory.fexp(f)
993a25 95
SP 96
97 class StringFormatter(FormatterFactory):
98     def __init__(self):
99         pass
100
101     def toFormat(self, string):
102         return string
103
104     def getValue(self, string):
105         return string
404823 106
SP 107
d89217 108 class SciFloatFormatter(FormatterFactory):
SP 109     def __init__(self, formatparameters):
404823 110         if len(formatparameters) != 1:
91fb15 111             raise Exceptions.WrongParameters("Sci format accept only one argument")
404823 112         self.precision = int(formatparameters[0])
SP 113
114     def toFormat(self, num):
115         try:
116             num = float(num)
117         except ValueError:
118             raise ValueError
119         except TypeError:
120             raise ValueError
121
7b5760 122         exp = self.fexp(num)
SP 123         man = self.fman(num)
78d798 124         if exp == 0:
08b2a2 125             return (
SP 126                 ("{:." + str(self.precision - 1) + "f}").format(man).replace(".", ",\!")
127             )
78d798 128         else:
08b2a2 129             return (
SP 130                 ("{:." + str(self.precision - 1) + "f} \cdot 10^{{{}}}")
131                 .format(man, int(exp))
132                 .replace(".", ",\!")
78d798 133             )
d89217 134
33c054 135     def getValue(self, num):
SP 136         exp = self.fexp(num)
137         man = self.fman(num)
78d798 138         man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp))
33c054 139         return float(man)
d89217 140
78d798 141
ce4fc9 142 class EngFloatFormatter(FormatterFactory):
d89217 143     def __init__(self, formatparameters):
SP 144         if len(formatparameters) != 1:
145             raise Exceptions.WrongParameters("Eng format accept only one argument")
146         self.precision = int(formatparameters[0])
147
ce4fc9 148     def realign3(self, exp, man):
SP 149         mul = exp % 3
150         man = man * 10 ** mul
151         exp = exp - mul
152         return (exp, man)
153
d89217 154     def toFormat(self, num):
SP 155         try:
156             num = float(num)
ce4fc9 157         except ValueError:
d89217 158             raise ValueError
ce4fc9 159         except TypeError:
SP 160             raise ValueError
5288d6 161
ce4fc9 162         exp = self.fexp(num)
SP 163         man = self.fman(num)
164         (exp, man) = self.realign3(exp, man)
165         if exp == 0:
166             return (
167                 ("{:." + str(self.precision - 1) + "f}").format(man).replace(".", ",\!")
168             )
169         else:
170             return (
171                 ("{:." + str(self.precision - 1) + "f} \cdot 10^{{{}}}")
172                 .format(man, int(exp))
173                 .replace(".", ",\!")
174             )
175
176     def getValue(self, num):
177         exp = self.fexp(num)
178         man = self.fman(num)
179         man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp))
180         return float(man)
181
182
5bc997 183 class PrefixFloatFormatter(EngFloatFormatter):
ce4fc9 184     def __init__(self, formatparameters):
SP 185         if len(formatparameters) != 1:
186             raise Exceptions.WrongParameters("Dec format accept only one argument")
187         self.precision = int(formatparameters[0])
188
189     def exp2prefix(self, exp):
190         prefixes = {
191             "24": "Y",
192             "21": "Z",
193             "18": "E",
194             "15": "P",
195             "12": "T",
196             "9": "G",
197             "6": "M",
198             "3": "k",
199             "-3": "m",
200             "-6":"\\upmu",
201             "-9":"n",
202             "-12":"p",
203             "-15":"f",
204             "-18":"a",
205             "-21":"z",
206             "-24":"y"
207         }
208         try:
209             prefix = prefixes[str(exp)]
210         except KeyError:
211             raise Exceptions.PrefixError("Could not change exponent " + str(exp) + " into prefix form!")
212         return prefix
213
214
215     def toFormat(self, num):
216         try:
217             num = float(num)
218         except ValueError:
219             raise ValueError
220         except TypeError:
221             raise ValueError
222
223         exp = self.fexp(num)
224         man = self.fman(num)
225         (exp, man) = self.realign3(exp, man)
226         if exp == 0:
227             return (
228                 ("{:." + str(self.precision - 1) + "f}").format(man).replace(".", ",\!")
229             )
230         else:
231             prefix = self.exp2prefix(exp)
232             return (
233                 ("{:." + str(self.precision - 1) + "f}~\mathrm{{{}}}")
234                 .format(man, prefix)
235                 .replace(".", ",\!")
236             )