4

Is there any (open source) solution for converting math expressions from a C-like expression syntax to LaTeX? When I say "solution", I mean either from outside LaTeX (i.e: an external program that makes the conversion and outputs LaTeX syntax), or from within LaTeX (i.e: some package that takes C-like math and displays it in formula format on-the-fly).

As an example, I'm asking for converting from 3*c/(a+2) to \frac{3 c}{a + 2} and yes, I know the conversion is not unique, as 3 \frac{c}{a + 2} would also be a legal conversion.

I know some open source CAS packages, such as Maxima or SymPy can do this, but I was wondering if there's any other simpler solution with a lower overhead, not needing to install a full CAS system.

  • Possible duplicate? tex.stackexchange.com/questions/332012/… – Steven B. Segletes Jan 6 '17 at 19:24
  • 2
    Maybe, although I'm not sure the answers given there are able to provide the kind of result I wish. For example, I see several unnecessary parentheses in the final output. Also, I'd like some support to common math functions, such as ´sqrt()´, trigonometry, etc... Although I admit the replies given there are impressive work. – cesss Jan 6 '17 at 19:35
  • 1
    It would be helpful if you provided a number of realistic C-like math expressions that you would like to see converted. – Mico Jan 7 '17 at 0:57
6

(I rewrote the code to make it consist of three separate files: A driver tex file that produces the screenshot; a style file (loaded by the driver file) that sets up the main user macro, called \prettymath; and a lua file (loaded from the style file via a dofile instruction) that performs the actual work.)

The following LuaLaTeX-based solution should not be viewed as a full-blown tool. For now, it's mainly intended to showcase the usefulness and versatility of some of Lua's string functions for the purpose of tackling the problem at hand.

It processes ** exponential notation, deletes single * instances, converts the roman-letter representations of selected lowercase Greek letters (e.g., alpha and pi) to their "native" Greek-character glyphs, and pretty-prints integral expressions, selected three-letter mathop functions (sin, cos, tan, and det -- it should be straightforward to extend this list) as well as square roots and fractions. It can handle nested fractions and square roots. Naturally, this list is far from complete. Hopefully, the code shown below is reasonably self-explanatory so that (I hope) it's not too difficult to handle other cases.

enter image description here


The driver file:

% !TeX program = lualatex
% Test file to check out operation of 'cmath2latex' package
\documentclass{article}
\usepackage{cmath2latex} 

% set up three test strings
\newcommand\mystringa{sqrt(3**(x)*(a*sin(exp(theta)) 
  *cos(2*pi)) / (det (A)*tan(gamma)) ) }
\newcommand\mystringb{3*c/(a+2), 1/pi, pi/2, 2*pi/3, a/b, 
  x/(y+z), (x+y)/z, (a/b)/(c/d)}
\newcommand\mystringc{sqrt( sqrt(sqrt(256))), Integral 
  (sqrt((2**(y))/(y)) , y )}

\begin{document}
\everymath{\displaystyle} % just for this example

\verb&sqrt(3**(x)*(a*sin(exp(theta))*cos(2*pi)) / (det (A)*tan(gamma)) )&

\prettymath{\mystringa}

\bigskip
\verb&3*c/(a+2), 1/pi, pi/2, 2*pi/3, a/b, x/(y+z), (x+y)/z, (a/b)/(c/d)&

\prettymath{\mystringb}

\bigskip
\verb&sqrt( sqrt(sqrt(256))), Integral (sqrt((2**(y))/y) , y )&

\prettymath{\mystringc}
\end{document}

The style file; I suggest you call it cmath2latex.sty:

% !TeX program = lualatex
\ProvidesPackage{cmath2latex}[2017/01/09, version 0.01]

\usepackage{luacode} % for "\luastring" macro
\usepackage{amsmath} % for "\ensuremath" macro

%% Load the Lua code
\directlua{dofile("cmath2latex.lua")} 

