10

I would like to generate a simple macro to make \x either 1 or -1. But I'm not sure how to do that.

I set up the code below, but I believe it randomly chooses between -1, 0, and 1.

What adjustment do I have to make to make it choose between only -1 and 1?

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}

\pgfmathsetseed{\number\pdfrandomseed}

\begin{document}

\pgfmathsetmacro{\x}{int(random(-1,1))}

\x

\end{document}
5
  • 1
    And more generally, how would I randomly assign\x a value from a fixed and arbitrary set of constants? Nov 12, 2016 at 1:41
  • Yes. I'd like each number in the set to be equally likely. Nov 12, 2016 at 4:44
  • I posted code to do exactly that to one of your questions the other day:-) Nov 12, 2016 at 9:07
  • You mention picking values from "a fixed and arbitrary set of constants" -- what kinds of constants do you have in mind? Numbers, one-dimensional string constants, multi-dimensional structures? Please clarify your objective(s).
    – Mico
    Nov 13, 2016 at 0:04
  • Just a set of numbers. Nov 13, 2016 at 5:37

6 Answers 6

12

There is a PGF math function to choose randomly from a list of items. This can be used to solve the general problem:

\documentclass{article}
\usepackage{pgffor}
\begin{document}
\pgfmathdeclarerandomlist{ones}{{-1}{1}}
\foreach \x in {1,...,10}{
\pgfmathrandomitem{\choice}{ones}
\choice\space
}

\pgfmathdeclarerandomlist{choices}{{1}{0}{-1}{2}{-2}}
\foreach\x in {1,...,10}{
\pgfmathrandomitem{\choice}{choices}
\choice\space
}
\end{document}

output of code

0
11

Here's a LuaLaTeX-based solution. It outputs the result of \x in math mode; if you don't need that, just remove the two $ symbols used in the definition of \x. (In case you're curious how this works: The Lua function math.random(2) generates the numbers 1 and 2 with equal probability. Multiplying math.random(2) by 2 and subtracting 3 thus generates the numbers -1 and 1 with equal probability.)

enter image description here

\documentclass{article}
\newcommand\x{$\directlua{tex.sprint(2*math.random(2)-3)}$}
\begin{document}
\x, \x, \x, \x, \x; \x, \x, \x, \x, \x; \x, \x, \x, \x, \x  
\end{document}

You further asked,

How would I randomly assign \x a value from a fixed and arbitrary set of constants?

I will assume that these constants can be either numbers or strings. It's straightforward to generalize the Lua-based approach shown above to handle this case. First, use a \luaexec directive to set up a Lua table -- not to be confused with a LaTeX table! -- that contains N constants -- basically, an Nx1 list of comma-separated numbers and strings; in the code below, N=5. (It is possible to have LaTeX macros among the string constants. Do observe, though, that it's necessary to "escape" backslash (\) characters, i.e., to input them as \\.) Second, set up a LaTeX macro -- named \x, as before -- that picks off 1 of the N entries using a math.random(N) call.

enter image description here

\documentclass{article}
\usepackage{luacode} % for "\luaexec" macro

% Define a Lua table that contains N (fairly) arbitrary entries
\luaexec{N = 5 ;
         mylist = {5, 
                   "abc", 
                   "DEF", 
                   "$\\Gamma$", 
                   "$\\frac{\\pi^2}{\\int_0^1\\!f(x)\\,dx}$" 
         } }

% Define a LaTeX macro that selects one of the N entries at random
\newcommand\x{\directlua{tex.sprint(mylist[math.random(N)])}}

\begin{document}
\obeylines % just for this example
\x, \x, \x, \x, \x
\x, \x, \x, \x, \x
\x, \x, \x, \x, \x  
\end{document}
2
  • A bunch of people have mentioned LuaLaTeX to me recently. Do you think it's worth learning? Nov 15, 2016 at 17:59
  • @WeCanLearnAnything - It really depends on your programming skills. I happen to find Lua, which is derived from C, fairly easy to master, and LuaTeX provides some very handy interfaces for Lua and TeX to interact. To be sure, LaTeX3 (which is still being developed) offers all kinds of neat programming "goodies" as well. However, speaking for myself, I find the C-based programming paradigm far more straightforward to master than the macro expansion paradigm of TeX/LaTeX/LaTeX3. Of course, your mileage may vary!
    – Mico
    Nov 15, 2016 at 18:42
