kmat 0.0.3

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +3 -0
  3. data/.gitignore +15 -0
  4. data/CHANGELOG.md +15 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.md +675 -0
  7. data/README.md +224 -0
  8. data/Rakefile +26 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/ext/kmat/arith/binary.c +1121 -0
  12. data/ext/kmat/arith/logical.c +332 -0
  13. data/ext/kmat/arith/math.c +34 -0
  14. data/ext/kmat/arith/statistics.c +173 -0
  15. data/ext/kmat/arith/unary.c +165 -0
  16. data/ext/kmat/auto_collect.rb +118 -0
  17. data/ext/kmat/elementwise_function.rb +149 -0
  18. data/ext/kmat/extconf.rb +75 -0
  19. data/ext/kmat/id.txt +80 -0
  20. data/ext/kmat/id_sym.rb +40 -0
  21. data/ext/kmat/km_util.h +97 -0
  22. data/ext/kmat/kmat.h +96 -0
  23. data/ext/kmat/lapack_headers/blas.h +354 -0
  24. data/ext/kmat/lapack_headers/lapacke.h +19455 -0
  25. data/ext/kmat/lapack_headers/lapacke_config.h +119 -0
  26. data/ext/kmat/lapack_headers/lapacke_mangling.h +17 -0
  27. data/ext/kmat/lapack_headers/lapacke_utils.h +579 -0
  28. data/ext/kmat/linalg/dla.c +1629 -0
  29. data/ext/kmat/linalg/linalg.c +267 -0
  30. data/ext/kmat/linalg/norm.c +727 -0
  31. data/ext/kmat/linalg/vla.c +102 -0
  32. data/ext/kmat/linalg/working.c +240 -0
  33. data/ext/kmat/main.c +95 -0
  34. data/ext/kmat/smat/accessor.c +719 -0
  35. data/ext/kmat/smat/array.c +108 -0
  36. data/ext/kmat/smat/boxmuller.c +72 -0
  37. data/ext/kmat/smat/constructer.c +302 -0
  38. data/ext/kmat/smat/convert.c +375 -0
  39. data/ext/kmat/smat/elem.c +171 -0
  40. data/ext/kmat/smat/fund.c +702 -0
  41. data/ext/kmat/smat/share.c +427 -0
  42. data/ext/kmat/smat/smat.c +530 -0
  43. data/ext/kmat/smat/sort.c +1156 -0
  44. data/ext/kmat/sym.txt +34 -0
  45. data/kmat.gemspec +46 -0
  46. data/lib/kmat.rb +20 -0
  47. data/lib/kmat/accessor.rb +164 -0
  48. data/lib/kmat/arith.rb +189 -0
  49. data/lib/kmat/linalg.rb +279 -0
  50. data/lib/kmat/logical.rb +150 -0
  51. data/lib/kmat/misc.rb +122 -0
  52. data/lib/kmat/random.rb +106 -0
  53. data/lib/kmat/statistics.rb +98 -0
  54. data/lib/kmat/version.rb +3 -0
  55. metadata +156 -0
