# Simplifying square roots

I want to create a command that, for a given integer n, type sets a simplified square root of n. For example, the output of

\rsqrt{4}
\rsqrt{8}
\rsqrt{18}
\rsqrt{7}


would be the same as that of

2
2\sqrt{2}
3\sqrt{2}
\sqrt{7}


where \rsqrt{} is the command in question.

I know that the algorithm would look somewhat like this

i = square root of n rounded down

while i > 0:
if n is divisible by i²:
simplification is i\sqrt{n/i²}
break loop
i = i - 1

%the simpification will always be found
%since every n is divisible by 1


where n is the given integer, i is the number before \sqrt and n/i² is the argument of \sqrt{...}.

But I have no idea how to implement this in latex?

EDIT: Clarified that the input number will always be an integer.

-
Please clarify what the term if not (n mod i²) denotes: what's being tested? Equality to zero? Please advise. – Mico Mar 20 at 21:22
it denotes if (n is divisible by i²) do. And yes, equality to zero of the (n mod i²) is being tested. – koralakralj Mar 20 at 21:27
Easy in lualatex. Would that do? – JPi Mar 20 at 23:01
@JPi - Please see the answer I just posted. :-) – Mico Mar 20 at 23:07
Nice! ......... – JPi Mar 20 at 23:13

The algorithm in the question is very inefficient: except of course if the original integer is a perfect square.

1. an approach with macros which mimics the simplest factorization algorithm,

2. an expandable approach using the algorithm as in OP. update very embarrassingly, the author had not understood the OP's algorithm and after having found a simplifying I such as I^2 divided N, he went one recursively with N<-N/I^2 not understanding that the algorithm could stop there. (as a pale excuse, he had implemented first the "bottom-up" way, which needs recursivity, contrarily to the "top-down" (less efficient) way). The answer is thus updated, apologies to all generous trustful early up-voters.

I am updating again (sorry) because I have now read more of xintexpr.sty's documentation, and I switched for efficiency from i=sqrt(N)..1 to i=-sqrt(N)++ (there is no -- available, hence a trick with minus sign). The former generates beforehand the whole list of floor(\sqrt{N}) numbers (sqrt means truncated square root in \xintiiexpr), the latter is an iterator which doesn't generate things beforehand. Furthermore the former syntax can only generate about 5000 values (sqrt(N)..[-1]..1 would have no such limitation, but still would generate everything beforehand).

3. an expandable implementation of faster (high-school factorization type) algorithm as in approach 1.

To be honest 2., 3. and even 1. would probably be better written entirely using \numexpr as their pretence at handling numbers bigger than 2^31 is a bit far-stretched, it takes time with a prime number of 10 digits to do tens of thousands of divisions to conclude it was square-free ... Implementation 2. has an intrinsic limit to 2^62 because the square root must be a TeX number (due to some construct inside).

In 2. and 3., we push a bit beyond reasonable range the possibilities of \xintexpr syntax with recursive sequences. The notation is a bit cumbersome. Besides xintexpr.sty 1.2g is needed because it changed relevant syntax.

## First approach (we change the algorithm)

Not to say that this is an easy problem. A bit of googling reveals that apparently mathematicians currently believe that finding the square free radical of an integer may be as hard as complete factorization: http://math.stackexchange.com/questions/171568/finding-the-radical-of-an-integer and http://math.stackexchange.com/questions/14667/square-free-integers-factorization.

Here is an approach (using macros) which mimicks simplest form of factorization algorithm.

Package xintexpr is used only in order to allow inputs such as 1e7 or even expressions. It also loads xinttools which is used in the syntax.

Apart from that all operations are done with macros available from xint. As we deal in the example almost only with numbers <2^31 we could employ a variant where all operations would be done using uniquely \numexpr, naturally that would be quite faster.

The code uses \xintiiDivision which computes simultaneously quotient and remainder. This is why \xintAssign is used to store them into two macros \A and \B. The code examines if \B vanishes to detect the divisibility by a Q=P^2.

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}

