15

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).

Mico
  • 506,678
Valentin
  • 161
  • 1
    Welcome to TeX.SE. It looks like you're aiming to perform the inverse of the operation described in Converting C-like math expressions to LaTeX. Is that right? – Mico Apr 18 '21 at 18:14
  • 2
    Ahhh, but the inverse problem...converting expressions you would use in a programming language into LaTeX code...now that is a challenge: https://tex.stackexchange.com/questions/332012/translate-in-line-equations-to-tex-code-any-package/332061#332061 – Steven B. Segletes Apr 18 '21 at 18:38
  • 1
    Also, standard math notation is notoriously bad for computation. For example (a*x+b)*x+c is both more accurate and faster than a*x^2+b*x+c.. – John Kormylo Apr 19 '21 at 03:10

4 Answers4

18

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

enter image description here

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

David Carlisle
  • 757,742
  • Take also a look at the Python package associated to WolframAlpha. Here is an article about it: https://www.geeksforgeeks.org/python-create-a-simple-assistant-using-wolfram-alpha-api/ . – projetmbc Apr 18 '21 at 19:52
12

(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.

enter image description here

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}
Mico
  • 506,678
  • The for loop could be replaced by a while one that calls dofrac while a new string is obtained. – projetmbc Apr 18 '21 at 22:21
  • @projetmbc - Many thanks for the suggestion to replace the for loop (with a predetermined number of repetitions) with a while loop that operates as long as \\[cdt]?frac is found in the input string s. Will implement the idea right away. – Mico Apr 19 '21 at 00:34
  • {a \over b} does not work. What gsub command we have to add? – wipet Apr 19 '21 at 17:09
  • @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 the do_frac function with do_over... – Mico Apr 19 '21 at 17:35
  • Thanks for quick reply. But \textocmath{ {{ 2 \over 2+1 }\over 3 } } hangs. – wipet Apr 19 '21 at 17:44
  • @wipet - I did answer your initial question correctly, didn't I? :-) [FWIW, I refuse to be drawn into the debate over whether \over-type infix notation is better or worse than \frac notation, as I have nothing original or new to say on this subject.] Incidentally, do_frac by design does not work on inputs such as \frac12 or \frac23 -- the Lua function's %b{} pattern match criterion requires the arguments to be enclosed in matching curly braces. Feel free to ask a new question about how one might write a do_over function that's equivalent to do_frac. – Mico Apr 19 '21 at 17:59
10

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.

projetmbc
  • 13,315
gigiair
  • 1,812
8

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.

Mark Omo
  • 277