Skip to content

Commit

Permalink
Package restructuring and naming (#223)
Browse files Browse the repository at this point in the history
* moved linops up in the namespace

* isort

* imports unified

* tests moved to correct dir and changed name back to linops

* renamed back to linops

* doctest problems fixed

* refactored aslinop into own file

* pylint fix

* doctest bug fixed in aslinop

* api doc structure unified

* unified import in tests
  • Loading branch information
JonathanWenger authored Oct 9, 2020
1 parent 07e3599 commit 8a0cc0d
Show file tree
Hide file tree
Showing 20 changed files with 102 additions and 88 deletions.
2 changes: 1 addition & 1 deletion benchmarks/random_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import numpy as np

import probnum.linalg.linops as linops
from benchmarks.benchmark_utils import SPD_MATRIX_5x5
from probnum import linops
from probnum import random_variables as rvs

# Module level variables
Expand Down
7 changes: 4 additions & 3 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ To learn how to use ProbNum check out the `quickstart guide <introduction/quicks
:maxdepth: 1
:caption: API Documentation

public_api/probnum
public_api/linalg
public_api/quad
public_api/diffeq
public_api/filtsmooth
public_api/linalg
public_api/linops
public_api/quad
public_api/random_variables
public_api/utils

.. toctree::
Expand Down
7 changes: 0 additions & 7 deletions docs/source/public_api/linalg.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
probnum.linalg
==============

probnum.linalg
**************
.. automodapi:: probnum.linalg
:no-heading:

probnum.linalg.linops
*********************
.. automodapi::probnum.linalg.linops
:no-heading:
5 changes: 5 additions & 0 deletions docs/source/public_api/linops.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
probnum.linops
==============

.. automodapi:: probnum.linops
:no-heading:
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
probnum
=======

probnum.random_variables
************************
========================

.. automodapi:: probnum.random_variables
:no-heading:
:no-heading:
2 changes: 1 addition & 1 deletion src/probnum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# -*- coding: utf-8 -*-
from pkg_resources import DistributionNotFound, get_distribution

from . import diffeq, filtsmooth, linalg, quad, random_variables, utils
from . import diffeq, filtsmooth, linalg, linops, quad, random_variables, utils
from .random_variables import RandomVariable, asrandvar

try:
Expand Down
3 changes: 1 addition & 2 deletions src/probnum/linalg/linearsolvers/linearsolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
import scipy.sparse

import probnum
from probnum import utils
from probnum.linalg import linops
from probnum import linops, utils
from probnum.linalg.linearsolvers.matrixbased import (
AsymmetricMatrixBasedSolver,
NoisySymmetricMatrixBasedSolver,
Expand Down
5 changes: 3 additions & 2 deletions src/probnum/linalg/linearsolvers/matrixbased.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import numpy as np

import probnum
from probnum import linops
from probnum import random_variables as rvs
from probnum.linalg import linops


class ProbabilisticLinearSolver(abc.ABC):
Expand Down Expand Up @@ -760,7 +760,8 @@ def _matvec(x):
A = rvs.Normal(mean=self.A_mean, cov=linops.SymmetricKronecker(A=_A_covfactor))

Ainv = rvs.Normal(
mean=self.Ainv_mean, cov=linops.SymmetricKronecker(A=_Ainv_covfactor)
mean=self.Ainv_mean,
cov=linops.SymmetricKronecker(A=_Ainv_covfactor),
)
# Induced distribution on x via Ainv
# Exp(x) = Ainv b, Cov(x) = 1/2 (W b'Wb + Wbb'W)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,35 @@
linear operator as a matrix in memory.
"""

from probnum.linalg.linops.kronecker import *
from probnum.linalg.linops.linearoperators import *
from ._kronecker import Kronecker, Svec, SymmetricKronecker, Symmetrize, Vec
from ._linear_operator import Identity, LinearOperator, MatrixMult, ScalarMult
from ._utils import aslinop

# Public classes and functions. Order is reflected in documentation.
__all__ = [
"aslinop",
"LinearOperator",
"Identity",
"ScalarMult",
"MatrixMult",
"Kronecker",
"SymmetricKronecker",
"Symmetrize",
"Vec",
"Svec",
"Symmetrize",
"aslinop",
]

# Set correct module paths. Corrects links and module paths in documentation.
LinearOperator.__module__ = "probnum.linalg.linops"
ScalarMult.__module__ = "probnum.linalg.linops"
LinearOperator.__module__ = "probnum.linops"

Identity.__module__ = "probnum.linops"
ScalarMult.__module__ = "probnum.linops"
MatrixMult.__module__ = "probnum.linops"

Kronecker.__module__ = "probnum.linops"
Svec.__module__ = "probnum.linops"
SymmetricKronecker.__module__ = "probnum.linops"
Symmetrize.__module__ = "probnum.linops"
Vec.__module__ = "probnum.linops"

aslinop.__module__ = "probnum.linops"
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"""
import numpy as np

from probnum.linalg.linops.linearoperators import LinearOperator, aslinop
from . import _linear_operator, _utils


class Symmetrize(LinearOperator):
class Symmetrize(_linear_operator.LinearOperator):
"""
Symmetrizes a vector in its matrix representation.
Expand All @@ -32,7 +32,7 @@ def _matvec(self, x):
return Y.reshape(-1, 1)


class Vec(LinearOperator):
class Vec(_linear_operator.LinearOperator):
"""
Vectorization operator.
Expand Down Expand Up @@ -68,7 +68,7 @@ def _matmat(self, X):
return X.ravel(order="F")


class Svec(LinearOperator):
class Svec(_linear_operator.LinearOperator):
"""
Symmetric vectorization operator.
Expand Down Expand Up @@ -148,7 +148,7 @@ def _matmat(self, X):
)


class Kronecker(LinearOperator):
class Kronecker(_linear_operator.LinearOperator):
"""
Kronecker product of two linear operators.
Expand Down Expand Up @@ -191,8 +191,8 @@ class Kronecker(LinearOperator):

# todo: extend this to list of operators
def __init__(self, A, B, dtype=None):
self.A = aslinop(A)
self.B = aslinop(B)
self.A = _utils.aslinop(A)
self.B = _utils.aslinop(B)
super().__init__(
dtype=dtype,
shape=(
Expand Down Expand Up @@ -258,7 +258,7 @@ def trace(self):
raise NotImplementedError


class SymmetricKronecker(LinearOperator):
class SymmetricKronecker(_linear_operator.LinearOperator):
"""
Symmetric Kronecker product of two linear operators.
Expand Down Expand Up @@ -297,13 +297,13 @@ class SymmetricKronecker(LinearOperator):

def __init__(self, A, B=None, dtype=None):
# Set parameters
self.A = aslinop(A)
self.A = _utils.aslinop(A)
self._ABequal = False
if B is None:
self.B = self.A
self._ABequal = True
else:
self.B = aslinop(B)
self.B = _utils.aslinop(B)
self._n = self.A.shape[0]
if self.A.shape != self.B.shape or self.A.shape[1] != self._n:
raise ValueError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ class LinearOperator(scipy.sparse.linalg.LinearOperator):
Implementing ``_adjoint`` is preferable; ``_rmatvec`` is mostly there for backwards
compatibility.
This class inherits from :class:`scipy.sparse.linalg.LinearOperator`.
Parameters
----------
shape : tuple
Expand All @@ -70,7 +68,7 @@ class LinearOperator(scipy.sparse.linalg.LinearOperator):
Examples
--------
>>> import numpy as np
>>> from probnum.linalg.linops import LinearOperator
>>> from probnum.linops import LinearOperator
>>> def mv(v):
... return np.array([2 * v[0] - v[1], 3 * v[1]])
...
Expand Down Expand Up @@ -575,39 +573,3 @@ def trace(self):
raise ValueError("The trace is only defined for square linear operators.")
else:
return np.trace(self.A)


def aslinop(A):
"""
Return `A` as a :class:`LinearOperator`.
Parameters
----------
A : array-like or LinearOperator or RandomVariable or object
Argument to be represented as a linear operator. When `A` is an object it needs
to have the attributes `.shape` and `.matvec`.
Notes
-----
If `A` has no `.dtype` attribute, the data type is determined by calling
:func:`LinearOperator.matvec()` - set the `.dtype` attribute to prevent this
call upon the linear operator creation.
See Also
--------
LinearOperator : Class representing linear operators.
Examples
--------
>>> from probnum.linalg.linops import aslinop
>>> M = np.array([[1,2,3],[4,5,6]], dtype=np.int32)
>>> aslinop(M)
<2x3 MatrixMult with dtype=int32>
"""
if isinstance(A, scipy.sparse.linalg.LinearOperator):
return A
elif isinstance(A, (np.ndarray, scipy.sparse.spmatrix)):
return MatrixMult(A=A)
else:
op = scipy.sparse.linalg.aslinearoperator(A)
return LinearOperator(op)
41 changes: 41 additions & 0 deletions src/probnum/linops/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import numpy as np
import scipy.sparse

from . import _linear_operator


def aslinop(A) -> _linear_operator.LinearOperator:
"""
Return ``A`` as a :class:`LinearOperator`.
Parameters
----------
A : array-like or LinearOperator or RandomVariable or object
Argument to be represented as a linear operator. When `A` is an object it needs
to have the attributes `.shape` and `.matvec`.
See Also
--------
LinearOperator : Class representing linear operators.
Notes
-----
If `A` has no `.dtype` attribute, the data type is determined by calling
:func:`LinearOperator.matvec()` - set the `.dtype` attribute to prevent this
call upon the linear operator creation.
Examples
--------
>>> import numpy as np
>>> from probnum.linops import aslinop
>>> M = np.array([[1,2,3],[4,5,6]], dtype=np.int32)
>>> aslinop(M)
<2x3 MatrixMult with dtype=int32>
"""
if isinstance(A, scipy.sparse.linalg.LinearOperator):
return A
elif isinstance(A, (np.ndarray, scipy.sparse.spmatrix)):
return _linear_operator.MatrixMult(A=A)
else:
op = scipy.sparse.linalg.aslinearoperator(A)
return _linear_operator.LinearOperator(op)
6 changes: 3 additions & 3 deletions src/probnum/random_variables/_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import numpy as np

import probnum.linops as _linear_operators
from probnum import utils as _utils
from probnum.linalg import linops as _linops

from ._dirac import Dirac as _Dirac
from ._normal import Normal as _Normal
Expand Down Expand Up @@ -280,8 +280,8 @@ def _matmul_normal_dirac(norm_rv: _Normal, dirac_rv: _Dirac) -> _Normal:
),
)
elif norm_rv.ndim == 2 and norm_rv.shape[0] > 1:
cov_update = _linops.Kronecker(
_linops.Identity(dirac_rv.shape[0]), dirac_rv.support
cov_update = _linear_operators.Kronecker(
_linear_operators.Identity(dirac_rv.shape[0]), dirac_rv.support
)

return _Normal(
Expand Down
2 changes: 1 addition & 1 deletion src/probnum/random_variables/_normal.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import scipy.linalg
import scipy.stats

from probnum import linops
from probnum import utils as _utils
from probnum.linalg import linops
from probnum.type import (
ArrayLikeGetitemArgType,
FloatArgType,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_linalg/test_linearsolvers/test_linearsolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
import scipy.sparse.linalg

import probnum
from probnum import linalg
from probnum import linalg, linops
from probnum import random_variables as rvs
from probnum.linalg import linops
from tests.testing import NumpyAssertions


Expand Down Expand Up @@ -383,7 +382,8 @@ def callback_iterates_CG(xk):
cov=linops.SymmetricKronecker(A=linops.Identity(A.shape[1])),
)
A0 = rvs.Normal(
mean=linops.Identity(A.shape[1]), cov=linops.SymmetricKronecker(A)
mean=linops.Identity(A.shape[1]),
cov=linops.SymmetricKronecker(A),
)
for kwargs in [{"assume_A": "sympos", "rtol": 10 ** -6}]:
with self.subTest():
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import numpy as np

from probnum.linalg import linops
from probnum import linops
from tests.testing import NumpyAssertions


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import scipy.sparse

from probnum.linalg import linops
from probnum import linops
from tests.testing import NumpyAssertions


Expand Down
Loading

0 comments on commit 8a0cc0d

Please sign in to comment.