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,34 @@
1
+ a
2
+ all
3
+ b
4
+ bool
5
+ boolean
6
+ c
7
+ col
8
+ column
9
+ complex
10
+ d
11
+ double
12
+ each
13
+ each_with_index2
14
+ f
15
+ float
16
+ full
17
+ i
18
+ infinity
19
+ int
20
+ integer
21
+ mmap
22
+ mmap_with_index2
23
+ n
24
+ none
25
+ o
26
+ object
27
+ one
28
+ r
29
+ random
30
+ row
31
+ serial
32
+ v
33
+ value
34
+ z
@@ -0,0 +1,46 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "kmat/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kmat"
8
+ spec.version = Mat::VERSION
9
+ spec.authors = ["KAZOON"]
10
+ spec.email = ["cycloawaodorin+gem@gmail.com"]
11
+ spec.license = "GPL-3.0"
12
+
13
+ spec.summary = %q{Kmat is a Ruby gem for matrix operations. Kmat uses BLAS/LAPACK as back-end.}
14
+ #spec.description = %q{TODO: Write a longer description or delete this line.}
15
+ spec.homepage = "https://github.com/cycloawaodorin/"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ #spec.metadata["allowed_push_host"] = "http://localhost"
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ spec.metadata["source_code_uri"] = "https://github.com/cycloawaodorin/kmat"
24
+ spec.metadata["changelog_uri"] = "https://github.com/cycloawaodorin/kmat/blob/master/CHANGELOG.md"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+ spec.extensions = ["ext/kmat/extconf.rb"]
39
+
40
+ spec.add_development_dependency "bundler", ">= 2.0"
41
+ spec.add_development_dependency "rake", ">= 10.0"
42
+ spec.add_development_dependency "rake-compiler"
43
+ spec.add_development_dependency "pry", ">= 0.12.2"
44
+
45
+ spec.required_ruby_version = '>= 2.6.0'
46
+ end
@@ -0,0 +1,20 @@
1
+ require "kmat/version"
2
+
3
+ class Mat
4
+ include Enumerable
5
+ end
6
+
7
+ class << Mat
8
+ private def _define_dup_escaped_method(method)
9
+ Mat.class_eval("def #{method}(*args, &block); self.dup.#{method}!(*args, &block); end")
10
+ end
11
+ end
12
+
13
+ require "kmat/kmat"
14
+ require "kmat/arith"
15
+ require "kmat/accessor"
16
+ require "kmat/linalg"
17
+ require "kmat/logical"
18
+ require "kmat/misc"
19
+ require "kmat/random"
20
+ require "kmat/statistics"
@@ -0,0 +1,164 @@
1
+ class Mat
2
+ def ===(other)
3
+ if other.kind_of?(Mat)
4
+ self == other
5
+ else
6
+ false
7
+ end
8
+ end
9
+
10
+ def [](*idx)
11
+ if block_given?
12
+ tmp = self.bracket(*idx)
13
+ ret = yield(tmp)
14
+ tmp.__send__(:_kill)
15
+ ret
16
+ else
17
+ self.bracket(*idx)
18
+ end
19
+ end
20
+
21
+ def temp
22
+ ret = yield(self)
23
+ _kill
24
+ ret
25
+ end
26
+
27
+ # for example, A.repmat(2, 3) returns [A, A, A: A, A, A]
28
+ def repmat(row_repeat, col_repeat)
29
+ ri = Mat.new(row_size()*row_repeat, 1, :int) do |i, j|
30
+ i % row_size()
31
+ end
32
+ ci = Mat.new(col_size()*col_repeat, 1, :int) do |i, j|
33
+ i % col_size()
34
+ end
35
+ self[ri, ci] do |m|
36
+ m.dup
37
+ end
38
+ end
39
+
40
+ # extend `other' to fit the shape of self
41
+ # this is similar to Python's numpy broadcasting
42
+ def broadcast(other, vt=nil)
43
+ if other.kind_of?(Mat)
44
+ if other.row_size == 1
45
+ if other.col_size == 1
46
+ other.repmat(row_size(), col_size())
47
+ elsif other.col_size == self.col_size
48
+ other.repmat(self.row_size, 1)
49
+ else
50
+ raise MismatchedDimensionError, "can't broadcast from (#{other.size.join(', ')}) to (#{self.size.join(', ')})"
51
+ end
52
+ elsif other.row_size == self.row_size
53
+ if other.col_size == 1
54
+ other.repmat(1, col_size())
55
+ elsif other.col_size == self.col_size
56
+ other
57
+ else
58
+ raise MismatchedDimensionError, "can't broadcast from (#{self.size.join(', ')}) to (#{other.size.join(', ')})"
59
+ end
60
+ else
61
+ raise MismatchedDimensionError, "can't broadcast from (#{self.size.join(', ')}) to (#{other.size.join(', ')})"
62
+ end
63
+ else
64
+ vt = vtype() if vt.nil?
65
+ Mat.new(row_size(), col_size(), vt).fill(other)
66
+ end
67
+ end
68
+
69
+ # replace self by repeated `src'
70
+ # self will be left-top of infinitly repeated `src'
71
+ def replace_rep(src)
72
+ ri = Mat.new(row_size(), 1, :int) do |i, j|
73
+ i % src.row_size
74
+ end
75
+ ci = Mat.new(col_size(), 1, :int) do |i, j|
76
+ i % src.col_size
77
+ end
78
+ src[ri, ci] do |m|
79
+ self.copy_from(m)
80
+ end
81
+ end
82
+
83
+ # flip row, column or both axis
84
+ # `dim' Symbol specifies fliping axis (:row, :col, :both, :none are available)
85
+ def flip(dim=:both)
86
+ dim = dim.to_sym if dim.respond_to?(:to_sym)
87
+ m, n = *shape()
88
+ case dim
89
+ when :both, :b
90
+ ri = Mat.new(m, 1, :int) do |i, j|
91
+ m-i-1
92
+ end
93
+ ci = Mat.new(n, 1, :int) do |i, j|
94
+ n-i-1
95
+ end
96
+ self[ri, ci]
97
+ when :row, :r
98
+ ri = Mat.new(m, 1, :int) do |i, j|
99
+ m-i-1
100
+ end
101
+ self[ri, nil]
102
+ when :col, :c
103
+ ci = Mat.new(n, 1, :int) do |i, j|
104
+ n-i-1
105
+ end
106
+ self[nil, ci]
107
+ when :none, :n
108
+ self[]
109
+ else
110
+ raise ArgumentError, "unknown axis symbol #{dim.inspect}"
111
+ end
112
+ end
113
+
114
+ def diag(k=0)
115
+ _diag_ul(k)
116
+ end
117
+ end
118
+
119
+ class << Mat
120
+ # for example, Mat.blocks([a, b], [c, d]) returns a single matrix of [a, b; c, d]
121
+ def blocks(*blocks)
122
+ vstack(*blocks.map do |row|
123
+ hstack(*row)
124
+ end)
125
+ end
126
+
127
+ def vstack(*mats)
128
+ m, n = *mats[0].shape
129
+ 1.upto(mats.size-1) do |i|
130
+ mat = mats[i]
131
+ raise MismatchedDimensionError, 'column-sizes must be the same' if mat.col_size != n
132
+ m += mat.row_size
133
+ end
134
+ ret = Mat.new(m, n, mats[0].vtype)
135
+ k = 0;
136
+ n = Mat.irange(n)
137
+ mats.each do |mat|
138
+ ret[Mat.new(mat.row_size, 1, :int) do |i, j|
139
+ i+k
140
+ end, n] = mat
141
+ k += mat.row_size
142
+ end
143
+ ret
144
+ end
145
+
146
+ def hstack(*mats)
147
+ m, n = *mats[0].shape
148
+ 1.upto(mats.size-1) do |i|
149
+ mat = mats[i]
150
+ raise MismatchedDimensionError, 'row-sizes must be the same' if mat.row_size != m
151
+ n += mat.col_size
152
+ end
153
+ ret = Mat.new(m, n, mats[0].vtype)
154
+ k = 0
155
+ m = Mat.irange(m)
156
+ mats.each do |mat|
157
+ ret[m, Mat.new(mat.col_size, 1, :int) do |i, j|
158
+ i+k
159
+ end] = mat
160
+ k += mat.col_size
161
+ end
162
+ ret
163
+ end
164
+ end
@@ -0,0 +1,189 @@
1
+ class Mat
2
+ # to define Numeric * Mat as Mat#scalar(Numeric) remaining Mat * Mat is undefined,
3
+ # this returns non‐standard value
4
+ def coerce(other)
5
+ if caller.first[/`([^']*)'/, 1] == '*'
6
+ [self, other]
7
+ else
8
+ raise TypeError, "Mat can't be coerced into #{other.class}"
9
+ end
10
+ end
11
+ def add(other)
12
+ if other.kind_of?(Mat)
13
+ self.dup.add!(broadcast(other))
14
+ else
15
+ self.dup.s_add!(other)
16
+ end
17
+ end
18
+ alias :+ :add
19
+ def sub(other)
20
+ if other.kind_of?(Mat)
21
+ self.dup.sub!(broadcast(other))
22
+ else
23
+ self.dup.s_sub!(other)
24
+ end
25
+ end
26
+ alias :- :sub
27
+ def e_mul(other)
28
+ if other.kind_of?(Mat)
29
+ self.dup.e_mul!(broadcast(other))
30
+ else
31
+ self.dup.s_mul!(other)
32
+ end
33
+ end
34
+ def e_div(other)
35
+ if other.kind_of?(Mat)
36
+ self.dup.e_div!(broadcast(other))
37
+ else
38
+ self.dup.s_div!(other)
39
+ end
40
+ end
41
+ module MatrixProductOperator
42
+ refine Mat do
43
+ def *(other)
44
+ if other.kind_of?(Mat)
45
+ mprod(other)
46
+ else
47
+ self.dup.s_mul!(other)
48
+ end
49
+ end
50
+ def /(other)
51
+ if other.kind_of?(Mat)
52
+ over(other)
53
+ else
54
+ self.dup.s_div!(other)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ def *(other)
60
+ if other.kind_of?(Mat)
61
+ raise ArgumentError, "Mat#* is available only for scalar multiplication. To use Mat#*(Mat) for matrix product, call `using Mat::MatrixProductOperator'"
62
+ else
63
+ self.dup.s_mul!(other)
64
+ end
65
+ end
66
+ def scalar(alpha)
67
+ self.dup.s_mul!(alpha)
68
+ end
69
+ alias :"scalar!" :"s_mul!"
70
+ def /(other)
71
+ if other.kind_of?(Mat)
72
+ raise ArgumentError, "Mat#/ is available only for scalar multiplication with reciprocal. To use Mat#/(Mat) as an alias of Mat#over, call `using Mat::MatrixProductOperator`"
73
+ else
74
+ self.dup.s_div!(other)
75
+ end
76
+ end
77
+
78
+ def add_times(other, alpha)
79
+ if other.kind_of?(Mat)
80
+ self.dup.add_times!(broadcast(other), alpha)
81
+ else
82
+ self.dup.s_mul!(other*alpha)
83
+ end
84
+ end
85
+
86
+ def maximum(other)
87
+ if other.kind_of?(Mat)
88
+ self.dup.maximum!(broadcast(other))
89
+ else
90
+ self.dup.s_maximum!(other)
91
+ end
92
+ end
93
+ def minimum(other)
94
+ if other.kind_of?(Mat)
95
+ self.dup.minimum!(broadcast(other))
96
+ else
97
+ self.dup.s_minimum!(other)
98
+ end
99
+ end
100
+
101
+ def pow(other)
102
+ if other.kind_of?(Mat)
103
+ self.dup.pow!(broadcast(other))
104
+ else
105
+ self.dup.s_pow!(other)
106
+ end
107
+ end
108
+ def rpow(other)
109
+ other.dup.pow!(other.broadcast(self))
110
+ end
111
+ def **(other)
112
+ case other
113
+ when Integer
114
+ ret, temp = self.dup, self.dup
115
+ ret.eye
116
+ if 0 <= other
117
+ a = self.dup
118
+ else
119
+ a = self.inv
120
+ other = -other
121
+ end
122
+ loop do
123
+ if other % 2 == 1
124
+ temp.mprod!(ret, a)
125
+ temp, ret = ret, temp
126
+ end
127
+ other = other.div(2)
128
+ break if other == 0
129
+ temp.mprod!(a, a)
130
+ temp, a = a, temp
131
+ end
132
+ ret
133
+ when Float
134
+ if self.symmetry?
135
+ v, d = self.symmetrize.sym_evd
136
+ d.diag.s_pow!(other)
137
+ foo = v.mprod(d)
138
+ d.mprod!(foo, v.t!)
139
+ else
140
+ raise UncomputableMatrixError, "cannot compute float power of non-symmetric matrcies"
141
+ end
142
+ when Rational
143
+ self ** other.to_f
144
+ else
145
+ raise ArgumentError, "Mat powered by #{other.class} is not supported"
146
+ end
147
+ end
148
+
149
+ def hypot(other)
150
+ if other.kind_of?(Mat)
151
+ self.dup.hypot!(broadcast(other))
152
+ else
153
+ self.dup.s_hypot!(other)
154
+ end
155
+ end
156
+ end
157
+
158
+ class << Mat
159
+ def max(*args)
160
+ case args.size
161
+ when 0
162
+ nil
163
+ when 1
164
+ args[0]
165
+ else
166
+ ret = args[0].dup
167
+ 1.upto(args.size-1) { |i|
168
+ ret.maximum!(args[i])
169
+ }
170
+ ret
171
+ end
172
+ end
173
+ alias :maximum :max
174
+ def min(*args)
175
+ case args.size
176
+ when 0
177
+ nil
178
+ when 1
179
+ args[0]
180
+ else
181
+ ret = args[0].dup
182
+ 1.upto(args.size-1) { |i|
183
+ ret.minimum!(args[i])
184
+ }
185
+ ret
186
+ end
187
+ end
188
+ alias :minimum :min
189
+ end