font - subindex python
Convertir una expresión numérica de python a LaTeX (5)
Aquí hay un método bastante largo pero aún incompleto que no involucra a Sympy de ninguna manera. Es suficiente para cubrir el ejemplo de (-b-sqrt(b**2-4*a*c))/(2*a)
que se traduce a /frac{- b - /sqrt{b^{2} - 4 /; a /; c}}{2 /; a}
/frac{- b - /sqrt{b^{2} - 4 /; a /; c}}{2 /; a}
/frac{- b - /sqrt{b^{2} - 4 /; a /; c}}{2 /; a}
y rinde como
Básicamente, crea el AST y lo hace produciendo la matemática de látex que corresponde a los nodos AST. Lo que hay debe dar suficiente idea de cómo extenderlo en los lugares que le faltan.
import ast
class LatexVisitor(ast.NodeVisitor):
def prec(self, n):
return getattr(self, ''prec_''+n.__class__.__name__, getattr(self, ''generic_prec''))(n)
def visit_Call(self, n):
func = self.visit(n.func)
args = '', ''.join(map(self.visit, n.args))
if func == ''sqrt'':
return ''/sqrt{%s}'' % args
else:
return r''/operatorname{%s}/left(%s/right)'' % (func, args)
def prec_Call(self, n):
return 1000
def visit_Name(self, n):
return n.id
def prec_Name(self, n):
return 1000
def visit_UnaryOp(self, n):
if self.prec(n.op) > self.prec(n.operand):
return r''%s /left(%s/right)'' % (self.visit(n.op), self.visit(n.operand))
else:
return r''%s %s'' % (self.visit(n.op), self.visit(n.operand))
def prec_UnaryOp(self, n):
return self.prec(n.op)
def visit_BinOp(self, n):
if self.prec(n.op) > self.prec(n.left):
left = r''/left(%s/right)'' % self.visit(n.left)
else:
left = self.visit(n.left)
if self.prec(n.op) > self.prec(n.right):
right = r''/left(%s/right)'' % self.visit(n.right)
else:
right = self.visit(n.right)
if isinstance(n.op, ast.Div):
return r''/frac{%s}{%s}'' % (self.visit(n.left), self.visit(n.right))
elif isinstance(n.op, ast.FloorDiv):
return r''/left/lfloor/frac{%s}{%s}/right/rfloor'' % (self.visit(n.left), self.visit(n.right))
elif isinstance(n.op, ast.Pow):
return r''%s^{%s}'' % (left, self.visit(n.right))
else:
return r''%s %s %s'' % (left, self.visit(n.op), right)
def prec_BinOp(self, n):
return self.prec(n.op)
def visit_Sub(self, n):
return ''-''
def prec_Sub(self, n):
return 300
def visit_Add(self, n):
return ''+''
def prec_Add(self, n):
return 300
def visit_Mult(self, n):
return ''//;''
def prec_Mult(self, n):
return 400
def visit_Mod(self, n):
return ''//bmod''
def prec_Mod(self, n):
return 500
def prec_Pow(self, n):
return 700
def prec_Div(self, n):
return 400
def prec_FloorDiv(self, n):
return 400
def visit_LShift(self, n):
return ''//operatorname{shiftLeft}''
def visit_RShift(self, n):
return ''//operatorname{shiftRight}''
def visit_BitOr(self, n):
return ''//operatorname{or}''
def visit_BitXor(self, n):
return ''//operatorname{xor}''
def visit_BitAnd(self, n):
return ''//operatorname{and}''
def visit_Invert(self, n):
return ''//operatorname{invert}''
def prec_Invert(self, n):
return 800
def visit_Not(self, n):
return ''//neg''
def prec_Not(self, n):
return 800
def visit_UAdd(self, n):
return ''+''
def prec_UAdd(self, n):
return 800
def visit_USub(self, n):
return ''-''
def prec_USub(self, n):
return 800
def visit_Num(self, n):
return str(n.n)
def prec_Num(self, n):
return 1000
def generic_visit(self, n):
if isinstance(n, ast.AST):
return r'''' % (n.__class__.__name__, '', ''.join(map(self.visit, [getattr(n, f) for f in n._fields])))
else:
return str(n)
def generic_prec(self, n):
return 0
def py2tex(expr):
pt = ast.parse(expr)
return LatexVisitor().visit(pt.body[0].value)
Necesito convertir cadenas con una sintaxis de python válida como:
''1+2**(x+y)''
y obtén el equivalente de LaTeX:
$1+2^{x+y}$
He probado la función de látex de sympy pero procesa la expresión real, en lugar de la forma de cadena de la misma:
>>> latex(1+2**(x+y))
''$1 + 2^{x + y}$''
>>> latex(''1+2**(x+y)'')
''$1+2**(x+y)$''
pero incluso para hacer esto, se requiere que xey sean declarados como tipo "símbolos".
Quiero algo más sencillo, preferiblemente factible con el analizador desde el módulo compilador.
>>> compiler.parse(''1+2**(x+y)'')
Module(None, Stmt([Discard(Add((Const(1), Power((Const(2), Add((Name(''x''), Name(''y''))))))))]))
Por último, pero no menos importante, el por qué: necesito generar esos fragmentos de látex para poder mostrarlos en una página web con mathjax.
Para basarse en la respuesta de tom10, puede definir un diccionario que genere símbolos y utilizarlo al llamar a eval:
from collections import defaultdict
class GenerateSymbols(defaultdict):
def __missing__(self, key):
return sympy.Symbol(key)
Entonces si usas
sympy.latex(eval(''1+2**(x+y)'',GenerateSymbols()))
no debería tener que preocuparse por la creación previa de símbolos para las variables.
Puedes usar sympy.latex
con eval
:
s = "1+2**(x+y)"
sympy.latex(eval(s)) # prints ''$1 + {2}^{x + y}$''
Aún tiene que declarar las variables como símbolos, pero si esto es realmente un problema, es mucho más fácil escribir un analizador para hacer esto que analizar todo y generar el látex desde cero.
Puedes usar SymPy. Simplemente pase la cadena a la función sympify()
primero, que la convertirá en una expresión SymPy válida (es decir, cree los Símbolos por usted, etc.). Para que pudieras hacer
>>> latex(sympify(''1+2**(x+y)''))
1 + 2^{x + y}
S()
también es un acceso directo a sympify()
, es decir, el latex(S(''1+2**(x+y)''))
también funciona.
Sólo una pequeña solución a la excelente respuesta de Geoff Reedy:
class GenerateSymbols(defaultdict):
def __missing__(self, key):
self[key] = sympy.Symbol(key)
return self[key]
Antes de que no agregaría el nuevo elemento al dict. Ahora puedes usar esto con tu expresión:
d= GenerateSymbols()
eq = ''(-b-sqrt(b**2-4*a*c))/(2*a)''
y puede simplificarlo aún más antes de convertirlo a LaTeX:
sympy.latex(sympy.simplify(eval(eq,d)))
y obtienes esto:
''$- //frac{b + //operatorname{sqrt}//left(- 4 a c + b^{2}//right)}{2 a}$''