Module: MachineLearningWorkbench::Monkey::AdvancelyOperationable
- Defined in:
- lib/machine_learning_workbench/monkey.rb
Overview
how am I supposed to name these things??
Instance Method Summary collapse
-
#eigen(which = :both) ⇒ Array<NMatrix, NMatrix[, NMatrix]>
Calculate matrix eigenvalues and eigenvectors using LAPACK often returned! For symmetric matrices use #eigen_symm_right below.
-
#eigen_symm ⇒ Array<NMatrix, NMatrix>
Eigenvalues and right eigenvectors for symmetric matrices using LAPACK.
-
#exponential ⇒ NMatrix
Matrix exponential: ‘e^self` (not to be confused with `self^n`!).
-
#outer(other) ⇒ NMatrix
Outer matrix relationship generalization.
-
#outer_flat(other) ⇒ NMatrix
Flat-output generalized outer relationship.
-
#to_consistent_a ⇒ Array<Array>
(also: #to_ca)
‘NMatrix#to_a` has inconsistent behavior: single-row matrices are converted to one-dimensional Arrays rather than a 2D Array with only one row.
Instance Method Details
#eigen(which = :both) ⇒ Array<NMatrix, NMatrix[, NMatrix]>
requires LAPACK
WARNING! a param ‘which` different than :both alters the returns
WARNING! machine-precision-error imaginary part Complex
Calculate matrix eigenvalues and eigenvectors using LAPACK often returned! For symmetric matrices use #eigen_symm_right below
103 104 105 106 |
# File 'lib/machine_learning_workbench/monkey.rb', line 103 def eigen which=:both raise ArgumentError unless [:both, :left, :right].include? which NMatrix::LAPACK.geev(self, which) end |
#eigen_symm ⇒ Array<NMatrix, NMatrix>
could it be possible to save some of the transpositions?
code taken from gem ‘nmatrix-atlas` NMatrix::LAPACK#geev
FOR SYMMETRIC MATRICES ONLY!!
WARNING: will return real matrices, imaginary parts are discarded!
WARNING: only left eigenvectors will be returned!
Eigenvalues and right eigenvectors for symmetric matrices using LAPACK
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/machine_learning_workbench/monkey.rb', line 115 def eigen_symm # TODO: check for symmetry if not too slow raise TypeError, "Only real-valued matrices" if complex_dtype? raise StorageTypeError, "Only dense matrices (because LAPACK)" unless dense? raise ShapeError, "Only square matrices" unless dim == 2 && shape[0] == shape[1] n = shape[0] # Outputs e_values = NMatrix.new([n, 1], dtype: dtype) e_values_img = NMatrix.new([n, 1], dtype: dtype) # to satisfy C alloc e_vectors = clone_structure NMatrix::LAPACK::lapack_geev( false, # compute left eigenvectors of A? :t, # compute right eigenvectors of A? (left eigenvectors of A**T) n, # order of the matrix transpose, # input matrix => needs to be column-wise # self, n, # leading dimension of matrix e_values, # real part of computed eigenvalues e_values_img, # imaginary part of computed eigenvalues (will be discarded) nil, # left eigenvectors, if applicable n, # leading dimension of left_output e_vectors, # right eigenvectors, if applicable n, # leading dimension of right_output 2*n # no clue what's this ) raise "Uhm why complex eigenvalues?" if e_values_img.any? {|v| v>1e-10} return [e_values, e_vectors.transpose] end |
#exponential ⇒ NMatrix
Matrix exponential: ‘e^self` (not to be confused with `self^n`!)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/machine_learning_workbench/monkey.rb', line 71 def exponential # special case: one-dimensional matrix: just exponentiate the values if (dim == 1) || (dim == 2 && shape.include?(1)) return NMatrix.new shape, collect(&Math.method(:exp)), dtype: dtype end # Eigenvalue decomposition method from scipy/linalg/matfuncs.py#expm2 # TODO: find out why can't I get away without double transpose! e_values, e_vectors = eigen_symm e_vals_exp_dmat = NMatrix.diagonal e_values.collect(&Math.method(:exp)) # ASSUMING WE'RE ONLY USING THIS TO EXPONENTIATE LOG_SIGMA IN XNES # Theoretically we need the right eigenvectors, which for a symmetric # matrix should be just transposes of the eigenvectors. # But we have a positive definite matrix, so the final composition # below holds without transposing # BUT, strangely, I can't seem to get eigen_symm to green the tests # ...with or without transpose # e_vectors = e_vectors.transpose e_vectors.dot(e_vals_exp_dmat).dot(e_vectors.invert)#.transpose end |
#outer(other) ⇒ NMatrix
This implementation works only for 2D matrices (same as most other methods here). It’s a quick hack, a proof of concept barely sufficient for my urgent needs.
Output size is fixed! Since NMatrix does not graciously yield to being composed of other NMatrices (by adapting the shape of the root matrix), the block cannot return matrices in there.
Outer matrix relationship generalization. Make a matrix the same shape as ‘self`; each element is a matrix, with the same shape as `other`, resulting from the interaction of the corresponding element in `self` and all the elements in `other`.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/machine_learning_workbench/monkey.rb', line 43 def outer other # NOTE: Map of map in NMatrix does not work as expected! # self.map { |v1| other.map { |v2| yield(v1,v2) } } # NOTE: this doesn't cut it either... can't capture the structure # NMatrix[ *self.collect { |v1| other.collect { |v2| yield(v1,v2) } } ] raise ArgumentError unless block_given? NMatrix.new(self.shape+other.shape).tap do |m| each_stored_with_indices do |v1,r1,c1| other.each_stored_with_indices do |v2,r2,c2| m[r1,c1,r2,c2] = yield(v1,v2) end end end end |
#outer_flat(other) ⇒ NMatrix
Flat-output generalized outer relationship. Same as ‘#outer`, but the result is a 2-dim matrix of the interactions between all the elements in `self` (as rows) and all the elements in `other` (as columns)
63 64 65 66 67 |
# File 'lib/machine_learning_workbench/monkey.rb', line 63 def outer_flat other raise ArgumentError unless block_given? data = collect { |v1| other.collect { |v2| yield(v1, v2) } } self.class[*data, dtype: dtype] end |
#to_consistent_a ⇒ Array<Array> Also known as: to_ca
‘NMatrix#to_a` has inconsistent behavior: single-row matrices are converted to one-dimensional Arrays rather than a 2D Array with only one row. Patching `#to_a` directly is not feasible as the constructor seems to depend on it, and I have little interest in investigating further.
155 156 157 |
# File 'lib/machine_learning_workbench/monkey.rb', line 155 def to_consistent_a dim == 2 && shape[0] == 1 ? [to_a] : to_a end |