nmatrix 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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