STACK Documentation

Documentation home | Category index | Site map

Random objects

STACK can generate structured random objects. STACK provides a Maxima function rand() which can be used in the question and answer variables.

Note: it is important not to use Maxima's own random() function. STACK creates pseudo-random numbers from a definite seed. This ensures that when a particular student returns they see the same variant of the question. Hence, STACK provides its own function rand().

For the purposes of learning and teaching, we do not need an algorithm which is statistically perfect. We are much more interested in simplicity, efficiency and reproducibility across platforms. Hence, we adopt a linear recurrence method of generating pseudo-random numbers.

rand()

  • rand(n) generates an integer between \(0\) and \(n-1\).
  • rand(n.0) generates a floating point number between \(0\) and \(n\). It is probably more useful to use something like a=float(rand(1000)/1000) to obtain an accurate number of decimal places. An alternative is to use the Maxima function round()
  • rand([a,b,...,z]) makes a random selection from a list.
  • rand(matrix(..)) applies rand to each element of the matrix.

It is probably much better not to use conditional statements when creating random objects. For example, if you would like to create a random small prime number, try

p : rand([2,3,5,7,11,13,17,19]);

This might not appear to be the neatest mathematical solution, but it is probably the most reliable. Usually we need to combine rand() with some code to generate objects. For example, if you want a matrix with integer elements in the range -5..5 you need something like

A:matrix([5,5],[5,5])-rand(matrix([11,11],[11,11]));

There are also Maxima's random functions. For example, to create a random list use random_permutation.

rand_with_step(lower,upper,step)

Returns a random number from the set {lower, lower+step, lower+2*step, ... , final}. The examples below explain behaviour the best. Examples:

  • rand_with_step(-5,5,1) returns a random number from the set \(\{-5,-4,-3,-2,-1,0,1,2,3,4,5\}\).
  • rand_with_step(-5,5,2) returns a random number from the set \(\{-5,-3,-1,1,3,5\}\).
  • rand_with_step(-5,3,3) returns a random number from the set \(\{-5,-2,1\}\).

The function rand_range(lower,upper,step) does the same thing.

rand_with_prohib(lower,upper,list)

Returns a random integer from the set [lower,upper] such that it cannot be any value in list. This list can include values which are also random variables, for example, generated by rand_with_step. Examples:

  • rand_with_prohib(-5,5,[0]) returns a random number from the set \(\{-5,-4,-3,-2,-1,1,2,3,4,5\}\).
  • rand_with_prohib(-5,5,[-1,0,1,sqrt(pi)]) returns a random number from the set \(\{-5,-4,-3,-2,2,3,4,5\}\).
  • rand_with_prohib(-5,3,[-5/2,a]) returns a random number from the set \(\{-5,-4,-3,-2,-1,0,1,2,3\}\backslash\{a\}\).

This can be used with matrices, to generate a matrix with non-zero entries for example. The unnamed function in this example ignores its arguments.

matrixmap(lambda([ex],rand_with_prohib(-5,5,[0])),zeromatrix(5,5));

rand_selection(ex, n)

Returns a list containing a random selection of n different items from the list ex. If ex contains duplicates, then the result may also contain duplicates.

Generating random polynomials

Here is an example which generates a random polynomial, of degree 5, with coefficients between 0 and 6.

apply("+",makelist(rand(7)*x^(k-1),k,6));

Generating random expressions which needs to be "gathered and sorted"

It is relatively common to want to be able to generate random expressions which need to be "gathered and sorted". For example in \(2y-y+3y+1\) we need to collect together the \(y\) terms.

simp:false;
p:apply("+",makelist(ev(rand_with_prohib(-5,5,[0])*y^rand(2),simp), ev(rand(6)+2,simp)));
p:unary_minus_sort(p);

Now, the output from the first expression will be a random expression in constants and \(y\) variables. The second line tidies up the unary minus. For more details of this, see simplification.

4*y+5*y+(-2*y)
4*y+5*y-2*y

Random objects with corresponding information

It is often necessary to generate a random object with a number of separate aspects to it. For example, if you have scientific data and you need to include this in a question.

t:rand(5)+3;
idx:rand(3)+1;  /* Array indexes in Maxima start at 1, rand(n) returns 0,...,n-1.  */
l1:["Mercury","Earth","Mars"];
l2:[3.61,9.8,3.75];
p:l1[idx];
ta:t*l2[idx]/(4*%pi^2);

The question text can then be

A pendulum is located on {@p@}. What length should the pendulum have in order to have a period of {@t@}s?

This indexing with the variable idx is quite robust. Note that indexes in Maxima start at \(1\), whereas rand(n) could return zero.

Random objects satisfying a condition

It is often necessary to create random objects which satisfy constraints. For example, if you want to randomly generate a "small" prime number, just select one from a list.

p:rand([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);

It is much better to (i) enumerate specific cases or (ii) reverse engineer the question to avoid conditional statements than randomly generate examples and "hope" one pops up eventually. The reason is that the pseudo-random number generator will repeat the process from a seed every time the question is generated! If you put in loops, this could risk delays and time-outs etc.

The following is NOT RECOMMENDED, but enough people have insisted on doing it to document this approach.

If you must (and you risk an infinite loop of course....) you can use Maxima's for command. A simple example is as follows.

q:1;
for k while not(is(primep(q))) do block(q:rand(98)+1);

See also

Maxima reference topics


Documentation home | Category index | Site map