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,224 @@
1
+ # kmat
2
+
3
+ Kmat is a Ruby gem for matrix operations. Kmat uses BLAS/LAPACK as back-end.
4
+
5
+ ## Requirements
6
+
7
+ BLAS/LAPACK libraries are needed to build kmat. MKL can also be used.
8
+ You need to modify extconf.rb to use the other BLAS/LAPACK compatible libraries (pull requests are welcome).
9
+
10
+ ## Installation
11
+
12
+ Kmat is available on RubyGems.org:
13
+
14
+ $ gem install kmat
15
+
16
+ or in your Gemfile:
17
+
18
+ ```ruby
19
+ gem 'kmat'
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ While the gem name is kmat, the top module of this gem is the class `Mat`. Most of the functions of kmat are defined under `Mat` (some monkey patches (e.g. `Random#randn`) are applied to built-in modules/classes).
25
+
26
+ `Mat` is a class of matricies. It has matrix operations as methods. Unlike numpy in Python, `Mat` cannot be a tensor with order other than 2. `Mat` with shape `(n, 1)` or `(1, n)` behaves as a vector (not be distinguished from each other) in some methods (e.g. `Mat#iprod`).
27
+
28
+ Matlab style expected return value comments appear in the following sample codes, but they are only in documents (kmat has no way to generate these strings from Mat instances nor way to generate Mat instances from these strings).
29
+
30
+ ### Construction of matricies
31
+
32
+ ```ruby
33
+ require 'kmat'
34
+
35
+ Mat[[1, 2], [3, 4]] #=> [1, 2; 3, 4]
36
+ Mat.ones(2, 2) #=> [1, 1; 1, 1]
37
+ Mat.eye(2, 2) #=> [1, 0; 0, 1]
38
+ Mat.randn(2, 2) #=> [-0.11, 0.25; 0.83, -0.03] (vary every call)
39
+ Mat.range(3) #=> [0; 1; 2]
40
+ Mat.new(2, 3){|i, j| i+j} #=> [0, 1, 2; 1, 2, 3]
41
+ ```
42
+
43
+ ### Arithmetic operations
44
+ ```ruby
45
+ require 'kmat'
46
+
47
+ a = Mat.ones; b = Mat[[2, 0], [0, 1]]
48
+ a+b #=> [3, 1; 1, 2]
49
+ a-b #=> [-1, 1; 1, 0]
50
+ a.mprod(b) #=> [2, 1; 2, 1] (matrix product)
51
+ a.e_mul(b) #=> [2, 0; 0, 1] (element-wise product)
52
+ b.under(a) #=> [0.5, 0.5; 1, 1] (like b\a in Matlab)
53
+ a.over(b) #=> [0.5, 1; 0.5, 1] (like a/b in Matlab)
54
+ a*b #=> ArgumentError (to avoid confusion of Mat#mprod vs Mat#e_mul)
55
+ using Mat::MatrixProductOperator
56
+ [a*b, a/b] #=> [ [2, 1; 2, 1], [0.5, 1; 0.5, 1] ] (refinements are available)
57
+ a.sin # Most of mathematical functions defined in math.h are available as element-wise operations
58
+ ```
59
+
60
+ ### Destructive operation
61
+ ```ruby
62
+ require 'kmat'
63
+
64
+ a = Mat.ones; b = Mat[[2, 0], [0, 1]]
65
+ a+b; a #=> [1, 1; 1, 1]
66
+ a.add!(b)
67
+ a #=> [3, 1; 1, 2]
68
+ c = Mat.new(2, 2)
69
+ c.mprod!(a, b)
70
+ c #=> [6, 1; 2, 2]
71
+ a.sub!(b); a.e_mul!(b); b.e_div!(a); c.under!(a, b)
72
+ ```
73
+
74
+ ### Numpy-like broadcasting
75
+ ```ruby
76
+ require 'kmat'
77
+
78
+ a = Mat.eye(2, 2); b = Mat.range(2)
79
+ a+b #=> [1, 1; 2, 2]
80
+ a.add!(a.broadcast(b)) # For destructive operation, you need to fit shape using Mat#broadcast
81
+ a.s_add!(1.5) # Or use Mat#s_xxx! for element-wise opertion with broadcasted scalar value
82
+ 0.5 * a # Numeric#* can be used as scalar multiplication (others like Numeric+Mat are not available)
83
+ ```
84
+
85
+ ### Element or submatrix accessing
86
+ ```ruby
87
+ rquire 'kmat'
88
+
89
+ a = Mat[[1, 2], [3, 4]]
90
+ a[1, 0] #=> 3.0
91
+ a[0, -1] #=> 2.0 (negative indexing is available)
92
+ a[nil, 1] #=> [2; 4] (nil works like `:' in numpy)
93
+ a[[1, 0], 0..1] #=> [3, 4; 1, 2]
94
+ a[a.gt(2)] #=> [3; 4] (boolean indexing returns a vector)
95
+ vidx = Mat.new(1, 2, :object){ |i, j| [j, i] }
96
+ a[vidx] #=> [1, 3] (=[a[0, 0], a[1, 0]])
97
+ b = a[0, nil] # a submatrix is like a `view' of numby
98
+ a[0, 0] = 5
99
+ b #=> [5, 2]
100
+ b[0, 1] = -1 # but it's writable and may change the `supermatrix'
101
+ a #=> [5, -1; 3, 4]
102
+ b.freeze # use Object#freeze to avoid it
103
+ a[0, 0] = -3 # but, freezing submatrix do not freeze the `supermatrix'
104
+ b #=> [-3, -1]
105
+ a.deep_freeze # use `supermatrix'.deep_freeze to freeze all the related matricies
106
+ b[0, 0] = 7 #=> FrozenError
107
+ c = a[0, nil] # submatrix made from frozen matrix is pre-frozen
108
+ c[0, 0] = 9 #=> FrozenError
109
+ a = Mat[[1, 2], [3, 4]]
110
+ a[nil, 0] = Mat.range(2) # multi-entry substitution is also available
111
+ a #=> [0, 2; 1, 4]
112
+ a.map(&:-@) #=> [0, -2; -1, -4]
113
+ a.map_with_index!{|e, i, j| e+j}
114
+ a.diag #=> [0; 4] (returns diagonal elements as a vector)
115
+ a[] #=> [0, 2; 1, 4] (with no argument is equivalent to a[nil, nil])
116
+ Mat.range(3)[2] #=> 2.0 (with single integer or single integer array is available for vectors)
117
+ ```
118
+
119
+ ### Value types
120
+ Mat in kmat has 5 value types.
121
+ #### Float
122
+ The default value type is `:float`. Values are `double` in C language and it is compatible with `Float` in Ruby. Most of linear argebraic operations are available only on float matricies.
123
+
124
+ #### Complex
125
+ `:complex` is available to deal with complex floats. Some operations are defined but the number of available operations is limitted.
126
+
127
+ #### Int
128
+ `:int` can be used as row or column index array. Values are `int` in C language, so it is not useful for matrix operations with large integer elements. We recomend to use `:object` with `Integer` for such usage.
129
+
130
+ #### Bool
131
+ `:bool` can be used as boolean indexing. Logical operations are available. In some operations, elements in boolean matricies behaves as a finite filed with order 2 (`+` is exclusive disjunction and `*` is logical conjunction).
132
+
133
+ #### Object
134
+ `:object` matricies can contain arbitrary Ruby objects. Operation behaviors are dependent on methods defined for the objects. For example, `Mat#solve` works if `K#==`, `K#quo`, `K#*` and `K#-` are defined appropriately, where `K` is a class of the elements.
135
+ `:object` matricies with 2-length `Array`s are used as indecies for other `Mat`s.
136
+
137
+ ```ruby
138
+ rquire 'kmat'
139
+
140
+ Mat.new(2, 2, :float){|i, j| i+j}
141
+ Mat.new(2, 2, :complex){|i, j| Complex.rect(i, j)}
142
+ Mat.new(2, 2, :int){|i, j| i-j}
143
+ Mat.new(2, 2, :bool){|i, j| i==j}
144
+ Mat.new(2, 2, :object){|i, j| Rational(i, j) }
145
+ Mat.new(1, 1).vtype #=> :float (Mat#vtype returns its value type as a Symbol above)
146
+ ```
147
+
148
+ ### Sort, stacking and logical operations
149
+ ```ruby
150
+ require 'kmat'
151
+
152
+ a = Mat[[3, 2, 1], [5, -3, 7]]
153
+ a.sort(:row) #=> [1, 2, 3; -3, 5, 7]
154
+ a.rsort(:col) #=> [5, 2, 7; 3, -3, 1]
155
+ a.flip(:both) #=> [7, -3, 5; 1, 2, 3]
156
+ a.t #=> [3, 5; 2, -3; 1, 7] (transpose)
157
+ b = Mat.range(2)
158
+ Mat.blocks([[a, b], [b, a]]) #=> [3, 2, 1, 0; 5, -3, 7, 1; 0, 3, 2, 1; 1, 5, -3, 7]
159
+ Mat.vstack(a, a); Mat.hstack(a, b)
160
+ a.gt(b) #=> [true, true, true; true, false, true] (numpy-like broadcasting)
161
+ a.eq(b); a.ne(b); a.ge(b); a.lt(b); a.le(b)
162
+ a.max #=> 7
163
+ a.maximum(b) #=> [3, 2, 1; 5, 1, 7]
164
+ Mat.maximum(a, b.repmat(1, 3), Mat.randn(2, 3))
165
+ #=> Mat.maximum can recieve arbitrary number of arguments but do not broadcast automatically
166
+ ```
167
+
168
+ ### Linear algebraic operations
169
+ Most of them are useing BLAS/LAPACK as a back-end.
170
+ ```ruby
171
+ require 'kmat'
172
+
173
+ a, b = Mat.randn(3, 3), Mat.rand(3, 1)
174
+ a.ls(b) # ls means least_squares, the return x mimimize a.mprod(x)-b
175
+ a.evd # eigendecomposition
176
+ a.svd # singular value decomposition
177
+ a.lup # LUP decomposition
178
+ a.det # determinant
179
+ a.qr # QR decomposition
180
+ Mat.rand_orth(3) # Random orthogonal matrix
181
+ a.tr # trace
182
+ ```
183
+
184
+ ### Copying elements
185
+ ```ruby
186
+ require 'kmat'
187
+
188
+ a, b = Mat.randn(2, 2), Mat.randn(2, 2)
189
+ a.dup # dup/clone are like Array#dup/clone
190
+ a.copy_from(b) # it is equivalent to a[] = b, value type is dependent on the reciever
191
+ a.replace(b[]) # Mat#replace copies submatrix relation and value type (Mat#copy_from do not)
192
+ a.fill(1.5) #=> [1.5, 1.5; 1.5, 1.5] (destructive)
193
+ Marshal.load(Marshal.dump(a))
194
+ # Marshal.dump/load are available
195
+ ```
196
+
197
+ ### Random
198
+ ```ruby
199
+ require 'kmat'
200
+
201
+ Mat.randn(2, 2, random: Random.new) # In kmat, methods using random value, the generator can be specified by keyword `random'
202
+ $MatRandom = Random.new # Or substitute into $MatRandom (default value of $MatRandom is Random::DEFAULT)
203
+ Random.new.randn # Random#randn returns a random value following N(0, 1)
204
+ randn() # Kernel#randn is equivalent to Random::DEFAULT.randn
205
+ ```
206
+
207
+
208
+ ## Contributing
209
+
210
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cycloawaodorin/kmat.
211
+
212
+ ## License
213
+ Kmat is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version3 of the License, or (at your option) any later version.
214
+
215
+ Kmat is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
216
+
217
+ You should have received a copy of the GNU General Public License along with the gem; see the file LICENSE.md. If not, see the website of [GPL](https://www.gnu.org/licenses/).
218
+
219
+ ## `/ext/lapack_headers/*.h`
220
+ The header files under `/ext/lapack_headers/` directory are modified or copied version of an Azalea Clive's product or Intel Corp's products. The original versions are distributed at the following.
221
+
222
+ `blas.h` is distributed at [BLASの簡単な使い方](http://azalea.s35.xrea.com/blas/sample1.html).
223
+
224
+ `lapacke.h`, `lapacke_config.h`, `lapacke_mangling.h` and `lapacke_utils.h` are distributed at the website of [LAPACKE](http://www.netlib.org/lapack/#_standard_c_language_apis_for_lapack) under modified BSD license.
@@ -0,0 +1,26 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/extensiontask"
3
+
4
+ task :build => :compile
5
+
6
+ def istrue(key)
7
+ val = ENV[key]
8
+ if val.nil?
9
+ false
10
+ elsif val.kind_of?(String)
11
+ if val == '0' || val =~ /false/i || val =~ /nil/i
12
+ false
13
+ else
14
+ true
15
+ end
16
+ else
17
+ raise "unknown environment value type #{val.class} for ENV['#{key}']"
18
+ end
19
+ end
20
+
21
+ Rake::ExtensionTask.new("kmat") do |ext|
22
+ ext.lib_dir = "lib/kmat"
23
+ ext.config_options = %w|debug| if istrue('KMAT_DEBUG')
24
+ end
25
+
26
+ task :default => [:clobber, :compile, :spec]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kmat"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,1121 @@
1
+ #include "../kmat.h"
2
+
3
+ // element-wise arithmetic operations
4
+ static void
5
+ km_add_d(double *y, double *x, void *null)
6
+ {
7
+ *y += *x;
8
+ }
9
+ static void
10
+ km_add_z(COMPLEX *y, COMPLEX *x, void *null)
11
+ {
12
+ *y += *x;
13
+ }
14
+ static void
15
+ km_add_i(int *y, int *x, void *null)
16
+ {
17
+ *y += *x;
18
+ }
19
+ static void
20
+ km_add_b(bool *y, bool *x, void *null)
21
+ {
22
+ *y = XOR(*y, *x);
23
+ }
24
+ static void
25
+ km_add_v(VALUE *y, VALUE *x, void *null)
26
+ {
27
+ *y = rb_funcall(*y, id_op_plus, 1, *x);
28
+ }
29
+ VALUE
30
+ kmm_mat_add_destl(VALUE self, VALUE other)
31
+ {
32
+ km_check_frozen(self);
33
+ SMAT *sy=km_mat2smat(self), *sx=km_mat2smat(other);
34
+ if ( sy->vtype != sx->vtype ) {
35
+ rb_raise(km_eVT, "value types must be same");
36
+ }
37
+ CHECK_SAME_SIZE(sy, sx);
38
+ if ( sy->vtype == VT_DOUBLE ) {
39
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
40
+ double alpha = 1.0; int len = LENGTH(sy), ione=1;
41
+ daxpy_(&len, &alpha, sx->dbody, &ione, sy->dbody, &ione);
42
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
43
+ double alpha = 1.0; int incy, stepy, incx, stepx;
44
+ if ( sy->trans ) {
45
+ incy = sy->ld; stepy = 1;
46
+ } else {
47
+ incy = 1; stepy = sy->ld;
48
+ }
49
+ if ( sx->trans ) {
50
+ incx = sx->ld; stepx = 1;
51
+ } else {
52
+ incx = 1; stepx = sx->ld;
53
+ }
54
+ for ( int i=0; i<(sy->n); i++ ) {
55
+ daxpy_(&(sy->m), &alpha, (sx->dbody)+(i*stepx), &incx, (sy->dbody)+(i*stepy), &incy);
56
+ }
57
+ } else {
58
+ km_smat_each2_d(sy, sx, km_add_d, NULL);
59
+ }
60
+ } else if ( sy->vtype == VT_COMPLEX ) {
61
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
62
+ COMPLEX alpha = cpack(1.0, 0.0); int len = LENGTH(sy), ione=1;
63
+ zaxpy_(&len, &alpha, sx->zbody, &ione, sy->zbody, &ione);
64
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
65
+ COMPLEX alpha = cpack(1.0, 0.0); int incy, stepy, incx, stepx;
66
+ if ( sy->trans ) {
67
+ incy = sy->ld; stepy = 1;
68
+ } else {
69
+ incy = 1; stepy = sy->ld;
70
+ }
71
+ if ( sx->trans ) {
72
+ incx = sx->ld; stepx = 1;
73
+ } else {
74
+ incx = 1; stepx = sx->ld;
75
+ }
76
+ for ( int i=0; i<(sy->n); i++ ) {
77
+ zaxpy_(&(sy->m), &alpha, (sx->zbody)+(i*stepx), &incx, (sy->zbody)+(i*stepy), &incy);
78
+ }
79
+ } else {
80
+ km_smat_each2_z(sy, sx, km_add_z, NULL);
81
+ }
82
+ } else if ( sy->vtype == VT_INT ) {
83
+ km_smat_each2_i(sy, sx, km_add_i, NULL);
84
+ } else if ( sy->vtype == VT_BOOL ) {
85
+ km_smat_each2_b(sy, sx, km_add_b, NULL);
86
+ } else if ( sy->vtype == VT_VALUE ) {
87
+ km_smat_each2_v(sy, sx, km_add_v, NULL);
88
+ } else {
89
+ rb_raise(km_eInternal, "unknown value type");
90
+ }
91
+ return self;
92
+ }
93
+
94
+ static void
95
+ km_sub_d(double *y, double *x, void *null)
96
+ {
97
+ *y -= *x;
98
+ }
99
+ static void
100
+ km_sub_z(COMPLEX *y, COMPLEX *x, void *null)
101
+ {
102
+ *y -= *x;
103
+ }
104
+ static void
105
+ km_sub_i(int *y, int *x, void *null)
106
+ {
107
+ *y -= *x;
108
+ }
109
+ static void
110
+ km_sub_v(VALUE *y, VALUE *x, void *null)
111
+ {
112
+ *y = rb_funcall(*y, id_op_minus, 1, *x);
113
+ }
114
+ VALUE
115
+ kmm_mat_sub_destl(VALUE self, VALUE other)
116
+ {
117
+ km_check_frozen(self);
118
+ SMAT *sy=km_mat2smat(self), *sx=km_mat2smat(other);
119
+ if ( sy->vtype != sx->vtype ) {
120
+ rb_raise(km_eVT, "value types must be same");
121
+ }
122
+ CHECK_SAME_SIZE(sy, sx);
123
+ if ( sy->vtype == VT_DOUBLE ) {
124
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
125
+ double alpha = -1.0; int len = LENGTH(sy), ione=1;
126
+ daxpy_(&len, &alpha, sx->dbody, &ione, sy->dbody, &ione);
127
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
128
+ double alpha = -1.0; int incy, stepy, incx, stepx;
129
+ if ( sy->trans ) {
130
+ incy = sy->ld; stepy = 1;
131
+ } else {
132
+ incy = 1; stepy = sy->ld;
133
+ }
134
+ if ( sx->trans ) {
135
+ incx = sx->ld; stepx = 1;
136
+ } else {
137
+ incx = 1; stepx = sx->ld;
138
+ }
139
+ for ( int i=0; i<(sy->n); i++ ) {
140
+ daxpy_(&(sy->m), &alpha, (sx->dbody)+(i*stepx), &incx, (sy->dbody)+(i*stepy), &incy);
141
+ }
142
+ } else {
143
+ km_smat_each2_d(sy, sx, km_sub_d, NULL);
144
+ }
145
+ } else if ( sy->vtype == VT_COMPLEX ) {
146
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
147
+ COMPLEX alpha = cpack(-1.0, 0.0); int len = LENGTH(sy), ione=1;
148
+ zaxpy_(&len, &alpha, sx->zbody, &ione, sy->zbody, &ione);
149
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
150
+ COMPLEX alpha = cpack(-1.0, 0.0); int incy, stepy, incx, stepx;
151
+ if ( sy->trans ) {
152
+ incy = sy->ld; stepy = 1;
153
+ } else {
154
+ incy = 1; stepy = sy->ld;
155
+ }
156
+ if ( sx->trans ) {
157
+ incx = sx->ld; stepx = 1;
158
+ } else {
159
+ incx = 1; stepx = sx->ld;
160
+ }
161
+ for ( int i=0; i<(sy->n); i++ ) {
162
+ zaxpy_(&(sy->m), &alpha, (sx->zbody)+(i*stepx), &incx, (sy->zbody)+(i*stepy), &incy);
163
+ }
164
+ } else {
165
+ km_smat_each2_z(sy, sx, km_sub_z, NULL);
166
+ }
167
+ } else if ( sy->vtype == VT_INT ) {
168
+ km_smat_each2_i(sy, sx, km_sub_i, NULL);
169
+ } else if ( sy->vtype == VT_BOOL ) {
170
+ km_smat_each2_b(sy, sx, km_add_b, NULL); // subtract is the same as add for boolean
171
+ } else if ( sy->vtype == VT_VALUE ) {
172
+ km_smat_each2_v(sy, sx, km_sub_v, NULL);
173
+ } else {
174
+ rb_raise(km_eInternal, "unkown value type");
175
+ }
176
+ return self;
177
+ }
178
+
179
+ static void
180
+ km_mul_d(double *y, double *x, void *null)
181
+ {
182
+ *y *= *x;
183
+ }
184
+ static void
185
+ km_mul_z(COMPLEX *y, COMPLEX *x, void *null)
186
+ {
187
+ *y *= *x;
188
+ }
189
+ static void
190
+ km_mul_i(int *y, int *x, void *null)
191
+ {
192
+ *y *= *x;
193
+ }
194
+ static void
195
+ km_mul_b(bool *y, bool *x, void *null)
196
+ {
197
+ *y = ( *y && *x );
198
+ }
199
+ static void
200
+ km_mul_v(VALUE *y, VALUE *x, void *null)
201
+ {
202
+ *y = rb_funcall(*y, id_op_mul, 1, *x);
203
+ }
204
+ VALUE
205
+ kmm_mat_e_mul_destl(VALUE self, VALUE other)
206
+ {
207
+ km_check_frozen(self);
208
+ SMAT *sy=km_mat2smat(self), *sx=km_mat2smat(other);
209
+ if ( sy->vtype != sx->vtype ) {
210
+ rb_raise(km_eVT, "value types must be same");
211
+ }
212
+ CHECK_SAME_SIZE(sy, sx);
213
+ if ( sy->vtype == VT_DOUBLE ) {
214
+ km_smat_each2_d(sy, sx, km_mul_d, NULL);
215
+ } else if ( sy->vtype == VT_COMPLEX ) {
216
+ km_smat_each2_z(sy, sx, km_mul_z, NULL);
217
+ } else if ( sy->vtype == VT_INT ) {
218
+ km_smat_each2_i(sy, sx, km_mul_i, NULL);
219
+ } else if ( sy->vtype == VT_BOOL ) {
220
+ km_smat_each2_b(sy, sx, km_mul_b, NULL);
221
+ } else if ( sy->vtype == VT_VALUE ) {
222
+ km_smat_each2_v(sy, sx, km_mul_v, NULL);
223
+ } else {
224
+ rb_raise(km_eInternal, "unknown value type");
225
+ }
226
+ return self;
227
+ }
228
+
229
+ static void
230
+ km_div_d(double *y, double *x, void *null)
231
+ {
232
+ if ( *x == 0.0 ) {
233
+ rb_raise(rb_eZeroDivError, "divided by 0");
234
+ }
235
+ *y /= *x;
236
+ }
237
+ static void
238
+ km_div_z(COMPLEX *y, COMPLEX *x, void *null)
239
+ {
240
+ if ( *x == cpack(0.0, 0.0) ) {
241
+ rb_raise(rb_eZeroDivError, "divided by 0");
242
+ }
243
+ *y /= *x;
244
+ }
245
+ static void
246
+ km_div_i(int *y, int *x, void *null)
247
+ {
248
+ if ( *x == 0 ) {
249
+ rb_raise(rb_eZeroDivError, "divided by 0");
250
+ }
251
+ *y /= *x;
252
+ }
253
+ static void
254
+ km_div_v(VALUE *y, VALUE *x, void *null)
255
+ {
256
+ *y = rb_funcall(*y, id_op_div, 1, *x);
257
+ }
258
+ VALUE
259
+ kmm_mat_e_div_destl(VALUE self, VALUE other)
260
+ {
261
+ km_check_frozen(self);
262
+ SMAT *sy=km_mat2smat(self), *sx=km_mat2smat(other);
263
+ if ( sy->vtype != sx->vtype ) {
264
+ rb_raise(km_eVT, "value types must be same");
265
+ }
266
+ CHECK_SAME_SIZE(sy, sx);
267
+ if ( sy->vtype == VT_DOUBLE ) {
268
+ km_smat_each2_d(sy, sx, km_div_d, NULL);
269
+ } else if ( sy->vtype == VT_COMPLEX ) {
270
+ km_smat_each2_z(sy, sx, km_div_z, NULL);
271
+ } else if ( sy->vtype == VT_INT ) {
272
+ km_smat_each2_i(sy, sx, km_div_i, NULL);
273
+ } else if ( sy->vtype == VT_BOOL ) {
274
+ rb_raise(km_eVT, "division for boolean is meaningless");
275
+ } else if ( sy->vtype == VT_VALUE ) {
276
+ km_smat_each2_v(sy, sx, km_div_v, NULL);
277
+ } else {
278
+ rb_raise(km_eInternal, "unknown value type");
279
+ }
280
+ return self;
281
+ }
282
+
283
+ static void
284
+ km_s_add_d(double *ent, void *data)
285
+ {
286
+ double *val = (double *)data;
287
+ *ent += *val;
288
+ }
289
+ static void
290
+ km_s_add_z(COMPLEX *ent, void *data)
291
+ {
292
+ COMPLEX *val = (COMPLEX *)data;
293
+ *ent += *val;
294
+ }
295
+ static void
296
+ km_s_add_i(int *ent, void *data)
297
+ {
298
+ int *val = (int *)data;
299
+ *ent += *val;
300
+ }
301
+ static void
302
+ km_s_add_b(bool *ent, void *data)
303
+ {
304
+ bool *val = (bool *)data;
305
+ *ent = XOR(*ent, *val);
306
+ }
307
+ static void
308
+ km_s_add_v(VALUE *ent, void *data)
309
+ {
310
+ VALUE val = (VALUE)data;
311
+ *ent = rb_funcall(*ent, id_op_plus, 1, val);
312
+ }
313
+ VALUE
314
+ kmm_mat_s_add_destl(VALUE self, VALUE vval)
315
+ {
316
+ km_check_frozen(self);
317
+ SMAT *sy = km_mat2smat(self);
318
+ if ( sy->vtype == VT_DOUBLE ) {
319
+ double val = NUM2DBL(vval);
320
+ if ( sy->stype == ST_FULL ) {
321
+ double alpha=1.0;
322
+ int len=LENGTH(sy), ione=1, izero=0;
323
+ daxpy_(&len, &alpha, &val, &izero, sy->dbody, &ione);
324
+ } else if ( sy->stype == ST_SSUB ) {
325
+ double alpha=1.0;
326
+ int ione=1, izero=0;
327
+ if ( sy->trans ) {
328
+ for ( int i=0; i<(sy->m); i++ ) {
329
+ daxpy_(&(sy->n), &alpha, &val, &izero, (sy->dbody)+(i*(sy->ld)), &ione);
330
+ }
331
+ } else {
332
+ for ( int i=0; i<(sy->n); i++ ) {
333
+ daxpy_(&(sy->m), &alpha, &val, &izero, (sy->dbody)+(i*(sy->ld)), &ione);
334
+ }
335
+ }
336
+ } else {
337
+ km_smat_each_d(sy, km_s_add_d, (void *)&val);
338
+ }
339
+ } else if ( sy->vtype == VT_COMPLEX ) {
340
+ COMPLEX val = km_v2c(vval);
341
+ if ( sy->stype == ST_FULL ) {
342
+ COMPLEX alpha=cpack(1.0, 0.0);
343
+ int len=LENGTH(sy), ione=1, izero=0;
344
+ zaxpy_(&len, &alpha, &val, &izero, sy->zbody, &ione);
345
+ } else if ( sy->stype == ST_SSUB ) {
346
+ COMPLEX alpha=cpack(1.0, 0.0);
347
+ int ione=1, izero=0;
348
+ if ( sy->trans ) {
349
+ for ( int i=0; i<(sy->m); i++ ) {
350
+ zaxpy_(&(sy->n), &alpha, &val, &izero, (sy->zbody)+(i*(sy->ld)), &ione);
351
+ }
352
+ } else {
353
+ for ( int i=0; i<(sy->n); i++ ) {
354
+ zaxpy_(&(sy->m), &alpha, &val, &izero, (sy->zbody)+(i*(sy->ld)), &ione);
355
+ }
356
+ }
357
+ } else {
358
+ km_smat_each_z(sy, km_s_add_z, (void *)&val);
359
+ }
360
+ } else if ( sy->vtype == VT_INT ) {
361
+ int val = NUM2INT(vval);
362
+ km_smat_each_i(sy, km_s_add_i, (void *)&val);
363
+ } else if ( sy->vtype == VT_BOOL ) {
364
+ bool val = RTEST(vval);
365
+ km_smat_each_b(sy, km_s_add_b, (void *)&val);
366
+ } else if ( sy->vtype == VT_VALUE ) {
367
+ km_smat_each_v(sy, km_s_add_v, (void *)vval);
368
+ } else {
369
+ rb_raise(km_eInternal, "unknown value type");
370
+ }
371
+ return self;
372
+ }
373
+
374
+ static void
375
+ km_s_sub_d(double *ent, void *data)
376
+ {
377
+ double *val = (double *)data;
378
+ *ent -= *val;
379
+ }
380
+ static void
381
+ km_s_sub_z(COMPLEX *ent, void *data)
382
+ {
383
+ COMPLEX *val = (COMPLEX *)data;
384
+ *ent -= *val;
385
+ }
386
+ static void
387
+ km_s_sub_i(int *ent, void *data)
388
+ {
389
+ int *val = (int *)data;
390
+ *ent -= *val;
391
+ }
392
+ static void
393
+ km_s_sub_v(VALUE *ent, void *data)
394
+ {
395
+ VALUE val = (VALUE)data;
396
+ *ent = rb_funcall(*ent, id_op_minus, 1, val);
397
+ }
398
+ VALUE
399
+ kmm_mat_s_sub_destl(VALUE self, VALUE vval)
400
+ {
401
+ km_check_frozen(self);
402
+ SMAT *sy = km_mat2smat(self);
403
+ if ( sy->vtype == VT_DOUBLE ) {
404
+ double val = NUM2DBL(vval);
405
+ if ( sy->stype == ST_FULL ) {
406
+ double alpha=-1.0;
407
+ int len=LENGTH(sy), ione=1, izero=0;
408
+ daxpy_(&len, &alpha, &val, &izero, sy->dbody, &ione);
409
+ } else if ( sy->stype == ST_SSUB ) {
410
+ double alpha=-1.0;
411
+ int ione=1, izero=0;
412
+ if ( sy->trans ) {
413
+ for ( int i=0; i<(sy->m); i++ ) {
414
+ daxpy_(&(sy->n), &alpha, &val, &izero, (sy->dbody)+(i*(sy->ld)), &ione);
415
+ }
416
+ } else {
417
+ for ( int i=0; i<(sy->n); i++ ) {
418
+ daxpy_(&(sy->m), &alpha, &val, &izero, (sy->dbody)+(i*(sy->ld)), &ione);
419
+ }
420
+ }
421
+ } else {
422
+ km_smat_each_d(sy, km_s_sub_d, (void *)&val);
423
+ }
424
+ } else if ( sy->vtype == VT_COMPLEX ) {
425
+ COMPLEX val = km_v2c(vval);
426
+ if ( sy->stype == ST_FULL ) {
427
+ COMPLEX alpha=cpack(-1.0, 0.0);
428
+ int len=LENGTH(sy), ione=1, izero=0;
429
+ zaxpy_(&len, &alpha, &val, &izero, sy->zbody, &ione);
430
+ } else if ( sy->stype == ST_SSUB ) {
431
+ COMPLEX alpha=cpack(-1.0, 0.0);
432
+ int ione=1, izero=0;
433
+ if ( sy->trans ) {
434
+ for ( int i=0; i<(sy->m); i++ ) {
435
+ zaxpy_(&(sy->n), &alpha, &val, &izero, (sy->zbody)+(i*(sy->ld)), &ione);
436
+ }
437
+ } else {
438
+ for ( int i=0; i<(sy->n); i++ ) {
439
+ zaxpy_(&(sy->m), &alpha, &val, &izero, (sy->zbody)+(i*(sy->ld)), &ione);
440
+ }
441
+ }
442
+ } else {
443
+ km_smat_each_z(sy, km_s_sub_z, (void *)&val);
444
+ }
445
+ } else if ( sy->vtype == VT_INT ) {
446
+ int val = NUM2INT(vval);
447
+ km_smat_each_i(sy, km_s_sub_i, (void *)&val);
448
+ } else if ( sy->vtype == VT_BOOL ) {
449
+ bool val = RTEST(vval);
450
+ km_smat_each_b(sy, km_s_add_b, (void *)&val); // subtract is the same as add for boolean
451
+ } else if ( sy->vtype == VT_VALUE ) {
452
+ km_smat_each_v(sy, km_s_sub_v, (void *)vval);
453
+ } else {
454
+ rb_raise(km_eInternal, "unknown value type");
455
+ }
456
+ return self;
457
+ }
458
+
459
+
460
+ static void
461
+ km_s_mul_d(double *ent, void *data)
462
+ {
463
+ double *val = (double *)data;
464
+ *ent *= *val;
465
+ }
466
+ static void
467
+ km_s_mul_z(COMPLEX *ent, void *data)
468
+ {
469
+ COMPLEX *val = (COMPLEX *)data;
470
+ *ent *= *val;
471
+ }
472
+ static void
473
+ km_s_mul_i(int *ent, void *data)
474
+ {
475
+ int *val = (int *)data;
476
+ *ent *= *val;
477
+ }
478
+ static void
479
+ km_s_mul_v(VALUE *ent, void *data)
480
+ {
481
+ VALUE val = (VALUE)data;
482
+ *ent = rb_funcall(*ent, id_op_mul, 1, val);
483
+ }
484
+ VALUE
485
+ kmm_mat_s_mul_destl(VALUE self, VALUE vval)
486
+ {
487
+ km_check_frozen(self);
488
+ SMAT *sy = km_mat2smat(self);
489
+ if ( sy->vtype == VT_DOUBLE ) {
490
+ double val = NUM2DBL(vval);
491
+ if ( sy->stype == ST_FULL ) {
492
+ int len=LENGTH(sy), ione=1;
493
+ dscal_(&len, &val, sy->dbody, &ione);
494
+ } else if ( sy->stype == ST_SSUB ) {
495
+ int ione=1;
496
+ if ( sy->trans ) {
497
+ for ( int i=0; i<(sy->m); i++ ) {
498
+ dscal_(&(sy->n), &val, (sy->dbody)+(i*(sy->ld)), &ione);
499
+ }
500
+ } else {
501
+ for ( int i=0; i<(sy->n); i++ ) {
502
+ dscal_(&(sy->m), &val, (sy->dbody)+(i*(sy->ld)), &ione);
503
+ }
504
+ }
505
+ } else {
506
+ km_smat_each_d(sy, km_s_mul_d, (void *)&val);
507
+ }
508
+ } else if ( sy->vtype == VT_COMPLEX ) {
509
+ COMPLEX val = km_v2c(vval);
510
+ if ( sy->stype == ST_FULL ) {
511
+ int len=LENGTH(sy), ione=1;
512
+ zscal_(&len, &val, sy->zbody, &ione);
513
+ } else if ( sy->stype == ST_SSUB ) {
514
+ int ione=1;
515
+ if ( sy->trans ) {
516
+ for ( int i=0; i<(sy->m); i++ ) {
517
+ zscal_(&(sy->n), &val, (sy->zbody)+(i*(sy->ld)), &ione);
518
+ }
519
+ } else {
520
+ for ( int i=0; i<(sy->n); i++ ) {
521
+ zscal_(&(sy->m), &val, (sy->zbody)+(i*(sy->ld)), &ione);
522
+ }
523
+ }
524
+ } else {
525
+ km_smat_each_z(sy, km_s_mul_z, (void *)&val);
526
+ }
527
+ } else if ( sy->vtype == VT_INT ) {
528
+ int val = NUM2INT(vval);
529
+ km_smat_each_i(sy, km_s_mul_i, (void *)&val);
530
+ } else if ( sy->vtype == VT_BOOL ) {
531
+ if ( RTEST(vval) ) {
532
+ // nothing to do
533
+ } else {
534
+ kmm_mat_fill(self, Qfalse);
535
+ }
536
+ } else if ( sy->vtype == VT_VALUE ) {
537
+ km_smat_each_v(sy, km_s_mul_v, (void *)vval);
538
+ } else {
539
+ rb_raise(km_eInternal, "unknown value type");
540
+ }
541
+ return self;
542
+ }
543
+
544
+ static void
545
+ km_s_div_i(int *ent, void *data)
546
+ {
547
+ int *val = (int *)data;
548
+ *ent /= *val;
549
+ }
550
+ static void
551
+ km_s_div_v(VALUE *ent, void *data)
552
+ {
553
+ VALUE val = (VALUE)data;
554
+ *ent = rb_funcall(*ent, id_op_div, 1, val);
555
+ }
556
+ VALUE
557
+ kmm_mat_s_div_destl(VALUE self, VALUE vval)
558
+ {
559
+ km_check_frozen(self);
560
+ SMAT *sy = km_mat2smat(self);
561
+ if ( sy->vtype == VT_DOUBLE ) {
562
+ double val = NUM2DBL(vval);
563
+ if ( val == 0.0 ) { rb_raise(rb_eZeroDivError, "divided by 0"); }
564
+ val = 1.0/val;
565
+ if ( sy->stype == ST_FULL ) {
566
+ int len=LENGTH(sy), ione=1;
567
+ dscal_(&len, &val, sy->dbody, &ione);
568
+ } else if ( sy->stype == ST_SSUB ) {
569
+ int ione=1;
570
+ if ( sy->trans ) {
571
+ for ( int i=0; i<(sy->m); i++ ) {
572
+ dscal_(&(sy->n), &val, (sy->dbody)+(i*(sy->ld)), &ione);
573
+ }
574
+ } else {
575
+ for ( int i=0; i<(sy->n); i++ ) {
576
+ dscal_(&(sy->m), &val, (sy->dbody)+(i*(sy->ld)), &ione);
577
+ }
578
+ }
579
+ } else {
580
+ km_smat_each_d(sy, km_s_mul_d, (void *)&val);
581
+ }
582
+ } else if ( sy->vtype == VT_COMPLEX ) {
583
+ COMPLEX val = km_v2c(vval);
584
+ if ( val == cpack(0.0, 0.0) ) { rb_raise(rb_eZeroDivError, "divided by 0"); }
585
+ val = cpack(1.0, 0.0)/val;
586
+ if ( sy->stype == ST_FULL ) {
587
+ int len=LENGTH(sy), ione=1;
588
+ zscal_(&len, &val, sy->zbody, &ione);
589
+ } else if ( sy->stype == ST_SSUB ) {
590
+ int ione=1;
591
+ if ( sy->trans ) {
592
+ for ( int i=0; i<(sy->m); i++ ) {
593
+ zscal_(&(sy->n), &val, (sy->zbody)+(i*(sy->ld)), &ione);
594
+ }
595
+ } else {
596
+ for ( int i=0; i<(sy->n); i++ ) {
597
+ zscal_(&(sy->m), &val, (sy->zbody)+(i*(sy->ld)), &ione);
598
+ }
599
+ }
600
+ } else {
601
+ km_smat_each_z(sy, km_s_mul_z, (void *)&val);
602
+ }
603
+ } else if ( sy->vtype == VT_INT ) {
604
+ int val = NUM2INT(vval);
605
+ if ( val == 0 ) { rb_raise(rb_eZeroDivError, "divided by 0"); }
606
+ km_smat_each_i(sy, km_s_div_i, (void *)&val);
607
+ } else if ( sy->vtype == VT_BOOL ) {
608
+ rb_raise(km_eVT, "division for boolean is meaningless");
609
+ } else if ( sy->vtype == VT_VALUE ) {
610
+ km_smat_each_v(sy, km_s_div_v, (void *)vval);
611
+ } else {
612
+ rb_raise(km_eInternal, "unknown value type");
613
+ }
614
+ return self;
615
+ }
616
+
617
+ static void
618
+ km_add_times_d(double *y, double *x, void *data)
619
+ {
620
+ double *a = (double *)data;
621
+ *y += ( (*x) * (*a) );
622
+ }
623
+ static void
624
+ km_add_times_z(COMPLEX *y, COMPLEX *x, void *data)
625
+ {
626
+ COMPLEX *a = (COMPLEX *)data;
627
+ *y += ( (*x) * (*a) );
628
+ }
629
+ static void
630
+ km_add_times_i(int *y, int *x, void *data)
631
+ {
632
+ int *a = (int *)data;
633
+ *y += ( (*x) * (*a) );
634
+ }
635
+ static void
636
+ km_add_times_v(VALUE *y, VALUE *x, void *data)
637
+ {
638
+ VALUE a = (VALUE)data;
639
+ a = rb_funcall(*x, id_op_mul, 1, a);
640
+ *y = rb_funcall(*y, id_op_plus, 1, a);
641
+ }
642
+ VALUE
643
+ kmm_mat_add_times_destl(VALUE self, VALUE other, VALUE valpha)
644
+ {
645
+ km_check_frozen(self);
646
+ SMAT *sy=km_mat2smat(self), *sx=km_mat2smat(other);
647
+ if ( sy->vtype != sx->vtype ) {
648
+ rb_raise(km_eVT, "value types must be same");
649
+ }
650
+ CHECK_SAME_SIZE(sx, sy);
651
+ if ( sy->vtype == VT_DOUBLE ) {
652
+ double alpha = NUM2DBL(valpha);
653
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
654
+ int len = LENGTH(sy), ione=1;
655
+ daxpy_(&len, &alpha, sx->dbody, &ione, sy->dbody, &ione);
656
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
657
+ int incy, stepy, incx, stepx;
658
+ if ( sy->trans ) {
659
+ incy = sy->ld; stepy = 1;
660
+ } else {
661
+ incy = 1; stepy = sy->ld;
662
+ }
663
+ if ( sx->trans ) {
664
+ incx = sx->ld; stepx = 1;
665
+ } else {
666
+ incx = 1; stepx = sx->ld;
667
+ }
668
+ for ( int i=0; i<(sy->n); i++ ) {
669
+ daxpy_(&(sy->m), &alpha, (sx->dbody)+(i*stepx), &incx, (sy->dbody)+(i*stepy), &incy);
670
+ }
671
+ } else {
672
+ km_smat_each2_d(sy, sx, km_add_times_d, (void *)&alpha);
673
+ }
674
+ } else if ( sy->vtype == VT_COMPLEX ) {
675
+ COMPLEX alpha = km_v2c(valpha);
676
+ if ( sy->stype == ST_FULL && sx->stype == ST_FULL && sy->trans == sx->trans ) {
677
+ int len = LENGTH(sy), ione=1;
678
+ zaxpy_(&len, &alpha, sx->zbody, &ione, sy->zbody, &ione);
679
+ } else if ( sy->stype != ST_RSUB && sx->stype != ST_RSUB ) {
680
+ int incy, stepy, incx, stepx;
681
+ if ( sy->trans ) {
682
+ incy = sy->ld; stepy = 1;
683
+ } else {
684
+ incy = 1; stepy = sy->ld;
685
+ }
686
+ if ( sx->trans ) {
687
+ incx = sx->ld; stepx = 1;
688
+ } else {
689
+ incx = 1; stepx = sx->ld;
690
+ }
691
+ for ( int i=0; i<(sy->n); i++ ) {
692
+ zaxpy_(&(sy->m), &alpha, (sx->zbody)+(i*stepx), &incx, (sy->zbody)+(i*stepy), &incy);
693
+ }
694
+ } else {
695
+ km_smat_each2_z(sy, sx, km_add_times_z, (void *)&alpha);
696
+ }
697
+ } else if ( sy->vtype == VT_INT ) {
698
+ int alpha = NUM2INT(valpha);
699
+ km_smat_each2_i(sy, sx, km_add_times_i, (void *)&alpha);
700
+ } else if ( sy->vtype == VT_BOOL ) {
701
+ if ( RTEST(valpha) ) {
702
+ kmm_mat_add_destl(self, other);
703
+ } else {
704
+ // nothing to do
705
+ }
706
+ } else if ( sy->vtype == VT_VALUE ) {
707
+ km_smat_each2_v(sy, sx, km_add_times_v, (void *)valpha);
708
+ } else {
709
+ rb_raise(km_eVT, "unknown value type");
710
+ }
711
+ return self;
712
+ }
713
+
714
+ // element-wise max/min operations of two matricies
715
+ static void
716
+ km_maximum_d(double *ey, double *ex, void *null)
717
+ {
718
+ if ( *ey < *ex ) {
719
+ *ey = *ex;
720
+ }
721
+ }
722
+ static void
723
+ km_maximum_i(int *ey, int *ex, void *null)
724
+ {
725
+ if ( *ey < *ex ) {
726
+ *ey = *ex;
727
+ }
728
+ }
729
+ static void
730
+ km_maximum_b(bool *ey, bool *ex, void *null)
731
+ {
732
+ if ( *ex ) {
733
+ *ey = true;
734
+ }
735
+ }
736
+ static void
737
+ km_maximum_v(VALUE *ey, VALUE *ex, void *null)
738
+ {
739
+ if ( rb_funcall(*ey, id_op_lt, 1, *ex) ) {
740
+ *ey = *ex;
741
+ }
742
+ }
743
+ VALUE
744
+ kmm_mat_maximum_destl(VALUE self, VALUE other)
745
+ {
746
+ km_check_frozen(self);
747
+ SMAT *sy = km_mat2smat(self), *sx = km_mat2smat(other);
748
+ if ( sy->vtype != sx->vtype ) {
749
+ rb_raise(km_eVT, "value types must be same");
750
+ }
751
+ CHECK_SAME_SIZE(sx, sy);
752
+ if ( sy->vtype == VT_DOUBLE ) {
753
+ km_smat_each2_d(sy, sx, km_maximum_d, NULL);
754
+ } else if ( sy->vtype == VT_COMPLEX ) {
755
+ VALUE oself = kmm_mat_to_omat(self);
756
+ sy = km_mat2smat(oself);
757
+ sx = km_mat2smat(kmm_mat_to_omat(other));
758
+ km_smat_each2_v(sy, sx, km_maximum_v, NULL);
759
+ kmm_mat_copy_from(self, oself);
760
+ } else if ( sy->vtype == VT_INT ) {
761
+ km_smat_each2_i(sy, sx, km_maximum_i, NULL);
762
+ } else if ( sy->vtype == VT_BOOL ) {
763
+ km_smat_each2_b(sy, sx, km_maximum_b, NULL);
764
+ } else if ( sy->vtype == VT_VALUE ) {
765
+ km_smat_each2_v(sy, sx, km_maximum_v, NULL);
766
+ } else {
767
+ rb_raise(km_eInternal, "unknown value type");
768
+ }
769
+ return self;
770
+ }
771
+
772
+ static void
773
+ km_s_maximum_d(double *ey, void *data)
774
+ {
775
+ double *val = (double *)data;
776
+ if ( *ey < *val ) {
777
+ *ey = *val;
778
+ }
779
+ }
780
+ static void
781
+ km_s_maximum_i(int *ey, void *data)
782
+ {
783
+ int *val = (int *)data;
784
+ if ( *ey < *val ) {
785
+ *ey = *val;
786
+ }
787
+ }
788
+ static void
789
+ km_s_maximum_b(bool *ey, void *data)
790
+ {
791
+ bool *val = (bool *)data;
792
+ if ( *val ) {
793
+ *ey = true;
794
+ }
795
+ }
796
+ static void
797
+ km_s_maximum_v(VALUE *ey, void *data)
798
+ {
799
+ VALUE val = (VALUE)data;
800
+ if ( rb_funcall(*ey, id_op_lt, 1, val) ) {
801
+ *ey = val;
802
+ }
803
+ }
804
+ VALUE
805
+ kmm_mat_s_maximum_destl(VALUE self, VALUE other)
806
+ {
807
+ km_check_frozen(self);
808
+ SMAT *sy = km_mat2smat(self);
809
+ if ( sy->vtype == VT_DOUBLE ) {
810
+ double data = NUM2DBL(other);
811
+ km_smat_each_d(sy, km_s_maximum_d, (void *)&data);
812
+ } else if ( sy->vtype == VT_COMPLEX ) {
813
+ VALUE oself = kmm_mat_to_omat(self);
814
+ sy = km_mat2smat(oself);
815
+ km_smat_each_v(sy, km_s_maximum_v, (void *)other);
816
+ kmm_mat_copy_from(self, oself);
817
+ } else if ( sy->vtype == VT_INT ) {
818
+ int data = NUM2INT(other);
819
+ km_smat_each_i(sy, km_s_maximum_i, (void *)&data);
820
+ } else if ( sy->vtype == VT_BOOL ) {
821
+ bool data = RTEST(other);
822
+ km_smat_each_b(sy, km_s_maximum_b, (void *)&data);
823
+ } else if ( sy->vtype == VT_VALUE ) {
824
+ km_smat_each_v(sy, km_s_maximum_v, (void *)other);
825
+ } else {
826
+ rb_raise(km_eInternal, "unknown value type");
827
+ }
828
+ return self;
829
+ }
830
+
831
+ static void
832
+ km_minimum_d(double *ey, double *ex, void *null)
833
+ {
834
+ if ( *ex < *ey ) {
835
+ *ey = *ex;
836
+ }
837
+ }
838
+ static void
839
+ km_minimum_i(int *ey, int *ex, void *null)
840
+ {
841
+ if ( *ex < *ey ) {
842
+ *ey = *ex;
843
+ }
844
+ }
845
+ static void
846
+ km_minimum_b(bool *ey, bool *ex, void *null)
847
+ {
848
+ if ( !*ex ) {
849
+ *ey = false;
850
+ }
851
+ }
852
+ static void
853
+ km_minimum_v(VALUE *ey, VALUE *ex, void *null)
854
+ {
855
+ if ( rb_funcall(*ex, id_op_lt, 1, *ey) ) {
856
+ *ey = *ex;
857
+ }
858
+ }
859
+ VALUE
860
+ kmm_mat_minimum_destl(VALUE self, VALUE other)
861
+ {
862
+ km_check_frozen(self);
863
+ SMAT *sy = km_mat2smat(self), *sx = km_mat2smat(other);
864
+ if ( sy->vtype != sx->vtype ) {
865
+ rb_raise(km_eVT, "value types must be same");
866
+ }
867
+ CHECK_SAME_SIZE(sx, sy);
868
+ if ( sy->vtype == VT_DOUBLE ) {
869
+ km_smat_each2_d(sy, sx, km_minimum_d, NULL);
870
+ } else if ( sy->vtype == VT_COMPLEX ) {
871
+ VALUE oself = kmm_mat_to_omat(self);
872
+ sy = km_mat2smat(oself);
873
+ sx = km_mat2smat(kmm_mat_to_omat(other));
874
+ km_smat_each2_v(sy, sx, km_minimum_v, NULL);
875
+ kmm_mat_copy_from(self, oself);
876
+ } else if ( sy->vtype == VT_INT ) {
877
+ km_smat_each2_i(sy, sx, km_minimum_i, NULL);
878
+ } else if ( sy->vtype == VT_BOOL ) {
879
+ km_smat_each2_b(sy, sx, km_minimum_b, NULL);
880
+ } else if ( sy->vtype == VT_VALUE ) {
881
+ km_smat_each2_v(sy, sx, km_minimum_v, NULL);
882
+ } else {
883
+ rb_raise(km_eInternal, "unknown value type");
884
+ }
885
+ return self;
886
+ }
887
+
888
+ static void
889
+ km_s_minimum_d(double *ey, void *data)
890
+ {
891
+ double *val = (double *)data;
892
+ if ( *val < *ey ) {
893
+ *ey = *val;
894
+ }
895
+ }
896
+ static void
897
+ km_s_minimum_i(int *ey, void *data)
898
+ {
899
+ int *val = (int *)data;
900
+ if ( *val < *ey ) {
901
+ *ey = *val;
902
+ }
903
+ }
904
+ static void
905
+ km_s_minimum_b(bool *ey, void *data)
906
+ {
907
+ bool *val = (bool *)data;
908
+ if ( !*val ) {
909
+ *ey = false;
910
+ }
911
+ }
912
+ static void
913
+ km_s_minimum_v(VALUE *ey, void *data)
914
+ {
915
+ VALUE val = (VALUE)data;
916
+ if ( rb_funcall(val, id_op_lt, 1, *ey) ) {
917
+ *ey = val;
918
+ }
919
+ }
920
+ VALUE
921
+ kmm_mat_s_minimum_destl(VALUE self, VALUE other)
922
+ {
923
+ km_check_frozen(self);
924
+ SMAT *sy = km_mat2smat(self);
925
+ if ( sy->vtype == VT_DOUBLE ) {
926
+ double data = NUM2DBL(other);
927
+ km_smat_each_d(sy, km_s_minimum_d, (void *)&data);
928
+ } else if ( sy->vtype == VT_COMPLEX ) {
929
+ VALUE oself = kmm_mat_to_omat(self);
930
+ sy = km_mat2smat(oself);
931
+ km_smat_each_v(sy, km_s_minimum_v, (void *)other);
932
+ kmm_mat_copy_from(self, oself);
933
+ } else if ( sy->vtype == VT_INT ) {
934
+ int data = NUM2INT(other);
935
+ km_smat_each_i(sy, km_s_minimum_i, (void *)&data);
936
+ } else if ( sy->vtype == VT_BOOL ) {
937
+ bool data = RTEST(other);
938
+ km_smat_each_b(sy, km_s_minimum_b, (void *)&data);
939
+ } else if ( sy->vtype == VT_VALUE ) {
940
+ km_smat_each_v(sy, km_s_minimum_v, (void *)other);
941
+ } else {
942
+ rb_raise(km_eInternal, "unknown value type");
943
+ }
944
+ return self;
945
+ }
946
+
947
+ // pow, hypot
948
+ static void
949
+ km_pow_d(double *b, double *e, void *null)
950
+ {
951
+ *b = pow(*b, *e);
952
+ }
953
+ static void
954
+ km_pow_z(COMPLEX *b, COMPLEX *e, void *null)
955
+ {
956
+ *b = cpow(*b, *e);
957
+ }
958
+ static void
959
+ km_pow_i(int *b, int *e, void *null)
960
+ {
961
+ if ( *e < 0 ) {
962
+ rb_raise(rb_const_get(rb_mMath, id_DomainError), "the exponent must be non-negative");
963
+ }
964
+ int a = *b;
965
+ *b = 1;
966
+ for (int i=*e; i>0; i>>=1) {
967
+ if ( i & 1 ) {
968
+ *b *= a;
969
+ }
970
+ a *= a;
971
+ }
972
+ }
973
+ static void
974
+ km_pow_b(bool *b, bool *e, void *null)
975
+ {
976
+ *b = ( *b || !*e );
977
+ }
978
+ static void
979
+ km_pow_v(VALUE *b, VALUE *e, void *null)
980
+ {
981
+ *b = rb_funcall(*b, id_op_pow, 1, *e);
982
+ }
983
+ VALUE
984
+ kmm_mat_pow_destl(VALUE self, VALUE other)
985
+ {
986
+ km_check_frozen(self);
987
+ SMAT *sb = km_mat2smat(self), *se = km_mat2smat(other);
988
+ if ( sb->vtype != se->vtype ) {
989
+ rb_raise(km_eVT, "value types must be same");
990
+ }
991
+ CHECK_SAME_SIZE(sb, se);
992
+ VT_SWITCH( sb->vtype,
993
+ km_smat_each2_d(sb, se, km_pow_d, NULL);,
994
+ km_smat_each2_z(sb, se, km_pow_z, NULL);,
995
+ km_smat_each2_i(sb, se, km_pow_i, NULL);,
996
+ km_smat_each2_b(sb, se, km_pow_b, NULL);,
997
+ km_smat_each2_v(sb, se, km_pow_v, NULL);
998
+ );
999
+ return self;
1000
+ }
1001
+
1002
+ static void
1003
+ km_s_pow_d(double *b, void *data)
1004
+ {
1005
+ double *e = (double *)data;
1006
+ *b = pow(*b, *e);
1007
+ }
1008
+ static void
1009
+ km_s_pow_z(COMPLEX *b, void *data)
1010
+ {
1011
+ COMPLEX *e = (COMPLEX *)data;
1012
+ *b = cpow(*b, *e);
1013
+ }
1014
+ static void
1015
+ km_s_pow_i(int *b, void *data)
1016
+ {
1017
+ int *e = (int *)data;
1018
+ if ( *e < 0 ) {
1019
+ rb_raise(rb_const_get(rb_mMath, id_DomainError), "the exponent must be non-negative");
1020
+ }
1021
+ int a = *b;
1022
+ *b = 1;
1023
+ for (int i=*e; i>0; i>>=1) {
1024
+ if ( i & 1 ) {
1025
+ *b *= a;
1026
+ }
1027
+ a *= a;
1028
+ }
1029
+ }
1030
+ static void
1031
+ km_s_pow_b(bool *b, void *data)
1032
+ {
1033
+ bool *e = (bool *)data;
1034
+ *b = ( *b || !*e );
1035
+ }
1036
+ static void
1037
+ km_s_pow_v(VALUE *b, void *data)
1038
+ {
1039
+ VALUE e = (VALUE)data;
1040
+ *b = rb_funcall(*b, id_op_pow, 1, e);
1041
+ }
1042
+ VALUE
1043
+ kmm_mat_s_pow_destl(VALUE self, VALUE other)
1044
+ {
1045
+ km_check_frozen(self);
1046
+ SMAT *sb = km_mat2smat(self);
1047
+ VT_SWITCH( sb->vtype,
1048
+ double data=NUM2DBL(other); km_smat_each_d(sb, km_s_pow_d, (void *)&data);,
1049
+ COMPLEX data=km_v2c(other); km_smat_each_z(sb, km_s_pow_z, (void *)&data);,
1050
+ int data=NUM2INT(other); km_smat_each_i(sb, km_s_pow_i, (void *)&data);,
1051
+ bool data=RTEST(other); km_smat_each_b(sb, km_s_pow_b, (void *)&data);,
1052
+ km_smat_each_v(sb, km_s_pow_v, (void *)other);
1053
+ );
1054
+ return self;
1055
+ }
1056
+
1057
+ static void
1058
+ km_hypot_d(double *y, double *x, void *null)
1059
+ {
1060
+ *y = hypot(*y, *x);
1061
+ }
1062
+ static void
1063
+ km_hypot_z(COMPLEX *y, COMPLEX *x, void *null)
1064
+ {
1065
+ *y = csqrt((*y)*(*y)+(*x)*(*x));
1066
+ }
1067
+ static void
1068
+ km_hypot_v(VALUE *y, VALUE *x, void *null)
1069
+ {
1070
+ *y = rb_funcall(rb_mMath, id_hypot, 2, *y, *x);
1071
+ }
1072
+ VALUE
1073
+ kmm_mat_hypot_destl(VALUE self, VALUE other)
1074
+ {
1075
+ km_check_frozen(self);
1076
+ SMAT *sy = km_mat2smat(self), *sx = km_mat2smat(other);
1077
+ if ( sy->vtype != sx->vtype ) {
1078
+ rb_raise(km_eVT, "value types must be same");
1079
+ }
1080
+ CHECK_SAME_SIZE(sy, sx);
1081
+ VT_SWITCH( sy->vtype,
1082
+ km_smat_each2_d(sy, sx, km_hypot_d, NULL);,
1083
+ km_smat_each2_z(sy, sx, km_hypot_z, NULL);,
1084
+ rb_raise(km_eVT, "Mat#hypot is not available for int matricies");,
1085
+ km_smat_each2_b(sy, sx, km_add_b, NULL);,
1086
+ km_smat_each2_v(sy, sx, km_hypot_v, NULL);
1087
+ );
1088
+ return self;
1089
+ }
1090
+
1091
+ static void
1092
+ km_s_hypot_d(double *y, void *data)
1093
+ {
1094
+ double *x = (double *)data;
1095
+ *y = hypot(*y, *x);
1096
+ }
1097
+ static void
1098
+ km_s_hypot_z(COMPLEX *y, void *data)
1099
+ {
1100
+ COMPLEX *x = (COMPLEX *)data;
1101
+ *y = csqrt((*y)*(*y)+(*x)*(*x));
1102
+ }
1103
+ static void
1104
+ km_s_hypot_v(VALUE *y, void *data)
1105
+ {
1106
+ *y = rb_funcall(rb_mMath, id_hypot, 2, *y, (VALUE)data);
1107
+ }
1108
+ VALUE
1109
+ kmm_mat_s_hypot_destl(VALUE self, VALUE other)
1110
+ {
1111
+ km_check_frozen(self);
1112
+ SMAT *sy = km_mat2smat(self);
1113
+ VT_SWITCH( sy->vtype,
1114
+ double data=NUM2DBL(other); km_smat_each_d(sy, km_s_hypot_d, (void *)&data);,
1115
+ COMPLEX data=km_v2c(other); km_smat_each_z(sy, km_s_hypot_z, (void *)&data);,
1116
+ rb_raise(km_eVT, "Mat#hypot is not available for int matricies");,
1117
+ bool data=RTEST(other); km_smat_each_b(sy, km_s_add_b, (void *)&data);,
1118
+ km_smat_each_v(sy, km_s_hypot_v, (void *)other);
1119
+ );
1120
+ return self;
1121
+ }