nmatrix 0.0.6 → 0.0.7

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile +5 -0
  4. data/History.txt +97 -0
  5. data/Manifest.txt +34 -7
  6. data/README.rdoc +13 -13
  7. data/Rakefile +36 -26
  8. data/ext/nmatrix/data/data.cpp +15 -2
  9. data/ext/nmatrix/data/data.h +4 -0
  10. data/ext/nmatrix/data/ruby_object.h +5 -14
  11. data/ext/nmatrix/extconf.rb +3 -2
  12. data/ext/nmatrix/{util/math.cpp → math.cpp} +296 -6
  13. data/ext/nmatrix/math/asum.h +143 -0
  14. data/ext/nmatrix/math/geev.h +82 -0
  15. data/ext/nmatrix/math/gemm.h +267 -0
  16. data/ext/nmatrix/math/gemv.h +208 -0
  17. data/ext/nmatrix/math/ger.h +96 -0
  18. data/ext/nmatrix/math/gesdd.h +80 -0
  19. data/ext/nmatrix/math/gesvd.h +78 -0
  20. data/ext/nmatrix/math/getf2.h +86 -0
  21. data/ext/nmatrix/math/getrf.h +240 -0
  22. data/ext/nmatrix/math/getri.h +107 -0
  23. data/ext/nmatrix/math/getrs.h +125 -0
  24. data/ext/nmatrix/math/idamax.h +86 -0
  25. data/ext/nmatrix/{util → math}/lapack.h +60 -356
  26. data/ext/nmatrix/math/laswp.h +165 -0
  27. data/ext/nmatrix/math/long_dtype.h +52 -0
  28. data/ext/nmatrix/math/math.h +1154 -0
  29. data/ext/nmatrix/math/nrm2.h +181 -0
  30. data/ext/nmatrix/math/potrs.h +125 -0
  31. data/ext/nmatrix/math/rot.h +141 -0
  32. data/ext/nmatrix/math/rotg.h +115 -0
  33. data/ext/nmatrix/math/scal.h +73 -0
  34. data/ext/nmatrix/math/swap.h +73 -0
  35. data/ext/nmatrix/math/trsm.h +383 -0
  36. data/ext/nmatrix/nmatrix.cpp +176 -152
  37. data/ext/nmatrix/nmatrix.h +1 -2
  38. data/ext/nmatrix/ruby_constants.cpp +9 -4
  39. data/ext/nmatrix/ruby_constants.h +1 -0
  40. data/ext/nmatrix/storage/dense.cpp +57 -41
  41. data/ext/nmatrix/storage/list.cpp +52 -50
  42. data/ext/nmatrix/storage/storage.cpp +59 -43
  43. data/ext/nmatrix/storage/yale.cpp +352 -333
  44. data/ext/nmatrix/storage/yale.h +4 -0
  45. data/lib/nmatrix.rb +2 -2
  46. data/lib/nmatrix/blas.rb +4 -4
  47. data/lib/nmatrix/enumerate.rb +241 -0
  48. data/lib/nmatrix/lapack.rb +54 -1
  49. data/lib/nmatrix/math.rb +462 -0
  50. data/lib/nmatrix/nmatrix.rb +210 -486
  51. data/lib/nmatrix/nvector.rb +0 -62
  52. data/lib/nmatrix/rspec.rb +75 -0
  53. data/lib/nmatrix/shortcuts.rb +136 -108
  54. data/lib/nmatrix/version.rb +1 -1
  55. data/spec/blas_spec.rb +20 -12
  56. data/spec/elementwise_spec.rb +22 -13
  57. data/spec/io_spec.rb +1 -0
  58. data/spec/lapack_spec.rb +197 -0
  59. data/spec/nmatrix_spec.rb +39 -38
  60. data/spec/nvector_spec.rb +3 -9
  61. data/spec/rspec_monkeys.rb +29 -0
  62. data/spec/rspec_spec.rb +34 -0
  63. data/spec/shortcuts_spec.rb +14 -16
  64. data/spec/slice_spec.rb +242 -186
  65. data/spec/spec_helper.rb +19 -0
  66. metadata +33 -5
  67. data/ext/nmatrix/util/math.h +0 -2612
