Is there a (hopefully simple) way to convert a mathematical TeX expression, such as \frac{\cos(x^2) - x}{x^2 + 1}
, to expressions which you would use in a programming language? The outcome of the example should be (cos(x^2) - x)/(x^2 + 1)
.
4 Answers
It is of course possible it depends what tools you want to use and what subset of latex you want to support (you show an easy case, if the latex has fonts and colours or explicit spacing it gets harder). Wolfram alpha for example can compute with the expression exactly as given, in latex syntax.
https://www.wolframalpha.com/input/?i=%5Cfrac%7Bcos%28x%5E2%29+-+x%7D%7Bx%5E2+%2B+1%7D
It also works with cos
corrected to \cos
https://www.wolframalpha.com/input/?i=%5Cfrac%7B%5Ccos%28x%5E2%29+-+x%7D%7Bx%5E2+%2B+1%7D
-
Take also a look at the Python package associated to WolframAlpha. Here is an article about it: geeksforgeeks.org/… . Apr 18, 2021 at 19:52
(augmented the Lua code so that instances of \sqrt{...}
are processed as well)
Here's a LuaLaTeX-based solution. It consists of a LaTeX utility macro called \latextocmath
and two Lua functions -- latex2cmath
and do_frac
-- which perfom most of the work with the help of Lua's built-in string functions and pattern matching capabilities.
The argument of \latextocmath
may contain line breaks. However, the argument of \latextocmath
is not expanded before it is passed to the Lua function latex2cmath
. Hence, if you define a LaTeX macro called, say, \mymacro
, via \newcommand\mymacro{1+1}
, then the output of \latextocmath{\mymacro}
is the string mymacro
, not 1+1
. I trust this restriction won't be burdensome.
If the numerator and denominator terms of a \frac
expression consist of a single letter or a number, the terms are not encased in parentheses. This should help reduce the amount of visual clutter in continued fractions as well as in simple expressions such as \frac{u}{v}
.
This approach can obviously be extended in many ways, depending on the programming code conventions you wish to adhere to and the types of math expressions that need to be fixed. Of course, converting commutative diagrams into inline C-type code will be very, very tedious, to say the least.
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{amsmath} % for \cfrac, \dfrac, and \tfrac
\usepackage{luacode} % for 'luacode*' env. and '\luastringN' macro
\begin{luacode*}
function do_frac ( s ) -- convert \\frac notation to inline-math notation
return ( s:gsub ( "\\[cdt]?frac%s-(%b{})%s-(%b{})" , function ( x , y )
x = x:sub ( 2 , -2 ) -- strip off the curly braces
y = y:sub ( 2 , -2 )
if not (string.len(x)==1 or tonumber(x)) then x = "("..x..")" end
if not (string.len(y)==1 or tonumber(y)) then y = "("..y..")" end
return x.."/"..y
end ) )
end
function latex2cmath ( s )
s = s:gsub ( "\\[,:;!]" , "" ) -- delete '\,' '\:' '\;' and '\!' substrings
s = s:gsub ( "\\mkern..-mu" , "" ) -- delete math kerns
s = s:gsub ( "\\[cl]?dots" , "..." ) -- (typographic) ellipses
s = s:gsub ( "\\sqrt%s-(%b{})" , "sqrt(%1)" )
while s:find ( "\\[cdt]?frac" ) do s = do_frac ( s ) end -- nested \frac-like terms
s = s:gsub ( "\\(%a+)" , "%1" ) -- drop leading backslashes from \cos, \Delta, etc
s = s:gsub ( "%^" , "\\textasciicircum " ) -- make carets visible
tex.sprint ( ( s:gsub ( "%s" , "" ) ) ) -- omit all whitespace
end
\end{luacode*}
%% The LaTeX utility macro:
\newcommand\latextocmath[1]{\texttt{\directlua{ latex2cmath ( \luastringN{#1} ) }}}
\begin{document}
\[
\frac {u}{v} \quad
\frac{ \sqrt { 2 } } {2} \quad
\frac {\cos (x^2) - x} {x^2 + 1} \quad
\dfrac{\dfrac{\alpha+\beta}{\Gamma+\Delta}}{\tfrac{3+4}{5+6}} \quad
1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{ 1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cdots}}}}}}}}
\]
\obeylines
\latextocmath{ \frac {u}{v} }
\latextocmath{ \frac{ \sqrt { 2 } } {2} }
\latextocmath{\frac {\cos (x^2) - x} {x^2 + 1}}
\latextocmath{ \dfrac{\dfrac{\alpha+\beta}{\Gamma+\Delta}}{\tfrac{3+4}{5+6}} }
\latextocmath{1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{ 1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cfrac{1}{1+\cdots}}}}}}}}}
\end{document}
-
The
for
loop could be replaced by awhile
one that callsdofrac
while a new string is obtained. Apr 18, 2021 at 22:21 -
@projetmbc - Many thanks for the suggestion to replace the
for
loop (with a predetermined number of repetitions) with awhile
loop that operates as long as\\[cdt]?frac
is found in the input strings
. Will implement the idea right away.– MicoApr 19, 2021 at 0:34 -
-
@wipet -- Just insert the following line right before the
while ...
line:s = s:gsub ( "{(.-)\\over%s*(.-)}" , "\\frac{%1}{%2}" )
. That, or feel free to replicate thedo_frac
function withdo_over
...– MicoApr 19, 2021 at 17:35 -
Thanks for quick reply. But
\textocmath{ {{ 2 \over 2+1 }\over 3 } }
hangs.– wipetApr 19, 2021 at 17:44
The Emacs calc-embedded mode can do the trick. assuming you are editing a LaTeX file containing
$ \frac {\cos (x ^ 2) - x} {x ^ 2 + 1} $
and the point (the cursor) on it, just type C-x * e
to enter calc-embedded mode. Then type d N
(display normal ) to display
$ (cos (x ^ 2) - x) / (x ^ 2 + 1) $
d L
(displays LaTeX) to return to LaTeX syntax.
C-x * e
to exit the calc-embedded mode and continue the LaTeX file editing.
Bonus
Note that calc-embedded is a nice feature for language syntaxes. Possible syntaxes include C, Fortran, Pascal, TeX, LaTeX, Yacas, Maxima, Giac, Maple, Mathematica, etc ...
calc-embedded also allows rapid entry of matrices in TeX or LaTeX syntax: you enter the matrix online in normal mode $[[a b c] [d e f]]$
and calc-embedded instantly converts to TeX or LaTeX mode active for the document (commas optional).
For example $ \ begin {pmatrix} a & b & c \\ d & e & f \ end {pmatrix} $
in LaTeX mode.
-
Interesting! I tried to find the source code of where this parsing from TeX syntax is done, and some of it seems to be in this file. Apr 19, 2021 at 1:14
I use Sympy for phrasing (and generating) Latex.
from sympy.parsing.latex import parse_latex
expr = parse_latex(r"\frac{\cos(x^2) - x}{x^2 + 1}")
print(expr) # Prints "(-x + cos(x**2))/(x**2 + 1)"
# Bonus
from sympy import latex
print(latex(expr)) # Prints "\frac{- x + \cos{\left(x^{2} \right)}}{x^{2} + 1}"
Sympy has code generators that you can use to generate code in, C, Fortran, Javascript, Julia, Mathematica, Octave/Matlab, and Python (which it, unsurprisingly, has rich support for).
from sympy import ccode, fcode, jscode, julia_code, mathematica_code, octave_code
# C code
print(ccode(expr)) # (-x + cos(pow(x, 2)))/(pow(x, 2) + 1)
# Fortran
print(fcode(expr)) # (-x + cos(x**2))/(x**2 + 1)
# Javascript
print(jscode(expr)) # (-x + Math.cos(Math.pow(x, 2)))/(Math.pow(x, 2) + 1)
# Julia
print(julia_code(expr)) # (-x + cos(x.^2))./(x.^2 + 1)
# Mathematica
print(mathematica_code(expr)) # (-x + Cos[x^2])/(x^2 + 1)
# Octave/Matlab
print(octave_code(expr)) # (-x + cos(x.^2))./(x.^2 + 1)
# Python
print(expr) # (-x + cos(x**2))/(x**2 + 1)
# Or use lambdify to directly make a Numpy accelerated callable python function
Some notes on getting this setup, you need the antlr4-python3-runtime
to use this feature. If you get an error like; ANTLR runtime and generated code versions disagree: 4.9.2!=4.7.2
, you need to install the version of the ANTLR runtime that matches the version that Sympy expects, i.e. pip install antlr4-python3-runtime==4.7.2
.
(a*x+b)*x+c
is both more accurate and faster thana*x^2+b*x+c
..