Source code for mindspore.ops.function.linalg_func

# Copyright 2022 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================

"""Operators for linalg function."""

import mindspore.ops as ops
from mindspore.common import dtype as mstype
from mindspore.common.tensor import Tensor
from mindspore.ops import operations as P
from mindspore.ops import functional as F
from mindspore.ops.operations import _inner_ops as inner
from mindspore.ops.function.math_func import _check_input_dtype, _check_attr_dtype
from mindspore._c_expression import Tensor as Tensor_

from ..operations import linalg_ops
from .._primitive_cache import _get_cache_prim


__all__ = ['svd', 'pinv']


[docs]def svd(a, full_matrices=False, compute_uv=True): """ Computes the singular value decompositions of one or more matrices. If :math:`A` is a matrix, the svd returns the singular values :math:`S`, the left singular vectors :math:`U` and the right singular vectors :math:`V`. It meets: .. math:: A=U*diag(S)*V^{T} Args: a (Tensor): Tensor of the matrices to be decomposed. The shape should be :math:`(*, M, N)`, the supported dtype are float32 and float64.. full_matrices (bool, optional): If true, compute full-sized :math:`U` and :math:`V`. If false, compute only the leading P singular vectors, with P is the minimum of M and N. Default: False. compute_uv (bool, optional): If true, compute the left and right singular vectors. If false, compute only the singular values. Default: True. Returns: - **s** (Tensor) - Singular values. The shape is :math:`(*, P)`. - **u** (Tensor) - Left singular vectors. If `compute_uv` is False, u will not be returned. The shape is :math:`(*, M, P)`. If `full_matrices` is True, the shape will be :math:`(*, M, M)`. - **v** (Tensor) - Right singular vectors. If `compute_uv` is False, v will not be returned. The shape is :math:`(*, N, P)`. If `full_matrices` is True, the shape will be :math:`(*, N, N)`. Raises: TypeError: If `full_matrices` or `compute_uv` is not the type of bool. TypeError: If the rank of input less than 2. TypeError: If the type of input is not one of the following dtype: float32, float64. Supported Platforms: ``GPU`` ``CPU`` Examples: >>> import numpy as np >>> from mindspore import Tensor, set_context >>> from mindspore import ops >>> set_context(device_target="CPU") >>> a = Tensor(np.array([[1, 2], [-4, -5], [2, 1]]).astype(np.float32)) >>> s, u, v = ops.svd(a, full_matrices=True, compute_uv=True) >>> print(s) [7.0652843 1.040081 ] >>> print(u) [[ 0.30821905 -0.48819482 0.81649697] [-0.90613353 0.11070572 0.40824813] [ 0.2896955 0.8656849 0.4082479 ]] >>> print(v) [[ 0.63863593 0.769509 ] [ 0.769509 -0.63863593]] """ svd_ = _get_cache_prim(linalg_ops.Svd)(full_matrices=full_matrices, compute_uv=compute_uv) if compute_uv: return svd_(a) s, _, _ = svd_(a) return s
[docs]def pinv(x, *, atol=None, rtol=None, hermitian=False): """ Computes the (Moore-Penrose) pseudo-inverse of a matrix. Args: x (Tensor): A matrix to be calculated. The matrix must be at least two dimensions. Only `float32`, `float64` are supported Tensor dtypes. Keyword args: atol (float, Tensor): absolute tolerance value. Default: None. rtol (float, Tensor): relative tolerance value. Default: None. hermitian (bool): An optional bool. x is assumed to be symmetric if real. Default: False. Returns: Tensor. Raises: TypeError: If `hermitian` is not a bool. TypeError: If `x` is not a Tensor. ValueError: If the dimension of `x` is less than 2. Supported Platforms: ``CPU`` Examples: >>> x = Tensor([[2., 1.], [1., 2.]], mindspore.float32) >>> output = ops.pinv(x) >>> print(output) [[ 0.6666667 -0.33333334] [-0.33333334 0.6666667 ]] """ if not isinstance(x, (Tensor, Tensor_)): raise TypeError("The input x must be tensor") if x.shape == (): raise TypeError("For pinv, the 0-D input is not supported") x_shape = F.shape(x) if len(x_shape) < 2: raise ValueError("input x should have 2 or more dimensions, " f"but got {len(x_shape)}.") x_dtype = _get_cache_prim(P.DType)()(x) _check_input_dtype("x", x_dtype, [mstype.float32, mstype.float64], "pinv") _check_attr_dtype("hermitian", hermitian, [bool], "pinv") if atol is not None: if rtol is None: rtol = Tensor(0.0) else: atol = Tensor(0.0) if rtol is None: rtol = max(ops.shape(x)) * ops.Eps()(Tensor(1.0, x.dtype)) if not inner.IsInstance()(rtol, mstype.tensor): rtol = Tensor(rtol, mstype.float32) if not inner.IsInstance()(atol, mstype.tensor): atol = Tensor(atol, mstype.float32) if not hermitian: s, u, v = x.svd() max_singular_val = ops.narrow(s, -1, 0, 1) threshold = ops.maximum(atol.expand_dims(-1), rtol.expand_dims(-1) * max_singular_val) condition = s > threshold reciprocal_s_before = Tensor(ops.Reciprocal()(s)).broadcast_to(condition.shape) zero = ops.Zeros()(condition.shape, s.dtype) s_pseudoinv = ops.select(condition, reciprocal_s_before, zero) output = ops.matmul(v * s_pseudoinv.expand_dims(-2), _nd_transpose(ops.Conj()(u))) else: s, u = _compare_eigh(x) s_abs = s.abs() max_singular_val = ops.amax(s_abs, -1, True) threshold = ops.maximum(atol.expand_dims(-1), rtol.expand_dims(-1) * max_singular_val) condition = s_abs > threshold reciprocal_s_before = Tensor(ops.Reciprocal()(s)) zero = ops.Zeros()(condition.shape, s.dtype) s_pseudoinv = ops.select(condition, reciprocal_s_before, zero) output = ops.matmul(u * s_pseudoinv.expand_dims(-2), _nd_transpose(ops.Conj()(u))) return output
def _compare_eigh(x): """ compare eigh """ from mindspore.scipy.ops import Eigh s, u = Eigh()(x) return s, u def _nd_transpose(a): """ _nd_transpose """ dims = a.ndim if dims < 2: raise TypeError("to do _nd_transpose for input a's ndim is not greater or equal to 2d, which is invalid.") axes = ops.make_range(0, dims) axes = axes[:-2] + (axes[-1],) + (axes[-2],) return ops.transpose(a, axes) __all__.sort()