@@ -185,68 +185,6 @@ class NVector < NMatrix
185
185
  end
186
186
  alias :norm2 :nrm2
187
187
 
188
- #
189
- # call-seq:
190
- # to_a -> Array
191
- #
192
- # Converts the NVector to a regular Ruby Array.
193
- def to_a
194
- if self.stype == :dense
195
- ary = Array.new(size)
196
- self.each.with_index { |v,idx| ary[idx] = v }
197
- else
198
- begin
199
- ary = Array.new(size, self[0] - self[0]) # Fill the Array with 0s of the appropriate class
200
- rescue NoMethodError # handle Ruby Object arrays that might have nils instead of 0s
201
- ary = Array.new(size)
202
- end
203
- self.each_stored_with_index { |v,idx| ary[idx] = v }
204
- end
205
- ary
206
- end
207
-
208
- #
209
- # call-seq:
210
- # each_stored_with_index -> Enumerator
211
- #
212
- # Allow iteration across an NVector's stored values. See also NMatrix#each_stored_with_indices
213
- #
214
- def each_stored_with_index(&block)
215
- return enum_for(:each_stored_with_index) unless block_given?
216
- self.each_stored_with_indices do |v, i, j|
217
- shape[0] == 1 ? yield(v,j) : yield(v,i)
218
- end
219
- self
220
- end
221
-
222
- #
223
- # call-seq:
224
- # shuffle! -> ...
225
- # shuffle!(random: rng) -> ...
226
- #
227
- # Re-arranges the contents of an NVector.
228
- #
229
- # TODO: Write more efficient version for Yale, list.
230
- def shuffle!(*args)
231
- ary = self.to_a
232
- ary.shuffle!(*args)
233
- ary.each.with_index { |v,idx| self[idx] = v }
234
- self
235
- end
236
-
237
-
238
- #
239
- # call-seq:
240
- # shuffle -> ...
241
- # shuffle(rng) -> ...
242
- #
243
- # Re-arranges the contents of an NVector.
244
- #
245
- # TODO: Write more efficient version for Yale, list.
246
- def shuffle(*args)
247
- t = self.clone
248
- t.shuffle!(*args)
249
- end
250
188
 
251
189
  #
252
190
  # call-seq:
@@ -0,0 +1,75 @@
1
+ # = NMatrix
2
+ #
3
+ # A linear algebra library for scientific computation in Ruby.
4
+ # NMatrix is part of SciRuby.
5
+ #
6
+ # NMatrix was originally inspired by and derived from NArray, by
7
+ # Masahiro Tanaka: http://narray.rubyforge.org
8
+ #
9
+ # == Copyright Information
10
+ #
11
+ # SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
12
+ # NMatrix is Copyright (c) 2012, Ruby Science Foundation
13
+ #
14
+ # Please see LICENSE.txt for additional copyright notices.
15
+ #
16
+ # == Contributing
17
+ #
18
+ # By contributing source code to SciRuby, you agree to be bound by
19
+ # our Contributor Agreement:
20
+ #
21
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
22
+ #
23
+ # == rspec.rb
24
+ #
25
+ # Monkey patches for RSpec improving its ability to work well with
26
+ # NMatrix (particularly #be_within).
27
+ #
28
+
29
+ require 'rspec'
30
+
31
+ # Amend RSpec to allow #be_within for matrices.
32
+ module RSpec::Matchers::BuiltIn #:nodoc:
33
+ class BeWithin
34
+
35
+ def of(expected)
36
+ @expected = expected
37
+ @unit = ''
38
+ if expected.is_a?(NMatrix)
39
+ @tolerance = if @delta.is_a?(NMatrix)
40
+ @delta.abs
41
+ elsif @delta.is_a?(Array)
42
+ NMatrix.new(:dense, expected.shape, @delta, :object).abs.cast(:dtype => expected.abs_dtype)
43
+ else
44
+ (NMatrix.ones_like(expected) * @delta).abs
45
+ end
46
+ else
47
+ @tolerance = @delta
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ def percent_of(expected)
54
+ @expected = expected
55
+ @unit = '%'
56
+ @tolerance = @expected.abs * @delta / 100.0 # <- only change is to reverse abs and @delta
57
+ self
58
+ end
59
+
60
+ def matches?(actual)
61
+ @actual = actual
62
+ raise needs_expected unless defined? @expected
63
+ raise needs_subtractable unless @actual.respond_to? :-
64
+ res = (@actual - @expected).abs <= @tolerance
65
+
66
+ #if res.is_a?(NMatrix)
67
+ # require 'pry'
68
+ # binding.pry
69
+ #end
70
+
71
+ res.is_a?(NMatrix) ? !res.any? { |x| !x } : res
72
+ end
73
+
74
+ end
75
+ end
@@ -34,7 +34,76 @@
34
34
 