%% The LaTeX macro "\prettymath" calls the Lua function
%% "prettymath" and outputs the result in math mode
\newcommand\prettymath[1]{\ensuremath{\directlua{%
    tex.sprint(prettymath(\luastring{#1}))}}}

The file that contains the Lua code; I suggest you call it cmath2latex.lua:

-- cmath2latex.lua
-- This file is called from cmath2latex.sty via a dofile call

-- "prettymath" is called by the "\prettymath" LaTeX macro
-- (which is defined in "prettymath.sty")

function prettymath ( s )

-- exponential notation
  s = string.gsub ( s , "%*%*%s-(%b())" , do_exp )

-- multiplication: delete all single instances of "*"
  s = string.gsub ( s , "%*" , "" )

-- integrals
  s = string.gsub ( s , "Integral%s-(%b())", do_integral )

-- some Greek letters
  s = string.gsub ( s , "alpha" , do_gr_letter )
  s = string.gsub ( s , "beta"  , do_gr_letter )
  s = string.gsub ( s , "gamma" , do_gr_letter )
  s = string.gsub ( s , "Gamma" , do_gr_letter )
  s = string.gsub ( s , "delta" , do_gr_letter )
  s = string.gsub ( s , "Delta" , do_gr_letter )
  s = string.gsub ( s , "theta" , do_gr_letter )
  s = string.gsub ( s , "pi"    , do_gr_letter )
  s = string.gsub ( s , "Pi"    , do_gr_letter )

-- some pre-defined 3-letter operators w/ args in parens
  s = string.gsub ( s , "(cos)%s-(%b())" , do_mathop )
  s = string.gsub ( s , "(det)%s-(%b())" , do_mathop )
  s = string.gsub ( s , "(exp)%s-(%b())" , do_mathop )
  s = string.gsub ( s , "(lim)%s-(%b())" , do_mathop )
  s = string.gsub ( s , "(sin)%s-(%b())" , do_mathop )
  s = string.gsub ( s , "(tan)%s-(%b())" , do_mathop )

-- sqrt function
  for i=1,3 do  -- allow for nested sqrt expressions
    s = string.gsub ( s , "sqrt%s-(%b())", do_sqrt )
  end

-- fraction expressions
  s = string.gsub ( s , "(%b())%s-/%s-(%b())" ,    do_frac_2parens )
  s = string.gsub ( s , "([\\%w]+)%s-/%s-(%b())" , do_frac_1parens_numer )
  s = string.gsub ( s , "(%b())%s-/%s-([\\%w]+)" , do_frac_1parens_denom )
  s = string.gsub ( s , "([\\%w]+)%s-/%s-([\\%w]+)", "\\frac{%1}{%2}" )

-- Feel free to add more string.gsub ops as needed:

-- Return the modified string
return s

end -- end of 'prettymath' function


-- Next, set up the helper functions
function do_exp ( u )
  return ( "^{" .. string.sub(u,2,-2) .. "}"  )
end
function do_gr_letter ( u )
  return ( "\\"..u )
end
function do_mathop ( u , v )
  return ( "\\" .. u .. v )
end
function do_integral ( u )
  u = string.sub ( u, 2, -2 )
  return ( "\\int\\! " ..  string.gsub ( u , "^(.*),(.*)$" , 
      "%1 \\,\\mathrm{d} %2" ) )
end
function do_sqrt ( u )
  return ( "\\sqrt{" .. string.sub(u,2,-2) .. "}" )
end
function do_frac_1parens_numer ( u , v )
  return ( "\\frac{" .. u .. "}{" .. string.sub(v,2,-2) .. "}" )
end
function do_frac_1parens_denom ( u , v )
  return ( "\\frac{" .. string.sub(u,2,-2) .. "}{" .. v .. "}" )
end
function do_frac_2parens ( u , v )
  return ( "\\frac{" .. string.sub(u,2,-2) .. "}{"
   .. string.sub(v,2,-2) .."}" )
end
  • This is impressive, Mico, thanks a lot. I'm just thinking that maybe I could modify some small library for expression evaluation, like TinyExpr so that you can choose whether to evaluate the expression numerically, or to convert it to LaTeX math syntax. Having both capabilities in the same library could be very helpful for my purposes. – cesss Jan 8 '17 at 12:03
  • @cesss - I'm glad you like the code. :-) I've rewritten the code to distinguish more clearly between (a) a "driver" file, (b) a LaTeX style file which is invoked from the driver file and which, in turn, loads a Lua code file, and (c) the Lua code file. Since it would appear that you're rather familiar with C programming, I trust you can easily make sense of the Lua code. Just be aware (if that's not already the case) that Lua doesn't do full regular expression stuff; instead, it does pattern matching, using some powerful built-in string library functions such as string.gsub. – Mico Jan 9 '17 at 1:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.