Skip to content

Instantly share code, notes, and snippets.

@certik
Created October 19, 2008 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save certik/17957 to your computer and use it in GitHub Desktop.
Save certik/17957 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
#latex.py
"""
Convert GAsympy output to LaTeX format
"""
import re as regrep
import string,copy,sys,os,StringIO,subprocess,types
from pyparsing import nestedExpr
from sympy import *
class LaTeX:
stdout = sys.stdout
strfile = StringIO.StringIO()
mode = ('^','_')
div = regrep.compile(r'\)/\(|\)/@[0-9]+|@[0-9]+/\(|@[0-9]+/@[0-9]+')
allvars = regrep.compile(r'([A-Za-z]+[_0-9]+)')
vars = regrep.compile(r'([A-Za-z]+)([_0-9]+)')
subs = regrep.compile(r'[A-Za-z]+')
xpon = regrep.compile(r'(\*\*[0-9]+|\*\*@[0-9]+)')
times = regrep.compile(r'(\*{1,2})')
greek = regrep.compile('(alpha|beta|gamma|delta|varepsilon|epsilon|zeta|'+\
'vartheta|theta|eta|iota|kappa|lambda|mu|nu|xi|varpi|pi|'+\
'rho|varrho|varsigma|sigma|tau|upsilon|varphi|phi|chi|'+\
'psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|'\
'Phi|Psi|Omega|partial|nabla)')
fcts = regrep.compile('(sin|cos|tan|cot|'+\
'asin|acos|atan|acot|'+\
'sinh|cosh|tanh|coth|'+\
'asinh|acosh|atanh|acoth|'+\
'exp|log|sqrt|abs)')
accents = regrep.compile('([A-Za-z]+)(hat|check|dot|breve|acute|'+\
'ddot|grave|tilde|mathring|bar|vec)')
fctdict = {'sin':'\\sin','cos':'\\cos','tan':'\\tan','cot':'\\cot',\
'asin':'\\mathrm{Sin}^{-1}','acos':'\\mathrm{Cos}^{-1}',\
'atan':'\\mathrm{Tan}^{-1}','acot':'\\mathrm{Cot}^{-1}',\
'sinh':'\\sinh','cosh':'\\cosh','tanh':'\\tanh','coth':'\\coth',\
'asinh':'\\mathrm{Sinh}^{-1}','acosh':'\\mathrm{Cosh}^{-1}',
'atanh':'\\mathrm{Tanh}^{-1}','acoth':'\\mathrm{Coth}^{-1}',\
'sqrt':'\\sqrt','exp':'\\exp','log':'\\mathrm{ln}','abs':'\\abs'}
argfcts = ('sqrt','abs')
ops = ('+','-','*','/')
preamble = '\\documentclass[12pt,letterpaper]{article}\n'+\
'\\pagestyle{empty}\n'+\
'\\usepackage[latin1]{inputenc}\n'+\
'\\usepackage{amsmath}\n'+\
'\\usepackage{amsfonts}\n'+\
'\\usepackage{amssymb}\n'+\
'\\newcommand{\\lp}{\\left (}\n'+\
'\\newcommand{\\rp}{\\right )}\n'+\
'\\newcommand{\\half}{\\frac{1}{2}}\n'+\
'\\newcommand{\\difftwo}[3]{\\frac{\\partial^{#1}{#3}}{#2}}'+\
'\\newcommand{\\diffthree}[3]{\\frac{\\partial^{#1}}{#2}\\lp{#3}\\rp}'+\
'\\begin{document}\n'
postscript = '\\end{document}\n'
body = ''
format = 0
subdict = {}
subcnt = 0
@staticmethod
def setaccent(x):
return('\\%s{%s}' % (x.group(2),x.group(1)))
@staticmethod
def setvars(x):
return('\\%s' % x.group(1))
@staticmethod
def setsubsup(x):
xtupl = x.groups()
if len(xtupl) == 0:
return(x)
else:
subsup = xtupl[1].split('_')
nsubsup = len(subsup)
if nsubsup == 1:
return('%s^{%s}' % (xtupl[0],subsup[0]))
if nsubsup == 2:
if subsup[0] != '':
return('%s^{%s}_{%s}' % (xtupl[0],subsup[0],subsup[1]))
else:
return('%s_{%s}' % (xtupl[0],subsup[1]))
if nsubsup > 2:
outstr = xtupl[0]
if subsup[0] == '':
if subsup[1] == '':
for i in range(2,nsubsup):
outstr += LaTeX.mode[i%2]+'{'+subsup[i]+'}{}'
return(outstr)
for i in range(1,nsubsup):
outstr += LaTeX.mode[i%2]+'{'+subsup[i]+'}{}'
return(outstr)
for i in range(nsubsup):
outstr += LaTeX.mode[i%2]+'{'+subsup[i]+'}{}'
return(outstr)
return(' ')
@staticmethod
def var_str(namestr):
if LaTeX.format == 0:
return(namestr)
pstr = regrep.sub(LaTeX.vars,LaTeX.setsubsup,namestr)
pstr = regrep.sub(LaTeX.accents,LaTeX.setaccent,pstr)
pstr = regrep.sub(LaTeX.greek,LaTeX.setvars,pstr)
return(pstr)
@staticmethod
def replace_all_vars(line):
line = regrep.sub(LaTeX.allvars,LaTeX.replace_vars,line)
return(line)
@staticmethod
def replace_vars(x):
xstr = x.group(1)
keystr = '@'+str(LaTeX.subcnt)
LaTeX.subdict[keystr] = '{'+LaTeX.var_str(xstr)+'}'
LaTeX.subcnt += 1
return(keystr)
@staticmethod
def setformat(format):
if format > 0:
LaTeX.format = format
LaTeX.body = ''
sys.stdout = LaTeX.strfile
return
@staticmethod
def derivative(line):
tmp = line
Dindx = 1
while Dindx != -1:
Dindx = tmp.find('D(')
if Dindx == -1:
break
else:
tmp = tmp[Dindx:]
Pindx = tmp.find(')')
sub = tmp[0:Pindx+1]
tmp = tmp[Pindx+1:]
subkey = '@'+str(LaTeX.subcnt)
LaTeX.subdict[subkey] = LaTeX.format_derivative(sub[2:-1])
line = line.replace(sub,subkey)
LaTeX.subcnt += 1
return(line)
@staticmethod
def format_derivative(dstr):
dstr = dstr.replace(',','')
dlst = dstr.split()
fstr = LaTeX.var_str(dlst[0])
dlst = dlst[1:]
vlst = LaTeX.nvar*[0]
for ivar in dlst:
indx = LaTeX.ivarlst.index(ivar)
vlst[indx] += 1
dstr = ''
i = 0
if LaTeX.format == 1:
for v in vlst:
if v == 1:
dstr += '\\partial_{'+str(i)+'}'
if v > 1:
dstr += '\\partial_{'+str(i)+'}^{'+str(v)+'}'
i += 1
dstr += fstr
if LaTeX.format == 2:
for v in vlst:
if v == 1:
dstr += '\\partial_{'+LaTeX.var_str(LaTeX.ivarlst[i])+'}'
if v > 1:
dstr += '\\partial_{'+LaTeX.var_str(LaTeX.ivarlst[i])+'}^{'+str(v)+'}'
i += 1
dstr += fstr
if LaTeX.format == 3 or LaTeX.format == 4:
sum = 0
for v in vlst:
sum += v
if v == 1:
dstr += '\\partial '+LaTeX.var_str(LaTeX.ivarlst[i])
if v > 1:
dstr += '\\partial^{'+str(v)+'}'+LaTeX.var_str(LaTeX.ivarlst[i])
i += 1
if sum == 1:
strsum = ''
else:
strsum = str(sum)
if LaTeX.format == 3:
dstr = '\\frac{\\partial^{'+strsum+'}'+fstr+'}{'+dstr+'}'
if LaTeX.format == 4:
dstr = '\\frac{\\partial^{'+strsum+'}}{'+dstr+'}\\lp '+fstr+'\\rp'
return(dstr)
@staticmethod
def replace_all_functions(line):
return(line)
@staticmethod
def replace_all_times(line):
line = line.replace('*','')
return(line)
@staticmethod
def replace_all_pow(line):
return(line)
@staticmethod
def replace_paren(line):
line = line.replace('(','\\lp ')
line = line.replace(')','\\rp ')
return(line)
@staticmethod
def nested_lst_to_str(lst):
global lstr
lstr = ''
def sub_lst(lst):
global lstr
for x in lst:
if isinstance(x,types.StringType):
lstr += x
else:
bflg = False
if lstr[-1] != '{':
lstr += '('
else:
bflg = True
sub_lst(x)
if bflg:
lstr += '}'
else:
lstr += ')'
sub_lst(lst)
return(lstr)
@staticmethod
def parse_nested_lst(lst):
def sub_lst(lst):
i = 0
for x in lst:
if isinstance(x,types.StringType):
lst[i] = LaTeX.parse_str(x)
else:
lst[i] = sub_lst(x)
i += 1
return(lst)
sub_lst(lst)
return
@staticmethod
def replace_fct(x):
xstr = x.group(1)
keystr = '@'+str(LaTeX.subcnt)
LaTeX.subcnt += 1
LaTeX.subdict[keystr] = LaTeX.fctdict[xstr]
if xstr in LaTeX.argfcts:
keystr += '{'
return(keystr)
@staticmethod
def replace_xpon(x):
xstr = x.group(1)
xstr = '^{'+xstr[2:]+'}'
return(xstr)
@staticmethod
def parse_str(x):
x = regrep.sub(LaTeX.fcts,LaTeX.replace_fct,x)
x = regrep.sub(LaTeX.allvars,LaTeX.replace_vars,x)
x = LaTeX.parse_xpon(x)
return(x)
@staticmethod
def parse_xpon(x):
xpon = x.rfind('**')
if xpon >= 0:
if xpon == len(x)-2:
x = x[:-2]+'^{'
x = regrep.sub(LaTeX.xpon,LaTeX.replace_xpon,x)
return(x)
@staticmethod
def parseline(line):
line = line.replace(LaTeX.ivarstr,'')
line = LaTeX.derivative(line)
line = string.join(line.split(),"")
tmp = '('+line+')'
nestlst = nestedExpr().searchString(tmp)[0][0]
LaTeX.parse_nested_lst(nestlst)
line = LaTeX.nested_lst_to_str(nestlst)
line = line.replace('*','')
return(line)
@staticmethod
def xdvi(ivars):
sys.stdout = LaTeX.stdout
LaTeX.body = LaTeX.strfile.getvalue()
tmp = LaTeX.body.strip()
LaTeX.nvar = len(ivars)
LaTeX.ivarlst = []
LaTeX.ivarstr = '('
for ivar in ivars:
strvar = str(ivar)
LaTeX.ivarlst.append(strvar)
LaTeX.ivarstr += strvar+', '
LaTeX.ivarstr = LaTeX.ivarstr[:-2]+')'
lines = tmp.split('\n')
indx = range(len(lines))
body = ''
LaTeX.subcnt = 0
LaTeX.subdict = {}
for line in lines:
if line.find('=') >= 0:
line = LaTeX.parseline(line)
body += '$$'+line+'$$\n'
else:
body += line+'\\newline\n'
for key in LaTeX.subdict.keys():
body = body.replace(key,LaTeX.subdict[key])
body = LaTeX.replace_paren(body)
LaTeX.body = LaTeX.preamble+body+LaTeX.postscript
if os.path.exists('textput.*'):
os.system('rm texput.*')
PIPE = subprocess.PIPE
p = subprocess.Popen("latex",stdin=PIPE)
p.stdin.write(LaTeX.body)
os.system('xdvi -geometry 900x400 texput &')
#os.wait()
return
if __name__ == '__main__':
"""
A set format argument of 1, 2, 3, or 4 will produce different
LaTeX formatting for partial derivatives. A set format of 0
produces standard (not pretty print) sympy printed output. Try
it and see the differences. Note that in xdiv(x) x is the tuple
of independent variables that one might have to differentiate with
respect to.
"""
LaTeX.setformat(3)
x = tuple(symbols('x1','x2'))
f = Function('f_12')(*x)
g = Function('g_34')(*x)
x1 = x[0]
x2 = x[1]
half = Rational(1,2)
dfx1 = diff(f,x1)
dgx2 = diff(g,x2)
h = x1*f-half*asin(x2)*g
dhx1 = diff(h,x1)
F = h+dhx1*dgx2
print 'F =',F/f
dF = diff(F,x2)
print 'dF =',dF
print 'Note that $x^{2}$ is not $xx$, but one of the independent variables $x^{1}$ and $x^{2}$.'
LaTeX.xdvi(x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment