class RandSVD

RandSVD is a class that performs truncated singular value decomposition using a randomized algorithm.

Constants

VERSION

Attributes

seed[R]

Public Class Methods

gesdd(mat, k, t = 0, seed = nil) click to toggle source

Compute the randomized singular value decompostion using NMatrix::LAPACK.gesdd method.

@param mat [NMatrix] The m-by-n input matrix to be decomposed. @param k [Integer] The number of singular values. @param t [Integer] The number of iterations for orthogonalization. @param seed [Integer] The random seed used to generate the random matrix.

@return [Array<NMatrix>]

Returns array containing the m-by-k matrix of left-singular vectors,
the k-by-1 matrix containing the singular values in decreasing order,
and the k-by-n transposed matrix of right-singular vectors.
# File lib/randsvd.rb, line 42
def gesdd(mat, k, t = 0, seed = nil)
  seed ||= srand
  @seed = seed
  rsvd(mat, k, t, 1)
end
gesvd(mat, k, t = 0, seed = nil) click to toggle source

Compute the randomized singular value decompostion using NMatrix::LAPACK.gesvd method.

@param mat [NMatrix] The m-by-n input matrix to be decomposed. @param k [Integer] The number of singular values. @param t [Integer] The number of iterations for orthogonalization. @param seed [Integer] The random seed used to generate the random matrix.

@return [Array<NMatrix>]

Returns array containing the m-by-k matrix of left-singular vectors,
the k-by-1 matrix containing the singular values in decreasing order,
and the k-by-n transposed matrix of right-singular vectors.
# File lib/randsvd.rb, line 24
def gesvd(mat, k, t = 0, seed = nil)
  seed ||= srand
  @seed = seed
  rsvd(mat, k, t, 0)
end

Private Class Methods

make_orthonormal_mat(mat, l, t) click to toggle source
# File lib/randsvd.rb, line 70
def make_orthonormal_mat(mat, l, t)
  m, n = mat.shape
  mat_q, = mat.transpose.dot(rand_normal([m, l])).factorize_qr
  t.times do
    mat_p, = mat.dot(mat_q[0..n - 1, 0..l - 1]).factorize_qr
    mat_q, = mat.transpose.dot(mat_p[0..m - 1, 0..l - 1]).factorize_qr
  end
  mat_q[0..n - 1, 0..l - 1]
end
rand_normal(shape, mu = 0.0, sigma = 1.0) click to toggle source
# File lib/randsvd.rb, line 64
def rand_normal(shape, mu = 0.0, sigma = 1.0)
  a = rand_uniform(shape)
  b = rand_uniform(shape)
  ((a.log * -2.0).sqrt * (b * 2.0 * Math::PI).sin) * sigma + mu
end
rand_uniform(shape) click to toggle source
# File lib/randsvd.rb, line 58
def rand_uniform(shape)
  rng = Random.new(@seed)
  rnd_vals = Array.new(NMatrix.size(shape)) { rng.rand }
  NMatrix.new(shape, rnd_vals, dtype: :float64, stype: :dense)
end
rsvd(mat, k, t, svd_type) click to toggle source
# File lib/randsvd.rb, line 50
def rsvd(mat, k, t, svd_type)
  n = mat.shape[1]
  mat_q = make_orthonormal_mat(mat, [k + 10, n].min, t)
  mat_a = mat.dot(mat_q)
  mat_u, vec_s, mat_vt = svd_type.zero? ? mat_a.gesvd : mat_a.gesdd
  truncate_svd_mats(mat_u, vec_s, mat_q.dot(mat_vt.transpose), k)
end
truncate_svd_mats(mat_u, vec_s, mat_v, k) click to toggle source
# File lib/randsvd.rb, line 80
def truncate_svd_mats(mat_u, vec_s, mat_v, k)
  m, = mat_u.shape
  n, = mat_v.shape
  [mat_u[0..m - 1, 0..k - 1],
   vec_s[0..k - 1],
   mat_v[0..n - 1, 0..k - 1].transpose]
end