Maxima: define a function that returns a random integer in a range, such that the value is distinct from another value or a list of other values

Viewed 332

N.B. the question in the title is addressed in the "Edit: Larger Problem" section, below


Is there a function that will return the type of a variable, in Maxima?

I'm not sure if type is the correct word (I'm very new to this but get the impression it may have a specific technical sense), what I'm looking for is a function that can return true or false if a variable x is a number or an array, e.g. if x : 6;

IsArray(x) = false
IsNumber(x) = true

or, e.g. if y : [1,2,3];

IsArray(y) = true;
IsNumber(y) = false;

I've tried searching the Maxima documentation but haven't been able to find anything. Any help would be appreciated.


Edit: Larger Problem.

I wrote a function that will return a random value y from a range, while ensuring that y is distinct from another value b:

DistinctValue(x,y,LowerLim,UpperLim):= block(
                  [newY:y], 
                  if x = newY 
                  then newY:DistinctValue(x,rand_range(LowerLim,UpperLim),LowerLim,UpperLim) 
                  else newY:y, return(newY));

where rand_range(LowerLim,UpperLim) is another custom function that chooses a random integer LowerLim ≤ x ≤ UpperLim.

It didn't take long for me to realize that sometimes I will need several such distinct values, so I tweaked the above code so that it can take an array as argument:

DistinctValue(x,y,LowerLim,UpperLim):= block([newY:y], 
    for i:1 thru length(x)
    do  if x[i] = newY
         then newY:DistinctValue(x,rand_range(LowerLim,UpperLim),LowerLim,UpperLim), 
    return(newY));

While I know the latter can be used for cases where there is a single number to exclude from the range, simply by placing it in square brackets, I was hoping to learn to write a function that could take x as either a number or an array. I figured the easiest way to do this would be to use an if / else statement that evaluated the type of variable x is, e.g.

DistinctValue(x,y,LowerLim,UpperLim):= block([newY:y], 
/* if it's a list, run the list version of the function */
 if IsList(x) 
 then
    for i:1 thru length(x)
    do  if x[i] = newY
         then  newY : DistinctValue(x, rand_range(LowerLim,UpperLim), LowerLim, UpperLim)
/* otherwise run the number version of the function */
 else  
      if x = newY 
      then newY : DistinctValue(x, rand_range(LowerLim,UpperLim), LowerLim,UpperLim) 
      else newY:y,, 
    return(newY));

While this may seem superfluous, we're implementing Maxima in another, fairly complicated environment, and it'll be used by folks who have even less experience than I. Moreover, I expect to encounter other cases where it will be more of a necessity, than an option, in the near future.

1 Answers

About the function DistinctValue, here's how I would implement a function which returns a random value from a range which is distinct from a single value or from all of a list of values.

DistinctValue(x, LowerLim, UpperLim) :=
    if listp(x)
        then block([y: rand_range(LowerLim, UpperLim)],
                    if member(y, x) /* need to try again */
                        then DistinctValue(x, LowerLim, UpperLim)
                        else y)
        else DistinctValue([x], LowerLim, UpperLim);

This is somewhat different from what's shown above; that might mean I've misunderstood the requirements. I'll let you be the judge of that.

rand_range can be expressed as just

rand_range(LowerLim, UpperLim) := LowerLim + random(UpperLim - LowerLim + 1);

The UpperLim - LowerLim + 1 assures that UpperLim can be returned, otherwise the maximum random value from rand_range is UpperLim minus 1, assuming LowerLim and UpperLim are integers.

EDIT: Seems to work -- here I've already load(descriptive); to get discrete_freq.

(%i32) makelist (DistinctValue ([13, 15, 17], 12, 18), 100);
(%o32) [18, 18, 14, 16, 18, 16, 12, 12, 18, 18, 12, 14, 12, 12, 
18, 18, 14, 12, 12, 14, 16, 18, 12, 16, 12, 16, 14, 18, 16, 12, 
14, 16, 14, 16, 16, 12, 14, 18, 14, 14, 14, 12, 16, 18, 14, 18, 
18, 14, 14, 18, 12, 16, 18, 12, 16, 16, 12, 14, 16, 18, 16, 14, 
16, 12, 16, 12, 14, 18, 16, 14, 12, 18, 14, 12, 16, 18, 12, 12, 
14, 14, 18, 16, 18, 14, 14, 18, 16, 14, 12, 12, 14, 12, 18, 18, 
12, 18, 12, 18, 18, 18]
(%i33) discrete_freq (%);
(%o33)        [[12, 14, 16, 18], [26, 25, 21, 28]]
Related