You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1682 lines
44 KiB
Python

#******************************************************************************
# Copyright (C) 2013 Kenneth L. Ho
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer. Redistributions in binary
# form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# None of the names of the copyright holders may be used to endorse or
# promote products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#******************************************************************************
"""
Direct wrappers for Fortran `id_dist` backend.
"""
import scipy.linalg._interpolative as _id
import numpy as np
_RETCODE_ERROR = RuntimeError("nonzero return code")
def _asfortranarray_copy(A):
"""
Same as np.asfortranarray, but ensure a copy
"""
A = np.asarray(A)
if A.flags.f_contiguous:
A = A.copy(order="F")
else:
A = np.asfortranarray(A)
return A
#------------------------------------------------------------------------------
# id_rand.f
#------------------------------------------------------------------------------
def id_srand(n):
"""
Generate standard uniform pseudorandom numbers via a very efficient lagged
Fibonacci method.
:param n:
Number of pseudorandom numbers to generate.
:type n: int
:return:
Pseudorandom numbers.
:rtype: :class:`numpy.ndarray`
"""
return _id.id_srand(n)
def id_srandi(t):
"""
Initialize seed values for :func:`id_srand` (any appropriately random
numbers will do).
:param t:
Array of 55 seed values.
:type t: :class:`numpy.ndarray`
"""
t = np.asfortranarray(t)
_id.id_srandi(t)
def id_srando():
"""
Reset seed values to their original values.
"""
_id.id_srando()
#------------------------------------------------------------------------------
# idd_frm.f
#------------------------------------------------------------------------------
def idd_frm(n, w, x):
"""
Transform real vector via a composition of Rokhlin's random transform,
random subselection, and an FFT.
In contrast to :func:`idd_sfrm`, this routine works best when the length of
the transformed vector is the power-of-two integer output by
:func:`idd_frmi`, or when the length is not specified but instead
determined a posteriori from the output. The returned transformed vector is
randomly permuted.
:param n:
Greatest power-of-two integer satisfying `n <= x.size` as obtained from
:func:`idd_frmi`; `n` is also the length of the output vector.
:type n: int
:param w:
Initialization array constructed by :func:`idd_frmi`.
:type w: :class:`numpy.ndarray`
:param x:
Vector to be transformed.
:type x: :class:`numpy.ndarray`
:return:
Transformed vector.
:rtype: :class:`numpy.ndarray`
"""
return _id.idd_frm(n, w, x)
def idd_sfrm(l, n, w, x):
"""
Transform real vector via a composition of Rokhlin's random transform,
random subselection, and an FFT.
In contrast to :func:`idd_frm`, this routine works best when the length of
the transformed vector is known a priori.
:param l:
Length of transformed vector, satisfying `l <= n`.
:type l: int
:param n:
Greatest power-of-two integer satisfying `n <= x.size` as obtained from
:func:`idd_sfrmi`.
:type n: int
:param w:
Initialization array constructed by :func:`idd_sfrmi`.
:type w: :class:`numpy.ndarray`
:param x:
Vector to be transformed.
:type x: :class:`numpy.ndarray`
:return:
Transformed vector.
:rtype: :class:`numpy.ndarray`
"""
return _id.idd_sfrm(l, n, w, x)
def idd_frmi(m):
"""
Initialize data for :func:`idd_frm`.
:param m:
Length of vector to be transformed.
:type m: int
:return:
Greatest power-of-two integer `n` satisfying `n <= m`.
:rtype: int
:return:
Initialization array to be used by :func:`idd_frm`.
:rtype: :class:`numpy.ndarray`
"""
return _id.idd_frmi(m)
def idd_sfrmi(l, m):
"""
Initialize data for :func:`idd_sfrm`.
:param l:
Length of output transformed vector.
:type l: int
:param m:
Length of the vector to be transformed.
:type m: int
:return:
Greatest power-of-two integer `n` satisfying `n <= m`.
:rtype: int
:return:
Initialization array to be used by :func:`idd_sfrm`.
:rtype: :class:`numpy.ndarray`
"""
return _id.idd_sfrmi(l, m)
#------------------------------------------------------------------------------
# idd_id.f
#------------------------------------------------------------------------------
def iddp_id(eps, A):
"""
Compute ID of a real matrix to a specified relative precision.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = _asfortranarray_copy(A)
k, idx, rnorms = _id.iddp_id(eps, A)
n = A.shape[1]
proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def iddr_id(A, k):
"""
Compute ID of a real matrix to a specified rank.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = _asfortranarray_copy(A)
idx, rnorms = _id.iddr_id(A, k)
n = A.shape[1]
proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
return idx, proj
def idd_reconid(B, idx, proj):
"""
Reconstruct matrix from real ID.
:param B:
Skeleton matrix.
:type B: :class:`numpy.ndarray`
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Reconstructed matrix.
:rtype: :class:`numpy.ndarray`
"""
B = np.asfortranarray(B)
if proj.size > 0:
return _id.idd_reconid(B, idx, proj)
else:
return B[:, np.argsort(idx)]
def idd_reconint(idx, proj):
"""
Reconstruct interpolation matrix from real ID.
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Interpolation matrix.
:rtype: :class:`numpy.ndarray`
"""
return _id.idd_reconint(idx, proj)
def idd_copycols(A, k, idx):
"""
Reconstruct skeleton matrix from real ID.
:param A:
Original matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:return:
Skeleton matrix.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
return _id.idd_copycols(A, k, idx)
#------------------------------------------------------------------------------
# idd_id2svd.f
#------------------------------------------------------------------------------
def idd_id2svd(B, idx, proj):
"""
Convert real ID to SVD.
:param B:
Skeleton matrix.
:type B: :class:`numpy.ndarray`
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
B = np.asfortranarray(B)
U, V, S, ier = _id.idd_id2svd(B, idx, proj)
if ier:
raise _RETCODE_ERROR
return U, V, S
#------------------------------------------------------------------------------
# idd_snorm.f
#------------------------------------------------------------------------------
def idd_snorm(m, n, matvect, matvec, its=20):
"""
Estimate spectral norm of a real matrix by the randomized power method.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param its:
Number of power method iterations.
:type its: int
:return:
Spectral norm estimate.
:rtype: float
"""
snorm, v = _id.idd_snorm(m, n, matvect, matvec, its)
return snorm
def idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its=20):
"""
Estimate spectral norm of the difference of two real matrices by the
randomized power method.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the transpose of the first matrix to a vector, with
call signature `y = matvect(x)`, where `x` and `y` are the input and
output vectors, respectively.
:type matvect: function
:param matvect2:
Function to apply the transpose of the second matrix to a vector, with
call signature `y = matvect2(x)`, where `x` and `y` are the input and
output vectors, respectively.
:type matvect2: function
:param matvec:
Function to apply the first matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param matvec2:
Function to apply the second matrix to a vector, with call signature
`y = matvec2(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec2: function
:param its:
Number of power method iterations.
:type its: int
:return:
Spectral norm estimate of matrix difference.
:rtype: float
"""
return _id.idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its)
#------------------------------------------------------------------------------
# idd_svd.f
#------------------------------------------------------------------------------
def iddr_svd(A, k):
"""
Compute SVD of a real matrix to a specified rank.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
U, V, S, ier = _id.iddr_svd(A, k)
if ier:
raise _RETCODE_ERROR
return U, V, S
def iddp_svd(eps, A):
"""
Compute SVD of a real matrix to a specified relative precision.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
k, iU, iV, iS, w, ier = _id.iddp_svd(eps, A)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# iddp_aid.f
#------------------------------------------------------------------------------
def iddp_aid(eps, A):
"""
Compute ID of a real matrix to a specified relative precision using random
sampling.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, w = idd_frmi(m)
proj = np.empty(n*(2*n2 + 1) + n2 + 1, order='F')
k, idx, proj = _id.iddp_aid(eps, A, w, proj)
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def idd_estrank(eps, A):
"""
Estimate rank of a real matrix to a specified relative precision using
random sampling.
The output rank is typically about 8 higher than the actual rank.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank estimate.
:rtype: int
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, w = idd_frmi(m)
ra = np.empty(n*n2 + (n + 1)*(n2 + 1), order='F')
k, ra = _id.idd_estrank(eps, A, w, ra)
return k
#------------------------------------------------------------------------------
# iddp_asvd.f
#------------------------------------------------------------------------------
def iddp_asvd(eps, A):
"""
Compute SVD of a real matrix to a specified relative precision using random
sampling.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, winit = _id.idd_frmi(m)
w = np.empty(
max((min(m, n) + 1)*(3*m + 5*n + 1) + 25*min(m, n)**2,
(2*n + 1)*(n2 + 1)),
order='F')
k, iU, iV, iS, w, ier = _id.iddp_asvd(eps, A, winit, w)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# iddp_rid.f
#------------------------------------------------------------------------------
def iddp_rid(eps, m, n, matvect):
"""
Compute ID of a real matrix to a specified relative precision using random
matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
proj = np.empty(m + 1 + 2*n*(min(m, n) + 1), order='F')
k, idx, proj, ier = _id.iddp_rid(eps, m, n, matvect, proj)
if ier != 0:
raise _RETCODE_ERROR
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def idd_findrank(eps, m, n, matvect):
"""
Estimate rank of a real matrix to a specified relative precision using
random matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:return:
Rank estimate.
:rtype: int
"""
k, ra, ier = _id.idd_findrank(eps, m, n, matvect)
if ier:
raise _RETCODE_ERROR
return k
#------------------------------------------------------------------------------
# iddp_rsvd.f
#------------------------------------------------------------------------------
def iddp_rsvd(eps, m, n, matvect, matvec):
"""
Compute SVD of a real matrix to a specified relative precision using random
matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
k, iU, iV, iS, w, ier = _id.iddp_rsvd(eps, m, n, matvect, matvec)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# iddr_aid.f
#------------------------------------------------------------------------------
def iddr_aid(A, k):
"""
Compute ID of a real matrix to a specified rank using random sampling.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
w = iddr_aidi(m, n, k)
idx, proj = _id.iddr_aid(A, k, w)
if k == n:
proj = np.empty((k, n-k), dtype='float64', order='F')
else:
proj = proj.reshape((k, n-k), order='F')
return idx, proj
def iddr_aidi(m, n, k):
"""
Initialize array for :func:`iddr_aid`.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param k:
Rank of ID.
:type k: int
:return:
Initialization array to be used by :func:`iddr_aid`.
:rtype: :class:`numpy.ndarray`
"""
return _id.iddr_aidi(m, n, k)
#------------------------------------------------------------------------------
# iddr_asvd.f
#------------------------------------------------------------------------------
def iddr_asvd(A, k):
"""
Compute SVD of a real matrix to a specified rank using random sampling.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
w = np.empty((2*k + 28)*m + (6*k + 21)*n + 25*k**2 + 100, order='F')
w_ = iddr_aidi(m, n, k)
w[:w_.size] = w_
U, V, S, ier = _id.iddr_asvd(A, k, w)
if ier != 0:
raise _RETCODE_ERROR
return U, V, S
#------------------------------------------------------------------------------
# iddr_rid.f
#------------------------------------------------------------------------------
def iddr_rid(m, n, matvect, k):
"""
Compute ID of a real matrix to a specified rank using random matrix-vector
multiplication.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
idx, proj = _id.iddr_rid(m, n, matvect, k)
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return idx, proj
#------------------------------------------------------------------------------
# iddr_rsvd.f
#------------------------------------------------------------------------------
def iddr_rsvd(m, n, matvect, matvec, k):
"""
Compute SVD of a real matrix to a specified rank using random matrix-vector
multiplication.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matvect:
Function to apply the matrix transpose to a vector, with call signature
`y = matvect(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvect: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
U, V, S, ier = _id.iddr_rsvd(m, n, matvect, matvec, k)
if ier != 0:
raise _RETCODE_ERROR
return U, V, S
#------------------------------------------------------------------------------
# idz_frm.f
#------------------------------------------------------------------------------
def idz_frm(n, w, x):
"""
Transform complex vector via a composition of Rokhlin's random transform,
random subselection, and an FFT.
In contrast to :func:`idz_sfrm`, this routine works best when the length of
the transformed vector is the power-of-two integer output by
:func:`idz_frmi`, or when the length is not specified but instead
determined a posteriori from the output. The returned transformed vector is
randomly permuted.
:param n:
Greatest power-of-two integer satisfying `n <= x.size` as obtained from
:func:`idz_frmi`; `n` is also the length of the output vector.
:type n: int
:param w:
Initialization array constructed by :func:`idz_frmi`.
:type w: :class:`numpy.ndarray`
:param x:
Vector to be transformed.
:type x: :class:`numpy.ndarray`
:return:
Transformed vector.
:rtype: :class:`numpy.ndarray`
"""
return _id.idz_frm(n, w, x)
def idz_sfrm(l, n, w, x):
"""
Transform complex vector via a composition of Rokhlin's random transform,
random subselection, and an FFT.
In contrast to :func:`idz_frm`, this routine works best when the length of
the transformed vector is known a priori.
:param l:
Length of transformed vector, satisfying `l <= n`.
:type l: int
:param n:
Greatest power-of-two integer satisfying `n <= x.size` as obtained from
:func:`idz_sfrmi`.
:type n: int
:param w:
Initialization array constructed by :func:`idd_sfrmi`.
:type w: :class:`numpy.ndarray`
:param x:
Vector to be transformed.
:type x: :class:`numpy.ndarray`
:return:
Transformed vector.
:rtype: :class:`numpy.ndarray`
"""
return _id.idz_sfrm(l, n, w, x)
def idz_frmi(m):
"""
Initialize data for :func:`idz_frm`.
:param m:
Length of vector to be transformed.
:type m: int
:return:
Greatest power-of-two integer `n` satisfying `n <= m`.
:rtype: int
:return:
Initialization array to be used by :func:`idz_frm`.
:rtype: :class:`numpy.ndarray`
"""
return _id.idz_frmi(m)
def idz_sfrmi(l, m):
"""
Initialize data for :func:`idz_sfrm`.
:param l:
Length of output transformed vector.
:type l: int
:param m:
Length of the vector to be transformed.
:type m: int
:return:
Greatest power-of-two integer `n` satisfying `n <= m`.
:rtype: int
:return:
Initialization array to be used by :func:`idz_sfrm`.
:rtype: :class:`numpy.ndarray`
"""
return _id.idz_sfrmi(l, m)
#------------------------------------------------------------------------------
# idz_id.f
#------------------------------------------------------------------------------
def idzp_id(eps, A):
"""
Compute ID of a complex matrix to a specified relative precision.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = _asfortranarray_copy(A)
k, idx, rnorms = _id.idzp_id(eps, A)
n = A.shape[1]
proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def idzr_id(A, k):
"""
Compute ID of a complex matrix to a specified rank.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = _asfortranarray_copy(A)
idx, rnorms = _id.idzr_id(A, k)
n = A.shape[1]
proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
return idx, proj
def idz_reconid(B, idx, proj):
"""
Reconstruct matrix from complex ID.
:param B:
Skeleton matrix.
:type B: :class:`numpy.ndarray`
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Reconstructed matrix.
:rtype: :class:`numpy.ndarray`
"""
B = np.asfortranarray(B)
if proj.size > 0:
return _id.idz_reconid(B, idx, proj)
else:
return B[:, np.argsort(idx)]
def idz_reconint(idx, proj):
"""
Reconstruct interpolation matrix from complex ID.
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Interpolation matrix.
:rtype: :class:`numpy.ndarray`
"""
return _id.idz_reconint(idx, proj)
def idz_copycols(A, k, idx):
"""
Reconstruct skeleton matrix from complex ID.
:param A:
Original matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:return:
Skeleton matrix.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
return _id.idz_copycols(A, k, idx)
#------------------------------------------------------------------------------
# idz_id2svd.f
#------------------------------------------------------------------------------
def idz_id2svd(B, idx, proj):
"""
Convert complex ID to SVD.
:param B:
Skeleton matrix.
:type B: :class:`numpy.ndarray`
:param idx:
Column index array.
:type idx: :class:`numpy.ndarray`
:param proj:
Interpolation coefficients.
:type proj: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
B = np.asfortranarray(B)
U, V, S, ier = _id.idz_id2svd(B, idx, proj)
if ier:
raise _RETCODE_ERROR
return U, V, S
#------------------------------------------------------------------------------
# idz_snorm.f
#------------------------------------------------------------------------------
def idz_snorm(m, n, matveca, matvec, its=20):
"""
Estimate spectral norm of a complex matrix by the randomized power method.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param its:
Number of power method iterations.
:type its: int
:return:
Spectral norm estimate.
:rtype: float
"""
snorm, v = _id.idz_snorm(m, n, matveca, matvec, its)
return snorm
def idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its=20):
"""
Estimate spectral norm of the difference of two complex matrices by the
randomized power method.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the adjoint of the first matrix to a vector, with
call signature `y = matveca(x)`, where `x` and `y` are the input and
output vectors, respectively.
:type matveca: function
:param matveca2:
Function to apply the adjoint of the second matrix to a vector, with
call signature `y = matveca2(x)`, where `x` and `y` are the input and
output vectors, respectively.
:type matveca2: function
:param matvec:
Function to apply the first matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param matvec2:
Function to apply the second matrix to a vector, with call signature
`y = matvec2(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec2: function
:param its:
Number of power method iterations.
:type its: int
:return:
Spectral norm estimate of matrix difference.
:rtype: float
"""
return _id.idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its)
#------------------------------------------------------------------------------
# idz_svd.f
#------------------------------------------------------------------------------
def idzr_svd(A, k):
"""
Compute SVD of a complex matrix to a specified rank.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
U, V, S, ier = _id.idzr_svd(A, k)
if ier:
raise _RETCODE_ERROR
return U, V, S
def idzp_svd(eps, A):
"""
Compute SVD of a complex matrix to a specified relative precision.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
k, iU, iV, iS, w, ier = _id.idzp_svd(eps, A)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# idzp_aid.f
#------------------------------------------------------------------------------
def idzp_aid(eps, A):
"""
Compute ID of a complex matrix to a specified relative precision using
random sampling.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, w = idz_frmi(m)
proj = np.empty(n*(2*n2 + 1) + n2 + 1, dtype='complex128', order='F')
k, idx, proj = _id.idzp_aid(eps, A, w, proj)
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def idz_estrank(eps, A):
"""
Estimate rank of a complex matrix to a specified relative precision using
random sampling.
The output rank is typically about 8 higher than the actual rank.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Rank estimate.
:rtype: int
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, w = idz_frmi(m)
ra = np.empty(n*n2 + (n + 1)*(n2 + 1), dtype='complex128', order='F')
k, ra = _id.idz_estrank(eps, A, w, ra)
return k
#------------------------------------------------------------------------------
# idzp_asvd.f
#------------------------------------------------------------------------------
def idzp_asvd(eps, A):
"""
Compute SVD of a complex matrix to a specified relative precision using
random sampling.
:param eps:
Relative precision.
:type eps: float
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
n2, winit = _id.idz_frmi(m)
w = np.empty(
max((min(m, n) + 1)*(3*m + 5*n + 11) + 8*min(m, n)**2,
(2*n + 1)*(n2 + 1)),
dtype=np.complex128, order='F')
k, iU, iV, iS, w, ier = _id.idzp_asvd(eps, A, winit, w)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# idzp_rid.f
#------------------------------------------------------------------------------
def idzp_rid(eps, m, n, matveca):
"""
Compute ID of a complex matrix to a specified relative precision using
random matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:return:
Rank of ID.
:rtype: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
proj = np.empty(
m + 1 + 2*n*(min(m, n) + 1),
dtype=np.complex128, order='F')
k, idx, proj, ier = _id.idzp_rid(eps, m, n, matveca, proj)
if ier:
raise _RETCODE_ERROR
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return k, idx, proj
def idz_findrank(eps, m, n, matveca):
"""
Estimate rank of a complex matrix to a specified relative precision using
random matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:return:
Rank estimate.
:rtype: int
"""
k, ra, ier = _id.idz_findrank(eps, m, n, matveca)
if ier:
raise _RETCODE_ERROR
return k
#------------------------------------------------------------------------------
# idzp_rsvd.f
#------------------------------------------------------------------------------
def idzp_rsvd(eps, m, n, matveca, matvec):
"""
Compute SVD of a complex matrix to a specified relative precision using
random matrix-vector multiplication.
:param eps:
Relative precision.
:type eps: float
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
k, iU, iV, iS, w, ier = _id.idzp_rsvd(eps, m, n, matveca, matvec)
if ier:
raise _RETCODE_ERROR
U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
S = w[iS-1:iS+k-1]
return U, V, S
#------------------------------------------------------------------------------
# idzr_aid.f
#------------------------------------------------------------------------------
def idzr_aid(A, k):
"""
Compute ID of a complex matrix to a specified rank using random sampling.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
w = idzr_aidi(m, n, k)
idx, proj = _id.idzr_aid(A, k, w)
if k == n:
proj = np.empty((k, n-k), dtype='complex128', order='F')
else:
proj = proj.reshape((k, n-k), order='F')
return idx, proj
def idzr_aidi(m, n, k):
"""
Initialize array for :func:`idzr_aid`.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param k:
Rank of ID.
:type k: int
:return:
Initialization array to be used by :func:`idzr_aid`.
:rtype: :class:`numpy.ndarray`
"""
return _id.idzr_aidi(m, n, k)
#------------------------------------------------------------------------------
# idzr_asvd.f
#------------------------------------------------------------------------------
def idzr_asvd(A, k):
"""
Compute SVD of a complex matrix to a specified rank using random sampling.
:param A:
Matrix.
:type A: :class:`numpy.ndarray`
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
A = np.asfortranarray(A)
m, n = A.shape
w = np.empty(
(2*k + 22)*m + (6*k + 21)*n + 8*k**2 + 10*k + 90,
dtype='complex128', order='F')
w_ = idzr_aidi(m, n, k)
w[:w_.size] = w_
U, V, S, ier = _id.idzr_asvd(A, k, w)
if ier:
raise _RETCODE_ERROR
return U, V, S
#------------------------------------------------------------------------------
# idzr_rid.f
#------------------------------------------------------------------------------
def idzr_rid(m, n, matveca, k):
"""
Compute ID of a complex matrix to a specified rank using random
matrix-vector multiplication.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:param k:
Rank of ID.
:type k: int
:return:
Column index array.
:rtype: :class:`numpy.ndarray`
:return:
Interpolation coefficients.
:rtype: :class:`numpy.ndarray`
"""
idx, proj = _id.idzr_rid(m, n, matveca, k)
proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
return idx, proj
#------------------------------------------------------------------------------
# idzr_rsvd.f
#------------------------------------------------------------------------------
def idzr_rsvd(m, n, matveca, matvec, k):
"""
Compute SVD of a complex matrix to a specified rank using random
matrix-vector multiplication.
:param m:
Matrix row dimension.
:type m: int
:param n:
Matrix column dimension.
:type n: int
:param matveca:
Function to apply the matrix adjoint to a vector, with call signature
`y = matveca(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matveca: function
:param matvec:
Function to apply the matrix to a vector, with call signature
`y = matvec(x)`, where `x` and `y` are the input and output vectors,
respectively.
:type matvec: function
:param k:
Rank of SVD.
:type k: int
:return:
Left singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Right singular vectors.
:rtype: :class:`numpy.ndarray`
:return:
Singular values.
:rtype: :class:`numpy.ndarray`
"""
U, V, S, ier = _id.idzr_rsvd(m, n, matveca, matvec, k)
if ier:
raise _RETCODE_ERROR
return U, V, S