0

In lua I have a function that takes a string and an number called "simpFracs" (It's supposed to take a fraction and a number, multiply them, return a number)

I have a pretty disgusting macro (It's a macro that shows working steps for a math problem)

\def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}

Which, with, eg with #1=10 and #2=8 it'll expand into

\frac{1}{4}

For LuaLatex, I wanted to pass xval as a string. The macro looks like:

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

The simpFracs macro works fine on a string such as

\simpFracs{\frac{1}{4}}{\frac{4}{1}}

works fine, But when I add in a macro, I have no clue how to get this to work...

\simpFracs{\xval}{\\frac{4}{1}}

I've tried looking up macro expansion for a couple hours, But I have no clue how they expand in strings

A full working example: (I left this out because its disgusting)

-- in math.lua
-- I am aware this code is bad, but it works, its an assignment, I dont care if its hacky

function simpfrac(a,b)     
    sign = false;
    if a < 0 then
        sign = true
    end
    if b < 0 then
        if sign == true then
            sign = false
        else
            sign = true
        end
    end

    a = math.abs(a)
    b = math.abs(b)

    local function gcd(a,b)   
        if b ~= 0 then
            return gcd(b, a % b)
        else
            return math.abs(a)
        end
    end

    t = gcd(a, b)
    if b/t == 1 then
        if sign == true then
         tex.sprint(-math.floor(a/t))
        else
            tex.sprint(math.floor(a/t))
        end
        
    else
        -- Floor removes the decimal points
        if sign == true then
            tex.sprint("-\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
        else
            tex.sprint("\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
        end
    end  
end    

function simpmult(a,b)
        tex.sprint(a*b)
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
    -- Parse frac
    -- frac{a} {b}
    local fraca = {}
    local fracb = {}
    for w in string.gmatch(a, "{([^{}]*)}") do
        table.insert(fraca,w)
    end
    for w in string.gmatch(b, "{([^{}]*)}") do
        table.insert(fracb,w)
    end
    c = fraca[1]/fraca[2]
    d = fracb[1]/fracb[2]
    tex.sprint(math.floor(c*d))
end

anyname.tex

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
  \directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
  \directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
    \def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
    $x = \xval$ \\
    $f(x) = #1xe^{-#2x}$ \\
    % Want it to be this (But without the \\frac{1}{4} hard coded)
    $y=\simpFracs{\\frac{1}{4}}{\\frac{#1}{1}}e^{\simpFracs{\\frac{1}{4}}{\\frac{-#2}{1}}}$ \\ 
    % Dont know how to make this compile
    %$y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}

UPDATE: Figured out how to fix the backslash issue, I just needed to change

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("#1","#2")}%
}

To

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

But now the arguments being passed from the macro is: "\protect {\begingroup 1\endgroup \over 4}" and "\protect {\begingroup 10\endgroup \over 1}" rather than "\frac{1}{4}" and "\frac{10}{1}" and I have no clue how to go about fixing it...

11
  • 1
    you should make a complete example that can be used for tests instead of showing some snippets. But beside this, it looks wrong to mix calculation and typesetting like this. – Ulrike Fischer Jul 14 '20 at 15:42
  • Added complete example. Some context as to why: I have to provide working for everything I put in a table for an assignment, I dont want a bunch of random errors in my working, I've already done this to produce 3 pages of working, It'd be a shame to change it midway through. – Ben Jul 14 '20 at 16:25
  • What's the output of \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}} supposed to be? 2e^{-2}? Please advise. – Mico Jul 14 '20 at 16:29
  • 2e^{-2}. correct. – Ben Jul 14 '20 at 16:32
  • Lua uses math.exp(1) for e. – user220367 Jul 14 '20 at 16:44
0

After the initial discovery of having to convert

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("#1","#2")}%
}

to

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

I realized that it took one of two type of inputs, so instead of trying to understand latex, I just used lua to parse them.
The input could've been \frac{a}{b} or \protect {\begingroup a\endgroup \over b}
To keep the code readable, I split it up into functions, which means I also had to parse constants. Leaving me with the final lua code of:

function parsefrac(a)
    print("A is", a)
    -- First check is input is constant (Format 1)
    local consta = {}
    for w in string.gmatch(a, "%d+") do
        table.insert(consta,w)
    end
    if consta[2] == nil then
        print("String is format 1!")
        b = consta[1]
        return b;
    end

    
    -- frac{a}{b} -- (Format 2)
    if a.sub(a,1,string.len("\\frac")) == "\\frac" then
        -- Format 1
        print("String is format 2!")
        local fraca = {}
        
        for w in string.gmatch(a, "{([^{}]*)}") do
            table.insert(fraca,w)
        end
        
        b = fraca[1]/fraca[2]
        
        return b
        
    else
        -- \protect {\begingroup a\endgroup \over b} -- (Format 3)
        print("String is format 3!")
        local fraca = {}
        for w in string.gmatch(a, "%d+") do
            table.insert(fraca,w)
        end
        b = fraca[1]/fraca[2]
        
        return b
    end
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
    -- Parse typesetting
    
    c = parsefrac(a)
    d = parsefrac(b)
    
    tex.sprint(math.floor(c*d))
end

Which given the input

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
  \directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
  \directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
    \def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
    $x = \xval$ \\
    $f(x) = #1xe^{-#2x}$ \\
    $y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}

Will produce the desired results.
This isn't in the scope of the original question, but for completeness, I'm aware there's a logical error in 1/4 * 10 = 2, but that was fixed by changing

tex.sprint(math.floor(c*d))

to

    if c*d == math.floor(c*d) then
        tex.sprint(math.floor(c*d))
    else
        simpfrac(c*d,1)
    end

in the end of the simpfracs function

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.