35
35
  class NMatrix
36
36
 
37
+
38
+
39
+ #
40
+ # call-seq:
41
+ # dense? -> true or false
42
+ # list? -> true or false
43
+ # yale? -> true or false
44
+ #
45
+ # Shortcut functions for quickly determining a matrix's stype.
46
+ #
47
+ def dense?; return stype == :dense; end
48
+ def yale?; return stype == :yale; end
49
+ def list?; return stype == :list; end
50
+
51
+
37
52
  class << self
53
+ #
54
+ # call-seq:
55
+ # NMatrix[array-of-arrays, dtype = nil]
56
+ #
57
+ # You can use the old +N+ constant in this way:
58
+ # N = NMatrix
59
+ # N[1, 2, 3]
60
+ # NMatrix needs to have a succinct way to create a matrix by specifying the
61
+ # components directly. This is very useful for using it as an advanced
62
+ # calculator, it is useful for learning how to use, for testing language
63
+ # features and for developing algorithms.
64
+ #
65
+ # The NMatrix::[] method provides a way to create a matrix in a way that is compact and
66
+ # natural. The components are specified using Ruby array syntax. Optionally,
67
+ # one can specify a dtype as the last parameter (default is :float64).
68
+ #
69
+ # Examples:
70
+ #
71
+ # a = NMatrix[ 1,2,3,4 ] => 1.0 2.0 3.0 4.0
72
+ #
73
+ # a = NMatrix[ 1,2,3,4, :int32 ] => 1 2 3 4
74
+ #
75
+ # a = NMatrix[ [1,2,3], [3,4,5] ] => 1.0 2.0 3.0
76
+ # 3.0 4.0 5.0
77
+ #
78
+ # SYNTAX COMPARISON:
79
+ #
80
+ # MATLAB: a = [ [1 2 3] ; [4 5 6] ] or [ 1 2 3 ; 4 5 6 ]
81
+ # IDL: a = [ [1,2,3] , [4,5,6] ]
82
+ # NumPy: a = array( [1,2,3], [4,5,6] )
83
+ #
84
+ # SciRuby: a = NMatrix[ [1,2,3], [4,5,6] ]
85
+ # Ruby array: a = [ [1,2,3], [4,5,6] ]
86
+ #
87
+ def [](*params)
88
+ dtype = params.last.is_a?(Symbol) ? params.pop : nil
89
+
90
+ # First find the dimensions of the array.
91
+ i = 0
92
+ shape = []
93
+ row = params
94
+ while row.is_a?(Array)
95
+ shape[i] = row.length
96
+ row = row[0]
97
+ i += 1
98
+ end
99
+
100
+ # A row vector should be stored as 1xN, not N
101
+ #shape.unshift(1) if shape.size == 1
102
+
103
+ # Then flatten the array.
104
+ NMatrix.new(shape, params.flatten, dtype)
105
+ end
106
+
38
107
  #
39
108
  # call-seq:
40
109
  # zeros(size) -> NMatrix
@@ -97,6 +166,34 @@ class NMatrix
97
166
  NMatrix.new(dim, 1, dtype)
98
167
  end
99
168
 
