Collect numbers a,b and c from equation $ax^2+bx+c=0$ with lpeg (luatex)

This is my first attempt to create macro with luatex. the macro \solveq to solve quadratic equation ax^2+bx+c=0 here my code

\documentclass[12pt]{article}
\usepackage{amssymb}
\usepackage{luacode}

\begin{luacode*}
function solve_equa(equa)
local a_here= string.find (equa,"x^2")
local b_here= string.find (equa,"x[^^]")
local c_here= string.find (equa,"x[-+](.-)=")

local a = string.match(equa,"%$(.-)x^2") or 0 local b = (b_here ~=nil) and ((a_here ~=nil) and string.match(equa,"x^2(.-)x") or string.match(equa,"%$(.-)x")) or 0
local c = (c_here ~=nil) and  ((a_here ~=nil) and  ((b_here ~=nil) and string.match(equa,"%b^x(.-)=") or string.match(equa,"%x^2(.-)="))  or
string.match(equa,"x(.-)=")) or 0

if a=="" or a=="+" then
a=1
elseif a=="-" then
a=-1
end

if b=="" or b=="+" then
b=1
elseif b=="-" then
b=-1
end

if a==0 then
local  temp =  (-c/b == -0) and 0 or -c/b
solution = "x = " .. temp
else

D = b*b-4*a*c

if D==0 then
solution = "$x = " .. -b/2/a .. "$"
else if D>0 then
solution  = "$x1 = " .. (-b+math.sqrt(D))/2/a .. "\\quad x2 =" .. (-b-math.sqrt(D))/2/a .. "$"
else
solution  =[[no solution in $\mathbb{R}$]]
end
end
end
return solution
end

\end{luacode*}

\def\solveq#1{solution of equation $#1$:\par
{\centering \directlua{solve_equa("$#1$") tex.print(solution)}\par}}

\begin{document}

\solveq{-x^2+5x+4=0}

\end{document}


My hope is to symplify collect of numbers a,b,c with the lpeg functions

• Are you familiar with the sagetex package? It gives you access to a computer algebra system with a lot of built in commands for mathematics. Want to collect a,b,c? Use coefficient(sparse=False) with your polynomial as shown here. You would, however, need Sage installed locally on your computer or use Cocalc. No need to reinvent the wheel! – DJP Oct 14 '18 at 1:17

Below I present an LPEG grammar which can do what you asked for, but focusing on simplicity. For more complicated parsing you need a more complicated parser. You might want to have a look at, and perhaps adapt the parser from my project here: https://github.com/hmenke/boost_matheval/blob/master/include/matheval.lua

\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{luacode}

\begin{luacode*}
local lpeg = require"lpeg"
local C, P, S = lpeg.C, lpeg.P, lpeg.S

local sgn = { [""] = 1, ["+"] = 1, ["-"] = -1 }

local w     = S" \t"^0
local eq    = P"="
local var   = P"x"
local pm    = C(S"+-"^0) / sgn
local num   = C((1 - var - eq)^0) / function(c) return c == "" and 1 or tonumber(c) end
local coeff = pm * w * num / function(a,b) return a * b end

local grammar = (
w * coeff * w * var * P"^2" *
w * coeff * w * var *
w * coeff *
w * eq *
w * coeff
)

local parse = function(exp)
return grammar:match(exp)
end

solve = function(exp)
local a, b, c, d = parse(exp)
c = c - d

local D = b^2 - 4*a*c

if D < 0 then
tex.sprint("\$\\text{no solution in \\mathbb{R}}\$")
return
end

if D == 0 then
tex.sprint("\$x_1 = " .. -b/(2*a) .."\$")
return
end

local x1 = (-b + math.sqrt(D))/(2*a)
local x2 = (-b - math.sqrt(D))/(2*a)
tex.sprint("\$x_1 = " .. x1 .. " \\quad x_2 = " .. x2 .. "\$")
end
\end{luacode*}

\def\solveq#1{$#1$ has the following solutions: \directlua{solve("\luaescapestring{#1}")}}

\begin{document}

\solveq{-x^2+5x+4=0}

\solveq{- x^2 + 3 x + 2 = 2}

\solveq{x^2+ x +1=0}

\solveq{-13x^2+0x+1=0}

\end{document}


• Thank's, the role of /sgn after local pm = C(S"+-"^0) ? – Salim Bou Oct 16 '18 at 9:41
• @SalimBou / sgn is a semantic action which uses the table sgn to map the capture ("" or "+" or "-") to a number (-1 or +1). – Henri Menke Oct 16 '18 at 12:16