1681 lines
44 KiB
Python
1681 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
|