@@ -0,0 +1,279 @@
1
+ class Mat
2
+ def least_squares!(a, b, tor: nil, weight: nil, transpose: false)
3
+ if tor
4
+ raise ArgumentError, "tor and weight must not specify at once" if weight
5
+ raise ArgumentError, "for conjugate LS, auto-transpose is not available" if transpose
6
+ _ls_conj(a, b, tor)
7
+ elsif weight
8
+ raise ArgumentError, "for weighted LS, auto-transpose is not available" if transpose
9
+ wls!(a, b, weight)
10
+ else
11
+ if transpose
12
+ tls!(a, b)
13
+ else
14
+ _ls(a, b)
15
+ end
16
+ end
17
+ end
18
+ def least_squares(b, tor: nil, weight: nil, transpose: false)
19
+ if tor
20
+ raise ArgumentError, "tor and weight must not specify at once" if weight
21
+ raise ArgumentError, "for conjugate LS, auto-transpose is not available" if transpose
22
+ ls_conj(b, tor)
23
+ elsif weight
24
+ raise ArgumentError, "for weighted LS, auto-transpose is not available" if transpose
25
+ wls(b, weight)
26
+ else
27
+ if transpose
28
+ tls(b)
29
+ else
30
+ n = self.col_size
31
+ Mat.new(n, n, :float).__send__(:_ls, b)
32
+ end
33
+ end
34
+ end
35
+ alias :ls :least_squares
36
+ alias :ls! :least_squares!
37
+
38
+ def ls_conj!(a, b, tor: Float::EPSILON)
39
+ _ls_conj(a, b, tor)
40
+ end
41
+ def ls_conj(b, tor: Float::EPSILON)
42
+ Mat.new(self.col_size, 1, :float).ls_conj!(self, b, tor: tor)
43
+ end
44
+
45
+ # weighted least squares
46
+ # weight `w' is a vector consists of standard deviations of errors
47
+ # a; (m, n)-matrix
48
+ # b: m-vector
49
+ # x: n-vector
50
+ def wls!(a, b, w)
51
+ nw = w.length
52
+ diag = Mat.new(nw, nw, :f)
53
+ diag.diag.temp do |dd|
54
+ begin
55
+ dd.copy_from(w)
56
+ rescue MismatchedDimensionError
57
+ dd.tcopy_from(w)
58
+ end
59
+ dd.sqrt!
60
+ end
61
+ glm!(a, diag, b)
62
+ end
63
+ def wls(b, w)
64
+ Mat.new(self.col_size, 1, :f).wls!(self, b, w)
65
+ end
66
+
67
+ def rand_orth(random: $MatRandom)
68
+ _rand_orth(random)
69
+ end
70
+ def self.rand_orth(n, random: $MatRandom)
71
+ Mat.new(n, n, :float).rand_orth(random: random)
72
+ end
73
+
74
+ def under(other)
75
+ if square?
76
+ begin
77
+ solve(other)
78
+ rescue UncomputableMatrixError
79
+ ls(other)
80
+ end
81
+ else
82
+ ls(other)
83
+ end
84
+ end
85
+ def under!(a, b)
86
+ if a.square?
87
+ begin
88
+ solve!(a, b)
89
+ rescue UncomputableMatrixError
90
+ ls!(a, b)
91
+ end
92
+ else
93
+ ls!(a, b)
94
+ end
95
+ end
96
+ def over(other)
97
+ if other.square?
98
+ begin
99
+ other.tsolve(self).t!
100
+ rescue UncomputableMatrixError
101
+ other.tls(self).t!
102
+ end
103
+ else
104
+ other.tls(self).t!
105
+ end
106
+ end
107
+ def over!(a, b)
108
+ if b.square?
109
+ begin
110
+ tsolve!(b, a).t!
111
+ rescue UncomputableMatrixError
112
+ tls!(b, a).t!
113
+ end
114
+ else
115
+ tls!(b, a).t!
116
+ end
117
+ end
118
+ def pinv
119
+ n = self.size.min
120
+ i = Mat.I(n)
121
+ if square?
122
+ begin
123
+ solve(i)
124
+ rescue UncomputableMatrixError
125
+ ls(i)
126
+ end
127
+ else
128
+ ls(i)
129
+ end
130
+ end
131
+ def eigen_values
132
+ if symmetry?
133
+ symmetrize().sym_eigen_values()
134
+ else
135
+ ge_eigen_values()
136
+ end
137
+ end
138
+ def evd
139
+ if symmetry?
140
+ symmetrize().sym_evd()
141
+ else
142
+ ge_evd()
143
+ end
144
+ end
145
+
146
+ # inner product
147
+ # let x and y are column vectors and M is a square matrix
148
+ # the following is available
149
+ # (1) x.iprod => x'*x
150
+ # (2) x.iprod(y) => x'*y
151
+ # (3) M.iprod(x) => x'*M*x
152
+ # (4) M.iprod(x, y) => x'*M*y
153
+ # if `inverse' is true, M is replaced by its Moore–Penrose inverse
154
+ # in case (1) or (2), `inverse' is ignored
155
+ # if x or y is row vector, take transpose automatically
156
+ def iprod(*args, inverse: false)
157
+ case args.size
158
+ when 0
159
+ if vector? # case 1
160
+ _iprod(self)
161
+ else
162
+ raise MismatchedDimensionError, "self must be a vector"
163
+ end
164
+ when 1
165
+ o = args[0]
166
+ if o.vector?
167
+ if vector? # case 2
168
+ _iprod(o)
169
+ else # case 3
170
+ if !square?
171
+ raise MismatchecDimensionError, "M must be square for M.iprod(x)"
172
+ elsif inverse
173
+ temp = Mat.new(row_size, 1, vtype)
174
+ if o.col_size == 1
175
+ begin
176
+ temp.solve!(self, o)
177
+ rescue UncomputableMatrixError
178
+ temp.ls!(self, o)
179
+ end
180
+ else
181
+ begin
182
+ temp.tsolve!(self, o)
183
+ rescue UncomputableMatrixError
184
+ temp.tls!(self, o)
185
+ end
186
+ end
187
+ else
188
+ temp = Mat.new(row_size, 1, vtype)
189
+ if o.col_size == 1
190
+ temp.mprod!(self, o)
191
+ else
192
+ temp.mprod!(o, self)
193
+ end
194
+ end
195
+ temp.__send__(:_iprod, o)
196
+ end
197
+ else
198
+ raise MismatchedDimensionError, "as iprod with single argument, x.iprod(y) and M.iprod(x) are available, not x.iprod(M) or others"
199
+ end
200
+ when 2 # case 4
201
+ x, y = *args
202
+ if !square? || !x.vector? || !y.vector? || x.length != row_size || y.length != row_size
203
+ raise MismatchecDimensionError, "as iprod with 2 arguments, only M.iprod(x, y) is available, not others"
204
+ end
205
+ temp = Mat(row_size, 1, vtype)
206
+ if y.col_size == 1
207
+ temp.mprod!(y)
208
+ else
209
+ if y.frozen?
210
+ y = y.dup
211
+ y.transpose
212
+ temp.mprod!(y)
213
+ else
214
+ begin
215
+ y.transpose
216
+ temp.mprod!(y)
217
+ ensure
218
+ y.transpose
219
+ end
220
+ end
221
+ end
222
+ x.__send__(:_iprod, temp)
223
+ else
224
+ raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..2)"
225
+ end
226
+ end
227
+ alias :inner_product :iprod
228
+
229
+ # distance (Frobenius norm of the difference)
230
+ def distance(other)
231
+ self.dup.sub!(other).normf
232
+ end
233
+ def squared_distance(other)
234
+ self.dup.sub!(other).iprod
235
+ end
236
+
237
+ # matrix norm
238
+ # `type' Symbol or Integer specifies norm definition
239
+ # if `elementwise' is true, return induced norm
240
+ # if `elementwise' is false, return elementwise norm
241
+ # if `type' is :fro, return Frobenius norm
242
+ def norm(type=:two, elementwise: false)
243
+ if elementwise
244
+ case type
245
+ when :one, :o, 1
246
+ norm_e1()
247
+ when :infinity, :i, :inf, :infty, Float::INFINITY
248
+ norm_einf()
249
+ when :two, :t, 2, :frobenius, :f, :fro
250
+ normf()
251
+ end
252
+ else
253
+ case type
254
+ when :one, :o, 1
255
+ norm1()
256
+ when :infinity, :i, :inf, :infty, Float::INFINITY
257
+ normi()
258
+ when :two, :t, 2
259
+ norm2()
260
+ when :frobenius, :f, :fro
261
+ normf()
262
+ end
263
+ end
264
+ end
265
+
266
+ def rcond(type=:two)
267
+ case type
268
+ when :one, :o, 1
269
+ _rcondoi(:one)
270
+ when :infinity, :i, :inf, :infty, Float::INFINITY
271
+ _rcondoi(:infinity)
272
+ when :two, :t, 2
273
+ _rcond2()
274
+ when :frobenius, :f, :fro
275
+ _rcondf()
276
+ end
277
+ end
278
+ end
279
+
@@ -0,0 +1,150 @@
1
+ class Mat
2
+ def all?(*args)
3
+ if block_given?
4
+ each do |ent|
5
+ return false unless yield(ent, *args)
6
+ end
7
+ elsif args.size == 0
8
+ if self.vtype == :bool
9
+ each do |ent|
10
+ return false unless ent
11
+ end
12
+ else
13
+ return enum_for(__method__)
14
+ end
15
+ else
16
+ each do |ent|
17
+ args.each do |arg|
18
+ return false unless arg === ent
19
+ end
20
+ end
21
+ end
22
+ return true
23
+ end
24
+ def any?(*args)
25
+ if block_given?
26
+ each do |ent|
27
+ return true if yield(ent, *args)
28
+ end
29
+ elsif args.size == 0
30
+ if self.vtype == :bool
31
+ each do |ent|
32
+ return true if ent
33
+ end
34
+ else
35
+ return enum_for(__method__)
36
+ end
37
+ else
38
+ each do |ent|
39
+ args.each do |arg|
40
+ return true if arg === ent
41
+ end
42
+ end
43
+ end
44
+ return false
45
+ end
46
+
47
+ def ==(other)
48
+ return true if self.equal?(other)
49
+ return false unless other.kind_of?(Mat)
50
+ if self.vtype == other.vtype && self.size == other.size
51
+ each_with_index do |e, i, j|
52
+ return false unless e == other[i, j]
53
+ end
54
+ true
55
+ else
56
+ false
57
+ end
58
+ end
59
+ def <(other)
60
+ return false if self.equal?(other)
61
+ unless other.kind_of?(Mat)
62
+ raise ArgumentError, "Mat < #{other.class} is not defined"
63
+ end
64
+ if self.vtype != other.vtype
65
+ raise ValueTypeError, "value types must be the same"
66
+ elsif self.size != other.size
67
+ raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
68
+ end
69
+ each_with_index do |e, i, j|
70
+ return false unless e < other[i, j]
71
+ end
72
+ true
73
+ end
74
+ def <=(other)
75
+ return false if self.equal?(other)
76
+ unless other.kind_of?(Mat)
77
+ raise ArgumentError, "Mat <= #{other.class} is not defined"
78
+ end
79
+ if self.vtype != other.vtype
80
+ raise ValueTypeError, "value types must be the same"
81
+ elsif self.size != other.size
82
+ raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
83
+ end
84
+ each_with_index do |e, i, j|
85
+ return false unless e <= other[i, j]
86
+ end
87
+ true
88
+ end
89
+ def >(other)
90
+ return false if self.equal?(other)
91
+ unless other.kind_of?(Mat)
92
+ raise ArgumentError, "Mat > #{other.class} is not defined"
93
+ end
94
+ if self.vtype != other.vtype
95
+ raise ValueTypeError, "value types must be the same"
96
+ elsif self.size != other.size
97
+ raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
98
+ end
99
+ each_with_index do |e, i, j|
100
+ return false unless e > other[i, j]
101
+ end
102
+ true
103
+ end
104
+ def >=(other)
105
+ return false if self.equal?(other)
106
+ unless other.kind_of?(Mat)
107
+ raise ArgumentError, "Mat > #{other.class} is not defined"
108
+ end
109
+ if self.vtype != other.vtype
110
+ raise ValueTypeError, "value types must be the same"
111
+ elsif self.size != other.size
112
+ raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
113
+ end
114
+ each_with_index do |e, i, j|
115
+ return false unless e >= other[i, j]
116
+ end
117
+ true
118
+ end
119
+
120
+ def eq(other)
121
+ unless other.kind_of?(Mat) && other.size == self.size
122
+ other = broadcast(other)
123
+ end
124
+ Mat.new(row_size(), col_size(), :bool).eq!(self, other)
125
+ end
126
+ def lt(other)
127
+ unless other.kind_of?(Mat) && other.size == self.size
128
+ other = broadcast(other)
129
+ end
130
+ Mat.new(row_size(), col_size(), :bool).lt!(self, other)
131
+ end
132
+ def le(other)
133
+ unless other.kind_of?(Mat) && other.size == self.size
134
+ other = broadcast(other)
135
+ end
136
+ Mat.new(row_size(), col_size(), :bool).le!(self, other)
137
+ end
138
+ def gt(other)
139
+ unless other.kind_of?(Mat) && other.size == self.size
140
+ other = broadcast(other)
141
+ end
142
+ Mat.new(row_size(), col_size(), :bool).gt!(self, other)
143
+ end
144
+ def ge(other)
145
+ unless other.kind_of?(Mat) && other.size == self.size
146
+ other = broadcast(other)
147
+ end
148
+ Mat.new(row_size(), col_size(), :bool).ge!(self, other)
149
+ end
150
+ end
@@ -0,0 +1,122 @@
1
+ class << Mat
2
+ def hilb(n, type=:float)
3
+ self.new(n, n, type) do |i, j|
4
+ 1.quo(i+j+1)
5
+ end
6
+ end
7
+ def load(file)
8
+ case file
9
+ when String
10
+ ret = nil
11
+ File.open(file) do |f|
12
+ ret = Marshal.load(f)
13
+ end
14
+ ret
15
+ when IO
16
+ Marshal.load(file)
17
+ else
18
+ raise ArgumentError, 'the argument must be a filepath or an IO object'
19
+ end
20
+ end
21
+ end
22
+
23
+ class Mat
24
+ def save(file)
25
+ case file
26
+ when String
27
+ File.open(file, 'w') do |f|
28
+ Marshal.dump(self, f)
29
+ end
30
+ when IO
31
+ Marshal.dump(self, file)
32
+ else
33
+ raise ArgumentError, 'the argument must be a filepath or an IO object'
34
+ end
35
+ nil
36
+ end
37
+
38
+ def geo_normalize!(arg=:all)
39
+ self.log!
40
+ foo = self.mean(arg)
41
+ if foo.kind_of?(Mat)
42
+ self.sub!(self.broadcast(foo))
43
+ else
44
+ self.s_sub!(foo)
45
+ end
46
+ self.exp!
47
+ end
48
+ def geo_normalize(arg=:all)
49
+ self.dup.geo_normalize!(arg)
50
+ end
51
+ def normalize!
52
+ if self.vector?
53
+ self.s_div!(self.normf)
54
+ elsif self.square?
55
+ ev = self.eigen_values
56
+ if ev[0] < 0
57
+ self.diag.s_add!(ev[0]*(-2))
58
+ ev.s_add!(ev[0]*(-2))
59
+ end
60
+ self.s_div!(Math.exp(ev.log!.mean))
61
+ else
62
+ raise MismatchedDimensionError, "normalize is available only for vectors or square matricies"
63
+ end
64
+ end
65
+ def normalize
66
+ self.dup.normalize!
67
+ end
68
+ end
69
+
70
+ class Array
71
+ def argsort
72
+ ret = Array.new(self.size, &:itself)
73
+ if block_given?
74
+ ret.sort! do |a, b|
75
+ yield(self[a], self[b])
76
+ end
77
+ else
78
+ ret.sort_by! do |elm|
79
+ self[elm]
80
+ end
81
+ end
82
+ end
83
+ def argsort!(ary)
84
+ if block_given?
85
+ sort! do |a, b|
86
+ yield(ary[a], ary[b])
87
+ end
88
+ else
89
+ sort_by! do |elm|
90
+ self[elm]
91
+ end
92
+ end
93
+ end
94
+ def argsort_by
95
+ if block_given?
96
+ Array.new(self.size, &:itself).sort_by! do |elm|
97
+ yield(self[elm])
98
+ end
99
+ else
100
+ self.to_enum(:argsort_by)
101
+ end
102
+ end
103
+ end
104
+ module Enumerable
105
+ def argsort(&block)
106
+ self.to_a.argsort(&block)
107
+ end
108
+ def argsort_by(&block)
109
+ self.to_a.argsort_by(&block)
110
+ end
111
+ end
112
+ class Numeric
113
+ def limit(min, max)
114
+ if ( self < min ) then
115
+ min
116
+ elsif ( max < self ) then
117
+ max
118
+ else
119
+ self
120
+ end
121
+ end
122
+ end