latex equation generation

This commit is contained in:
Yeongdo Park 2019-08-14 08:59:15 +09:00
parent b6210acb01
commit a901ebe932
2 changed files with 163 additions and 15 deletions

View file

@ -6,7 +6,8 @@ import argparse
parser = argparse.ArgumentParser()
parser.add_argument("term_file", help="name of file containing postprocessing term spec")
parser.add_argument("-b", "--build-info", action="store_true", help="print build_info instead of code")
parser.add_argument("-p", "--print_report", action="store_true", help="print code generation report instead of code")
parser.add_argument("-x", "--print-latex", action="store_true", help="print latex equation instead of code")
parser.add_argument("-p", "--print-report", action="store_true", help="print code generation report instead of code")
args = parser.parse_args()
from lark import Lark, Visitor, Transformer, v_args, Token
@ -20,14 +21,15 @@ calc_grammar = """
?start: statement*
?statement: NAME [ "(" [attr_list] ")" ] "=" sum -> assign_var
?statement: NAME [ attr_list ] "=" sum -> assign_var
| avg "{" [NAME ("," NAME)*] "}" -> assign_avg_var
| varlist
?attr_list: attr_pair ("," attr_pair)*
attr_list: "(" [attr_pair ("," attr_pair)*] ")"
?attr_pair: NAME "=" BOOL
| NAME "=" INT
| NAME "=" ESCAPED_STRING
?sum: product
| sum "+" product -> add
@ -42,7 +44,7 @@ calc_grammar = """
| NAME -> var
| NAME "'" -> fluc
| "$" NAME -> env
| "(" sum ")"
| "(" sum ")" -> paren
| inlinefunc "(" sum ")" -> icall
| mathfunc "(" sum ("," sum)* ")" -> fcall
| derivative "(" NAME ")" -> dnx
@ -68,6 +70,7 @@ calc_grammar = """
%import common.CNAME -> NAME
%import common.NUMBER
%import common.ESCAPED_STRING
%import common.INT
%import common.WS
@ -89,6 +92,11 @@ def tok_to_int(tok):
# tok.type == 'INT'
return Token.new_borrow_pos(tok.type, int(tok), tok)
def tok_to_str(tok):
"Convert the value of `tok` from string to string, while maintaining line number & column."
# tok.type == 'ESCAPED_STRING'
return Token.new_borrow_pos(tok.type, tok.value.strip('"'), tok)
class VersionInfo(object):
def __init__ (self, input_raw):
@ -127,12 +135,13 @@ class VersionInfo(object):
def test(terms_raw, report=False):
def test(terms_raw, report=False, latex=False):
parser = Lark(calc_grammar,
parser='lalr',
lexer_callbacks =
{
'ESCAPED_STRING': tok_to_str,
'INT': tok_to_int,
'BOOL': tok_to_bool
}
@ -150,10 +159,18 @@ def test(terms_raw, report=False):
cdict = ir4.print_program()
if not report:
print mod_form.format( cdict )
else:
if report:
ir4.save_ir()
elif latex:
print "{"
for avg in ir4.averaged.values():
print "'{}' : ".format(avg.name)
# print r"\begin{equation}"
print "'${}$' ,".format(avg.latex)
# print r"\end{equation}"
print "}"
else:
print mod_form.format( cdict )
@ -173,4 +190,4 @@ if __name__ == '__main__':
if args.build_info:
build_info(terms_raw)
else:
test(terms_raw, args.print_report)
test(terms_raw, report=args.print_report, latex=args.print_latex)

View file

@ -1,4 +1,5 @@
from lark import Lark, Visitor, Transformer, v_args, Token
import warnings
class CollectDefinitions(Visitor):
@ -70,6 +71,120 @@ class ExpInspector(Visitor):
self.deriv.add((op.data, v.value))
@v_args(inline=True) # Affects the signatures of the methods
class ExpToLatex(Transformer):
def __init__(self, fdict):
self.fdict = fdict
def arithmatic_rooted(self, name):
try:
exproot = self.fdict[name].exp.data
except AttributeError:
exproot = "something_11fasq2afa3rfzsaerqw23"
return ((exproot == "add") or (exproot == "sub") or
(exproot == "mul") or (exproot == "div"))
def parenthise(self, name):
try:
latex = self.fdict[name].latex
latex_given = self.fdict[name].latex_given
except KeyError:
warnings.warn(name + " is not found")
latex = r"\mathrm{{{}}}".format(name)
latex_given = None
if self.arithmatic_rooted(name) and (latex_given is None):
latex = "(" + latex + ")"
return latex
def number(self, numeral):
return numeral
def env(self, name):
return r"\mathrm{{{}}}".format(name.value)
def paren(self, name):
return "({})".format(str(name))
def var(self, name):
return self.parenthise(name.value)
def fluc(self, name):
return self.parenthise(name.value)+ "''"
def dnx (self, partial, b):
fmt = r"\partial_{{{}}}"
coord = partial.data[-1]
op = fmt.format(coord + coord if len(partial.data) > 3 else coord)
signature = "{}_{}".format(partial.data, b.value)
try:
eq = self.fdict[signature].latex
except KeyError:
eq = op + self.parenthise(b.value)
warnings.warn(signature + " is not found: " + eq)
return eq
def icall (self, a, b):
if a.data == "sqr":
fcode = "({0})^2".format(b)
elif a.data == "pow3":
fcode = "({0})^3".format(b)
else:
fcode = "({0})".format(b)
return fcode
def fcall (self, *args):
a = args[0]
b = ", ".join(args[1:])
if a == 'sqrt':
fcode = r"\sqrt{{{}}}".format(b)
return fcode
elif a == 'abs':
fcode = r"\left| {} \right|".format(b)
return fcode
elif a.startswith("\\"):
fcode = r"{}{{({})}}".format(a, b)
return fcode
else:
fcode = r"\mathrm{{{}}}({})".format(a, b)
return fcode
def neg(self, b):
fcode = "(-{})".format(b)
return fcode
def add(self, a, b):
fcode = "{} + {}".format(a, b)
return fcode
def sub(self, a, b):
fcode = "{} - {}".format(a, b)
return fcode
def mul(self, a, b):
fcode = "{} {}".format(a, b)
return fcode
def div(self, a, b):
fcode = "{} / {}".format(a, b)
return fcode
log = lambda self : "\log"
exp = lambda self : "\exp"
sqrt = lambda self : "sqrt"
abs = lambda self : "abs"
rxn_rate = lambda self : "\omega"
udf = lambda self, a : a.value
@v_args(inline=True) # Affects the signatures of the methods
class ExpToCode(Transformer):
@ -82,6 +197,9 @@ class ExpToCode(Transformer):
def env(self, name):
return name.value
def paren(self, name):
return "({})".format(str(name))
def var(self, name):
try:
arrname = self.fdict[name.value].array
@ -307,12 +425,13 @@ class Field (FieldBase):
self.fluc, self.dep, self.derivs = ExpInspector.inspect(exp)
self.comment = self.name + " = " + ExpToCode(self.fdict).transform(self.exp)
self.exporter = None
try:
if self.attr["export"]:
self.exporter = FieldExporter(self.name, self.attr, self)
except KeyError:
pass
self.latex_given = self.attr.get("latex")
if self.latex_given is None:
self.latex = ExpToLatex(self.fdict).transform(self.exp)
else:
self.latex = self.latex_given
self.exporter = self.attr.get("export")
'''
for a in self.dep:
@ -402,6 +521,8 @@ class PrimaryField (FieldBase):
super(PrimaryField,self).__init__(name, fdict)
self.derivs = set([])
self.prime = True
self.latex = name
self.latex_given = None
def code (self, alloc=None):
return "! {} is read from file".format(self.name)
@ -425,6 +546,12 @@ class DerivedField (FieldBase):
self.v = v
self.dep = set([v])
fmt = r"\partial_{{{}}}"
coord = op[-1]
partial = fmt.format(coord + coord if len(op) > 3 else coord)
self.latex = partial + "(" + fdict[v].latex + ")"
def code (self, alloc=None):
self.array = alloc[self.name] if alloc else self.name
varray = alloc[self.v] if alloc else self.v
@ -451,6 +578,8 @@ class AveragedField (FieldBase):
tfield = fdict[tgt]
self.fset = tfield.checkFluctuation()
self.latex = r"\langle {} \rangle".format(tfield.latex)
if not self.fset:
self.tgt = tgt
self.dep.add(tgt)
@ -463,6 +592,8 @@ class AveragedField (FieldBase):
if w:
self.w = fdict[w]
self.dep.add(w)
self.latex += ("_{{{}}}".format(w))
def code (self, alloc=None):