169
+ ##
170
+ # call-seq:
171
+ # ones_like(nm) -> NMatrix
172
+ #
173
+ # Creates a new matrix of ones with the same dtype and shape as the
174
+ # provided matrix.
175
+ #
176
+ # @param [NMatrix] nm the nmatrix whose dtype and shape will be used
177
+ # @return [NMatrix] a new nmatrix filled with ones.
178
+ #
179
+ def ones_like(nm)
180
+ NMatrix.ones(nm.shape, nm.dtype)
181
+ end
182
+
183
+ ##
184
+ # call-seq:
185
+ # zeros_like(nm) -> NMatrix
186
+ #
187
+ # Creates a new matrix of zeros with the same stype, dtype, and shape
188
+ # as the provided matrix.
189
+ #
190
+ # @param [NMatrix] nm the nmatrix whose stype, dtype, and shape will be used
191
+ # @return [NMatrix] a new nmatrix filled with zeros.
192
+ #
193
+ def zeros_like(nm)
194
+ NMatrix.zeros(nm.stype, nm.shape, nm.dtype)
195
+ end
196
+
100
197
  #
101
198
  # call-seq:
102
199
  # eye(size) -> NMatrix
@@ -140,7 +237,6 @@ class NMatrix
140
237
  m
141
238
  end
142
239
  alias :identity :eye
143
-
144
240
  #
145
241
  # call-seq:
146
242
  # diagonals(array) -> NMatrix
@@ -324,75 +420,50 @@ as dimension."
324
420
  end
325
421
 
326
422
  end
423
+ end
327
424
 
328
- #
329
- # call-seq:
330
- # column(column_number) -> NMatrix
331
- # column(column_number, get_by) -> NMatrix
332
- #
333
- # Returns the column specified. Uses slicing by copy as default.
334
- #
335
- # * *Arguments* :
336
- # - +column_number+ -> Integer.
337
- # - +get_by+ -> Type of slicing to use, +:copy+ or +:reference+.
338
- # * *Returns* :
339
- # - A NMatrix representing the requested column as a column vector.
340
- #
341
- # Examples:
342
- #
343
- # m = NMatrix.new(2, [1, 4, 9, 14], :int32) # => 1 4
344
- # 9 14
345
- #
346
- # m.column(1) # => 4
347
- # 14
348
- #
349
- def column(column_number, get_by = :copy)
350
- unless [:copy, :reference].include?(get_by)
351
- raise ArgumentError, "column() 2nd parameter must be :copy or :reference"
352
- end
353
-
354
- if get_by == :copy
355
- self.slice(0 ... self.shape[0], column_number)
356
- else # by reference
357
- self[0 ... self.shape[0], column_number]
358
- end
359
- end
425
+ module NVector
360
426
 
361
- alias :col :column
427
+ class << self
428
+ #
429
+ # call-seq:
430
+ # new(shape) -> NVector
431
+ # new(stype, shape) -> NVector
432
+ # new(shape, init) -> NVector
433
+ # new(:dense, shape, init) -> NVector
434
+ # new(:list, shape, init) -> NVector
435
+ # new(shape, init, dtype) -> NVector
436
+ # new(stype, shape, init, dtype) -> NVector
437
+ # new(stype, shape, dtype) -> NVector
438
+ #
439
+ # Creates a new NVector. See also NMatrix#initialize for a more detailed explanation of
440
+ # the arguments.
441
+ #
442
+ # * *Arguments* :
443
+ # - +stype+ -> (optional) Storage type of the vector (:list, :dense, :yale). Defaults to :dense.
444
+ # - +shape+ -> Shape of the vector. Accepts [n,1], [1,n], or n, where n is a Fixnum.
445
+ # - +init+ -> (optional) Yale: capacity; List: default value (0); Dense: initial value or values (uninitialized by default).
446
+ # - +dtype+ -> (optional if +init+ provided) Data type stored in the vector. For :dense and :list, can be inferred from +init+.
447
+ # * *Returns* :
448
+ # -
449
+ #
450
+ def new(*args)
451
+ stype = args[0].is_a?(Symbol) ? args.shift : :dense
452
+ shape = args[0].is_a?(Array) ? args.shift : [1,args.shift]
362
453
 
363
- #
364
- # call-seq:
365
- # row(row_number) -> NMatrix
366
- # row(row_number, get_by) -> NMatrix
367
- #
368
- # * *Arguments* :
369
- # - +row_number+ -> Integer.
370
- # - +get_by+ -> Type of slicing to use, +:copy+ or +:reference+.
371
- # * *Returns* :
372
- # - A NMatrix representing the requested row .
373
- #
374
- def row(row_number, get_by = :copy)
375
- unless [:copy, :reference].include?(get_by)
376
- raise ArgumentError, "row() 2nd parameter must be :copy or :reference"
377
- end
454
+ if shape.size != 2 || !shape.include?(1) || shape == [1,1]
455
+ raise(ArgumentError, "shape must be a Fixnum or an Array of positive Fixnums where exactly one value is 1")
456
+ end
378
457
 