10

The apparent choice from -1,0, and 1 is due to a bug and random shouldn't be used with negative arguments as given in \pgfmathparse returns a phantom .0.0

Instead you can use the macro in the designated domain and then shift/scale.

simplest is perhaps

\pgfmathsetmacro{\x}{int(2*random(0,1)-1)}
1
  • 1
    Great hack! I will definitely use this when I only need to choose form -1 and 1. Nov 15, 2016 at 17:59
8

This doesn't answer the general question, but it will get you 1 or -1.

rnd returns a number between 0 and 1. If rnd is above 0.5 the ifthenelse returns 1, else it returns -1.

\documentclass{article}
\usepackage{pgf}
\pgfmathsetseed{\number\pdfrandomseed}
\pgfmathsetmacro{\x}{int(ifthenelse(rnd>0.5,1,-1))}
\begin{document}
\x
\end{document}
1
6

Table of contents:

  • initial answer about randomly choosing 1 or -1,

  • first addendum about using package xinttools to more generally choose expandably among braced items. For general principle of a more efficient -- if doing many times -- package free but non expandable approach see the comments,

  • second addendum for the case of numerical values only will pick up(again expandably) randomly in a comma separated list using xintexpr.


initial answer

You are using anyhow pdftex named random-related utilities (\pdfrandomseed). Simplest (and probably fastest) is just

\documentclass{article}
%\usepackage{pgf}
%\pgfmathsetseed{\number\pdfrandomseed}% not needed here
\makeatletter
\def\plusorminusone{\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1}
\makeatother
\begin{document}
\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\plusorminusone

\end{document}

enter image description here

(the code uses \tw@, \z@ --- hence the \makeatletter --- in a silly idea that it may be slightly faster than 2 and 0 and to not have to worry about leaving a space token to properly terminate them (here, the 0 only)) In certain contexts you may prefer the variant

\ifnum\pdfuniformdeviate\tw@>\z@\expandafter-\fi 1

or perhaps

\the\numexpr\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1\relax

Also, you may be used to \pgfmathparse type of syntax, then maybe something like this

\makeatletter
\def\plusorminusoneset #1{\edef#1{\ifnum\pdfuniformdeviate\tw@>\z@-\fi 1}}
\makeatother
\plusorminusoneset\x

\x

\plusorminusoneset\x

\x

but this looks very cumbersome to use.


first addendum

To choose expandably randomly from a (not pre-defined) list, you can use \xintNthElt from package xinttools.

\documentclass{article}

