pnmatrix 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/ext/nmatrix/binary_format.txt +53 -0
  3. data/ext/nmatrix/data/complex.h +388 -0
  4. data/ext/nmatrix/data/data.cpp +274 -0
  5. data/ext/nmatrix/data/data.h +651 -0
  6. data/ext/nmatrix/data/meta.h +64 -0
  7. data/ext/nmatrix/data/ruby_object.h +386 -0
  8. data/ext/nmatrix/extconf.rb +70 -0
  9. data/ext/nmatrix/math/asum.h +99 -0
  10. data/ext/nmatrix/math/cblas_enums.h +36 -0
  11. data/ext/nmatrix/math/cblas_templates_core.h +507 -0
  12. data/ext/nmatrix/math/gemm.h +241 -0
  13. data/ext/nmatrix/math/gemv.h +178 -0
  14. data/ext/nmatrix/math/getrf.h +255 -0
  15. data/ext/nmatrix/math/getrs.h +121 -0
  16. data/ext/nmatrix/math/imax.h +82 -0
  17. data/ext/nmatrix/math/laswp.h +165 -0
  18. data/ext/nmatrix/math/long_dtype.h +62 -0
  19. data/ext/nmatrix/math/magnitude.h +54 -0
  20. data/ext/nmatrix/math/math.h +751 -0
  21. data/ext/nmatrix/math/nrm2.h +165 -0
  22. data/ext/nmatrix/math/rot.h +117 -0
  23. data/ext/nmatrix/math/rotg.h +106 -0
  24. data/ext/nmatrix/math/scal.h +71 -0
  25. data/ext/nmatrix/math/trsm.h +336 -0
  26. data/ext/nmatrix/math/util.h +162 -0
  27. data/ext/nmatrix/math.cpp +1368 -0
  28. data/ext/nmatrix/nm_memory.h +60 -0
  29. data/ext/nmatrix/nmatrix.cpp +285 -0
  30. data/ext/nmatrix/nmatrix.h +476 -0
  31. data/ext/nmatrix/ruby_constants.cpp +151 -0
  32. data/ext/nmatrix/ruby_constants.h +106 -0
  33. data/ext/nmatrix/ruby_nmatrix.c +3130 -0
  34. data/ext/nmatrix/storage/common.cpp +77 -0
  35. data/ext/nmatrix/storage/common.h +183 -0
  36. data/ext/nmatrix/storage/dense/dense.cpp +1096 -0
  37. data/ext/nmatrix/storage/dense/dense.h +129 -0
  38. data/ext/nmatrix/storage/list/list.cpp +1628 -0
  39. data/ext/nmatrix/storage/list/list.h +138 -0
  40. data/ext/nmatrix/storage/storage.cpp +730 -0
  41. data/ext/nmatrix/storage/storage.h +99 -0
  42. data/ext/nmatrix/storage/yale/class.h +1139 -0
  43. data/ext/nmatrix/storage/yale/iterators/base.h +143 -0
  44. data/ext/nmatrix/storage/yale/iterators/iterator.h +131 -0
  45. data/ext/nmatrix/storage/yale/iterators/row.h +450 -0
  46. data/ext/nmatrix/storage/yale/iterators/row_stored.h +140 -0
  47. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +169 -0
  48. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +124 -0
  49. data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
  50. data/ext/nmatrix/storage/yale/yale.cpp +2074 -0
  51. data/ext/nmatrix/storage/yale/yale.h +203 -0
  52. data/ext/nmatrix/types.h +55 -0
  53. data/ext/nmatrix/util/io.cpp +279 -0
  54. data/ext/nmatrix/util/io.h +115 -0
  55. data/ext/nmatrix/util/sl_list.cpp +627 -0
  56. data/ext/nmatrix/util/sl_list.h +144 -0
  57. data/ext/nmatrix/util/util.h +78 -0
  58. data/lib/nmatrix/blas.rb +378 -0
  59. data/lib/nmatrix/cruby/math.rb +744 -0
  60. data/lib/nmatrix/enumerate.rb +253 -0
  61. data/lib/nmatrix/homogeneous.rb +241 -0
  62. data/lib/nmatrix/io/fortran_format.rb +138 -0
  63. data/lib/nmatrix/io/harwell_boeing.rb +221 -0
  64. data/lib/nmatrix/io/market.rb +263 -0
  65. data/lib/nmatrix/io/point_cloud.rb +189 -0
  66. data/lib/nmatrix/jruby/decomposition.rb +24 -0
  67. data/lib/nmatrix/jruby/enumerable.rb +13 -0
  68. data/lib/nmatrix/jruby/error.rb +4 -0
  69. data/lib/nmatrix/jruby/math.rb +501 -0
  70. data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
  71. data/lib/nmatrix/jruby/operators.rb +283 -0
  72. data/lib/nmatrix/jruby/slice.rb +264 -0
  73. data/lib/nmatrix/lapack_core.rb +181 -0
  74. data/lib/nmatrix/lapack_plugin.rb +44 -0
  75. data/lib/nmatrix/math.rb +953 -0
  76. data/lib/nmatrix/mkmf.rb +100 -0
  77. data/lib/nmatrix/monkeys.rb +137 -0
  78. data/lib/nmatrix/nmatrix.rb +1172 -0
  79. data/lib/nmatrix/rspec.rb +75 -0
  80. data/lib/nmatrix/shortcuts.rb +1163 -0
  81. data/lib/nmatrix/version.rb +39 -0
  82. data/lib/nmatrix/yale_functions.rb +118 -0
  83. data/lib/nmatrix.rb +28 -0
  84. data/spec/00_nmatrix_spec.rb +892 -0
  85. data/spec/01_enum_spec.rb +196 -0
  86. data/spec/02_slice_spec.rb +407 -0
  87. data/spec/03_nmatrix_monkeys_spec.rb +80 -0
  88. data/spec/2x2_dense_double.mat +0 -0
  89. data/spec/4x4_sparse.mat +0 -0
  90. data/spec/4x5_dense.mat +0 -0
  91. data/spec/blas_spec.rb +215 -0
  92. data/spec/elementwise_spec.rb +311 -0
  93. data/spec/homogeneous_spec.rb +100 -0
  94. data/spec/io/fortran_format_spec.rb +88 -0
  95. data/spec/io/harwell_boeing_spec.rb +98 -0
  96. data/spec/io/test.rua +9 -0
  97. data/spec/io_spec.rb +159 -0
  98. data/spec/lapack_core_spec.rb +482 -0
  99. data/spec/leakcheck.rb +16 -0
  100. data/spec/math_spec.rb +1363 -0
  101. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  102. data/spec/nmatrix_yale_spec.rb +286 -0
  103. data/spec/rspec_monkeys.rb +56 -0
  104. data/spec/rspec_spec.rb +35 -0
  105. data/spec/shortcuts_spec.rb +474 -0
  106. data/spec/slice_set_spec.rb +162 -0
  107. data/spec/spec_helper.rb +172 -0
  108. data/spec/stat_spec.rb +214 -0
  109. data/spec/test.pcd +20 -0
  110. data/spec/utm5940.mtx +83844 -0
  111. metadata +295 -0
