From c14f9ea270e1a058308b6bb96929e39c991a97be Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Fri, 18 Oct 2024 09:18:44 +0000 Subject: [PATCH 1/7] First pass at improving documentation for trivial operators --- .../operators/IdentityOperator.py | 10 ++--- .../optimisation/operators/MatrixOperator.py | 44 ++++++++++++++++--- .../optimisation/operators/ZeroOperator.py | 22 ++++++---- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index 22ebd20960..a15f7370c0 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -23,10 +23,10 @@ class IdentityOperator(LinearOperator): - '''IdentityOperator: Id: X -> Y, Id(x) = x\in Y + r''' `IdentityOperator`: :math:`\mathrm{Id}: X \rightarray 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` ) ''' @@ -42,7 +42,7 @@ def __init__(self, domain_geometry, range_geometry=None): def direct(self,x,out=None): - '''Returns Id(x)''' + '''Returns :math:`Id(x)` ''' if out is None: return x.copy() @@ -52,7 +52,7 @@ def direct(self,x,out=None): def adjoint(self,x, out=None): - '''Returns Id(x)''' + '''Returns :math:`\mathrm{Id}(x)=x ` ''' if out is None: diff --git a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py index 6191c2f393..682f62a0db 100644 --- a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py @@ -22,17 +22,17 @@ from cil.optimisation.operators import LinearOperator class MatrixOperator(LinearOperator): - """ Matrix wrapped into a LinearOperator + r""" Matrix wrapped into a LinearOperator - :param: a numpy matrix + Parameters + ---------- + A: a numpy matrix + The matrix to be wrapped into a LinearOperator """ 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) @@ -42,7 +42,20 @@ def __init__(self,A): range_geometry=range_geometry) def direct(self,x, out=None): - + r"""Returns :math:`A*x` + + Parameters + ---------- + x : DataContainer + Input data + out : DataContainer, optional + Output data, default is None + Returns + ------- + DataContainer + :math:`A*x` + """ + if out is None: tmp = self.range_geometry().allocate() tmp.fill(numpy.dot(self.A,x.as_array())) @@ -55,6 +68,21 @@ def direct(self,x, out=None): return out def adjoint(self,x, out=None): + r"""Returns :math:`A^{T}*x` + + Parameters + ---------- + x : DataContainer + Input data + out : DataContainer, optional + Output data, 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())) @@ -64,4 +92,6 @@ def adjoint(self,x, out=None): return out def size(self): + r"""Returns the size of the matrix + """ return self.A.shape diff --git a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py index f6a5463495..c99cc43167 100644 --- a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py @@ -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) > + \langle O(x), y \rangle = \langle x, O^{*}(y) \rangle ''' def __init__(self, domain_geometry, range_geometry=None): if range_geometry is None: @@ -39,7 +45,7 @@ def __init__(self, domain_geometry, range_geometry=None): range_geometry=range_geometry) def direct(self,x,out=None): - '''Returns O(x)''' + r'''Returns :math:`\mathrm{O}(x)`''' if out is None: return self.range_geometry().allocate(value=0) else: @@ -47,7 +53,7 @@ def direct(self,x,out=None): return out def adjoint(self,x, out=None): - '''Returns O^{*}(y)''' + r'''Returns :math:`\mathrm{O}^{*}(y)` ''' if out is None: return self.domain_geometry().allocate(value=0) else: @@ -55,5 +61,5 @@ def adjoint(self,x, out=None): return out def calculate_norm(self, **kwargs): - '''Evaluates operator norm of ZeroOperator''' + r'''Evaluates operator norm of `ZeroOperator`''' return 0 From 1f52c0bab02aa548f68b269a74a269e60a4a4594 Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Fri, 18 Oct 2024 09:36:20 +0000 Subject: [PATCH 2/7] Second attempt --- .../optimisation/operators/IdentityOperator.py | 8 ++++---- .../cil/optimisation/operators/MatrixOperator.py | 15 +++++++-------- .../cil/optimisation/operators/ZeroOperator.py | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index a15f7370c0..062d57db12 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -23,7 +23,7 @@ class IdentityOperator(LinearOperator): - r''' `IdentityOperator`: :math:`\mathrm{Id}: X \rightarray Y`, :math:`\mathrm{Id}(x) = x` + r''' `IdentityOperator`: :math:`\mathrm{Id}: X \rightarrow Y`, :math:`\mathrm{Id}(x) = x` :math:`X` : domain :math:`Y` : range ( Default: :math:`Y = X` ) @@ -42,7 +42,7 @@ def __init__(self, domain_geometry, range_geometry=None): def direct(self,x,out=None): - '''Returns :math:`Id(x)` ''' + r'''Returns :math:`\mathrm{Id}(x)` ''' if out is None: return x.copy() @@ -52,7 +52,7 @@ def direct(self,x,out=None): def adjoint(self,x, out=None): - '''Returns :math:`\mathrm{Id}(x)=x ` ''' + r'''Returns :math:`\mathrm{Id}(x)=x` ''' if out is None: @@ -63,7 +63,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 diff --git a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py index 682f62a0db..60ab1fd779 100644 --- a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py @@ -22,12 +22,12 @@ from cil.optimisation.operators import LinearOperator class MatrixOperator(LinearOperator): - r""" Matrix wrapped into a LinearOperator + r""" Matrix wrapped in a CIL Operator to be used in optimisation algorithms. - Parameters + Parameters ---------- A: a numpy matrix - The matrix to be wrapped into a LinearOperator + The matrix to be wrapped into a CIL Operator """ @@ -37,12 +37,11 @@ def __init__(self,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 :math:`A*x` + r"""Returns :math:`Ax` Parameters ---------- @@ -53,7 +52,7 @@ def direct(self,x, out=None): Returns ------- DataContainer - :math:`A*x` + :math:`Ax` """ if out is None: @@ -68,7 +67,7 @@ def direct(self,x, out=None): return out def adjoint(self,x, out=None): - r"""Returns :math:`A^{T}*x` + r"""Returns :math:`A^{T}x` Parameters ---------- @@ -80,7 +79,7 @@ def adjoint(self,x, out=None): Returns ------- DataContainer - :math:`A^{T}*x` + :math:`A^{T}x` """ if out is None: diff --git a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py index c99cc43167..ee652f11e1 100644 --- a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py @@ -35,7 +35,7 @@ class ZeroOperator(LinearOperator): ----- .. math:: - O^{*}: Y^{*} -> X^{*} \text{(Adjoint)} + 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): From a6784f95064e60997e7a41cd4963a8e88b97552b Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Fri, 18 Oct 2024 09:48:32 +0000 Subject: [PATCH 3/7] Third attempt --- Wrappers/Python/cil/optimisation/operators/IdentityOperator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index 062d57db12..e855cd6ec2 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -85,8 +85,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 From ef28fc289a1c516fd752ba73d6ef52befc112ac2 Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Fri, 18 Oct 2024 10:38:27 +0000 Subject: [PATCH 4/7] 4th attempt --- .../Python/cil/optimisation/operators/IdentityOperator.py | 6 ++++++ .../Python/cil/optimisation/operators/MatrixOperator.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index e855cd6ec2..a92049adf1 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -28,6 +28,12 @@ class IdentityOperator(LinearOperator): :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 ''' diff --git a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py index 60ab1fd779..cbfadf924a 100644 --- a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py @@ -91,6 +91,6 @@ def adjoint(self,x, out=None): return out def size(self): - r"""Returns the size of the matrix + r"""Returns the shape of the matrix """ return self.A.shape From 844c73ce2166e51d39255eebb2a21947e99a0ac4 Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Fri, 18 Oct 2024 15:21:49 +0000 Subject: [PATCH 5/7] Updates from Laura's review --- .../operators/IdentityOperator.py | 33 +++++++++++++++++-- .../optimisation/operators/MatrixOperator.py | 4 +-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index a92049adf1..bd600a677d 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -48,7 +48,21 @@ def __init__(self, domain_geometry, range_geometry=None): def direct(self,x,out=None): - r'''Returns :math:`\mathrm{Id}(x)` ''' + r'''Returns :math:`\mathrm{Id}(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() @@ -57,8 +71,21 @@ def direct(self,x,out=None): return out def adjoint(self,x, out=None): - - r'''Returns :math:`\mathrm{Id}(x)=x` ''' + r'''Returns :math:`\mathrm{Id}^*(x)=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: diff --git a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py index cbfadf924a..93b77e97d9 100644 --- a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py @@ -48,7 +48,7 @@ def direct(self,x, out=None): x : DataContainer Input data out : DataContainer, optional - Output data, default is None + 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 @@ -74,7 +74,7 @@ def adjoint(self,x, out=None): x : DataContainer Input data out : DataContainer, optional - Output data, default is None + 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 ------- From a4f2604dbbaeaf8cc342d400349e56a04dafbd17 Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Mon, 21 Oct 2024 08:05:15 +0000 Subject: [PATCH 6/7] Docstrings for zero operator --- .../optimisation/operators/ZeroOperator.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py index ee652f11e1..3f18cb9af1 100644 --- a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py @@ -45,7 +45,20 @@ def __init__(self, domain_geometry, range_geometry=None): range_geometry=range_geometry) def direct(self,x,out=None): - r'''Returns :math:`\mathrm{O}(x)`''' + r'''Returns :math:`\mathrm{O}(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 + :math:`\mathrm{O}(x)` + ''' if out is None: return self.range_geometry().allocate(value=0) else: @@ -53,7 +66,21 @@ def direct(self,x,out=None): return out def adjoint(self,x, out=None): - r'''Returns :math:`\mathrm{O}^{*}(y)` ''' + r'''Returns :math:`\mathrm{O}^{*}(y)` + + 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: From ad96ba907f64150ee8b1568ada21b0ead337ac27 Mon Sep 17 00:00:00 2001 From: Margaret Duff Date: Tue, 22 Oct 2024 07:40:04 +0000 Subject: [PATCH 7/7] Updates from Hannah's review --- .../Python/cil/optimisation/operators/IdentityOperator.py | 4 ++-- Wrappers/Python/cil/optimisation/operators/MatrixOperator.py | 4 ++-- Wrappers/Python/cil/optimisation/operators/ZeroOperator.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py index bd600a677d..c04977047b 100644 --- a/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/IdentityOperator.py @@ -48,7 +48,7 @@ def __init__(self, domain_geometry, range_geometry=None): def direct(self,x,out=None): - r'''Returns :math:`\mathrm{Id}(x)` + r'''Returns the input data :math:`x` Parameters ---------- @@ -71,7 +71,7 @@ def direct(self,x,out=None): return out def adjoint(self,x, out=None): - r'''Returns :math:`\mathrm{Id}^*(x)=x` + r'''Returns the input data, :math:`x` Parameters ---------- diff --git a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py index 93b77e97d9..9acb7e7785 100644 --- a/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/MatrixOperator.py @@ -41,7 +41,7 @@ def __init__(self,A): range_geometry=range_geometry) def direct(self,x, out=None): - r"""Returns :math:`Ax` + r"""Returns the matrix vector product :math:`Ax` Parameters ---------- @@ -67,7 +67,7 @@ def direct(self,x, out=None): return out def adjoint(self,x, out=None): - r"""Returns :math:`A^{T}x` + r"""Returns the matrix vector product :math:`A^{T}x` Parameters ---------- diff --git a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py index 3f18cb9af1..16602f7bae 100644 --- a/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py +++ b/Wrappers/Python/cil/optimisation/operators/ZeroOperator.py @@ -45,7 +45,7 @@ def __init__(self, domain_geometry, range_geometry=None): range_geometry=range_geometry) def direct(self,x,out=None): - r'''Returns :math:`\mathrm{O}(x)` + r'''Returns an element of the range space filled with zeros Parameters ---------- @@ -66,7 +66,7 @@ def direct(self,x,out=None): return out def adjoint(self,x, out=None): - r'''Returns :math:`\mathrm{O}^{*}(y)` + r'''Returns an element of the domain space filled with zeros Parameters ----------