# Creating random assignment operators

New random operators can be created by extending the `PlanOutOpRandom`

class,
and implementing a `simpleExecute()`

and `options()`

method.
This class is the workhorse of PlanOut’s random assignment capabilities.
Random assignments are done primarily through two built-in helper methods that come with `PlanOutOpRandom`

:

`getHash()`

gets a random integer between`0`

and a very large number (`0xFFFFFFFFFFFFFFF`

), inclusive. Many random assignment procedures will mod the integer returned by this method to perform some type of random assignment.`getUniform()`

gets a floating point number between some range of values. This number should be uniform across the specified minimum and maximum value (default values are 0.0 and 1.0).

Hashes and numbers generated by these methods use the experiment-level,
variable-level, and unit-level salts, as described in the
How PlanOut Works guide.
They may also take optional argument, `appended_unit`

, which can
either be a scalar (e.g., integer or string) or list value
(consisting of scalars). This appended unit may be used to generate
multiple independent random numbers.

## Examples

We use examples to show how implementing random operators works in practice.

### UniformChoice

UniformChoice picks an element from a given input list by generating a random integer and modding it by the appropriate range.

```
class UniformChoice(PlanOutOpRandom):
def options(self):
return {'choices': {'required': 1, 'description': 'elements to draw from'}}
def simpleExecute(self):
choices = self.args.get('choices')
if len(choices) == 0:
return []
rand_index = self.getHash() % len(choices)
return choices[rand_index]
```

Here, we can see that the operator has one required argument, `choices`

. The `simpleExecute()`

method grabs this input parameter from `self.parameters`

, and then generates a random index by calling `self.getHash()`

.

### RandomFloat

RandomFloat generates a random floating point number between two values.

```
class RandomFloat(PlanOutOpRandom):
def options(self):
return {
'min': {'required': 0, 'description': 'min (float) value drawn'},
'max': {'required': 0, 'description': 'max (float) value being drawn'}}
def simpleExecute(self):
min_val = self.args.get('min', 0)
max_val = self.args.get('max', 1)
return self.getUniform(min_val, max_val)
```

`RandomFloat`

takes two optional parameters, ‘min’ and ‘max’, which it passes into `self.getUniform`

to generate a uniform random number.

### Generating normally distributed numbers

So far we have only looked at examples where random assignment is done by generating a single random number. Many operations, however, involve drawing multiple random numbers. For example, normally distributed numbers can be generated in a pseudo-random fashion using two independent uniformly distributed random numbers:

```
class Normal(PlanOutOpRandom):
def options(self):
return {
'mean': {'required': 1, 'description': 'mean value drawn'},
'sd': {'required': 1, 'description': 'standard deviation of normal'}}
def options():
def simpleEvaluate():
mean = self.args.get('mean')
sd = self.args.get('sd')
# Use the Box-Muller transform to generate a normal from two
# independent draws from a Uniform[0,1] distribution
# see http://en.wikipedia.org/wiki/Box-Muller_transform
theta = 2.0 * math.pi * self.getUniform(0.0, 1.0, 'theta')
rho = sqrt(-2.0 * log(1.0 - self.getUniform(0.0, 1.0, 'rho')))
return mean + sd * rho * math.cos(theta)
```

In the code above, we use the optional appended_unit parameter (the third parameter to `getUniform()`

) to make multiple draws from the uniform distribution to generate a normally distributed floating point number, using the Box-Muller transform.