@@ -0,0 +1,253 @@
1
+ #--
2
+ # = NMatrix
3
+ #
4
+ # A linear algebra library for scientific computation in Ruby.
5
+ # NMatrix is part of SciRuby.
6
+ #
7
+ # NMatrix was originally inspired by and derived from NArray, by
8
+ # Masahiro Tanaka: http://narray.rubyforge.org
9
+ #
10
+ # == Copyright Information
11
+ #
12
+ # SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ # NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
+ #
15
+ # Please see LICENSE.txt for additional copyright notices.
16
+ #
17
+ # == Contributing
18
+ #
19
+ # By contributing source code to SciRuby, you agree to be bound by
20
+ # our Contributor Agreement:
21
+ #
22
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ #
24
+ # == enumerate.rb
25
+ #
26
+ # Enumeration methods for NMatrix
27
+ #++
28
+
29
+ class NMatrix
30
+ include Enumerable
31
+
32
+ ##
33
+ # call-seq:
34
+ # each -> Enumerator
35
+ #
36
+ # Enumerate through the matrix. @see Enumerable#each
37
+ #
38
+ # For dense, this actually calls a specialized each iterator (in C). For yale and list, it relies upon
39
+ # #each_with_indices (which is about as fast as reasonably possible for C code).
40
+ def each &bl
41
+ if self.stype == :dense
42
+ self.__dense_each__(&bl)
43
+ elsif block_given?
44
+ self.each_with_indices(&bl)
45
+ else # Handle case where no block is given
46
+ Enumerator.new do |yielder|
47
+ self.each_with_indices do |params|
48
+ yielder.yield params
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ #
55
+ # call-seq:
56
+ # flat_map -> Enumerator
57
+ # flat_map { |elem| block } -> Array
58
+ #
59
+ # Maps using Enumerator (returns an Array or an Enumerator)
60
+ alias_method :flat_map, :map
61
+
62
+ ##
63
+ # call-seq:
64
+ # map -> Enumerator
65
+ # map { |elem| block } -> NMatrix
66
+ #
67
+ # Returns an NMatrix if a block is given. For an Array, use #flat_map
68
+ #
69
+ # Note that #map will always return an :object matrix, because it has no way of knowing
70
+ # how to handle operations on the different dtypes.
71
+ #
72
+ def map(&bl)
73
+ return enum_for(:map) unless block_given?
74
+ # NMatrix-jruby currently supports only doubles
75
+ cp = jruby? ? self : self.cast(dtype: :object)
76
+ cp.map!(&bl)
77
+ cp
78
+ end
79
+
80
+ ##
81
+ # call-seq:
82
+ # map! -> Enumerator
83
+ # map! { |elem| block } -> NMatrix
84
+ #
85
+ # Maps in place.
86
+ # @see #map
87
+ #
88
+ def map!
89
+ return enum_for(:map!) unless block_given?
90
+ iterated = false
91
+ self.each_stored_with_indices do |e, *i|
92
+ iterated = true
93
+ self[*i] = (yield e)
94
+ end
95
+ #HACK: if there's a single element in a non-dense matrix, it won't iterate and
96
+ #won't change the default value; this ensures that it does get changed.
97
+ unless iterated then
98
+ self.each_with_indices do |e, *i|
99
+ self[*i] = (yield e)
100
+ end
101
+ end
102
+ end
103
+
104
+
105
+ #
106
+ # call-seq:
107
+ # each_rank() -> NMatrix
108
+ # each_rank() { |rank| block } -> NMatrix
109
+ # each_rank(dimen) -> Enumerator
110
+ # each_rank(dimen) { |rank| block } -> NMatrix
111
+ #
112
+ # Generic for @each_row, @each_col
113
+ #
114
+ # Iterate through each rank by reference.
115
+ #
116
+ # @param [Fixnum] dimen the rank being iterated over.
117
+ #
118
+ def each_rank(dimen=0, get_by=:reference)
119
+ return enum_for(:each_rank, dimen, get_by) unless block_given?
120
+ (0...self.shape[dimen]).each do |idx|
121
+ yield self.rank(dimen, idx, get_by)
122
+ end
123
+ self
124
+ end
125
+ alias :each_along_dim :each_rank
126
+
127
+ #
128
+ # call-seq:
129
+ # each_row { |row| block } -> NMatrix
130
+ #
131
+ # Iterate through each row, referencing it as an NMatrix slice.
132
+ def each_row(get_by=:reference)
133
+ return enum_for(:each_row, get_by) unless block_given?
134
+ (0...self.shape[0]).each do |i|
135
+ yield self.row(i, get_by)
136
+ end
137
+ self
138
+ end
139
+
140
+ #
141
+ # call-seq:
142
+ # each_column { |column| block } -> NMatrix
143
+ #
144
+ # Iterate through each column, referencing it as an NMatrix slice.
145
+ def each_column(get_by=:reference)
146
+ return enum_for(:each_column, get_by) unless block_given?
147
+ (0...self.shape[1]).each do |j|
148
+ yield self.column(j, get_by)
149
+ end
150
+ self
151
+ end
152
+
153
+ #
154
+ # call-seq:
155
+ # each_layer -> { |column| block } -> ...
156
+ #
157
+ # Iterate through each layer, referencing it as an NMatrix slice.
158
+ #
159
+ # Note: If you have a 3-dimensional matrix, the first dimension contains rows,
160
+ # the second contains columns, and the third contains layers.
161
+ def each_layer(get_by=:reference)
162
+ return enum_for(:each_layer, get_by) unless block_given?
163
+ (0...self.shape[2]).each do |k|
164
+ yield self.layer(k, get_by)
165
+ end
166
+ self
167
+ end
168
+
169
+
170
+ #
171
+ # call-seq:
172
+ # each_stored_with_index -> Enumerator
173
+ #
174
+ # Allow iteration across a vector NMatrix's stored values. See also @each_stored_with_indices
175
+ #
176
+ def each_stored_with_index(&block)
177
+ raise(NotImplementedError, "only works for dim 2 vectors") unless self.dim <= 2
178
+ return enum_for(:each_stored_with_index) unless block_given?
179
+
180
+ self.each_stored_with_indices do |v, i, j|
181
+ if shape[0] == 1
182
+ yield(v,j)
183
+ elsif shape[1] == 1
184
+ yield(v,i)
185
+ else
186
+ method_missing(:each_stored_with_index, &block)
187
+ end
188
+ end
189
+ self
190
+ end
191
+
192
+
193
+ ##
194
+ # call-seq:
195
+ # inject_rank() -> Enumerator
196
+ # inject_rank(dimen) -> Enumerator
197
+ # inject_rank(dimen, initial) -> Enumerator
198
+ # inject_rank(dimen, initial, dtype) -> Enumerator
199
+ # inject_rank() { |elem| block } -> NMatrix
200
+ # inject_rank(dimen) { |elem| block } -> NMatrix
201
+ # inject_rank(dimen, initial) { |elem| block } -> NMatrix
202
+ # inject_rank(dimen, initial, dtype) { |elem| block } -> NMatrix
203
+ #
204
+ # Reduces an NMatrix using a supplied block over a specified dimension.
205
+ # The block should behave the same way as for Enumerable#reduce.
206
+ #
207
+ # @param [Integer] dimen the dimension being reduced
208
+ # @param [Numeric] initial the initial value for the reduction
209
+ # (i.e. the usual parameter to Enumerable#reduce). Supply nil or do not
210
+ # supply this argument to have it follow the usual Enumerable#reduce
211
+ # behavior of using the first element as the initial value.
212
+ # @param [Symbol] dtype if non-nil/false, forces the accumulated result to have this dtype
213
+ # @return [NMatrix] an NMatrix with the same number of dimensions as the
214
+ # input, but with the input dimension now having size 1. Each element
215
+ # is the result of the reduction at that position along the specified
216
+ # dimension.
217
+ #
218
+ def inject_rank(dimen=0, initial=nil, dtype=nil)
219
+
220
+ raise(RangeError, "requested dimension (#{dimen}) does not exist (shape: #{shape})") if dimen > self.dim
221
+
222
+ return enum_for(:inject_rank, dimen, initial, dtype) unless block_given?
223
+
224
+ new_shape = shape.dup
225
+ new_shape[dimen] = 1
226
+
227
+ first_as_acc = false
228
+
229
+ if initial then
230
+ acc = NMatrix.new(new_shape, initial, :dtype => dtype || self.dtype, stype: self.stype)
231
+ else
232
+ each_rank(dimen) do |sub_mat|
233
+ acc = (sub_mat.is_a?(NMatrix) and !dtype.nil? and dtype != self.dtype) ? sub_mat.cast(self.stype, dtype) : sub_mat
234
+ break
235
+ end
236
+ first_as_acc = true
237
+ end
238
+
239
+ each_rank(dimen) do |sub_mat|
240
+ if first_as_acc
241
+ first_as_acc = false
242
+ next
243
+ end
244
+ acc = yield(acc, sub_mat)
245
+ end
246
+
247
+ acc
248
+ end
249
+
250
+ alias :reduce_along_dim :inject_rank
251
+ alias :inject_along_dim :inject_rank
252
+
253
+ end
@@ -0,0 +1,241 @@
1
+ #--
2
+ # = NMatrix
3
+ #
4
+ # A linear algebra library for scientific computation in Ruby.
5
+ # NMatrix is part of SciRuby.
6
+ #
7
+ # NMatrix was originally inspired by and derived from NArray, by
8
+ # Masahiro Tanaka: http://narray.rubyforge.org
9
+ #
10
+ # == Copyright Information
11
+ #
12
+ # SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ # NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
+ #
15
+ # Please see LICENSE.txt for additional copyright notices.
16
+ #
17
+ # == Contributing
18
+ #
19
+ # By contributing source code to SciRuby, you agree to be bound by
20
+ # our Contributor Agreement:
21
+ #
22
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ #
24
+ # == homogeneous.rb
25
+ #
26
+ # This file contains optional shortcuts for generating homogeneous
27
+ # transformations.
28
+ #
29
+ #++
30
+
31
+ class NMatrix
32
+ class << self
33
+ #
34
+ # call-seq:
35
+ # x_rotation(angle_in_radians) -> NMatrix
36
+ # x_rotation(angle_in_radians, dtype: dtype) -> NMatrix
37
+ # y_rotation(angle_in_radians) -> NMatrix
38
+ # y_rotation(angle_in_radians, dtype: dtype) -> NMatrix
39
+ # z_rotation(angle_in_radians) -> NMatrix
40
+ # z_rotation(angle_in_radians, dtype: dtype) -> NMatrix
41
+ #
42
+ # Generate a 4x4 homogeneous transformation matrix representing a rotation
43
+ # about the x, y, or z axis respectively.
44
+ #
45
+ # * *Arguments* :
46
+ # - +angle_in_radians+ -> The angle of rotation in radians.
47
+ # - +dtype+ -> (optional) Default is +:float64+
48
+ # * *Returns* :
49
+ # - A homogeneous transformation matrix consisting of a single rotation.
50
+ #
51
+ # Examples:
52
+ #
53
+ # NMatrix.x_rotation(Math::PI.quo(6)) # =>
54
+ # 1.0 0.0 0.0 0.0
55
+ # 0.0 0.866025 -0.499999 0.0
56
+ # 0.0 0.499999 0.866025 0.0
57
+ # 0.0 0.0 0.0 1.0
58
+ #
59
+ #
60
+ # NMatrix.x_rotation(Math::PI.quo(6), dtype: :float32) # =>
61
+ # 1.0 0.0 0.0 0.0
62
+ # 0.0 0.866025 -0.5 0.0
63
+ # 0.0 0.5 0.866025 0.0
64
+ # 0.0 0.0 0.0 1.0
65
+ #
66
+ def x_rotation angle_in_radians, opts={}
67
+ c = Math.cos(angle_in_radians)
68
+ s = Math.sin(angle_in_radians)
69
+ NMatrix.new(4, [1.0, 0.0, 0.0, 0.0,
70
+ 0.0, c, -s, 0.0,
71
+ 0.0, s, c, 0.0,
72
+ 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts))
73
+ end
74
+
75
+ def y_rotation angle_in_radians, opts={}
76
+ c = Math.cos(angle_in_radians)
77
+ s = Math.sin(angle_in_radians)
78
+ NMatrix.new(4, [ c, 0.0, s, 0.0,
79
+ 0.0, 1.0, 0.0, 0.0,
80
+ -s, 0.0, c, 0.0,
81
+ 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts))
82
+ end
83
+
84
+ def z_rotation angle_in_radians, opts={}
85
+ c = Math.cos(angle_in_radians)
86
+ s = Math.sin(angle_in_radians)
87
+ NMatrix.new(4, [ c, -s, 0.0, 0.0,
88
+ s, c, 0.0, 0.0,
89
+ 0.0, 0.0, 1.0, 0.0,
90
+ 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts))
91
+ end
92
+
93
+
94
+ #
95
+ # call-seq:
96
+ # translation(x, y, z) -> NMatrix
97
+ # translation([x,y,z]) -> NMatrix
98
+ # translation(translation_matrix) -> NMatrix
99
+ # translation(translation_matrix) -> NMatrix
100
+ # translation(translation, dtype: dtype) -> NMatrix
101
+ # translation(x, y, z, dtype: dtype) -> NMatrix
102
+ #
103
+ # Generate a 4x4 homogeneous transformation matrix representing a translation.
104
+ #
105
+ # * *Returns* :
106
+ # - A homogeneous transformation matrix consisting of a translation.
107
+ #
108
+ # Examples:
109
+ #
110
+ # NMatrix.translation(4.0,5.0,6.0) # =>
111
+ # 1.0 0.0 0.0 4.0
112
+ # 0.0 1.0 0.0 5.0
113
+ # 0.0 0.0 1.0 6.0
114
+ # 0.0 0.0 0.0 1.0
115
+ #
116
+ # NMatrix.translation(4.0,5.0,6.0, dtype: :int64) # =>
117
+ # 1 0 0 4
118
+ # 0 1 0 5
119
+ # 0 0 1 6
120
+ # 0 0 0 1
121
+ # NMatrix.translation(4,5,6) # =>
122
+ # 1 0 0 4
123
+ # 0 1 0 5
124
+ # 0 0 1 6
125
+ # 0 0 0 1
126
+ #
127
+ def translation *args
128
+ xyz = args.shift if args.first.is_a?(NMatrix) || args.first.is_a?(Array)
129
+ default_dtype = xyz.respond_to?(:dtype) ? xyz.dtype : NMatrix.guess_dtype(xyz)
130
+ opts = {dtype: default_dtype}
131
+ opts = opts.merge(args.pop) if args.size > 0 && args.last.is_a?(Hash)
132
+ xyz ||= args
133
+
134
+ n = if args.size > 0
135
+ NMatrix.eye(4, opts)
136
+ else
137
+ NMatrix.eye(4, opts)
138
+ end
139
+ n[0..2,3] = xyz
140
+ n
141
+ end
142
+ end
143
+
144
+ #
145
+ # call-seq:
146
+ # quaternion -> NMatrix
147
+ #
148
+ # Find the quaternion for a 3D rotation matrix.
149
+ #
150
+ # Code borrowed from: http://courses.cms.caltech.edu/cs171/quatut.pdf
151
+ #
152
+ # * *Returns* :
153
+ # - A length-4 NMatrix representing the corresponding quaternion.
154
+ #
155
+ # Examples:
156
+ #
157
+ # n.quaternion # => [1, 0, 0, 0]
158
+ #
159
+ def quaternion
160
+ raise(ShapeError, "Expected square matrix") if self.shape[0] != self.shape[1]
161
+ raise(ShapeError, "Expected 3x3 rotation (or 4x4 homogeneous) matrix") if self.shape[0] > 4 || self.shape[0] < 3
162
+
163
+ q = NMatrix.new([4], dtype: self.dtype == :float32 ? :float32: :float64)
164
+ rotation_trace = self[0,0] + self[1,1] + self[2,2]
165
+ if rotation_trace >= 0
166
+ self_w = self.shape[0] == 4 ? self[3,3] : 1.0
167
+ root_of_homogeneous_trace = Math.sqrt(rotation_trace + self_w)
168
+ q[0] = root_of_homogeneous_trace * 0.5
169
+ s = 0.5 / root_of_homogeneous_trace
170
+ q[1] = (self[2,1] - self[1,2]) * s
171
+ q[2] = (self[0,2] - self[2,0]) * s
172
+ q[3] = (self[1,0] - self[0,1]) * s
173
+ else
174
+ h = 0
175
+ h = 1 if self[1,1] > self[0,0]
176
+ h = 2 if self[2,2] > self[h,h]
177
+
178
+ case_macro = Proc.new do |i,j,k,ii,jj,kk|
179
+ qq = NMatrix.new([4], dtype: :float64)
180
+ self_w = self.shape[0] == 4 ? self[3,3] : 1.0
181
+ s = Math.sqrt( (self[ii,ii] - (self[jj,jj] + self[kk,kk])) + self_w)
182
+ qq[i] = s*0.5
183
+ s = 0.5 / s
184
+ qq[j] = (self[ii,jj] + self[jj,ii]) * s
185
+ qq[k] = (self[kk,ii] + self[ii,kk]) * s
186
+ qq[0] = (self[kk,jj] - self[jj,kk]) * s
187
+ qq
188
+ end
189
+
190
+ case h
191
+ when 0
192
+ q = case_macro.call(1,2,3, 0,1,2)
193
+ when 1
194
+ q = case_macro.call(2,3,1, 1,2,0)
195
+ when 2
196
+ q = case_macro.call(3,1,2, 2,0,1)
197
+ end
198
+
199
+ self_w = self.shape[0] == 4 ? self[3,3] : 1.0
200
+ if self_w != 1
201
+ s = 1.0 / Math.sqrt(self_w)
202
+ q[0] *= s
203
+ q[1] *= s
204
+ q[2] *= s
205
+ q[3] *= s
206
+ end
207
+ end
208
+
209
+ q
210
+ end
211
+
212
+ #
213
+ # call-seq:
214
+ # angle_vector -> [angle, about_vector]
215
+ #
216
+ # Find the angle vector for a quaternion. Assumes the quaternion has unit length.
217
+ #
218
+ # Source: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/
219
+ #
220
+ # * *Returns* :
221
+ # - An angle (in radians) describing the rotation about the +about_vector+.
222
+ # - A length-3 NMatrix representing the corresponding quaternion.
223
+ #
224
+ # Examples:
225
+ #
226
+ # q.angle_vector # => [1, 0, 0, 0]
227
+ #
228
+ def angle_vector
229
+ raise(ShapeError, "Expected length-4 vector or matrix (quaternion)") if self.shape[0] != 4
230
+ raise("Expected unit quaternion") if self[0] > 1
231
+
232
+ xyz = NMatrix.new([3], dtype: self.dtype)
233
+
234
+ angle = 2 * Math.acos(self[0])
235
+ s = Math.sqrt(1.0 - self[0]*self[0])
236
+
237
+ xyz[0..2] = self[1..3]
238
+ xyz /= s if s >= 0.001 # avoid divide by zero
239
+ return [angle, xyz]
240
+ end
241
+ end
@@ -0,0 +1,138 @@
1
+ #--
2
+ # = NMatrix
3
+ #
4
+ # A linear algebra library for scientific computation in Ruby.
5
+ # NMatrix is part of SciRuby.
6
+ #
7
+ # NMatrix was originally inspired by and derived from NArray, by
8
+ # Masahiro Tanaka: http://narray.rubyforge.org
9
+ #
10
+ # == Copyright Information
11
+ #
12
+ # SciRuby is Copyright (c) 2010 - 2016, Ruby Science Foundation
13
+ # NMatrix is Copyright (c) 2012 - 2016, John Woods and the Ruby Science Foundation
14
+ #
15
+ # Please see LICENSE.txt for additional copyright notices.
16
+ #
17
+ # == Contributing
18
+ #
19
+ # By contributing source code to SciRuby, you agree to be bound by
20
+ # our Contributor Agreement:
21
+ #
22
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ #
24
+ # == io/matlab/fortran_format.rb
25
+ #
26
+ # A parser for making sense of FORTRAN formats.
27
+ # => Only handles R (real), F (float) and E (exponential) format codes.
28
+ #++
29
+
30
+ class NMatrix
31
+ module IO
32
+ module FortranFormat
33
+
34
+ # Class for reading strings in FORTRAN format for specifying attributes
35
+ # of numerical data in a file. Supports F (float), E (exponential) and
36
+ # R (real).
37
+ #
38
+ # == Usage
39
+ #
40
+ # p = NMatrix::IO::FortranFormat::Reader.new("(16I5)")
41
+ # v = p.parse
42
+ # puts v #=> { :format_code => "INT_ID",
43
+ # #=> :repeat => 16,
44
+ # #=> :field_width => 5 }
45
+ class Reader
46
+
47
+ # Accepts a string in FORTRAN format and initializes the
48
+ # NMatrix::IO::FortranFormat::Reader object for further parsing of the
49
+ # data.
50
+ #
51
+ # == Arguments
52
+ #
53
+ # * +string+ - FORTRAN format string to be parsed.
54
+ def initialize string
55
+ @string = string
56
+ end
57
+
58
+ # Parses the FORTRAN format string passed in initialize and returns
59
+ # a hash of the results.
60
+ #
61
+ # == Result Hash Format
62
+ #
63
+ # Take note that some of the below parameters may be absent in the hash
64
+ # depending on the type of string being parsed.
65
+ #
66
+ # * +:format_code+ - A string containing the format code of the read data.
67
+ # Can be "INT_ID", "FP_ID" or "EXP_ID"
68
+ # * +:repeat+ - Number of times this format will repeat in a line.
69
+ # * +:field_width+ - Width of the numerical part of the number.
70
+ # * +:post_decimal_width+ - Width of the numerals after the decimal point.
71
+ # * +:exponent_width+ - Width of exponent part of the number.
72
+ def parse
73
+ raise(IOError, "Left or right parentheses missing") \
74
+ if parentheses_missing? # change tests to handle 'raise' not return
75
+
76
+ @result = {}
77
+ @string = @string[1..-2]
78
+
79
+ if valid_fortran_format?
80
+ load_result
81
+ else
82
+ raise(IOError, "Invalid FORTRAN format specified. Only Integer, Float or Exponential acceptable.")
83
+ end
84
+
85
+ @result
86
+ end
87
+
88
+ private
89
+ def parentheses_missing?
90
+ true if @string[0] != '(' or @string[-1] != ')'
91
+ end
92
+
93
+ # Changing any of the following regular expressions can lead to disaster
94
+ def valid_fortran_format?
95
+ @mdata = @string.match(/\A(\d*)(I)(\d+)\z/) # check for integer format
96
+ @mdata = @string.match(/\A(\d*)(F)(\d+)\.(\d+)\z/) \
97
+ if @mdata.nil? # check for floating point if not integer
98
+ @mdata = @string.match(/\A(\d*)(E)(\d+)\.(\d+)(E)?(\d*)\z/) \
99
+ if @mdata.nil? # check for exponential format if not floating point
100
+
101
+ @mdata
102
+ end
103
+
104
+ def load_result
105
+ if @mdata.to_a.include? "I"
106
+ create_integer_hash
107
+ elsif @mdata.to_a.include? "F"
108
+ create_float_hash
109
+ else
110
+ create_exp_hash
111
+ end
112
+ end
113
+
114
+ def create_integer_hash
115
+ @result[:format_code] = "INT_ID"
116
+ @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
117
+ @result[:field_width] = @mdata[3].to_i
118
+ end
119
+
120
+ def create_float_hash
121
+ @result[:format_code] = "FP_ID"
122
+ @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
123
+ @result[:field_width] = @mdata[3].to_i
124
+ @result[:post_decimal_width] = @mdata[4].to_i
125
+ end
126
+
127
+ def create_exp_hash
128
+ @result[:format_code] = "EXP_ID"
129
+ @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty?
130
+ @result[:field_width] = @mdata[3].to_i
131
+ @result[:post_decimal_width] = @mdata[4].to_i
132
+ @result[:exponent_width] = @mdata[6].to_i if !@mdata[6].empty?
133
+ end
134
+ end
135
+
136
+ end
137
+ end
138
+ end