diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index bef121c02..308840f10 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -36,13 +36,3 @@ jobs: run: pip install tox - name: Run pylint through tox run: tox -e pylint - - pylint-tox-config-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Check if the list of disabled messages in the local and global linting passes in ./tox.ini are correctly synchronized - run: python .github/workflows/pylint_check.py diff --git a/.github/workflows/pylint_check.py b/.github/workflows/pylint_check.py deleted file mode 100644 index 2e4879670..000000000 --- a/.github/workflows/pylint_check.py +++ /dev/null @@ -1,48 +0,0 @@ -from pathlib import Path - -TOXINI_FILE = Path("tox.ini") -GLOBAL_DISABLES = {} - - -# Parse ./tox.ini -tox_lines = TOXINI_FILE.read_text().splitlines() -tox_pylint_lines = [ - l for l in tox_lines if l.strip().startswith("pylint src") and "--disable" in l -] -tox_global_disables = {m for m in tox_pylint_lines[0].split('"')[1].split(",")} -tox_per_package_disables = { - m for l in tox_pylint_lines[1:] for m in l.split('"')[1].split(",") -} - - -# Check correctness and raise errors -try: - global_but_not_per_package = tox_global_disables.difference( - tox_per_package_disables - ).difference(GLOBAL_DISABLES) - assert not global_but_not_per_package -except AssertionError: - raise Exception( - f""" - The following pylint messages seem to be disabled in the global linting pass, but - not in the per-package linting passes in `./tox.ini`: {global_but_not_per_package}. - This could have two reasons with different solutions: - 1. You fixed one or many pylint errors in one of the packages and there is no - package left that needs this specific message disabled. Then, please also remove - it from the global linting pass in `tox.ini` such that pylint runs in the - strictest configuration possible. - 2. You decided to disable a message in the global linting pass in `./tox.ini`.. - In this case either add it to the list of messages that should be disabled in the - long term (`pyproject.toml`) or add it to the `GLOBAL_DISABLES` variable in this - python script (`./github/workflows/pylint_check.py`) if the message should only - be disabled in the short term. - If you are not sure what exactly you are supposed to do, or if you think that this - message is wrong please feel free to open an issue on GitHub. - """ - ) - - -print( - "The disabled pylint messages of the global and per-package linting passes in " - "`./tox.ini` seem to be correctly synchronized." -) diff --git a/linting-requirements.txt b/linting-requirements.txt index 5cdbc3277..551d2831e 100644 --- a/linting-requirements.txt +++ b/linting-requirements.txt @@ -1,4 +1,4 @@ # Dependencies for code linting -pylint == 2.9.* +pylint~=2.16.2 # mypy diff --git a/pyproject.toml b/pyproject.toml index 3b05cbd90..fc24751ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -163,18 +163,17 @@ load-plugins = [ "pylint.extensions.docstyle", "pylint.extensions.overlapping_exceptions", "pylint.extensions.mccabe", + "pylint.extensions.no_self_use", ] [tool.pylint.messages_control] disable = [ - # Exceptions suggested by Black: - # https://github.com/psf/black/blob/7f75fe3669ebf0627b1b0476a6d02047e909b959/docs/compatible_configs.md#black-compatible-configurations - "bad-continuation", - "bad-whitespace", # We allow TODO comments in the following format: `# TODO (#[ISSUE NUMBER]): This needs to be done.` "fixme", # We want to use "mathematical notation" to name some of our variables, e.g. `A` for matrices "invalid-name", + # Assigning lambda expressions to a variable is sometimes useful, e.g. for defining `LambdaLinearOperator`s + "unnecessary-lambda-assignment", # Temporary ignore, see https://github.com/probabilistic-numerics/probnum/discussions/470#discussioncomment-1998097 for an explanation "missing-return-doc", "missing-yield-doc", @@ -183,13 +182,23 @@ disable = [ [tool.pylint.format] max-line-length = "88" +[tool.pylint.parameter_documentation] +accept-no-param-doc = false +accept-no-raise-doc = false +accept-no-return-doc = false +accept-no-yields-doc = false + [tool.pylint.design] max-args = 10 max-complexity = 14 max-locals = 20 [tool.pylint.similarities] -ignore-imports = "yes" +ignore-comments = true +ignore-docstrings = true +ignore-imports = true +ignore-signatures = true +min-similarity-lines = 4 ################################################################################ # Formatting Configuration # diff --git a/src/probnum/_config.py b/src/probnum/_config.py index 8cc6f98e9..098ab9fed 100644 --- a/src/probnum/_config.py +++ b/src/probnum/_config.py @@ -1,3 +1,5 @@ +"""ProbNum library configuration""" + import contextlib import dataclasses from typing import Any @@ -35,6 +37,9 @@ class Configuration: @dataclasses.dataclass class Option: + """Representation of a single configuration option as a key-value pair with a + default value and a description string for documentation purposes.""" + name: str default_value: Any description: str @@ -49,7 +54,7 @@ def __init__(self) -> None: # This is the equivalent of `self._options_registry = dict()`. # After rewriting the `__setattr__` method, we have to fall back on the # `__setattr__` method of the super class. - object.__setattr__(self, "_options_registry", dict()) + object.__setattr__(self, "_options_registry", {}) def __getattr__(self, key: str) -> Any: if key not in self._options_registry: @@ -68,7 +73,7 @@ def __repr__(self) -> str: @contextlib.contextmanager def __call__(self, **kwargs) -> None: """Context manager used to set values of registered config options.""" - old_options = dict() + old_options = {} for key, value in kwargs.items(): if key not in self._options_registry: @@ -96,6 +101,11 @@ def register(self, key: str, default_value: Any, description: str) -> None: The default value of the configuration option. description: A short description of the configuration option and what it controls. + + Raises + ------ + KeyError + If the configuration option already exists. """ if key in self._options_registry: raise KeyError( @@ -156,5 +166,9 @@ def register(self, key: str, default_value: Any, description: str) -> None: ] # ... and register the default configuration options. -for key, default_value, descr in _DEFAULT_CONFIG_OPTIONS: - _GLOBAL_CONFIG_SINGLETON.register(key, default_value, descr) +def _register_defaults(): + for key, default_value, descr in _DEFAULT_CONFIG_OPTIONS: + _GLOBAL_CONFIG_SINGLETON.register(key, default_value, descr) + + +_register_defaults() diff --git a/src/probnum/conftest.py b/src/probnum/conftest.py index 7a2faa201..68c279ef7 100644 --- a/src/probnum/conftest.py +++ b/src/probnum/conftest.py @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True) -def autoimport_packages(doctest_namespace): +def autoimport_packages(doctest_namespace): # pylint: disable=missing-any-param-doc """This fixture 'imports' standard packages automatically in order to avoid boilerplate code in doctests""" diff --git a/src/probnum/functions/_function.py b/src/probnum/functions/_function.py index 12573c6ec..27fcf5c80 100644 --- a/src/probnum/functions/_function.py +++ b/src/probnum/functions/_function.py @@ -129,9 +129,8 @@ def __sub__(self, other): @functools.singledispatchmethod def __mul__(self, other): if np.ndim(other) == 0: - from ._algebra_fallbacks import ( # pylint: disable=import-outside-toplevel - ScaledFunction, - ) + # pylint: disable=import-outside-toplevel,cyclic-import + from ._algebra_fallbacks import ScaledFunction return ScaledFunction(function=self, scalar=other) @@ -140,9 +139,8 @@ def __mul__(self, other): @functools.singledispatchmethod def __rmul__(self, other): if np.ndim(other) == 0: - from ._algebra_fallbacks import ( # pylint: disable=import-outside-toplevel - ScaledFunction, - ) + # pylint: disable=import-outside-toplevel,cyclic-import + from ._algebra_fallbacks import ScaledFunction return ScaledFunction(function=self, scalar=other) diff --git a/src/probnum/linops/_arithmetic_fallbacks.py b/src/probnum/linops/_arithmetic_fallbacks.py index cf9a1106b..52f7c73ec 100644 --- a/src/probnum/linops/_arithmetic_fallbacks.py +++ b/src/probnum/linops/_arithmetic_fallbacks.py @@ -137,10 +137,10 @@ def __neg__(self): return SumLinearOperator(*(-summand for summand in self._summands)) def __repr__(self): - res = "SumLinearOperator [\n" - for s in self._summands: - res += f"\t{s}, \n" - return res + "]" + res = "SumLinearOperator [\n\t" + res += ",\n\t".join(repr(summand) for summand in self._summands) + res += "\n]" + return res @staticmethod def _expand_sum_ops(*summands: LinearOperator) -> Tuple[LinearOperator, ...]: @@ -230,10 +230,10 @@ def _expand_prod_ops(*factors: LinearOperator) -> Tuple[LinearOperator, ...]: return tuple(expanded_factors) def __repr__(self): - res = "ProductLinearOperator [\n" - for s in self._factors: - res += f"\t{s}, \n" - return res + "]" + res = "ProductLinearOperator [\n\t" + res += ",\n\t".join(repr(factor) for factor in self._factors) + res += "\n]" + return res def _solve(self, B: np.ndarray) -> np.ndarray: return functools.reduce(lambda b, op: op.solve(b), self._factors, B) diff --git a/src/probnum/linops/_linear_operator.py b/src/probnum/linops/_linear_operator.py index b1b8662cc..8bf5e642c 100644 --- a/src/probnum/linops/_linear_operator.py +++ b/src/probnum/linops/_linear_operator.py @@ -10,7 +10,7 @@ import scipy.linalg import scipy.sparse -from probnum import config +from probnum import config # pylint: disable=cyclic-import from probnum.typing import ArrayLike, DTypeLike, ScalarLike, ShapeLike import probnum.utils @@ -384,6 +384,13 @@ def todense(self, cache: bool = True) -> np.ndarray: This method can be computationally very costly depending on the shape of the linear operator. Use with caution. + Parameters + ---------- + cache + If this is set to :data:`True`, then the dense matrix representation will + be cached and subsequent calls will return the cached value (even if + :code:`dense` is set to :data:`False` in these subsequent calls). + Returns ------- matrix : np.ndarray @@ -413,7 +420,14 @@ def is_symmetric(self) -> Optional[bool]: """Whether the ``LinearOperator`` :math:`L` is symmetric, i.e. :math:`L = L^T`. If this is ``None``, it is unknown whether the operator is symmetric or not. - Only square operators can be symmetric.""" + Only square operators can be symmetric. + + Raises + ------ + ValueError + When setting :attr:`is_symmetric` to :data:`True` on a non-square + :class:`LinearOperator`. + """ return self._is_symmetric @is_symmetric.setter @@ -458,6 +472,12 @@ def is_positive_definite(self) -> Optional[bool]: If this is ``None``, it is unknown whether the matrix is positive-definite or not. Only symmetric operators can be positive-definite. + + Raises + ------ + ValueError + When setting :attr:`is_positive_definite` to :data:`True` while + :attr:`is_symmetric` is :data:`False`. """ return self._is_positive_definite @@ -520,7 +540,13 @@ def _eigvals(self) -> np.ndarray: return np.linalg.eigvals(self.todense(cache=False)) def eigvals(self) -> np.ndarray: - """Eigenvalue spectrum of the linear operator.""" + """Eigenvalue spectrum of the linear operator. + + Raises + ------ + numpy.linalg.LinAlgError + If :meth:`eigvals` is called on a non-square operator. + """ if self._eigvals_cache is None: if not self.is_square: raise np.linalg.LinAlgError( @@ -871,9 +897,8 @@ def _lu_factor(self): #################################################################################### def __neg__(self) -> "LinearOperator": - from ._arithmetic import ( # pylint: disable=import-outside-toplevel - NegatedLinearOperator, - ) + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import NegatedLinearOperator return NegatedLinearOperator(self) @@ -912,6 +937,18 @@ def transpose(self, *axes: Union[int, Tuple[int]]) -> "LinearOperator": """Transpose this linear operator. Can be abbreviated self.T instead of self.transpose(). + + Parameters + ---------- + *axes + Permutation of the axes of the :class:`LinearOperator`. + + Raises + ------ + ValueError + If the given axis indices do not constitute a valid permutation of the axes. + numpy.AxisError + If the axis indices are out of bounds. """ if len(axes) > 0: if len(axes) == 1 and isinstance(axes[0], tuple): @@ -1167,7 +1204,8 @@ def __matmul__( return y - from ._arithmetic import matmul # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import matmul return matmul(self, other) @@ -1193,7 +1231,8 @@ def __rmatmul__( return y - from ._arithmetic import matmul # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import matmul return matmul(other, self) @@ -1731,7 +1770,7 @@ def __init__(self, indices, shape, dtype=np.double): ) @property - def indices(self): + def indices(self) -> Tuple[int]: """Indices which will be selected when applying the linear operator to a vector.""" return self._indices diff --git a/src/probnum/linops/_vectorize.py b/src/probnum/linops/_vectorize.py index bc40d1e5d..bdf88e815 100644 --- a/src/probnum/linops/_vectorize.py +++ b/src/probnum/linops/_vectorize.py @@ -1,20 +1,32 @@ """Vectorization utilities for matrix-{vector, matrix} products.""" import functools -from typing import Callable, Optional +from typing import Callable, Optional, Union import numpy as np +_VectorizationDecoratorReturnType = Union[ + Callable[[np.ndarray], np.ndarray], + Callable[[Callable[[np.ndarray], np.ndarray]], Callable[[np.ndarray], np.ndarray]], +] + def vectorize_matmat( matmat: Optional[Callable[[np.ndarray], np.ndarray]] = None, method: bool = False, -): +) -> _VectorizationDecoratorReturnType: """Broadcasting for a (implicitly defined) matrix-matrix product. Convenience function / decorator to broadcast the definition of a matrix-matrix product to stacks of matrices. This can be used to easily construct a new linear operator only from a matrix-matrix product. + + Parameters + ---------- + matmat + Function computing a matrix-matrix product. + method + Whether the decorator is being applied to a method or a function. """ def _vectorize_matmat( @@ -43,12 +55,19 @@ def vectorized_matmat(*args) -> np.ndarray: def vectorize_matvec( matvec: Optional[Callable[[np.ndarray], np.ndarray]] = None, method: bool = False, -): +) -> _VectorizationDecoratorReturnType: """Broadcasting for a (implicitly defined) matrix-vector product. Convenience function / decorator to broadcast the definition of a matrix-vector product. This can be used to easily construct a new linear operator only from a matrix-vector product. + + Parameters + ---------- + matvec + Function computing a matrix-vector product. + method + Whether the decorator is being applied to a method or a function. """ def _vectorize_matvec( diff --git a/src/probnum/randprocs/_random_process.py b/src/probnum/randprocs/_random_process.py index 5fba2462b..061a1f8db 100644 --- a/src/probnum/randprocs/_random_process.py +++ b/src/probnum/randprocs/_random_process.py @@ -96,7 +96,7 @@ def __init__( if cov is not None: if not isinstance(cov, kernels.Kernel): raise TypeError( - "The covariance functions must be implemented as a " "`Kernel`." + "The covariance functions must be implemented as a `Kernel`." ) if cov.input_shape != self._input_shape: @@ -169,7 +169,7 @@ def __call__(self, args: InputType) -> randvars.RandomVariable[OutputType]: at the input(s). """ - def marginal(self, args: InputType) -> randvars._RandomVariableList: + def marginal(self, args: InputType) -> "randvars._RandomVariableList": """Batch of random variables defining the marginal distributions at the inputs. Parameters @@ -183,7 +183,13 @@ def marginal(self, args: InputType) -> randvars._RandomVariableList: @property def mean(self) -> functions.Function: - r"""Mean function :math:`m(x) := \mathbb{E}[f(x)]` of the random process.""" + r"""Mean function :math:`m(x) := \mathbb{E}[f(x)]` of the random process. + + Raises + ------ + NotImplementedError + If no mean function was assigned to the random process. + """ if self._mean is None: raise NotImplementedError @@ -202,6 +208,11 @@ def cov(self) -> kernels.Kernel: (f(x_1) - \mathbb{E}[f(x_1)])^\top \right] \end{equation} + + Raises + ------ + NotImplementedError + If no covariance function was assigned to the random process. """ if self._cov is None: raise NotImplementedError @@ -304,6 +315,11 @@ def sample( i.e. callables are returned. size Size of the sample. + + Raises + ------ + NotImplementedError + General path sampling is currently not supported. """ if args is None: raise NotImplementedError diff --git a/src/probnum/randprocs/kernels/_arithmetic.py b/src/probnum/randprocs/kernels/_arithmetic.py index 0d7d460ae..51592d8ab 100644 --- a/src/probnum/randprocs/kernels/_arithmetic.py +++ b/src/probnum/randprocs/kernels/_arithmetic.py @@ -3,6 +3,7 @@ from ._kernel import BinaryOperandType, Kernel +# pylint: disable=missing-param-doc def add(op1: BinaryOperandType, op2: BinaryOperandType) -> Kernel: """Kernel summation.""" return SumKernel(op1, op2) @@ -11,3 +12,6 @@ def add(op1: BinaryOperandType, op2: BinaryOperandType) -> Kernel: def mul(op1: BinaryOperandType, op2: BinaryOperandType) -> Kernel: """Kernel multiplication.""" return _mul_fallback(op1, op2) + + +# pylint: enable=missing-param-doc diff --git a/src/probnum/randprocs/kernels/_arithmetic_fallbacks.py b/src/probnum/randprocs/kernels/_arithmetic_fallbacks.py index fda387ee9..c6db31dae 100644 --- a/src/probnum/randprocs/kernels/_arithmetic_fallbacks.py +++ b/src/probnum/randprocs/kernels/_arithmetic_fallbacks.py @@ -113,10 +113,10 @@ def _evaluate_linop( ) def __repr__(self): - res = "SumKernel [\n" - for s in self._summands: - res += f"\t{s}, \n" - return res + "]" + res = "SumKernel [\n\t" + res += ",\n\t".join(repr(summand) for summand in self._summands) + res += "\n]" + return res @staticmethod def _expand_sum_kernels(*summands: Kernel) -> Tuple[Kernel, ...]: @@ -173,10 +173,10 @@ def _evaluate(self, x0: np.ndarray, x1: Optional[np.ndarray]) -> np.ndarray: ) def __repr__(self): - res = "ProductKernel [\n" - for s in self._factors: - res += f"\t{s}, \n" - return res + "]" + res = "ProductKernel [\n\t" + res += ",\n\t".join(repr(factor) for factor in self._factors) + res += "\n]" + return res @staticmethod def _expand_prod_kernels(*factors: Kernel) -> Tuple[Kernel, ...]: diff --git a/src/probnum/randprocs/kernels/_exponentiated_quadratic.py b/src/probnum/randprocs/kernels/_exponentiated_quadratic.py index 9b61f44f2..a42c0eb55 100644 --- a/src/probnum/randprocs/kernels/_exponentiated_quadratic.py +++ b/src/probnum/randprocs/kernels/_exponentiated_quadratic.py @@ -69,7 +69,7 @@ def lengthscales(self) -> np.ndarray: return self._lengthscales @property - def lengthscale(self) -> np.ndarray: + def lengthscale(self) -> np.ndarray: # pylint: disable=missing-raises-doc """Deprecated.""" if self._lengthscales.shape == (): return self._lengthscales diff --git a/src/probnum/randprocs/kernels/_kernel.py b/src/probnum/randprocs/kernels/_kernel.py index 3aecfcf8d..7ebf8db6b 100644 --- a/src/probnum/randprocs/kernels/_kernel.py +++ b/src/probnum/randprocs/kernels/_kernel.py @@ -195,7 +195,13 @@ def input_size_1(self) -> int: @property def input_shape(self) -> ShapeType: r"""Shorthand for the input shape of a covariance function with - :attr:`input_shape_0` ``==`` :attr:`input_shape_1`.""" + :attr:`input_shape_0` ``==`` :attr:`input_shape_1`. + + Raises + ------ + ValueError + If the input shapes of the :class:`Kernel` are not equal. + """ if self.input_shape_0 != self.input_shape_1: raise ValueError("The input shapes of the `Kernel` are not equal.") @@ -648,22 +654,26 @@ def _euclidean_inner_products( """ def __add__(self, other: BinaryOperandType) -> Kernel: - from ._arithmetic import add # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import add return add(self, other) def __radd__(self, other: BinaryOperandType) -> Kernel: - from ._arithmetic import add # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import add return add(other, self) def __mul__(self, other: BinaryOperandType) -> Kernel: - from ._arithmetic import mul # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import mul return mul(self, other) def __rmul__(self, other: BinaryOperandType) -> Kernel: - from ._arithmetic import mul # pylint: disable=import-outside-toplevel + # pylint: disable=import-outside-toplevel,cyclic-import + from ._arithmetic import mul return mul(other, self) diff --git a/src/probnum/randprocs/kernels/_matern.py b/src/probnum/randprocs/kernels/_matern.py index f7b5449d6..186a15848 100644 --- a/src/probnum/randprocs/kernels/_matern.py +++ b/src/probnum/randprocs/kernels/_matern.py @@ -152,7 +152,7 @@ def lengthscales(self) -> np.ndarray: return self._lengthscales @property - def lengthscale(self) -> np.ndarray: + def lengthscale(self) -> np.ndarray: # pylint: disable=missing-raises-doc """Deprecated.""" if self._lengthscales.shape == (): return self._lengthscales diff --git a/src/probnum/randprocs/kernels/_product_matern.py b/src/probnum/randprocs/kernels/_product_matern.py index 8b14ea26c..74fcc9cf6 100644 --- a/src/probnum/randprocs/kernels/_product_matern.py +++ b/src/probnum/randprocs/kernels/_product_matern.py @@ -71,21 +71,21 @@ def __init__( input_dim = 1 if input_shape == () else input_shape[0] # If only single scalar lengthcsale or nu is given, use this in every dimension - def expand_array(x, ndim): + def _expand_array(x, ndim): return np.full((ndim,), _utils.as_numpy_scalar(x)) if isinstance(lengthscales, np.ndarray): if lengthscales.shape == (): - lengthscales = expand_array(lengthscales, input_dim) + lengthscales = _expand_array(lengthscales, input_dim) if isinstance(nus, np.ndarray): if nus.shape == (): - nus = expand_array(nus, input_dim) + nus = _expand_array(nus, input_dim) # also expand if scalars are given if np.isscalar(lengthscales): - lengthscales = expand_array(lengthscales, input_dim) + lengthscales = _expand_array(lengthscales, input_dim) if np.isscalar(nus): - nus = expand_array(nus, input_dim) + nus = _expand_array(nus, input_dim) univariate_materns = [] for dim in range(input_dim): diff --git a/src/probnum/utils/argutils.py b/src/probnum/utils/argutils.py index 55754dba0..cde3f70bf 100644 --- a/src/probnum/utils/argutils.py +++ b/src/probnum/utils/argutils.py @@ -17,6 +17,15 @@ def as_shape(x: ShapeLike, ndim: Optional[numbers.Integral] = None) -> ShapeType ---------- x Shape representation. + ndim + The required number of dimensions in the shape. + + Raises + ------ + TypeError + If ``x`` is not a valid :const:`ShapeLike`. + TypeError + If ``x`` does not feature the required number of dimensions. """ if isinstance(x, (int, numbers.Integral, np.integer)): shape = (int(x),) @@ -51,6 +60,11 @@ def as_numpy_scalar(x: ScalarLike, dtype: DTypeLike = None) -> np.ndarray: Scalar value. dtype Data type of the scalar. + + Raises + ------ + ValueError + If :code:`x` can not be interpreted as a scalar. """ if np.ndim(x) != 0: diff --git a/src/probnum/utils/arrayutils.py b/src/probnum/utils/arrayutils.py index c18a9675a..279de4d56 100644 --- a/src/probnum/utils/arrayutils.py +++ b/src/probnum/utils/arrayutils.py @@ -1,14 +1,19 @@ """Utility functions for arrays and the like.""" -from typing import Union +from typing import Sequence, Union import numpy as np -import scipy +import scipy.sparse import probnum.randvars +from probnum.typing import ArrayLike -def atleast_1d(*rvs): +def atleast_1d( # pylint: disable=missing-raises-doc + *rvs: Union[ArrayLike, scipy.sparse.spmatrix, "probnum.randvars.RandomVariable"], +) -> Sequence[ + Union[np.ndarray, scipy.sparse.spmatrix, "probnum.randvars.RandomVariable"] +]: """Convert arrays or random variables to arrays or random variables with at least one dimension. diff --git a/src/probnum/utils/linalg/_cholesky_updates.py b/src/probnum/utils/linalg/_cholesky_updates.py index a35c08105..cdca28c12 100644 --- a/src/probnum/utils/linalg/_cholesky_updates.py +++ b/src/probnum/utils/linalg/_cholesky_updates.py @@ -85,6 +85,11 @@ def tril_to_positive_tril(tril_mat: np.ndarray) -> np.ndarray: In other words, make it a valid lower Cholesky factor. The name of the function is based on `np.tril`. + + Parameters + ---------- + tril_mat: + A lower-triangular matrix. """ d = np.sign(np.diag(tril_mat)) diff --git a/tox.ini b/tox.ini index ac8ee1154..42938cdae 100644 --- a/tox.ini +++ b/tox.ini @@ -64,20 +64,20 @@ deps = ignore_errors = true commands = # Global Linting Pass - pylint src/probnum --disable="no-member,abstract-method,arguments-differ,arguments-renamed,redefined-builtin,redefined-outer-name,too-many-instance-attributes,too-many-arguments,too-many-locals,too-many-lines,too-many-statements,too-many-branches,too-complex,too-few-public-methods,protected-access,unnecessary-pass,unused-variable,unused-argument,attribute-defined-outside-init,no-else-return,no-else-raise,no-self-use,else-if-used,consider-using-from-import,duplicate-code,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,useless-param-doc,useless-type-doc,missing-return-type-doc" --jobs=0 + pylint src/probnum \ + --ignore-paths=src/probnum/_pnmethod,src/probnum/diffeq/,src/probnum/filtsmooth/,src/probnum/linalg/,src/probnum/problems/,src/probnum/quad/,src/probnum/randprocs/markov/,src/probnum/randvars/ \ + --jobs=0 # Per-package Linting Passes - pylint src/probnum/diffeq --disable="redefined-outer-name,too-many-instance-attributes,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unnecessary-pass,unused-variable,unused-argument,no-self-use,duplicate-code,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc" --jobs=0 - pylint src/probnum/filtsmooth --disable="no-member,arguments-differ,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unused-variable,unused-argument,no-self-use,duplicate-code,useless-param-doc" --jobs=0 - pylint src/probnum/linalg --disable="no-member,abstract-method,arguments-differ,else-if-used,redefined-builtin,too-many-instance-attributes,too-many-arguments,too-many-locals,too-many-lines,too-many-statements,too-many-branches,too-complex,too-few-public-methods,protected-access,unused-argument,attribute-defined-outside-init,no-else-return,no-else-raise,no-self-use,duplicate-code,missing-module-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc" --jobs=0 - pylint src/probnum/linops --jobs=0 - pylint src/probnum/problems --disable="too-many-arguments,too-many-locals,unused-variable,unused-argument,consider-using-from-import,duplicate-code,missing-module-docstring,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc" --jobs=0 - pylint src/probnum/quad --disable="too-many-arguments,missing-module-docstring" --jobs=0 - pylint src/probnum/randprocs --disable="arguments-differ,arguments-renamed,too-many-instance-attributes,too-many-arguments,too-many-locals,protected-access,unused-argument,no-else-return,duplicate-code,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-type-doc,missing-raises-doc,useless-param-doc,useless-type-doc,missing-return-type-doc" --jobs=0 - pylint src/probnum/randprocs/kernels --disable="duplicate-code" --jobs=0 - pylint src/probnum/randvars --disable="too-many-arguments,too-many-locals,too-many-branches,too-few-public-methods,protected-access,unused-argument,duplicate-code,missing-function-docstring,missing-raises-doc" --jobs=0 - pylint src/probnum/utils --disable="missing-raises-doc,missing-return-type-doc" --jobs=0 + pylint src/probnum/_pnmethod --disable="missing-param-doc,too-few-public-methods" --jobs=0 + pylint src/probnum/diffeq --disable="redefined-outer-name,too-many-instance-attributes,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unnecessary-pass,unused-variable,unused-argument,used-before-assignment,no-self-use,duplicate-code,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc,missing-yield-type-doc,missing-any-param-doc" --jobs=0 + pylint src/probnum/filtsmooth --disable="no-member,arguments-differ,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unused-variable,unused-argument,no-self-use,duplicate-code,useless-param-doc,missing-return-type-doc,missing-param-doc,missing-type-doc,missing-raises-doc,missing-yield-type-doc" --jobs=0 + pylint src/probnum/linalg --disable="no-member,abstract-method,arguments-differ,else-if-used,redefined-builtin,too-many-instance-attributes,too-many-arguments,too-many-locals,too-many-lines,too-many-statements,too-many-branches,too-complex,too-few-public-methods,protected-access,unused-argument,attribute-defined-outside-init,no-else-return,no-else-raise,no-self-use,duplicate-code,missing-module-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc,consider-using-f-string,missing-any-param-doc" --jobs=0 + pylint src/probnum/problems --disable="too-many-arguments,too-many-locals,unused-variable,unused-argument,consider-using-from-import,duplicate-code,missing-module-docstring,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc,missing-timeout,use-dict-literal,missing-any-param-doc" --jobs=0 + pylint src/probnum/quad --disable="too-many-arguments,missing-module-docstring,use-dict-literal" --jobs=0 + pylint src/probnum/randprocs/markov --disable="arguments-differ,arguments-renamed,too-many-instance-attributes,too-many-arguments,too-many-locals,protected-access,unused-argument,no-else-return,duplicate-code,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-type-doc,missing-raises-doc,useless-param-doc,useless-type-doc,missing-return-type-doc,missing-param-doc,missing-any-param-doc,method-cache-max-size-none" --jobs=0 + pylint src/probnum/randvars --disable="too-many-arguments,too-many-locals,too-many-branches,too-few-public-methods,protected-access,unused-argument,duplicate-code,missing-function-docstring,missing-raises-doc,missing-return-type-doc,missing-param-doc,broad-exception-raised" --jobs=0 # Benchmark and Test Code Linting Pass # pylint benchmarks --disable="unused-argument,attribute-defined-outside-init,missing-function-docstring" --jobs=0 # not a work in progress, but final - pylint benchmarks --disable="unused-argument,attribute-defined-outside-init,no-else-return,no-self-use,consider-using-from-import,missing-module-docstring,missing-class-docstring,missing-function-docstring" --jobs=0 + pylint benchmarks --disable="unused-argument,attribute-defined-outside-init,no-else-return,no-self-use,consider-using-from-import,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-return-type-doc,missing-any-param-doc,missing-raises-doc,missing-param-doc,missing-type-doc" --jobs=0 # pylint tests --disable="missing-function-docstring" --jobs=0 # not a work in progress, but final - pylint tests --disable="arguments-differ,redefined-outer-name,too-many-instance-attributes,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unnecessary-pass,unused-variable,unused-argument,unused-private-member,attribute-defined-outside-init,no-else-return,no-self-use,consider-using-from-import,duplicate-code,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc,redundant-returns-doc" --jobs=0 + pylint tests --disable="arguments-differ,redefined-outer-name,too-many-instance-attributes,too-many-arguments,too-many-locals,too-few-public-methods,protected-access,unnecessary-pass,unused-variable,unused-argument,unused-private-member,attribute-defined-outside-init,no-else-return,no-self-use,consider-using-from-import,duplicate-code,missing-module-docstring,missing-class-docstring,missing-function-docstring,missing-param-doc,missing-type-doc,missing-raises-doc,missing-return-type-doc,redundant-returns-doc,missing-any-param-doc,unexpected-keyword-arg,no-member,use-dict-literal,import-error,superfluous-parens,used-before-assignment" --jobs=0