\makeatletter
\def\Rsqrt@ {%
\def\Nroot {1}%
% we will always have original N = \Nrad times \Nroot^2
% first we check powers of 2
\def\P{2}%
\def\Q{4}% \Q is always square of \P
\xintloop
% try to divide \Nrad by 4. If possible, multiply \Nroot by 2
\xintiiifZero{\B}
\edef\Nroot{\xintiiMul{\Nroot}{\P}}%
\iftrue}
{\iffalse}%
\repeat
% try to divide \Nrad by 9=3^2, then by 25=5^2, etc...
% unfortunately we divide by all odd integers, but only odd prime
% integers would be really needed
\def\P{3}%
\xintloop
\edef\Q{\xintiiSqr{\P}}%
{\iffalse}%
{\xintloop
\xintiiifZero{\B}
\edef\Nroot{\xintiiMul{\P}{\Nroot}}%
\iftrue}
{\iffalse}%
\repeat
\iftrue
}%
\repeat
% at this stage \N = \Nrad times \Nroot^2
\xintiiifOne{\Nroot}{}{\Nroot}%
}%

\newcommand* \Rsqrt[1]{%
\begingroup
\edef\N{\xinttheiexpr #1\relax}%
\xintiiifSgn \N
{\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
{0}
{\xintiiifOne \N{1}{\Rsqrt@}}
\endgroup
}

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing
% \begin{multicols}{4}
% \xintFor* #1 in {\xintSeq {10000}{10100}}\do
%        {$\sqrt{#1}=\Rsqrt{#1}$\par}
% \end{multicols}

% $\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}, \Rsqrt{1e21}$

\pdfsetrandomseed 123456789

\begin{multicols}{3}
\xintiloop [1+1]
\edef\Z {\xinttheiiexpr
(\pdfuniformdeviate 1000)^2
*\pdfuniformdeviate 1000\relax }%
$\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<50
\repeat
\end{multicols}

\end{document}


## Second approach (same algorithm as in OP, expandable implementation)

With the original algorithm. Here we define \ExtractRadical which expandably returns A,B with N=A^2 B. A non-expandable wrapper re-cycles \Rsqrt from faster approach above to produce A\sqrt{B}, distinguishing cases of negative N or N=0, 1.

I have added code comments to explain implementation. An earlier version was very lame (see top of answer) and additionally required xintexpr 1.2g which is not the case anymore.

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}

% Aim: given N find largest I such as I^2 divides N.
% Then compute J=N/I^2 and print I\sqrt{J}.

% Algorithm: compute first truncated square root Imax of N.
% With I = Imax try to divide N by I^2, if it does not work
% repeat with I replaced by I-1 and so on.
% As soon as it works the seeked-for I has been found.

% **** Notice: embarrassingly the author of this answer initially continued
% **** the algorithm recursively with N<-N/I^2, which was very stupid, but
% **** explainable from the fact that he had implemented first another (much
% **** faster) algorithm which divided not from the top down, but from the
% **** bottom up.

% The code is far simpler now. And it does not require xintexpr 1.2g anymore,
% earlier versions of xintexpr.sty work, too.

% The iteration over i used Imax..1 syntax which requires Imax
% to be <2^31. Else we could use Imax..[-1]..1, but we don't
% really consider realistic to iterate over 2^31 or more values !

% After an update we use (-Imax)++ syntax; this also requires Imax<2^31.

\xinttheiiexpr
subs(
% we return I, #1//I^2 where I is biggest integer such as I^2 divides #1.
(I, #1//I^2),
% The I is computed via the "seq" here. Theoretically this "seq"
% evaluates as many values as the last list indicates.
% But here we omit all i's such that i^2 does not divide #1
% and as soon as we have found one, we stop here and now by
% "break". We work topdown, at the worst I=1.
% The i=A..B syntax pre-generates all values, which is wasteful
% and limited to about at most 5000 values.
%       I=seq((#1/:i^2)?{omit}{break(i)}, i=sqrt(#1)..1)
% On the contrary the N++ syntax does not pre-generate anything.
I=seq((#1/:i^2)?{omit}{break(-i)}, i=-sqrt(#1)++)
% There is currently no "n--" only "n++", thus we tricked with a minus sign.
)
\relax
}

\makeatletter

\def\Rsqrt@ {\expandafter\Rsqrt@@\romannumeral-0\ExtractRadical\N,}

% The #2#3 trick is to get rid of a space after the comma
% because \ExtractRadical does \xinttheiiexpr which in case
% of comma separated values on output always inserts such a space.
% Naturally as the typesetting is in math mode the space is
% not a real problem (it is not a problem either in \xintiiifOne
% as here its argument is already expanded anyhow).
\def\Rsqrt@@ #1,#2#3,{\xintiiifOne{#1}{}{#1}\xintiiifOne{#2#3}{}{\sqrt{#2#3}}}

\newcommand* \Rsqrt[1]{%
\begingroup
\edef\N{\xinttheiexpr #1\relax}%
\xintiiifSgn \N
{\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
{0}
{\xintiiifOne \N{1}{\Rsqrt@}}
\endgroup
}

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing

\begin{multicols}{4}
\xintFor* #1 in {\xintSeq {10000}{10099}}\do
{$\sqrt{#1}=\Rsqrt{#1}$\par}
\end{multicols}

% $\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}$%,

% this one does not work because 10^10.5 > 2^31 causes an arithmetic
% overflow in the "sqrt(J)..1" part.
% It would not overflow with "sqrt(J)..[-1]..1"
% but then we can wait long time ...
% from 31622776601 downto
%      10000000000 that's a lot of iterations !
%$\Rsqrt{1e21}$
% The update uses n++ syntax, but this also requires abs(n) to be <2^31
% hence the same remark applies: a "Number too big" error is generated.
% Better actually than to wait the completion of 21622776601 iterations ;-)

% \stop

\pdfsetrandomseed 123456789

% we try with smaller numbers... 1000 replaced by 100...
\begin{multicols}{3}
\xintiloop [1+1]
\edef\Z {\xinttheiiexpr
(\pdfuniformdeviate 100)^2
*\pdfuniformdeviate 100\relax }%
$\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<51
\repeat
\end{multicols}

\end{document}


## Third approach: again the faster algorithm, but expandably.

It would be more reasonable to code this à la \numexpr but well. Details in the code comment. The example has now 51 random examples, and funny enough the missing one (from first approach) turned out to be a random square (with the random seed to pdftex random number generator set at 123456789).

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}[2016/03/19]%
% needs xintexpr 1.2g due to
%  - changed meaning of iter
%  - shift by 1 in [L][n] syntax

% syntax \ExtractRadical {N or <integer expression>} expands to "A, B" with
% N=A^2 B, B square-free
% Algorithm:
% main variable a triple (P, I, J) where
%  - always N = I^2 J
%  - J's prime factors < P have multiplicity one.
% START: (2, 1, N)
% ITER:  (P, I, J)
% Q=P^2
% is Q > J ?
%   - yes: STOP(I, J)
%   - no:
%         does Q divide J ?
%         - yes: I<-I*P, J<-J/Q and repeat until Q does not divide J
%         - no; continue with (P+2, I, J). Except if P=2 then we go
%                      on with P=3.
% Also works with N=0 (produces 1, 0) and with N=1 (produces 1, 1)
%

\xinttheiiexpr
iter (2, 1, #1; % starting triple P=2, I=1, J=N
subs(subs(subs(subs(
% apart from Q=P^2, these substitutions are mainly because [@][n] syntax
% is cumbersome; and inefficient as it allows n to be itself a complicated
% expression, hence does some rather unneeded parsing here of n= 0, 1, 2.
% We really need some better syntax like iter(P=2, I=1, J=#1;...) and then
% work with P, I, J standing for the last values.
% Or at least something like subs(..., (Q, P, I, J)=(...)).
% (not yet with xintexpr 1.2g).
(Q>J)?
{break(I, J)}
{(J/:Q)?
{(n)?{P+2}{3}, I, J}
% must use parentheses here: ([@][1]). Else ]/: will confuse parser.
% I could have used again subs, but well.
{iter(P*I,J//Q;(([@][1])/:Q)?{break((n)?{P+2}{3},@)}
{(P*[@][0],([@][1])//Q)},e=1++)
}
}
, Q=P^2), P=[@][0]), I=[@][1]), J=[@][2]), n=0++)
\relax
}

\makeatletter

\def\Rsqrt@@ #1,#2,{\xintiiifOne{#1}{}{#1}\xintiiifOne{#2}{}{\sqrt{#2}}}

\newcommand* \Rsqrt[1]{%
\begingroup
\edef\N{\xinttheiexpr #1\relax}%
\xintiiifSgn \N
{\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
{0}
{\xintiiifOne \N{1}{\Rsqrt@}}
\endgroup
}

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing

% \xintFor* #1 in {\xintSeq {0}{50}}\do

% \stop

% $\Rsqrt{5000}$

% \stop

% \begin{multicols}{4}
% \xintFor* #1 in {\xintSeq {10000}{10099}}\do
%        {$\sqrt{#1}=\Rsqrt{#1}$\par}
% \end{multicols}

$\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}, \Rsqrt {1e21}$%,

\pdfsetrandomseed 123456789

\begin{multicols}{3}
\xintiloop [1+1]
\edef\Z {\xinttheiiexpr
(\pdfuniformdeviate 1000)^2
*\pdfuniformdeviate 1000\relax }%
$\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<51
\repeat
\end{multicols}

\end{document}


-
I presented the above algorithm because i need the implementation for a single document, so the speed is not really an issue. However, if one was to write the command to redistribute it through a package, a more efficient algorithm would naturally be needed. Anyway, great answer! – koralakralj Mar 21 at 13:23
@user414064 it is possible to implement the original algorithm using a syntax a bit alike the one in Mico's answer, but using traditional pdftex engine. I didn't do it because I have changed the relevant xintexpr.sty syntax very recently. But will add it. – jfbu Mar 21 at 13:26
Although all the answers are great, i ended up using this approach, since i'm already using the package xintexpr in my document. – koralakralj Mar 21 at 17:34
In 1. and 3., criterion Q^2>J is sub-optimal, we possibly should test Q^2>K where K would be J freed from all prime divisors P found on the way. In the current implementation, J keeps a copy of each P with an odd exponent in original N. – jfbu Mar 21 at 20:47
@user414064 thanks for the tick and apologies because in my implementation of the algorithm from your question, I initially did some completely un-needed recursion. I feel like hitting my head fifty times against the wall to reset my brain ;-) Updated code in "approach 2" is now much much simpler. – jfbu Mar 22 at 9:15

Here's a LuaLaTeX-based solution. The code sets up a LaTeX macro named \rsqrt, which invokes a Lua function named Rsqrt. The latter implements the simplification algorithm you've proposed -- with the following exceptions:

• For n=0 or n=1, the code simply returns n (without a square root symbol), and

• Care is taken to omit the \sqrt{n/i²} term if it's equal to 1, i.e., if n is a square number (4, 9, 16, etc).

No input sanity checking is performed, i.e., the user is responsible for providing an argument to \rsqrt that is either a non-negative integer or represents a non-negative integer. Thus, it's ok to write \rsqrt{1e6} and \rsqrt{3.6e7}: the macro will return 1000 and 6000, respectively.

% !TEX TS-program = lualatex
\documentclass{article}

%% Lua-side code
\usepackage{luacode}
\begin{luacode}
function Rsqrt ( n )
n = tonumber ( n )
if n == 0 or n == 1 then   -- Nothing to do
return ( tex.sprint ( n ) )
else
i = math.floor ( math.sqrt ( n ) )
while i > 1 do
if ( n % i^2 == 0 ) then
k = n / i^2
if k == 1 then  -- "n" is a square number
return ( tex.sprint ( tostring(i) ) )
else
return ( tex.sprint ( tostring(i) .. "\\sqrt{" .. k .. "}" ) )
end
end
i = i-1
end
-- No simplification is possible
return ( tex.sprint ("\\sqrt{" .. n .. "}" ) )
end
end
\end{luacode}

%% TeX-side code: "wrapper" macro that invokes the Lua function defined above
\newcommand\rsqrt[1]{\directlua{Rsqrt(\luastring{#1})}}

\begin{document}
\renewcommand\arraystretch{1.25}
$\begin{array}{rcc} \texttt{n} & \texttt{\string\sqrt} & \texttt{\string\rsqrt} \\ 0 & \sqrt{0} & \rsqrt{0} \\ 1 & \sqrt{1} & \rsqrt{1} \\ 2 & \sqrt{2} & \rsqrt{2} \\ 3 & \sqrt{3} & \rsqrt{3} \\ 4 & \sqrt{4} & \rsqrt{4} \\ 5 & \sqrt{5} & \rsqrt{5} \\ 7 & \sqrt{7} & \rsqrt{7} \\ 12 & \sqrt{12} & \rsqrt{12} \\ 16 & \sqrt{16} & \rsqrt{16} \\ 18 & \sqrt{18} & \rsqrt{18} \\ 27 & \sqrt{27} & \rsqrt{27} \\ 32 & \sqrt{32} & \rsqrt{32} \\ \end{array}$
\end{document}

-
I think this will output 2\sqrt{8} for \sqrt{32} instead of 4\sqrt{2}. – Michael Anderson Mar 21 at 5:35
@MichaelAnderson - Did you run the code? For sure, I get 4\sqrt{2} on my system. – Mico Mar 21 at 5:39
Nope, just reading the code, and missed that it counts down rather than up. Sorry. – Michael Anderson Mar 21 at 6:01
Aside: The seventh upvote on this answer pushed my rep point count above the 150K mark. Many thanks to all up-voters!! – Mico Mar 21 at 8:17
Congrats Mico :) – cmhughes Mar 21 at 13:04

In expl3:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\rsqrt}{m}
{
\manual_rsqrt:n { #1 }
}

\int_new:N \l_manual_rsqrt_int

\cs_new_protected:Nn \manual_rsqrt:n
{
\int_set:Nn \l_manual_rsqrt_int { \fp_to_decimal:n { trunc(sqrt(#1),0) } }
\bool_until_do:nn
{
\int_compare_p:n { \int_mod:nn { #1 } { \l_manual_rsqrt_int * \l_manual_rsqrt_int } == 0 }
}
{
\int_decr:N \l_manual_rsqrt_int
}
\int_compare:nTF { \l_manual_rsqrt_int == 1 }
{
\sqrt{#1}
}
{
\int_to_arabic:n { \l_manual_rsqrt_int }
\int_compare:nF { #1 == \l_manual_rsqrt_int*\l_manual_rsqrt_int }
{
\sqrt{ \int_to_arabic:n { #1/(\l_manual_rsqrt_int*\l_manual_rsqrt_int) } }
}
}
}
\ExplSyntaxOff

\begin{document}

$\rsqrt{4}$

$\rsqrt{8}$

$\rsqrt{18}$

$\rsqrt{12}$

$\rsqrt{7}$

\end{document}


If you want to deal with arguments 0 and 1 and also with negative arguments, you can change the main definition into

\NewDocumentCommand{\rsqrt}{m}
{
\int_compare:nTF { #1 < 0 }
{
\int_compare:nTF { #1 = -1 } { i } { \manual_rsqrt:n { -#1 } i }
}
{
\int_compare:nTF { #1 < 2 } { #1 } { \manual_rsqrt:n { #1 } }
}
}


Now the input

$\rsqrt{0}$ and $\rsqrt{1}$

$\rsqrt{-1}$ and $\rsqrt{-4}$ and $\rsqrt{-32}$


would output

-
For n=1 and n=0, the code produces \sqrt{1} (somewhat ugly; nicer: 1) and an Arithmetic overflow warning message, respectively. OK, so maybe 0 isn't a true integer... :-) – Mico Mar 21 at 6:04
@Mico Dealing with these two cases is left as an exercise 😉 – egreg Mar 21 at 8:59
it should be better to write 2i\sqrt{2} for readability reasons. – Tarass Mar 21 at 12:08
@Tarass Another exercise for the reader. – egreg Mar 21 at 12:48
@egreg by the way,\sqrt{-4} has no sens as it has to be a positive value, 2i isn't, nor -2i. – Tarass Mar 21 at 18:37

And here is an example how to do this using only classical TeX:

\newcount\numA \newcount\numB  \newcount\numC  \newcount\numD

\def\rsqrt#1{\numA=2 \numC=#1 \rsqrtA}
\def\rsqrtA{%
\numB=\numA \multiply\numB by\numA
\ifnum\numB>\numC \sqrt{\the\numC}\else
\divisibleCbyB\iftrue \the\numA
\divide\numC by\numB
\ifnum\numC>1 \cdot \rsqrtA \fi
\else
\expandafter\expandafter\expandafter\rsqrtA
\fi\fi
}
\def\divisibleCbyB#1{\numD=\numC \divide\numD by\numB \multiply\numD by\numB
\ifnum\numD=\numC
}

$\sqrt{32} = \rsqrt{32}, \quad \sqrt{79755174} = \rsqrt{79755174}$

\bye

-
+1. :-) I don't think, though, that the OP was asking for the square numbers being factored out of the square root expression to be decomposed further into products of primes. – Mico Mar 21 at 12:56

If you're not averse to jumping outside of LaTeX, here's a solution using the pythontex package. I called it sroot for simple root. Obviously, you can call it anything you want. This version requires a

pdflatex *filename*.tex, pythontex filename*.tex, pdflatex *filename*.tex execution sequence for your document.

\documentclass{article}
\usepackage{pythontex}
\begin{document}
\newcommand{\sroot}[1]{\ensuremath{\py{simpleroot(#1)}}}
\begin{pycode}
from math import *
def simpleroot(n):
if n==0:
return(str(0))
j=int(sqrt(n))
flag_continue=True
while flag_continue:
b=n*1./(j*j)
if b==int(b):
mystring=str(j)+'\\sqrt{'+str(int(b)) +'}'
flag_continue=False
else:
j-=1

if int(b)==1:
mystring=str(j)
if int(b)==n and b>1:
mystring='\\sqrt{'+str(int(b)) +'}'

return(mystring)
\end{pycode}

This is a test.

The $\sqrt{1}$ is \sroot{1}.

The $\sqrt{4}$ is \sroot{4}.

The $\sqrt{7}$ is \sroot{7}.

The $\sqrt{8}$ is \sroot{8}.

The $\sqrt{18}$ is \sroot{18}.

The $\sqrt{23}$ is \sroot{23}.

The $\sqrt{27}$ is \sroot{27}.

The $\sqrt{32}$ is \sroot{32}.

The $\sqrt{64}$ is \sroot{64}.

The $\sqrt{80}$ is \sroot{80}.

The $\sqrt{1000}$ is \sroot{1000}.

The $\sqrt{3000033}$ is \sroot{3000033}.

Goodbye.
\end{document}

-
I didn't know about pythontex. Coming from a python background that's good to hear. Thanks – koralakralj Mar 22 at 9:42
Alas... xintexpr will lose about its sole user ;-) ! – jfbu Mar 22 at 21:45
Does pythontex work with MiKTeX for someone who's not very good with Windows command line? – dejongbrent Mar 23 at 1:28
pythontex should be a package in MiKTeX (I haven't tried it--using TeXLive, but it should be in MiKTeX, too). I use the TeXstudio editor and have set up a user command which runs pythontex %.tex. That executes a script which compiles and executes the python items. I let TeXstudio compile, then execute the user command, then recompile and view the pdf. The MiKTeX installation should set the path for LaTeX, and your Python installation should have it set for running the script. – Bill N Mar 23 at 1:57