From 07f2972f1fa45eb29cb3137180cb8ae961cf906f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Thu, 22 Oct 2020 13:57:13 +0200 Subject: [PATCH 01/14] Modify tox.yaml --- .github/workflows/tox.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml index 34df42a..d613785 100644 --- a/.github/workflows/tox.yaml +++ b/.github/workflows/tox.yaml @@ -1,10 +1,10 @@ -name: Merge master, run tests and build docu +name: Merge main, run tests and build docu on: push: - branches: [master] + branches: [main, develop] pull_request: - branches: [master] + branches: [main] jobs: build: @@ -14,10 +14,10 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Merge master into current branch + - name: Merge main into current branch run: | - git fetch origin master:master --update-head-ok - git merge master + git fetch origin main:main --update-head-ok + git merge main - name: Setup Python 3.8 uses: actions/setup-python@v1 with: From 0bac2bbb7a12e0a1b869b352b0ac879d968afaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Thu, 22 Oct 2020 14:15:49 +0200 Subject: [PATCH 02/14] Add code line for test of workflow --- scripts/test_run.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_run.py b/scripts/test_run.py index 0899e03..a4ee5e5 100644 --- a/scripts/test_run.py +++ b/scripts/test_run.py @@ -3,6 +3,8 @@ from hmirls.operators import SamplingMatrixOperator from hmirls.problem import Problem +# Simple example + u = np.array([1.0, 10.0, -2.0, 0.1]).reshape((-1, 1)) v = np.array([1.0, 2.0, 3.0, 4.0]).reshape((-1, 1)) X = np.matmul(u, v.transpose()) From f0225825a67093ea2f8470782cc241e1c089f771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Fri, 23 Oct 2020 13:22:53 +0200 Subject: [PATCH 03/14] Add github token to tox.yaml --- .github/workflows/tox.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml index d613785..a4f662d 100644 --- a/.github/workflows/tox.yaml +++ b/.github/workflows/tox.yaml @@ -18,6 +18,8 @@ jobs: run: | git fetch origin main:main --update-head-ok git merge main + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Python 3.8 uses: actions/setup-python@v1 with: From 545898e819959678a8655cabeb505ee0947f3a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Fri, 23 Oct 2020 13:23:31 +0200 Subject: [PATCH 04/14] Extend docu for FixedRankSpectralShiftRegularizationRule --- src/hmirls/regularization.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/hmirls/regularization.py b/src/hmirls/regularization.py index c2bbd30..f76056f 100644 --- a/src/hmirls/regularization.py +++ b/src/hmirls/regularization.py @@ -24,7 +24,7 @@ def compute_regularized_inverse_weights( :param x: array of shape :math:`(d_1, d_2)` :param schatten_p_parameter: - :return: :math:`\\left(R_1(xx^{\\star})^{\\frac{2-p}{2}}, R_2(x^{\\star}x)^{\\frac{2-p}{2}} \\right)` + :return: :math:`R_1(xx^{\\star})^{\\frac{2-p}{2}}, R_2(x^{\\star}x)^{\\frac{2-p}{2}}` """ pass @@ -53,6 +53,28 @@ def shift_parameter(self): def compute_regularized_inverse_weights( self, x: np.ndarray, schatten_p_parameter: np.float64 ): + """ + Regularization via spectral shift + + .. math:: + + R_1 : \\mathbb{C}^{d_1 \\times d_1} \\rightarrow \\mathbb{C}^{d_1 \\times d_1}, x \\mapsto xx^{\\star}+\\varepsilon \cdot Id_{d_1}, + + R_2 : \\mathbb{C}^{d_2 \\times d_2} \\rightarrow \\mathbb{C}^{d_2 \\times d_2}, x \\mapsto x^{\\star}x +\\varepsilon \cdot Id_{d_2}. + + Spectral shift :math:`\\varepsilon` is given by + + .. math:: + + \\varepsilon = \\min(\\max(\\sigma_{\\text{rank_estimate}}(x), \\text{minimal_shift}), \\text{shift_parameter}), + + where :math:`\sigma_{\\text{rank_estimate}}(x)` is the rank_estimate-th singular value of x. + + :param x: array of shape :math:`(d_1, d_2)` + :param schatten_p_parameter: + :return: :math:`\\left(xx^{\\star}+\\varepsilon \cdot Id_{d_1}\\right)^{\\frac{2-p}{2}}, \\left(x^{\\star}x +\\varepsilon \cdot Id_{d_2}\\right)^{\\frac{2-p}{2}}` + """ + u, s, v = self._svd_engine.svd(x) min_non_zero_dim = min(u.shape[0], v.shape[0]) regularized_singular_values = self._compute_regularized_singular_values( From 16b8056038a752800901a539079749d7f25e58a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Fri, 23 Oct 2020 13:26:09 +0200 Subject: [PATCH 05/14] Update tox.yaml --- .github/workflows/tox.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml index a4f662d..a4cfc67 100644 --- a/.github/workflows/tox.yaml +++ b/.github/workflows/tox.yaml @@ -14,12 +14,11 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 + repo-token: ${{ secrets.GIT_TOKEN }} - name: Merge main into current branch run: | git fetch origin main:main --update-head-ok git merge main - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Python 3.8 uses: actions/setup-python@v1 with: From 3bec92d9b006fbf16f1c93bb446f2a755dccd4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Fri, 23 Oct 2020 14:04:13 +0200 Subject: [PATCH 06/14] Update tox.yaml --- .github/workflows/tox.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml index a4cfc67..a0069f3 100644 --- a/.github/workflows/tox.yaml +++ b/.github/workflows/tox.yaml @@ -14,10 +14,9 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - repo-token: ${{ secrets.GIT_TOKEN }} - name: Merge main into current branch run: | - git fetch origin main:main --update-head-ok + git fetch https://schroedk:${{secrets.GITHUB_TOKEN}}@github.com/schroedk/hmirls.git main:main --update-head-ok git merge main - name: Setup Python 3.8 uses: actions/setup-python@v1 From fa51274081bf1922801c2796cb5b5a646abe6017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:22:57 +0100 Subject: [PATCH 07/14] Add simple example script --- scripts/{test_run.py => simple_example.py} | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) rename scripts/{test_run.py => simple_example.py} (77%) diff --git a/scripts/test_run.py b/scripts/simple_example.py similarity index 77% rename from scripts/test_run.py rename to scripts/simple_example.py index a4ee5e5..21e880e 100644 --- a/scripts/test_run.py +++ b/scripts/simple_example.py @@ -3,7 +3,15 @@ from hmirls.operators import SamplingMatrixOperator from hmirls.problem import Problem -# Simple example +""" +Simple example for recovering a low-rank matrix via minimization + + .. math:: + + \\min_{x \\in \\mathbb{C}^{d_1 \\times d_2}} \\operatorname{rank}(x), \\text{s.t.} \\Phi(x) = y, + + +""" u = np.array([1.0, 10.0, -2.0, 0.1]).reshape((-1, 1)) v = np.array([1.0, 2.0, 3.0, 4.0]).reshape((-1, 1)) From 70b33b24cbd5b90eeca13233cdc5ed43e6b0236d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:23:11 +0100 Subject: [PATCH 08/14] Modify tox.yaml --- .github/workflows/tox.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tox.yaml b/.github/workflows/tox.yaml index a0069f3..cc689e1 100644 --- a/.github/workflows/tox.yaml +++ b/.github/workflows/tox.yaml @@ -1,8 +1,8 @@ -name: Merge main, run tests and build docu +name: Run tests and build docu on: push: - branches: [main, develop] + branches: [main] pull_request: branches: [main] @@ -14,10 +14,6 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Merge main into current branch - run: | - git fetch https://schroedk:${{secrets.GITHUB_TOKEN}}@github.com/schroedk/hmirls.git main:main --update-head-ok - git merge main - name: Setup Python 3.8 uses: actions/setup-python@v1 with: From 62e38969eda17e5edba51b386cf7b521ead1af5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:23:37 +0100 Subject: [PATCH 09/14] Update Readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5158536..c36f720 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This repository contains python code to implement a basic variant of the Harmoni > Available online: https://jmlr.org/papers/volume19/17-244/17-244.pdf ## Version history -* Version 0.0.1, 10/21/2020 +* Version 0.0.1, 10/25/2020 ## Author -Kristof Schröder +Kristof Schröder \ No newline at end of file From 841cf035e47acecbc673df7c5df7d5c590120a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:23:48 +0100 Subject: [PATCH 10/14] Modify conf.py --- docs/conf.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4ac2194..afe6f74 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,8 +27,19 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.linkcode', 'sphinx_rtd_theme'] +extensions = ['sphinx.ext.napoleon', + 'sphinx.ext.doctest', 'sphinx.ext.intersphinx','sphinx.ext.linkcode', 'sphinx_rtd_theme', 'sphinx.ext.autodoc', 'sphinx.ext.autodoc.typehints' + ] +autodoc_typehints = 'description' + +intersphinx_mapping = { + 'numpy': ('https://numpy.org/doc/stable/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), +} + +napoleon_use_param = True +typehints_fully_qualified = True # adding links to source files # see https://www.sphinx-doc.org/en/master/usage/extensions/linkcode.html#module-sphinx.ext.linkcode @@ -40,7 +51,8 @@ def linkcode_resolve(domain, info): path, linkExtension = getPathAndLinkExtension(info['module']) objectName = info['fullname'] - if "." in objectName: # don't add source link to methods within classes (we might want to change that in the future) + # don't add source link to methods within classes (we might want to change that in the future) + if "." in objectName: return None lineno = findLineFromObjectName(path, objectName) @@ -67,7 +79,8 @@ def getPathAndLinkExtension(module: str): linkExtension = f"src/{filename}/__init__.py" return os.path.join(sourcePathPrefix, "__init__.py"), linkExtension else: - raise Exception(f"{sourcePathPrefix} is neither a module nor a package with init - did you fortet to add an __init__.py?") + raise Exception( + f"{sourcePathPrefix} is neither a module nor a package with init - did you fortet to add an __init__.py?") def findLineFromObjectName(sourceFile, objectName): @@ -81,6 +94,7 @@ def findLineFromObjectName(sourceFile, objectName): else: return desiredNode.lineno + autodoc_default_options = { 'exclude-members': 'log, DuplicateColumnNamesException', 'member-order': 'bysource', From 33282099b03ed9bf36fc2e7d59824049481bc2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:24:03 +0100 Subject: [PATCH 11/14] Modify docs requirements --- docs/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 5576e19..22c489e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ numpy -scipy \ No newline at end of file +scipy +sphinx_rtd_theme \ No newline at end of file From 94ad81d22a0ef0274ab5a15450f3e05b07a08693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:24:41 +0100 Subject: [PATCH 12/14] Improve docu for operator classes --- src/hmirls/operators.py | 116 +++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/src/hmirls/operators.py b/src/hmirls/operators.py index b3c1be1..9017e64 100644 --- a/src/hmirls/operators.py +++ b/src/hmirls/operators.py @@ -1,8 +1,8 @@ from enum import Enum -from typing import Tuple, List, Union, Callable +from typing import Tuple, List, Union, Callable, Optional import numpy as np from scipy.sparse import csr_matrix, kron, eye -from scipy.sparse.linalg import LinearOperator as ScipyLinearOperator, aslinearoperator +from scipy.sparse.linalg import LinearOperator, aslinearoperator class MatrixOperatorCompatibility: @@ -64,26 +64,42 @@ def _same_indexing_order( class MatrixOperator: class IndexingOrder(Enum): + """ + Enum for order argument for :func:`numpy.reshape` and :func:`numpy.flatten` + """ ROW_MAJOR = "C" COLUMN_MAJOR = "F" def __init__( self, - flattened_operator: Union[ScipyLinearOperator, np.ndarray, csr_matrix], + flattened_operator: Union[LinearOperator, np.ndarray, csr_matrix], input_shape: Tuple[int, int], output_shape: Tuple[int, int], - representing_matrix: Union[np.ndarray, csr_matrix] = None, - order=IndexingOrder, + order: IndexingOrder, + representing_matrix: Optional[Union[np.ndarray, csr_matrix]] = None, ): """ - # ToDO More detailed description, doc tests - Takes care on flattening and reshaping. - Wraps a scipy linear operator or numpy array. + Represents an operator + + .. math:: + + \\Phi: \\mathbb{C}^{d_1 \\times d_2} \\rightarrow \\mathbb{C}^{m_1 \\times m_2}. + + Takes care on flattening and reshaping. Wraps a scipy linear operator or numpy array. + + :param flattened_operator: Represents the flattened map + + .. math:: + + \\varphi: \\mathbb{C}^{d_1 \\cdot d_2} \\rightarrow \\mathbb{C}^{m_1 \\cdot m_2}, + + such that :math:`\\varphi(\\operatorname{vec}(x)) = \\operatorname{vec}(\\Phi(x))`. + + :param input_shape: :math:`(d_1,d_2)` + :param output_shape: :math:`(m_1,m_2)` + :param order: order for vectorization :math:`\\operatorname{vec}` + :param representing_matrix: matrix representation of flattened operator - :type output_shape: - :param flattened_operator: - :param input_shape: - :param order: """ self._output_shape = output_shape self._input_shape = input_shape @@ -109,8 +125,8 @@ def __add__(self, other: "MatrixOperator"): self._flattened_operator + other._flattened_operator, self._input_shape, self._output_shape, - representing_matrix, self._order, + representing_matrix, ) raise ValueError(f"Operators are not compatible") return NotImplemented @@ -126,11 +142,11 @@ def dot(self, x): Parameters ---------- - x : array_like or MatrixOperator or scalar + x : array_like of shape :math:`(d_1, d_2)` or MatrixOperator compatible for composition or scalar Returns ------- - Ax : array or MatrixOperator that represents + :math:`\\Phi(x)` : array or MatrixOperator that represents the result of applying this linear operator on x. """ @@ -146,18 +162,18 @@ def dot(self, x): ) return MatrixOperator( self.flattened_operator.dot(x.flattened_operator), - input_shape=x.input_shape, - output_shape=self.output_shape, - representing_matrix=representing_matrix, - order=self.order, + x.input_shape, + self.output_shape, + self.order, + representing_matrix, ) elif np.isscalar(x): return MatrixOperator._from_callable(self, lambda op: x * op) else: if x.shape == self.input_shape: - x_flattened = x.flatten(self.order) + x_flattened = x.flatten(order=self.order.value) return self.flattened_operator(x_flattened).reshape( - self.output_shape, order=self.order + self.output_shape, order=self.order.value ) else: raise ValueError( @@ -207,8 +223,8 @@ def _from_callable( cls, matrix_operator: "MatrixOperator", fcn: Callable[ - [Union[ScipyLinearOperator, np.ndarray]], - Union[ScipyLinearOperator, np.ndarray], + [Union[LinearOperator, np.ndarray]], + Union[LinearOperator, np.ndarray], ], ): """ @@ -220,13 +236,12 @@ def _from_callable( representing_matrix = None if matrix_operator.representing_matrix is not None: representing_matrix = fcn(matrix_operator.representing_matrix) - return cls( - fcn(matrix_operator.flattened_operator), - input_shape=matrix_operator.input_shape, - output_shape=matrix_operator.output_shape, - representing_matrix=representing_matrix, - order=matrix_operator.order, - ) + return cls(fcn(matrix_operator.flattened_operator), + matrix_operator.input_shape, + matrix_operator.output_shape, + matrix_operator.order, + representing_matrix, + ) @property def output_shape(self): @@ -257,7 +272,7 @@ def adjoint(self): Returns ------- - A_H : :class:`~MatrixOperator` + :math:`\\Phi^{\\star}` : :class:`~MatrixOperator` Hermitian adjoint of self. """ return self._adjoint() @@ -272,7 +287,7 @@ def transpose(self): Returns ------- - A_T : :class:`~MatrixOperator` + :math:`\\Phi^{\\star}` : :class:`~MatrixOperator` adjoint of self. """ @@ -284,31 +299,22 @@ def _adjoint(self): """Default implementation of _adjoint""" representing_matrix = None if self.representing_matrix is not None: - representing_matrix = self._representing_matrix.H + representing_matrix = self._representing_matrix.conjugate().transpose() return MatrixOperator( self._flattened_operator.H, self._output_shape, self._input_shape, - representing_matrix, self.order, + representing_matrix, ) def _transpose(self): """ Default implementation of _transpose""" - representing_matrix = None - if self.representing_matrix is not None: - representing_matrix = self._representing_matrix.T - return MatrixOperator( - self._flattened_operator.T, - self._output_shape, - self._input_shape, - representing_matrix, - self.order, - ) + return MatrixOperator._from_callable(self, lambda op: op.T) -class SamplingOperator(ScipyLinearOperator): - def __init__(self, indices: List[int], input_dimension: int): +class SamplingOperator(LinearOperator): + def __init__(self, indices: Union[List[int], np.ndarray], input_dimension: int): """ :type input_dimension: @@ -349,11 +355,12 @@ def _construct_sampling_matrix(self): @classmethod def from_matrix_indices( - cls, row_indices: List[int], column_indices: List[int], shape, order="F" + cls, row_indices: List[int], column_indices: List[int], shape: Tuple[int, int], + order: MatrixOperator.IndexingOrder = MatrixOperator.IndexingOrder.COLUMN_MAJOR ): return cls( - np.ravel_multi_index((row_indices, column_indices), shape, order=order), - input_dimension=np.prod(shape), + np.ravel_multi_index((row_indices, column_indices), shape, order=order.value), + input_dimension=np.product(shape), ) @@ -363,17 +370,17 @@ def __init__( row_indices: List[int], column_indices: List[int], shape: Tuple[int, int], - order="F", + order: MatrixOperator.IndexingOrder = MatrixOperator.IndexingOrder.COLUMN_MAJOR, ): flattened_operator = SamplingOperator.from_matrix_indices( row_indices, column_indices, shape, order ) - super(SamplingMatrixOperator, self).__init__( + super().__init__( flattened_operator, shape, (len(row_indices), 1), - flattened_operator.sampling_matrix, order, + flattened_operator.sampling_matrix, ) @@ -401,6 +408,7 @@ def __init__( flattened_operator, shape, shape, - representing_matrix=weight_matrix, - order=order, + order, + weight_matrix, + ) From a63599214aecb3487902571d7836998a26f491b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:25:07 +0100 Subject: [PATCH 13/14] Improve docu for Problem class and fix small bug --- src/hmirls/problem.py | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/hmirls/problem.py b/src/hmirls/problem.py index fdafce9..0ad6fff 100644 --- a/src/hmirls/problem.py +++ b/src/hmirls/problem.py @@ -1,11 +1,10 @@ from abc import ABC, abstractmethod from typing import Union, Tuple -from scipy.sparse.linalg import ( - LinearOperator as scipyLinearOperator, - aslinearoperator, -) +import scipy import numpy as np -from scipy.sparse import eye +from scipy.sparse import eye, csr_matrix +from scipy.sparse.linalg import LinearOperator + from .operators import MatrixOperator, InverseWeightOperator from .regularization import RegularizationRule, FixedRankSpectralShiftRegularizationRule @@ -16,13 +15,26 @@ class StoppingCriteria(ABC): + """ + Abstract base class for iteration stopping criteria + """ @abstractmethod - def satisfied(self, *args, **kwargs) -> bool: + def satisfied(self, previous_iterate: np.ndarray, current_iterate: np.ndarray) -> bool: + """ + Specifies if criteria is satisfied. + :param current_iterate: + :param previous_iterate: + :return: + """ pass class ResidualNormStoppingCriteria(StoppingCriteria): def __init__(self, tol=1e-9): + """ + Stopping criteria based on the relative residual between two iterations is less than a given tolerance + :param tol: tolerance for residual + """ self._tol = tol @property @@ -30,6 +42,17 @@ def tol(self): return self._tol def satisfied(self, previous_iterate: np.ndarray, current_iterate: np.ndarray): + """ + Returns true if + + .. math:: + + \\frac{\\|X_{\\text{prev}} - X_{\\text{curr}}\\||_{F}}{\\|X_{\\text{prev}}\\|_{F}} < tol. + + :param previous_iterate: :math:`X_{\\text{prev}` + :param current_iterate: :math:`X_{\\text{curr}` + :return: + """ return ( np.linalg.norm(previous_iterate - current_iterate) / np.linalg.norm(previous_iterate) @@ -40,12 +63,17 @@ def satisfied(self, previous_iterate: np.ndarray, current_iterate: np.ndarray): class Problem: def __init__( self, - measurement_operator: Union[scipyLinearOperator, np.ndarray, MatrixOperator], + measurement_operator: Union[LinearOperator, np.ndarray, csr_matrix, MatrixOperator], data: np.array, indexing_order: MatrixOperator.IndexingOrder = None, input_shape: Tuple[int, int] = None, ): """ + Description for a rank minimization problem + + .. math:: + + \\min_{x \\in \\mathbb{C}^{d_1 \\times d_2}} \\operatorname{rank}(x), \\text{s.t.} \\Phi(x) = y, :param measurement_operator: @@ -61,7 +89,7 @@ def __init__( f"provide indexing order and input shape" ) measurement_operator = MatrixOperator( - measurement_operator, input_shape, data.shape, order=indexing_order + measurement_operator, input_shape, data.shape, indexing_order ) self.data = data @@ -103,11 +131,11 @@ def _initialize_inverse_weight_matrix_operator(): Initialize inverse weight matrix operator with identity matrix :return: MatrixOperator """ - flattened_input_length = np.prod(self.measurement_operator.input_shape) + flattened_input_length = np.product(self.measurement_operator.input_shape) order = self.measurement_operator.order input_shape = self.measurement_operator.input_shape return MatrixOperator( - aslinearoperator(eye(flattened_input_length)), + scipy.sparse.linalg.aslinearoperator(eye(flattened_input_length)), input_shape, input_shape, representing_matrix=eye(flattened_input_length), From b6488cdd0f7bd0bf2bc0232c6fedcae7505ecafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristof=20Schr=C3=B6der?= Date: Sun, 25 Oct 2020 15:25:26 +0100 Subject: [PATCH 14/14] Improve docu for regularization classes --- src/hmirls/regularization.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hmirls/regularization.py b/src/hmirls/regularization.py index f76056f..205b835 100644 --- a/src/hmirls/regularization.py +++ b/src/hmirls/regularization.py @@ -58,9 +58,9 @@ def compute_regularized_inverse_weights( .. math:: - R_1 : \\mathbb{C}^{d_1 \\times d_1} \\rightarrow \\mathbb{C}^{d_1 \\times d_1}, x \\mapsto xx^{\\star}+\\varepsilon \cdot Id_{d_1}, + R_1 : \\mathbb{C}^{d_1 \\times d_1} \\rightarrow \\mathbb{C}^{d_1 \\times d_1}, x \\mapsto xx^{\\star}+\\varepsilon^2 \cdot Id_{d_1}, - R_2 : \\mathbb{C}^{d_2 \\times d_2} \\rightarrow \\mathbb{C}^{d_2 \\times d_2}, x \\mapsto x^{\\star}x +\\varepsilon \cdot Id_{d_2}. + R_2 : \\mathbb{C}^{d_2 \\times d_2} \\rightarrow \\mathbb{C}^{d_2 \\times d_2}, x \\mapsto x^{\\star}x +\\varepsilon^2 \cdot Id_{d_2}. Spectral shift :math:`\\varepsilon` is given by @@ -68,7 +68,7 @@ def compute_regularized_inverse_weights( \\varepsilon = \\min(\\max(\\sigma_{\\text{rank_estimate}}(x), \\text{minimal_shift}), \\text{shift_parameter}), - where :math:`\sigma_{\\text{rank_estimate}}(x)` is the rank_estimate-th singular value of x. + where :math:`\\sigma_{\\text{rank_estimate}}(x)` is the rank_estimate-th singular value of x. :param x: array of shape :math:`(d_1, d_2)` :param schatten_p_parameter: