machine_learning_workbench 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/machine_learning_workbench/monkey.rb +179 -179
- data/lib/machine_learning_workbench/tools/verification.rb +17 -15
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59f6c7b552e7165e67222a70e5ceb231bf482d69
|
4
|
+
data.tar.gz: '09e9df7a6e045fadec71456f327f1a8118e31a5d'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5eae025849e2640b3137128a912cb54ce6f48fad9c27c63462dc08cd787c1a53527c2bcdcd06f0230bc0e7b1b50d8699f3778878ea7331f00a66bbc7ec114baf
|
7
|
+
data.tar.gz: 6aced52a85fd32650bdc88810c596d3305d2f3efeab2034a0ac73e58f3691dda5a4013e89a79546da033cb5ed81833bb090b0b69b7d7ed32e94d46b900bab165
|
@@ -26,157 +26,157 @@ module MachineLearningWorkbench::Monkey
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
module AdvancelyOperationable # how am I supposed to name these things??
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
end
|
29
|
+
# module AdvancelyOperationable # how am I supposed to name these things??
|
30
|
+
|
31
|
+
# # Outer matrix relationship generalization.
|
32
|
+
# # Make a matrix the same shape as `self`; each element is a matrix,
|
33
|
+
# # with the same shape as `other`, resulting from the interaction of
|
34
|
+
# # the corresponding element in `self` and all the elements in `other`.
|
35
|
+
# # @param other [NMatrix] other matrix
|
36
|
+
# # @note This implementation works only for 2D matrices (same as most
|
37
|
+
# # other methods here). It's a quick hack, a proof of concept barely
|
38
|
+
# # sufficient for my urgent needs.
|
39
|
+
# # @note Output size is fixed! Since NMatrix does not graciously yield to
|
40
|
+
# # being composed of other NMatrices (by adapting the shape of the root
|
41
|
+
# # matrix), the block cannot return matrices in there.
|
42
|
+
# # @return [NMatrix]
|
43
|
+
# def outer other
|
44
|
+
# # NOTE: Map of map in NMatrix does not work as expected!
|
45
|
+
# # self.map { |v1| other.map { |v2| yield(v1,v2) } }
|
46
|
+
# # NOTE: this doesn't cut it either... can't capture the structure
|
47
|
+
# # NMatrix[ *self.collect { |v1| other.collect { |v2| yield(v1,v2) } } ]
|
48
|
+
# raise ArgumentError unless block_given?
|
49
|
+
# NMatrix.new(self.shape+other.shape).tap do |m|
|
50
|
+
# each_stored_with_indices do |v1,r1,c1|
|
51
|
+
# other.each_stored_with_indices do |v2,r2,c2|
|
52
|
+
# m[r1,c1,r2,c2] = yield(v1,v2)
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
|
58
|
+
# # Flat-output generalized outer relationship. Same as `#outer`, but the
|
59
|
+
# # result is a 2-dim matrix of the interactions between all the elements
|
60
|
+
# # in `self` (as rows) and all the elements in `other` (as columns)
|
61
|
+
# # @param other [NMatrix] other matrix
|
62
|
+
# # @return [NMatrix]
|
63
|
+
# def outer_flat other
|
64
|
+
# raise ArgumentError unless block_given?
|
65
|
+
# data = collect { |v1| other.collect { |v2| yield(v1, v2) } }
|
66
|
+
# self.class[*data, dtype: dtype]
|
67
|
+
# end
|
68
|
+
|
69
|
+
# # Matrix exponential: `e^self` (not to be confused with `self^n`!)
|
70
|
+
# # @return [NMatrix]
|
71
|
+
# def exponential
|
72
|
+
# # special case: one-dimensional matrix: just exponentiate the values
|
73
|
+
# if (dim == 1) || (dim == 2 && shape.include?(1))
|
74
|
+
# return NMatrix.new shape, collect(&Math.method(:exp)), dtype: dtype
|
75
|
+
# end
|
76
|
+
|
77
|
+
# # Eigenvalue decomposition method from scipy/linalg/matfuncs.py#expm2
|
78
|
+
|
79
|
+
# # TODO: find out why can't I get away without double transpose!
|
80
|
+
# e_values, e_vectors = eigen_symm
|
81
|
+
|
82
|
+
# e_vals_exp_dmat = NMatrix.diagonal e_values.collect(&Math.method(:exp))
|
83
|
+
# # ASSUMING WE'RE ONLY USING THIS TO EXPONENTIATE LOG_SIGMA IN XNES
|
84
|
+
# # Theoretically we need the right eigenvectors, which for a symmetric
|
85
|
+
# # matrix should be just transposes of the eigenvectors.
|
86
|
+
# # But we have a positive definite matrix, so the final composition
|
87
|
+
# # below holds without transposing
|
88
|
+
# # BUT, strangely, I can't seem to get eigen_symm to green the tests
|
89
|
+
# # ...with or without transpose
|
90
|
+
# # e_vectors = e_vectors.transpose
|
91
|
+
# e_vectors.dot(e_vals_exp_dmat).dot(e_vectors.invert)#.transpose
|
92
|
+
# end
|
93
|
+
|
94
|
+
# # Calculate matrix eigenvalues and eigenvectors using LAPACK
|
95
|
+
# # @param which [:both, :left, :right] which eigenvectors do you want?
|
96
|
+
# # @return [Array<NMatrix, NMatrix[, NMatrix]>]
|
97
|
+
# # eigenvalues (as column vector), left eigenvectors, right eigenvectors.
|
98
|
+
# # A value different than `:both` for param `which` reduces the return size.
|
99
|
+
# # @note requires LAPACK
|
100
|
+
# # @note WARNING! a param `which` different than :both alters the returns
|
101
|
+
# # @note WARNING! machine-precision-error imaginary part Complex
|
102
|
+
# # often returned! For symmetric matrices use #eigen_symm_right below
|
103
|
+
# def eigen which=:both
|
104
|
+
# raise ArgumentError unless [:both, :left, :right].include? which
|
105
|
+
# NMatrix::LAPACK.geev(self, which)
|
106
|
+
# end
|
107
|
+
|
108
|
+
# # Eigenvalues and right eigenvectors for symmetric matrices using LAPACK
|
109
|
+
# # @note code taken from gem `nmatrix-atlas` NMatrix::LAPACK#geev
|
110
|
+
# # @note FOR SYMMETRIC MATRICES ONLY!!
|
111
|
+
# # @note WARNING: will return real matrices, imaginary parts are discarded!
|
112
|
+
# # @note WARNING: only left eigenvectors will be returned!
|
113
|
+
# # @todo could it be possible to save some of the transpositions?
|
114
|
+
# # @return [Array<NMatrix, NMatrix>] eigenvalues and (left) eigenvectors
|
115
|
+
# def eigen_symm
|
116
|
+
# # TODO: check for symmetry if not too slow
|
117
|
+
# raise TypeError, "Only real-valued matrices" if complex_dtype?
|
118
|
+
# raise StorageTypeError, "Only dense matrices (because LAPACK)" unless dense?
|
119
|
+
# raise ShapeError, "Only square matrices" unless dim == 2 && shape[0] == shape[1]
|
120
|
+
|
121
|
+
# n = shape[0]
|
122
|
+
|
123
|
+
# # Outputs
|
124
|
+
# e_values = NMatrix.new([n, 1], dtype: dtype)
|
125
|
+
# e_values_img = NMatrix.new([n, 1], dtype: dtype) # to satisfy C alloc
|
126
|
+
# e_vectors = clone_structure
|
127
|
+
|
128
|
+
# NMatrix::LAPACK::lapack_geev(
|
129
|
+
# false, # compute left eigenvectors of A?
|
130
|
+
# :t, # compute right eigenvectors of A? (left eigenvectors of A**T)
|
131
|
+
# n, # order of the matrix
|
132
|
+
# transpose, # input matrix => needs to be column-wise # self,
|
133
|
+
# n, # leading dimension of matrix
|
134
|
+
# e_values, # real part of computed eigenvalues
|
135
|
+
# e_values_img, # imaginary part of computed eigenvalues (will be discarded)
|
136
|
+
# nil, # left eigenvectors, if applicable
|
137
|
+
# n, # leading dimension of left_output
|
138
|
+
# e_vectors, # right eigenvectors, if applicable
|
139
|
+
# n, # leading dimension of right_output
|
140
|
+
# 2*n # no clue what's this
|
141
|
+
# )
|
142
|
+
|
143
|
+
# raise "Uhm why complex eigenvalues?" if e_values_img.any? {|v| v>1e-10}
|
144
|
+
# return [e_values, e_vectors.transpose]
|
145
|
+
# end
|
146
|
+
|
147
|
+
|
148
|
+
# # The NMatrix documentation refers to a function `#nrm2` (aliased to `#norm2`)
|
149
|
+
# # to compute the norm of a matrix. Fun fact: that is the implementation for vectors,
|
150
|
+
# # and calling it on a matrix returns NotImplementedError :) you have to toggle the
|
151
|
+
# # source to understand why:
|
152
|
+
# # http://sciruby.com/nmatrix/docs/NMatrix.html#method-i-norm2 .
|
153
|
+
# # A search for the actual source on GitHub reveals a (I guess new?) method
|
154
|
+
# # `#matrix_norm`, with a decent choice of norms to choose from. Unfortunately, as the
|
155
|
+
# # name says, it is stuck to compute full-matrix norms.
|
156
|
+
# # So I resigned to dance to `Array`s and back, and implemented it with `#each_rank`.
|
157
|
+
# # Unexplicably, I get a list of constant values as the return value; same with
|
158
|
+
# # `#each_row`.
|
159
|
+
# # What can I say, we're back to referencing rows by index. I am just wasting too much
|
160
|
+
# # time figuring out these details to write a generalized version with an optional
|
161
|
+
# # `dimension` to go along.
|
162
|
+
# # @return [NMatrix] the vector norm along the rows
|
163
|
+
# def row_norms
|
164
|
+
# norms = rows.times.map { |i| row(i).norm2 }
|
165
|
+
# NMatrix.new [rows, 1], norms, dtype: dtype
|
166
|
+
# end
|
167
|
+
|
168
|
+
# # `NMatrix#to_a` has inconsistent behavior: single-row matrices are
|
169
|
+
# # converted to one-dimensional Arrays rather than a 2D Array with
|
170
|
+
# # only one row. Patching `#to_a` directly is not feasible as the
|
171
|
+
# # constructor seems to depend on it, and I have little interest in
|
172
|
+
# # investigating further.
|
173
|
+
# # @return [Array<Array>] a consistent array representation, such that
|
174
|
+
# # `nmat.to_consistent_a.to_nm == nmat` holds for single-row matrices
|
175
|
+
# def to_consistent_a
|
176
|
+
# dim == 2 && shape[0] == 1 ? [to_a] : to_a
|
177
|
+
# end
|
178
|
+
# alias :to_ca :to_consistent_a
|
179
|
+
# end
|
180
180
|
|
181
181
|
module NumericallyApproximatable
|
182
182
|
# Verifies if `self` and `other` are withing `epsilon` of each other.
|
@@ -189,34 +189,34 @@ module MachineLearningWorkbench::Monkey
|
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
-
module MatrixApproximatable
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
end
|
210
|
-
|
211
|
-
module CPtrDumpable
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
end
|
192
|
+
# module MatrixApproximatable
|
193
|
+
# # Verifies if all values at corresponding indices approximate each other.
|
194
|
+
# # @param other [NMatrix]
|
195
|
+
# # @param epsilon [Float]
|
196
|
+
# def approximates? other, epsilon=1e-5
|
197
|
+
# return false unless self.shape == other.shape
|
198
|
+
# # two ways to go here:
|
199
|
+
# # - epsilon is aggregated: total cumulative accepted error
|
200
|
+
# # => `(self - other).reduce(:+) < epsilon`
|
201
|
+
# # - epsilon is local: per element accepted error
|
202
|
+
# # => `v.approximates? other[*idxs], epsilon`
|
203
|
+
# # Given the use I make (near-equality), I choose the first interpretation
|
204
|
+
# # Note the second is sensitive to opposite signs balancing up
|
205
|
+
# self.each_stored_with_indices.all? do |v,*idxs|
|
206
|
+
# v.approximates? other[*idxs], epsilon
|
207
|
+
# end
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
# module CPtrDumpable
|
212
|
+
# def marshall_dump
|
213
|
+
# [shape, dtype, data_pointer]
|
214
|
+
# end
|
215
|
+
|
216
|
+
# def marshall_load
|
217
|
+
# raise NotImplementedError, "There's no setter for the data pointer!"
|
218
|
+
# end
|
219
|
+
# end
|
220
220
|
|
221
221
|
module ToNArrayConvertible
|
222
222
|
def to_na
|
@@ -1,20 +1,22 @@
|
|
1
1
|
module MachineLearningWorkbench::Tools
|
2
2
|
module Verification
|
3
|
-
|
4
|
-
# Raise if values not in range
|
5
|
-
vmin, vmax = vrange.to_a
|
6
|
-
nmat.each_with_indices do |v, *idxs|
|
7
|
-
raise "Value not in range" unless v&.between? vmin, vmax
|
8
|
-
end
|
9
|
-
end
|
3
|
+
# TODO: switch to NArray
|
10
4
|
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
5
|
+
# def self.in_range! nmat, vrange
|
6
|
+
# # Raise if values not in range
|
7
|
+
# vmin, vmax = vrange.to_a
|
8
|
+
# nmat.each_with_indices do |v, *idxs|
|
9
|
+
# raise "Value not in range" unless v&.between? vmin, vmax
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
|
13
|
+
# # Fix if values not in range
|
14
|
+
# def self.in_range nmat, vrange
|
15
|
+
# vmin, vmax = vrange.to_a
|
16
|
+
# nmat.each_with_indices do |v, *idxs|
|
17
|
+
# nmat[*idxs] = vmin if v < vmin
|
18
|
+
# nmat[*idxs] = vmax if v > vmax
|
19
|
+
# end
|
20
|
+
# end
|
19
21
|
end
|
20
22
|
end
|