379
- if get_by == :copy
380
- self.slice(row_number, 0 ... self.shape[1])
381
- else # by reference
382
- self[row_number, 0 ... self.shape[1]]
458
+ NMatrix.new(stype, shape, *args)
383
459
  end
384
- end
385
- end
386
-
387
- class NVector < NMatrix
388
460
 
389
- class << self
390
461
  #
391
462
  # call-seq:
392
463
  # zeros(size) -> NMatrix
393
464
  # zeros(size, dtype) -> NMatrix
394
465
  #
395
- # Creates a new matrix of zeros with the dimensions supplied as
466
+ # Creates a new vector of zeros with the dimensions supplied as
396
467
  # parameters.
397
468
  #
398
469
  # * *Arguments* :
@@ -492,14 +563,10 @@ class NVector < NMatrix
492
563
  # 1.0
493
564
  # 2.0
494
565
  #
495
- def seq(n, dtype = :int64)
496
- unless n.is_a?(Integer)
497
- raise ArgumentError, "NVector::seq() only accepts integers as size."
498
- end
566
+ def seq(size, dtype = :int64)
567
+ values = (0 ... size).to_a
499
568
 
500
- values = (0 ... n).to_a
501
-
502
- NVector.new(n, values, dtype)
569
+ NVector.new(size, values, dtype)
503
570
  end
504
571
 
505
572
  #
@@ -645,15 +712,8 @@ class NVector < NMatrix
645
712
  end
646
713
  end
647
714
 
648
- # NMatrix needs to have a succinct way to create a matrix by specifying the
649
- # components directly. This is very useful for using it as an advanced
650
- # calculator, it is useful for learning how to use, for testing language
651
- # features and for developing algorithms.
652
- #
653
- # The N class provides a way to create a matrix in a way that is compact and
654
- # natural. The components are specified using Ruby array syntax. Optionally,
655
- # one can specify a dtype as the last parameter (default is :float64).
656
- #
715
+
716
+ # Use this constant as you would use NMatrix[].
657
717
  # Examples:
658
718
  #
659
719
  # a = N[ 1,2,3,4 ] => 1.0 2.0 3.0 4.0
@@ -663,36 +723,4 @@ end
663
723
  # a = N[ [1,2,3], [3,4,5] ] => 1.0 2.0 3.0
664
724
  # 3.0 4.0 5.0
665
725
  #
666
- # SYNTAX COMPARISON:
667
- #
668
- # MATLAB: a = [ [1 2 3] ; [4 5 6] ] or [ 1 2 3 ; 4 5 6 ]
669
- # IDL: a = [ [1,2,3] , [4,5,6] ]
670
- # NumPy: a = array( [1,2,3], [4,5,6] )
671
- #
672
- # SciRuby: a = N[ [1,2,3], [4,5,6] ]
673
- # Ruby array: a = [ [1,2,3], [4,5,6] ]
674
- #
675
- class N
676
- class << self
677
- #
678
- # call-seq:
679
- # N[array-of-arrays, dtype = nil]
680
- #
681
- def [](*params)
682
- dtype = params.last.is_a?(Symbol) ? params.pop : nil
683
-
684
- # First find the dimensions of the array.
685
- i = 0
686
- dim = []
687
- foo = params
688
- while foo.is_a?(Array)
689
- dim[i] = foo.length
690
- foo = foo[0]
691
- i += 1
692
- end
693
-
694
- # Then flatten the array.
695
- NMatrix.new(dim, params.flatten, dtype)
696
- end
697
- end
698
- end
726
+ N = NMatrix
@@ -26,6 +26,6 @@ class NMatrix
26
26
  # Note that the format of the VERSION string is needed for NMatrix
27
27
  # native IO. If you change the format, please make sure that native
28
28
  # IO can still understand NMatrix::VERSION.
29
- VERSION = "0.0.6"
29
+ VERSION = "0.0.7"
30
30
  end
31
31