Skip to content

Commit

Permalink
Trivial operators - improve documentation (#1960)
Browse files Browse the repository at this point in the history
  • Loading branch information
MargaretDuff authored Oct 22, 2024
1 parent 662bad3 commit 23187c9
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 24 deletions.
49 changes: 42 additions & 7 deletions Wrappers/Python/cil/optimisation/operators/IdentityOperator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@

class IdentityOperator(LinearOperator):

'''IdentityOperator: Id: X -> Y, Id(x) = x\in Y
r''' `IdentityOperator`: :math:`\mathrm{Id}: X \rightarrow Y`, :math:`\mathrm{Id}(x) = x`
X : gm_domain
Y : gm_range ( Default: Y = X )
:math:`X` : domain
:math:`Y` : range ( Default: :math:`Y = X` )
Parameters
----------
domain_geometry: CIL Geometry
domain of the operator
range_geometry: CIL Geometry, optional
range of the operator, default: same as domain
'''


Expand All @@ -42,7 +48,21 @@ def __init__(self, domain_geometry, range_geometry=None):

def direct(self,x,out=None):

'''Returns Id(x)'''
r'''Returns the input data :math:`x`
Parameters
----------
x : DataContainer or BlockDataContainer
Input data
out : DataContainer or BlockDataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer or BlockDataContainer
:math:`\mathrm{Id}(x) = x`
'''

if out is None:
return x.copy()
Expand All @@ -51,8 +71,21 @@ def direct(self,x,out=None):
return out

def adjoint(self,x, out=None):

'''Returns Id(x)'''
r'''Returns the input data, :math:`x`
Parameters
----------
x : DataContainer or BlockDataContainer
Input data
out : DataContainer or BlockDataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer or BlockDataContainer
:math:`\mathrm{Id}^*(x)=x`
'''


if out is None:
Expand All @@ -63,7 +96,7 @@ def adjoint(self,x, out=None):

def calculate_norm(self, **kwargs):

'''Evaluates operator norm of IdentityOperator'''
'''Evaluates operator norm of `IdentityOperator`'''

return 1.0

Expand All @@ -85,8 +118,10 @@ def sum_abs_col(self):

def is_orthogonal(self):
'''Returns if the operator is orthogonal
Returns
-------
`Bool`
Always returns `True` for `IdentityOperator`
'''
return True
45 changes: 37 additions & 8 deletions Wrappers/Python/cil/optimisation/operators/MatrixOperator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,39 @@
from cil.optimisation.operators import LinearOperator

class MatrixOperator(LinearOperator):
""" Matrix wrapped into a LinearOperator
r""" Matrix wrapped in a CIL Operator to be used in optimisation algorithms.
:param: a numpy matrix
Parameters
----------
A: a numpy matrix
The matrix to be wrapped into a CIL Operator
"""

def __init__(self,A):
'''creator
:param A: numpy ndarray representing a matrix
'''
"""Constructor"""
self.A = A
M_A, N_A = self.A.shape
domain_geometry = VectorGeometry(N_A, dtype=A.dtype)
range_geometry = VectorGeometry(M_A, dtype=A.dtype)
self.s1 = None # Largest singular value, initially unknown
super(MatrixOperator, self).__init__(domain_geometry=domain_geometry,
range_geometry=range_geometry)

def direct(self,x, out=None):

r"""Returns the matrix vector product :math:`Ax`
Parameters
----------
x : DataContainer
Input data
out : DataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer
:math:`Ax`
"""

if out is None:
tmp = self.range_geometry().allocate()
tmp.fill(numpy.dot(self.A,x.as_array()))
Expand All @@ -55,6 +67,21 @@ def direct(self,x, out=None):
return out

def adjoint(self,x, out=None):
r"""Returns the matrix vector product :math:`A^{T}x`
Parameters
----------
x : DataContainer
Input data
out : DataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer
:math:`A^{T}x`
"""

if out is None:
tmp = self.domain_geometry().allocate()
tmp.fill(numpy.dot(self.A.transpose().conjugate(),x.as_array()))
Expand All @@ -64,4 +91,6 @@ def adjoint(self,x, out=None):
return out

def size(self):
r"""Returns the shape of the matrix
"""
return self.A.shape
51 changes: 42 additions & 9 deletions Wrappers/Python/cil/optimisation/operators/ZeroOperator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@
from cil.optimisation.operators import LinearOperator

class ZeroOperator(LinearOperator):
r'''ZeroOperator: O: X -> Y, maps any element of :math:`x\in X` into the zero element :math:`\in Y, O(x) = O_{Y}`
r''' `ZeroOperator`: :math:`\mathrm{O}: X \rightarrow Y`, maps any element of :math:`x\in X` into the zero element in the space :math:`Y`, so :math:`\mathrm{O}(x) = \mathrm{O}_{Y}`.
:param gm_domain: domain of the operator
:param gm_range: range of the operator, default: same as domain
Parameters
----------
domain_geometry: CIL Geometry
domain of the operator
range_geometry: CIL Geometry, optional
range of the operator, default: same as domain
Note:
Note
-----
.. math::
O^{*}: Y^{*} -> X^{*} \text{(Adjoint)}
< O(x), y > = < x, O^{*}(y) >
O^{*}: Y^{*} -> X^{*} \text{(Adjoint)} \quad \text{such that} \quad
\langle O(x), y \rangle = \langle x, O^{*}(y) \rangle
'''
def __init__(self, domain_geometry, range_geometry=None):
if range_geometry is None:
Expand All @@ -39,21 +45,48 @@ def __init__(self, domain_geometry, range_geometry=None):
range_geometry=range_geometry)

def direct(self,x,out=None):
'''Returns O(x)'''
r'''Returns an element of the range space filled with zeros
Parameters
----------
x : DataContainer or BlockDataContainer
Input data
out : DataContainer or BlockDataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer
:math:`\mathrm{O}(x)`
'''
if out is None:
return self.range_geometry().allocate(value=0)
else:
out.fill(self.range_geometry().allocate(value=0))
return out

def adjoint(self,x, out=None):
'''Returns O^{*}(y)'''
r'''Returns an element of the domain space filled with zeros
Parameters
----------
x : DataContainer or BlockDataContainer
Input data
out : DataContainer or BlockDataContainer, optional
If out is not None the output of the Operator will be filled in out, otherwise a new object is instantiated and returned. The default is None.
Returns
-------
DataContainer
:math:`\mathrm{O}^{*}(y)`
'''
if out is None:
return self.domain_geometry().allocate(value=0)
else:
out.fill(self.domain_geometry().allocate(value=0))
return out

def calculate_norm(self, **kwargs):
'''Evaluates operator norm of ZeroOperator'''
r'''Evaluates operator norm of `ZeroOperator`'''
return 0

0 comments on commit 23187c9

Please sign in to comment.