# Pair of Random Numbers without Common Factors

My goal is to define \avar and \bvar such that they are integers between 1 and 11 inclusively but share no common factors and they should never be equal.

I think that the code I've written should do that, but sometimes it does not and I don't know why.

Is there a fundamentally easier way to do this? Or is there an easy way to fix the code I've got?

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}
\usepackage{multicol}

\pgfmathsetseed{\number\pdfrandomseed}

\newcommand{\InitVariablesDOS}
{%
% This randomly sets \avar to be a whole number between 1 and 10.
% I am using the list format so that when I'm not doing a MWE,
% I can easily weight, say, 7s to come more often.
% Let's say in our example \avar is randomly set to 6....
\pgfmathdeclarerandomlist{avar}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathrandomitem{\avar}{avar}

% If \avar=6 I want \bvar to share no common factors (other than 1) with 6.
% So, \bvar is selected from {DOSIfSix},
% which are whole numbers which do not have the factors 2,3, or 6.
\pgfmathdeclarerandomlist{DOSIfOne}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfTwo}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfThree}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfFour}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfFive}{{1}{2}{3}{4}{6}{7}{8}{9}}
\pgfmathdeclarerandomlist{DOSIfSix}{{1}{5}{7}{11}}
\pgfmathdeclarerandomlist{DOSIfSeven}{{1}{2}{3}{4}{5}{6}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfEight}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfNine}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfTen}{{1}{3}{7}{9}{11}}

\ifcase\avar\relax% This should define \bvar so that it shares no common factors with \avar.
\or \pgfmathrandomitem{\bvar}{DOSIfOne}
\or \pgfmathrandomitem{\bvar}{DOSIfTwo}
\or \pgfmathrandomitem{\bvar}{DOSIfThree}
\or \pgfmathrandomitem{\bvar}{DOSIfFour}
\or \pgfmathrandomitem{\bvar}{DOSIfFive}
\or \pgfmathrandomitem{\bvar}{DOSIfSix}
\or \pgfmathrandomitem{\bvar}{DOSIfSeven}
\or \pgfmathrandomitem{\bvar}{DOSIfEight}
\or \pgfmathrandomitem{\bvar}{DOSIfNine}
\or \pgfmathrandomitem{\bvar}{DOSIfTen}
\fi
\xdef\bvar{\bvar}
}

\newcommand{\avarandbvar}
{%
\InitVariablesDOS
$$avar=\avar$$

$$bvar=\bvar$$

\vspace{0.5cm}
}

