pnmatrix 1.2.4

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 (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