---
id: creating-new-operators
title: Creating new PlanOut operators
layout: docs
permalink: /docs/creating-new-operators.html
next: creating-random-operators.html
prev: extending-logging.html
---

This page explains the anatomy of the operator class and shows you how to
create new operators for use with the PlanOut interpreter.

## PlanOutOp
New PlanOut operators are created by subclassing `PlanOutOp`
(located in `ops/base.py), ` or one of its child classes (described beloow).
One initialized, all operator objects have an instance variable,
`self.args` that is populated with
the keyword arguments of the operator object when it is first constructed.
Developers extending `PlanOutOp` implement the `execute()` method, which
does computations with the `self.args` input data, and returns an output
value (typically a scalar but sometimes an array).

As the PlanOut interpreter traverses serialized PlanOut code (nested dictionaries),
it checks each dictionary to see if it contains an `op` key, which identifies
the dictionary is an operator. This name is the same as the
operator name to class dispatch, located in `utils.ops.Operators.initFactory()`.
The `initFactory()` method contains a dictionary mapping operator
names (as read by the PlanOut interpreter) to classes.

Developers also specify required and optional parameters through the
`options()` method, which is used to check the correctness of PlanOut code.
The function returns a dictionary whose keys are variable names, and values
are dictionaries specifying whether the variables are required, and a description
of the variable. This data may be used to automatically construct graphical
interfaces for assembling experiments.

Let's consider one such operator, `get`, which retrieves the value of
a given given variable `var` from the PlanOut execution environment:

```python
class Get(PlanOutOp):
  def options(self):
    return {'var': {'required': 1, 'description': 'variable to get'}}

  def execute(self, mapper):
    return mapper.get(self.args['var'])
```

Here, we can see that the operator has one required argument: `var`. Execution
occurs by implementing the `execute()` method, which reads data from `self.args`,
and optionally the `mapper` object, and returns a value.
The mapper object contains variables from the PlanOut execution environment.
In this case, the `var` argument from `self.args` is used to extract a variable
from the PlanOut mapper.

## SimpleOp
The `execute()` method from `PlanOutOp` requires that the developer manually
evaluate code input arguments as needed.
This allows developers to implement operators like 'or',
'and', and 'cond' (ifelse). But in many cases, we just want to use already-evaluated
arguments. This can be accomplished by sublassing `SimpleOp` instead of `PlanOutOp`,
and implementing the `simpleExecute()` method which reads already evaluated arguments
from the dictionary, `self.parameters`.

For example, array indexing is implemented as follows:

```python
class Index(PlanOutOpSimple):
  def simpleExecute(self):
      return self.parameters['base'][self.parameters['index']]
```


## Standardized operator types
Other base operator classes include those for creating
unary operators, binary operators, and "commutative" operators.
These operators subclass `PlanOutOpSimple` and use
standard naming conventions.

### PlanOutOpUnary
Unary ops have one required argument, 'value', which gets passed into the
`unaryExecute()` method.

Here is how 'Not' (!) is implemented:

```python
class Not(PlanOutOpUnary):
  def unaryExecute(self, value):
      return not value
```


### PlanOutOpBinary
Binary operators have two required arguments, 'left' and 'right'.
Here is how Equals is implemented:

```python
class Equals(PlanOutOpBinary):
  def binaryExecute(self, left, right):
    return left == right
```

### PlanOutOpCommutative
Commutative operators have a single parameter called `values`. Note that these
operators need not be commutative, they just take a single array as an argument.

```python
class Min(PlanOutOpCommutative):
  def commutativeExecute(self, values):
      return min(values)
```