\newcommand{\manyavarandbvars}[1]{\foreach \x in {1,...,#1} {\avarandbvar}}

\pagestyle{empty}

\begin{document}
\begin{multicols}{5}
\manyavarandbvars{70}
\end{multicols}
\end{document}


• It is sitting inside a loop, did you try making \avar global too ? Jul 22 '17 at 14:49
• I don't really know what your comment means. I need \avar and \bvar to be generated a whole bunch of times so I can make series of math exercises. Jul 22 '17 at 14:51
• you are declaring \bvar to be global via \xdef. Do the same thing to \avar Jul 22 '17 at 14:54
• Wow, I think that fixed it! But why did that work? ... and what does 'global' really mean? [I copy/pasted \xdef into my code weeks ago due to advice, but I never really knew what it meant/did.] Jul 22 '17 at 14:56
• Euclid's algorithm (en.wikipedia.org/wiki/Euclidean_algorithm) is the usual test for common roots. Jul 22 '17 at 16:12

For comparison, here is a luatex based solution. (I use ConTeXt, but it should be straightforward to translate this to LaTeX as well). To make it more challenging, I generate the list of bvars algorithmically.

I wasn't sure why some lists went until 10, while others went until 11. In the code below, all lists go until 10.

\startluacode
-- Euclid's algorithm for gcd
local gcd = function(m, n)
while m ~= 0 do
m, n = math.mod(n,m), m
end
return n
end

local avars = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local bvars = {}

-- Generate bvars
for i = 1, #avars do
local a = avars[i]
if bvars[a] == nil then
local b = {1}
for j = 2, 10 do
if gcd(a, j) == 1 then
b[#b + 1] = j
end
end
bvars[a] = b
end
end

local random, format = math.random, string.format

local sampleAandB = function()
local i = random(#avars)
local a = avars[i]
local j = random(#bvars[a])
local b = bvars[a][j]

return a, b
end

local avarandombvar = function()
local a, b = sampleAandB()
context.dontleavehmode()
context.framed({"frame=off, align=middle"}, format("avar = %s \\crlf bvar = %s", a, b))
context.blank{"big"}
end

interfaces.definecommand ("avarandombvar", {macro = avarandombvar})

\stopluacode

\starttext

\startcolumns[n=5]
\dorecurse{70}{\avarandombvar}
\stopcolumns

\stoptext


which gives

First the solution for your pronlem:

You need to preserve \avar to keep it from changing. This can be done adding \edef\avar{\avar} after \pgfmathrandomitem{\avar}{avar}.

As a recommendation: you can move the declarations of the random lists into the preamble. This way, they are defined only once and not every time \InitVariablesDOS is used. And you should comment out the line ends of several lines in \InitVariablesDOS. Otherwise they can produce spurios spaces, depending on where the macro is called.

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}
\usepackage{multicol}

\pgfmathsetseed{\number\pdfrandomseed}
\pgfmathdeclarerandomlist{avar}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfOne}{{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfTwo}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfThree}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfFour}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfFive}{{1}{2}{3}{4}{6}{7}{8}{9}}
\pgfmathdeclarerandomlist{DOSIfSix}{{1}{5}{7}{11}}
\pgfmathdeclarerandomlist{DOSIfSeven}{{1}{2}{3}{4}{5}{6}{8}{9}{10}}
\pgfmathdeclarerandomlist{DOSIfEight}{{1}{3}{5}{7}{9}}
\pgfmathdeclarerandomlist{DOSIfNine}{{1}{2}{4}{5}{7}{8}{10}}
\pgfmathdeclarerandomlist{DOSIfTen}{{1}{3}{7}{9}{11}}

\newcommand{\InitVariablesDOS}
{%
\pgfmathrandomitem{\avar}{avar}%
\edef\avar{\avar}%
% to show the problem, uncomment the next line and comment out the previous one
% $$avar=\avar$$

\ifcase\avar\relax% This should define \bvar so that it shares no common factors with \avar.
\or \pgfmathrandomitem{\bvar}{DOSIfOne}%
\or \pgfmathrandomitem{\bvar}{DOSIfTwo}%
\or \pgfmathrandomitem{\bvar}{DOSIfThree}%
\or \pgfmathrandomitem{\bvar}{DOSIfFour}%
\or \pgfmathrandomitem{\bvar}{DOSIfFive}%
\or \pgfmathrandomitem{\bvar}{DOSIfSix}%
\or \pgfmathrandomitem{\bvar}{DOSIfSeven}%
\or \pgfmathrandomitem{\bvar}{DOSIfEight}%
\or \pgfmathrandomitem{\bvar}{DOSIfNine}%
\or \pgfmathrandomitem{\bvar}{DOSIfTen}%
\fi
\edef\bvar{\bvar}%
}

\newcommand{\avarandbvar}
{%
\InitVariablesDOS

$$avar=\avar$$

$$bvar=\bvar$$

\vspace{0.5cm}
}

\newcommand{\manyavarandbvars}[1]{\foreach \x in {1,...,#1} {\avarandbvar}}

\pagestyle{empty}

\begin{document}
\begin{multicols}{5}
\manyavarandbvars{70}
\end{multicols}
\end{document}


Now the reason for the problem:

In this case, it has nothing to do with groups and/or making \avar global. The problem comes from pgf and how it defines a macro with \pgfmathrandomitem. If the latter is called for different macros, e.g.

\pgfmathrandomitem{\avar}{avar}
\pgfmathrandomitem{\bvar}{bvar}


the second call will also change the result of the first. Therefore, the first result has to be preserved with \edef\avar{\avar}.

The details (you may stop reading here):

The macro is simply defined with \def (pgfmathfunctions.random.code.tex, lines 241 and 242):

\pgfmathrandominteger{\pgfmath@randomtemp}{1}{\pgfmath@randomlistlength}%
\def#1{\csname pgfmath@randomlist@#2@\pgfmath@randomtemp\endcsname}}}


As can be seen, the contents of the macro depends on \pgfmath@randomtemp. If it changes, the macro changes too. And this will happen every time \pgfmathrandomitem is called, even if this is done for a different macro from a different list.

Since I can't think of a reason for using \def instead of \edef here, which would prevent this problem, I would consider this a bug.