\usepackage{xinttools}
\newcommand\myrandomelement [1]% this comment character isn't needed but pretty
  {\xintNthElt{1+\pdfuniformdeviate \xintNthElt{0}{#1}}{#1}}

\begin{document}


\myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement
{ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF},
\myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement
{ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}, \myrandomelement {ABCDEF}

\end{document}

enter image description here

Use braces if needed: \myrandomelement {{ABC}{$1$}{\par}}.

Remarks:

  • the code is expandable

  • the code will recompute the total number of elements each time, thus in contexts where this information is stable, it might be better to have a macro with two arguments whose second argument will be the already known number of elements,

  • we need to shift by one, because elements are numbered starting at one, (the 0 is used to get the number of elements...)

  • xinttools has some inner macros which handle rather comma separated lists and count starting at zero not at one; but they are private... well, ok, let's be open, the macros to be used are \xintCSVNthEltPy and \xintCSVLength. The source code contains these comments:

    We don't take any precaution here regarding brace stripping or spaces. And the macros are short. They will remain undocumented in the user manual for the time being for the reasons above and to preserve the possibility to modify the interface in case some evolution on the xintexpr side requires it. Nevertheless, directly usable names are also provided.

  • you can still handle comma separated values by using \xintCSVtoList.

  • the list argument may be a macro it does not have to be explicit like in my example.


second addendum

When handling numerical values you can do this using the list syntax provided by the xintexpr expressions.

\documentclass{article}

\usepackage{xintexpr}

\begin{document}

\xintdeffloatvar Pi := 3.1415926535897932;

\xintdeffloatvar e :=  2.7182818284590452;

\xintthefloatexpr \empty [sqrt(3), Pi, e][\pdfuniformdeviate 3]\relax

\xintthefloatexpr ([sqrt(3), Pi, e][\pdfuniformdeviate 3])\relax

\xintthefloatexpr [4]
   subs(seq(([S, Pi, e][\pdfuniformdeviate 3]), i=1..10), S = sqrt(3))\relax

\end{document}

Some comments:

  • the \empty is because \xintthefloatexpr may admit an optional argument, like the [4] in the last example which means to round the output to 4 digits of precision; the \empty serves to calm down the (expandable) parser, as the brackets are used for something altogether different next,

  • in the second example, parentheses are used instead,

  • in the third example we want to do it ten times, but not redo the evaluation of square root of three ten times; hence we use the mechanism of substitution; the comma which separates the expression from the assigned variable must not be confused with earlier commas. Here a seq(uence) construct hides the earlier commas, however we need to put parentheses around the list extractor, because seq has an iteration variable (here i) and the comma before the i must not be mixed-up with an earlier one. I think braces may be used too, but that would need a check in the manual.

enter image description here

It is possible to code the last example this way:

\xintthefloatexpr [4]
   subs(seq([L][\pdfuniformdeviate 3], i=1..10), L = sqrt(3), Pi, e)\relax

which has the advantage to not need extra parentheses.

enter image description here

5
  • and we could use \csname ...\endcsname with predefined macros expanding to <empty>, -, or to 1 resp. -1, or to +1 resp. -1 rather than an \ifnum. I should, but never tested if there is efficiency difference.
    – user4686
    Nov 12, 2016 at 14:56
  • +1. How might your approach be generalized to address the OP's follow-up question, viz., "more generally, how would I randomly assign \x a value from a fixed and arbitrary set of constants?"
    – Mico
    Nov 12, 2016 at 15:08
  • 1
    @Mico it depends if the set of constants is pre-defined. In that case I would e.g. define via \@namedef{constant<number>} the macros holding the contants, with <number> starting at 0. Then you can do \@nameuse{constant\pdfuniformdeviate<N>} where <N> is the total number of constants (which may be a count or explicit, anyhow it is terminated by the \endcsname) If the set of constants is arbitrary and presented on the spot, then it depends how, it depends if you want to maintain expandability etc... (the above is expandable by construction).
    – user4686
    Nov 12, 2016 at 15:13
  • 1
    I would also do \let\namedef\@namedef, \let\nameuse\@nameuse somewhere in the preamble if the above is to be used straightforwardly in document, not inside macros.
    – user4686
    Nov 12, 2016 at 15:17
  • Wow, lots to digest here. I will take a closer look tonight. Nov 15, 2016 at 18:00
5

With pdflatex or lualatex (not xelatex, unfortunately). The argument to \randomelement is a list of items that need to be braced if they consist of more than one token.

Note that this is fully expandable, so

\edef\foo{\randomelement{ABCDEF}}

would work. Here's the code:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

% we need an interface to a primitive
\cs_new:Nn \egreg_uniformdeviate:n
 {
  \pdftex_uniformdeviate:D \int_eval:n { #1 }
 }

\DeclareExpandableDocumentCommand{\randomelement}{m}
 {
  \tl_item:nn { #1 } { \egreg_uniformdeviate:n { \tl_count:n { #1 } } + 1 }
 }

\ExplSyntaxOff

\begin{document}

\randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}}
\randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}}
\randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}} \randomelement{{$-1$}{$1$}}

\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}
\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}
\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}
\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}
\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}
\randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF} \randomelement{ABCDEF}

\end{document}

enter image description here

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.