Class: NMatrix
- Inherits:
-
Object
- Object
- NMatrix
- Defined in:
- lib/mixed_models/nmatrix_methods.rb
Overview
Copyright © 2015 Alexej Gossmann
Class Method Summary collapse
-
.block_diagonal(*params) ⇒ Object
Generate a block-diagonal NMatrix from the supplied 2D square matrices.
Instance Method Summary collapse
-
#khatri_rao_rows(mat) ⇒ Object
Compute a simplified version of the Khatri-Rao product of
selfand other NMatrixmat. -
#kron_prod_1D(v) ⇒ Object
Compute the the Kronecker product of two row vectors (NMatrix of shape [1,n]).
-
#matrix_valued_solve(rhs_mat) ⇒ Object
Solve a matrix-valued linear system A * X = B, where A is a nxn matrix, B and X are nxp matrices.
-
#triangular_solve(uplo, rhs) ⇒ Object
Solve a linear system A * X = B, where A is a lower triangular matrix, X and B are vectors or matrices.
Class Method Details
.block_diagonal(*params) ⇒ Object
Generate a block-diagonal NMatrix from the supplied 2D square matrices.
Arguments
-
params- An array that collects all arguments passed to the method. The method can receive any number of arguments. The last entry ofparamsis a hash of options from NMatrix#initialize. All other entries ofparamsare the blocks of the desired block-diagonal matrix, which are supplied as square 2D NMatrix objects.
Usage
a = NMatrix.new([2,2],[1,2,3,4])
b = NMatrix.new([1,1],[123],dtype: :int32)
c = NMatrix.new([3,3],[1,2,3,1,2,3,1,2,3], dtype: :float64)
m = NMatrix.block_diagonal(a,b,c,dtype: :int64, stype: :yale)
=>
[
[1, 2, 0, 0, 0, 0]
[3, 4, 0, 0, 0, 0]
[0, 0, 123, 0, 0, 0]
[0, 0, 0, 1, 2, 3]
[0, 0, 0, 1, 2, 3]
[0, 0, 0, 1, 2, 3]
]
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/mixed_models/nmatrix_methods.rb', line 134 def block_diagonal(*params) = params.last.is_a?(Hash) ? params.pop : {} block_sizes = [] #holds the size of each matrix block params.each do |b| raise ArgumentError, "Only NMatrix objects allowed" unless b.is_a?(NMatrix) raise ArgumentError, "Only 2D matrices allowed" unless b.shape.size == 2 raise ArgumentError, "Only square matrices allowed" unless b.shape[0] == b.shape[1] block_sizes << b.shape[0] end bdiag = NMatrix.zeros(block_sizes.sum, ) (0...params.length).each do |n| # First determine the size and position of the n'th block in the block-diagonal matrix k = block_sizes[n] block_pos = block_sizes[0...n].sum # populate the n'th block in the block-diagonal matrix (0...k).each do |i| (0...k).each do |j| bdiag[block_pos+i,block_pos+j] = params[n][i,j] end end end return bdiag end |
Instance Method Details
#khatri_rao_rows(mat) ⇒ Object
Compute a simplified version of the Khatri-Rao product of self and other NMatrix mat. The i’th row of the resulting matrix is the Kronecker product of the i’th row of self and the i’th row of mat.
Arguments
-
mat- A 2D NMatrix object
Usage
a = NMatrix.new([3,2], [1,2,1,2,1,2], dtype: dtype, stype: stype)
b = NMatrix.new([3,2], (1..6).to_a, dtype: dtype, stype: stype)
m = a.khatri_rao_rows b # => [ [1.0, 2.0, 2.0, 4.0]
[3.0, 4.0, 6.0, 8.0]
[5.0, 6.0, 10.0, 12.0] ]
43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/mixed_models/nmatrix_methods.rb', line 43 def khatri_rao_rows(mat) raise NotImplementedError, "Implemented for 2D matrices only" unless self.dimensions==2 and mat.dimensions==2 n = self.shape[0] raise NotImplementedError, "Both matrices must have the same number of rows" unless n==mat.shape[0] m = self.shape[1]*mat.shape[1] prod_dtype = NMatrix.upcast(self.dtype, mat.dtype) khrao_prod = NMatrix.new([n,m], dtype: prod_dtype) (0...n).each do |i| kronecker_prod = self.row(i).kron_prod_1D mat.row(i) khrao_prod[i,0...m] = kronecker_prod end return khrao_prod end |
#kron_prod_1D(v) ⇒ Object
17 18 19 20 21 22 23 24 25 |
# File 'lib/mixed_models/nmatrix_methods.rb', line 17 def kron_prod_1D(v) unless self.dimensions==2 && v.dimensions==2 && self.shape[0]==1 && v.shape[0]==1 raise ArgumentError, "Implemented for NMatrix of shape [1,n] (i.e. one row) only." end #TODO: maybe some outer product function from LAPACK would be more efficient to compute for m m = self.transpose.dot v l = self.shape[1]*v.shape[1] return m.reshape([1,l]) end |
#matrix_valued_solve(rhs_mat) ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/mixed_models/nmatrix_methods.rb', line 69 def matrix_valued_solve(rhs_mat) # This is a workaround. See NMatrix issue: # https://github.com/SciRuby/nmatrix/issues/374 rhs_mat_t = rhs_mat.transpose lhs_mat = self.clone NMatrix::LAPACK::clapack_gesv(:row, lhs_mat.shape[0], rhs_mat.shape[1], lhs_mat, lhs_mat.shape[0], rhs_mat_t, rhs_mat.shape[0]) return rhs_mat_t.transpose end |
#triangular_solve(uplo, rhs) ⇒ Object
Solve a linear system A * X = B, where A is a lower triangular matrix, X and B are vectors or matrices.
Arguments
-
uplo- flag indicating whether the matrix is lower or upper triangular; possible values are :lower and :upper -
rhs- the right hand side, an NMatrix object
Usage
a = NMatrix.new(3, [4, 0, 0, -2, 2, 0, -4, -2, -0.5], dtype: :float64)
b = NMatrix.new([3,1], [-1, 17, -9], dtype: :float64)
x = a.triangular_solve(:lower, b)
a.dot x # => [ [-1.0] [17.0] [-9.0] ]
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/mixed_models/nmatrix_methods.rb', line 95 def triangular_solve(uplo, rhs) raise(ArgumentError, "uplo should be :lower or :upper") unless uplo == :lower or uplo == :upper b = rhs.clone # this is the correct function call; it came up in during # discussion in https://github.com/SciRuby/nmatrix/issues/374 NMatrix::BLAS::cblas_trsm(:row, :left, uplo, false, :nounit, b.shape[0], b.shape[1], 1.0, self, self.shape[0], b, b.shape[1]) return b end |