Operators¶
Operators in ODL are represented by the abstract Operator
class. As an abstract class, it cannot be used directly but must be
subclassed for concrete implementation. To define your own operator,
you start by writing:
class MyOperator(odl.Operator):
    ...
Operator has a couple of abstract methods which need to
be explicitly overridden by any subclass, namely
- domain:- Set
- Set of elements to which the operator can be applied 
- range- Set
- Set in which the operator takes values 
As a simple example, you can implement the matrix multiplication operator

for a matrix  as follows:
 as follows:
class MatrixOperator(odl.Operator):
    def __init__(self, matrix):
        self.matrix = matrix
        dom = odl.rn(matrix.shape[1])
        ran = odl.rn(matrix.shape[0])
        super(MatrixOperator, self).__init__(dom, ran)
In addition, an Operator needs at least one way of
evaluation, in-place or out-of-place.
In place evaluation¶
In-place evaluation means that the operator is evaluated on a
Operator.domain element, and the result is written to an
already existing Operator.range element. To implement
this behavior, create the (private) Operator._call
method with the following signature, here given for the above
example:
class MatrixOperator(odl.Operator):
    ...
    def _call(self, x, out):
        self.matrix.dot(x, out=out.asarray())
In-place evaluation is usually more efficient and should be used whenever possible.
Out-of-place evaluation¶
Out-of-place evaluation means that the operator is evaluated on a domain element, and
the result is written to a newly allocated range element. To implement this
behavior, use the following signature for Operator._call (again given for the above example):
class MatrixOperator(odl.Operator):
    ...
    def _call(self, x):
        return self.matrix.dot(x)
Out-of-place evaluation is usually less efficient since it requires allocation of an array and a full copy and should be generally avoided.
Important: Do not call these methods directly. Use the call pattern
operator(x) or operator(x, out=y), e.g.:
matrix = np.array([[1, 0],
                   [0, 1],
                   [1, 1]])
operator = MatrixOperator(matrix)
x = odl.rn(2).one()
y = odl.rn(3).element()
# Out-of-place evaluation
y = operator(x)
# In-place evaluation
operator(x, out=y)
This public calling interface is (duck-)type-checked, so the private methods can safely assume that their input data is of the operator domain element type.
Operator arithmetic¶
It is common in applications to perform arithmetic with operators, for example the addition of matrices
![[A+B]x = Ax + Bx](../_images/math/ebd6a58595abf6705b05708ea5cd1b65f1bcab27.png)
or multiplication of a functional by a scalar
 = \alpha x^* (x)](../_images/math/2a081d4a46e91d44355815bf4065524745012a1a.png)
Another example is matrix multiplication, which corresponds to operator composition
 = A(Bx)](../_images/math/f36ea7611eb4e6b3b5befd2e4e500c28c5e510cf.png)
All available operator arithmetic is shown below. A, B represent arbitrary Operator's,
f is an Operator whose Operator.range is a Field (sometimes called a functional), and
a is a scalar.
| Code | Meaning | Class | 
|---|---|---|
| 
 | 
 | |
| 
 | 
 | |
| 
 | 
 | |
| 
 | 
 | |
| 
 | 
 | |
| 
 | 
 | |
| 
 | 
 | |
| not available | 
 | 
There are also a few derived expressions using the above:
| Code | Meaning | 
|---|---|
| 
 | 
 | 
| 
 | 
 | 
| 
 | 
 | 
| 
 | 
 | 
| 
 | 
 | 
| 
 | 
 | 
Except for composition, operator arithmetic is generally only defined when Operator.domain and
Operator.range are either instances of LinearSpace or Field.