nmatrix 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/nmatrix/blas.rb CHANGED
@@ -61,9 +61,9 @@ module NMatrix::BLAS
61
61
  # - +ArgumentError+ -> The dtype of the matrices must be equal.
62
62
  #
63
63
  def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, transpose_a = false, transpose_b = false, m = nil, n = nil, k = nil, lda = nil, ldb = nil, ldc = nil)
64
- raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless a.is_a?(NMatrix) and b.is_a?(NMatrix) and a.stype == :dense and b.stype == :dense
65
- raise ArgumentError, 'Expected nil or dense NMatrix as third argument.' unless c.nil? or (c.is_a?(NMatrix) and c.stype == :dense)
66
- raise ArgumentError, 'NMatrix dtype mismatch.' unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true)
64
+ raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') unless a.is_a?(NMatrix) and b.is_a?(NMatrix) and a.stype == :dense and b.stype == :dense
65
+ raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') unless c.nil? or (c.is_a?(NMatrix) and c.stype == :dense)
66
+ raise(ArgumentError, 'NMatrix dtype mismatch.') unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true)
67
67
 
68
68
  # First, set m, n, and k, which depend on whether we're taking the
69
69
  # transpose of a and b.
@@ -133,9 +133,9 @@ module NMatrix::BLAS
133
133
  # - ++ ->
134
134
  #
135
135
  def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, transpose_a = false, m = nil, n = nil, lda = nil, incx = nil, incy = nil)
136
- raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless a.is_a?(NMatrix) and x.is_a?(NMatrix) and a.stype == :dense and x.stype == :dense
137
- raise ArgumentError, 'Expected nil or dense NMatrix as third argument.' unless y.nil? or (y.is_a?(NMatrix) and y.stype == :dense)
138
- raise ArgumentError, 'NMatrix dtype mismatch.' unless a.dtype == x.dtype and (y ? a.dtype == y.dtype : true)
136
+ raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') unless a.is_a?(NMatrix) and x.is_a?(NMatrix) and a.stype == :dense and x.stype == :dense
137
+ raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') unless y.nil? or (y.is_a?(NMatrix) and y.stype == :dense)
138
+ raise(ArgumentError, 'NMatrix dtype mismatch.') unless a.dtype == x.dtype and (y ? a.dtype == y.dtype : true)
139
139
 
140
140
  m ||= transpose_a ? a.shape[1] : a.shape[0]
141
141
  n ||= transpose_a ? a.shape[0] : a.shape[1]
@@ -179,9 +179,9 @@ module NMatrix::BLAS
179
179
  # - +ArgumentError+ -> Need to supply n for non-standard incx, incy values.
180
180
  #
181
181
  def rot(x, y, c, s, incx = 1, incy = 1, n = nil)
182
- raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless x.is_a?(NMatrix) and y.is_a?(NMatrix) and x.stype == :dense and y.stype == :dense
183
- raise ArgumentError, 'NMatrix dtype mismatch.' unless x.dtype == y.dtype
184
- raise ArgumentError, 'Need to supply n for non-standard incx, incy values' if n.nil? && incx != 1 && incx != -1 && incy != 1 && incy != -1
182
+ raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') unless x.is_a?(NMatrix) and y.is_a?(NMatrix) and x.stype == :dense and y.stype == :dense
183
+ raise(ArgumentError, 'NMatrix dtype mismatch.') unless x.dtype == y.dtype
184
+ raise(ArgumentError, 'Need to supply n for non-standard incx, incy values') if n.nil? && incx != 1 && incx != -1 && incy != 1 && incy != -1
185
185
 
186
186
  n ||= x.size > y.size ? y.size : x.size
187
187
 
@@ -192,5 +192,51 @@ module NMatrix::BLAS
192
192
 
193
193
  return [xx,yy]
194
194
  end
195
+
196
+ #
197
+ # call-seq:
198
+ # asum(x, incx, n)
199
+ #
200
+ # Calculate the sum of absolute values of the entries of a vector +x+ of size +n+
201
+ #
202
+ # * *Arguments* :
203
+ # - +x+ -> an NVector (will also allow an NMatrix, but will treat it as if it's a vector )
204
+ # - +incx+ -> the skip size (defaults to 1)
205
+ # - +n+ -> the size of +x+ (defaults to +x.size / incx+)
206
+ # * *Returns* :
207
+ # - The sum
208
+ # * *Raises* :
209
+ # - +ArgumentError+ -> Expected dense NVector (or NMatrix on rare occasions) for arg 0
210
+ # - +RangeError+ -> n out of range
211
+ #
212
+ def asum(x, incx = 1, n = nil)
213
+ n ||= x.size / incx
214
+ raise(ArgumentError, "Expected dense NVector (or NMatrix on rare occasions) for arg 0") unless x.is_a?(NMatrix)
215
+ raise(RangeError, "n out of range") if n*incx > x.size || n*incx <= 0 || n <= 0
216
+ ::NMatrix::BLAS.cblas_asum(n, x, incx)
217
+ end
218
+
219
+ #
220
+ # call-seq:
221
+ # nrm2(x, incx, n)
222
+ #
223
+ # Calculate the 2-norm of a vector +x+ of size +n+
224
+ #
225
+ # * *Arguments* :
226
+ # - +x+ -> an NVector (will also allow an NMatrix, but will treat it as if it's a vector )
227
+ # - +incx+ -> the skip size (defaults to 1)
228
+ # - +n+ -> the size of +x+ (defaults to +x.size / incx+)
229
+ # * *Returns* :
230
+ # - The 2-norm
231
+ # * *Raises* :
232
+ # - +ArgumentError+ -> Expected dense NVector (or NMatrix on rare occasions) for arg 0
233
+ # - +RangeError+ -> n out of range
234
+ #
235
+ def nrm2(x, incx = 1, n = nil)
236
+ n ||= x.size / incx
237
+ raise(ArgumentError, "Expected dense NVector (or NMatrix on rare occasions) for arg 0") unless x.is_a?(NMatrix)
238
+ raise(RangeError, "n out of range") if n*incx > x.size || n*incx <= 0 || n <= 0
239
+ ::NMatrix::BLAS.cblas_nrm2(n, x, incx)
240
+ end
195
241
  end
196
242
  end
@@ -29,6 +29,7 @@
29
29
 
30
30
  require_relative './shortcuts.rb'
31
31
  require_relative './lapack.rb'
32
+ require_relative './yale_functions.rb'
32
33
 
33
34
  class NMatrix
34
35
  # Read and write extensions for NMatrix. These are only loaded when needed.
@@ -53,7 +54,7 @@ class NMatrix
53
54
  # TODO: Make this actually pretty.
54
55
  def pretty_print(q = nil) #:nodoc:
55
56
  if dim != 2 || (dim == 2 && shape[1] > 10) # FIXME: Come up with a better way of restricting the display
56
- inspect
57
+ puts self.inspect
57
58
  else
58
59
 
59
60
  arr = (0...shape[0]).map do |i|
@@ -292,6 +293,290 @@ class NMatrix
292
293
  '[' + ary.collect { |a| a ? a : 'nil'}.join(',') + ']'
293
294
  end
294
295
 
296
+ ##
297
+ # call-seq:
298
+ # each_along_dim() -> Enumerator
299
+ # each_along_dim(dimen) -> Enumerator
300
+ # each_along_dim() { |elem| block } -> NMatrix
301
+ # each_along_dim(dimen) { |elem| block } -> NMatrix
302
+ #
303
+ # Successively yields submatrices at each coordinate along a specified
304
+ # dimension. Each submatrix will have the same number of dimensions as
305
+ # the matrix being iterated, but with the specified dimension's size
306
+ # equal to 1.
307
+ #
308
+ # @param [Integer] dimen the dimension being iterated over.
309
+ #
310
+ def each_along_dim(dimen=0)
311
+ return enum_for(:each_along_dim, dimen) unless block_given?
312
+ dims = shape
313
+ shape.each_index { |i| dims[i] = 0...(shape[i]) unless i == dimen }
314
+ 0.upto(shape[dimen]-1) do |i|
315
+ dims[dimen] = i
316
+ yield self[*dims]
317
+ end
318
+ end
319
+
320
+ ##
321
+ # call-seq:
322
+ # reduce_along_dim() -> Enumerator
323
+ # reduce_along_dim(dimen) -> Enumerator
324
+ # reduce_along_dim(dimen, initial) -> Enumerator
325
+ # reduce_along_dim(dimen, initial, dtype) -> Enumerator
326
+ # reduce_along_dim() { |elem| block } -> NMatrix
327
+ # reduce_along_dim(dimen) { |elem| block } -> NMatrix
328
+ # reduce_along_dim(dimen, initial) { |elem| block } -> NMatrix
329
+ # reduce_along_dim(dimen, initial, dtype) { |elem| block } -> NMatrix
330
+ #
331
+ # Reduces an NMatrix using a supplied block over a specified dimension.
332
+ # The block should behave the same way as for Enumerable#reduce.
333
+ #
334
+ # @param [Integer] dimen the dimension being reduced
335
+ # @param [Numeric] initial the initial value for the reduction
336
+ # (i.e. the usual parameter to Enumerable#reduce). Supply nil or do not
337
+ # supply this argument to have it follow the usual Enumerable#reduce
338
+ # behavior of using the first element as the initial value.
339
+ # @param [Symbol] dtype if non-nil/false, forces the accumulated result to have this dtype
340
+ # @return [NMatrix] an NMatrix with the same number of dimensions as the
341
+ # input, but with the input dimension now having size 1. Each element
342
+ # is the result of the reduction at that position along the specified
343
+ # dimension.
344
+ #
345
+ def reduce_along_dim(dimen=0, initial=nil, dtype=nil)
346
+
347
+ if dimen > shape.size then
348
+ raise ArgumentError, "Requested dimension does not exist. Requested: #{dimen}, shape: #{shape}"
349
+ end
350
+
351
+ return enum_for(:reduce_along_dim, dimen, initial) unless block_given?
352
+
353
+ new_shape = shape
354
+ new_shape[dimen] = 1
355
+
356
+ first_as_acc = false
357
+
358
+ if initial then
359
+ acc = NMatrix.new(new_shape, initial, dtype || self.dtype)
360
+ else
361
+ each_along_dim(dimen) do |sub_mat|
362
+ if sub_mat.is_a?(NMatrix) and dtype and dtype != self.dtype then
363
+ acc = sub_mat.cast(self.stype, dtype)
364
+ else
365
+ acc = sub_mat
366
+ end
367
+ break
368
+ end
369
+ first_as_acc = true
370
+ end
371
+
372
+ each_along_dim(dimen) do |sub_mat|
373
+ if first_as_acc then
374
+ first_as_acc = false
375
+ next
376
+ end
377
+ acc = (yield acc, sub_mat)
378
+ end
379
+
380
+ acc
381
+
382
+ end
383
+
384
+ alias_method :inject_along_dim, :reduce_along_dim
385
+
386
+ ##
387
+ # call-seq:
388
+ # integer_dtype?() -> Boolean
389
+ #
390
+ # Checks if dtype is an integer type
391
+ #
392
+ def integer_dtype?
393
+ [:byte, :int8, :int16, :int32, :int64].include?(self.dtype)
394
+ end
395
+
396
+ ##
397
+ # call-seq:
398
+ # mean() -> NMatrix
399
+ # mean(dimen) -> NMatrix
400
+ #
401
+ # Calculates the mean along the specified dimension.
402
+ #
403
+ # This will force integer types to float64 dtype.
404
+ #
405
+ # @see #reduce_along_dim
406
+ #
407
+ def mean(dimen=0)
408
+ reduce_dtype = nil
409
+ if integer_dtype? then
410
+ reduce_dtype = :float64
411
+ end
412
+ reduce_along_dim(dimen, 0.0, reduce_dtype) do |mean, sub_mat|
413
+ mean + sub_mat/shape[dimen]
414
+ end
415
+ end
416
+
417
+ ##
418
+ # call-seq:
419
+ # sum() -> NMatrix
420
+ # sum(dimen) -> NMatrix
421
+ #
422
+ # Calculates the sum along the specified dimension.
423
+ #
424
+ # @see #reduce_along_dim
425
+ def sum(dimen=0)
426
+ reduce_along_dim(dimen, 0.0) do |sum, sub_mat|
427
+ sum + sub_mat
428
+ end
429
+ end
430
+
431
+
432
+ ##
433
+ # call-seq:
434
+ # min() -> NMatrix
435
+ # min(dimen) -> NMatrix
436
+ #
437
+ # Calculates the minimum along the specified dimension.
438
+ #
439
+ # @see #reduce_along_dim
440
+ #
441
+ def min(dimen=0)
442
+ reduce_along_dim(dimen) do |min, sub_mat|
443
+ if min.is_a? NMatrix then
444
+ min * (min <= sub_mat) + ((min)*0.0 + (min > sub_mat)) * sub_mat
445
+ else
446
+ min <= sub_mat ? min : sub_mat
447
+ end
448
+ end
449
+ end
450
+
451
+ ##
452
+ # call-seq:
453
+ # max() -> NMatrix
454
+ # max(dimen) -> NMatrix
455
+ #
456
+ # Calculates the maximum along the specified dimension.
457
+ #
458
+ # @see #reduce_along_dim
459
+ #
460
+ def max(dimen=0)
461
+ reduce_along_dim(dimen) do |max, sub_mat|
462
+ if max.is_a? NMatrix then
463
+ max * (max >= sub_mat) + ((max)*0.0 + (max < sub_mat)) * sub_mat
464
+ else
465
+ max >= sub_mat ? max : sub_mat
466
+ end
467
+ end
468
+ end
469
+
470
+
471
+ ##
472
+ # call-seq:
473
+ # variance() -> NMatrix
474
+ # variance(dimen) -> NMatrix
475
+ #
476
+ # Calculates the sample variance along the specified dimension.
477
+ #
478
+ # This will force integer types to float64 dtype.
479
+ #
480
+ # @see #reduce_along_dim
481
+ #
482
+ def variance(dimen=0)
483
+ reduce_dtype = nil
484
+ if integer_dtype? then
485
+ reduce_dtype = :float64
486
+ end
487
+ m = mean(dimen)
488
+ reduce_along_dim(dimen, 0.0, reduce_dtype) do |var, sub_mat|
489
+ var + (m - sub_mat)*(m - sub_mat)/(shape[dimen]-1)
490
+ end
491
+ end
492
+
493
+ ##
494
+ # call-seq:
495
+ # std() -> NMatrix
496
+ # std(dimen) -> NMatrix
497
+ #
498
+ #
499
+ # Calculates the sample standard deviation along the specified dimension.
500
+ #
501
+ # This will force integer types to float64 dtype.
502
+ #
503
+ # @see #reduce_along_dim
504
+ #
505
+ def std(dimen=0)
506
+ variance(dimen).map! { |e| Math.sqrt(e) }
507
+ end
508
+
509
+ ##
510
+ # call-seq:
511
+ # to_f() -> Float
512
+ #
513
+ # Converts an nmatrix with a single element (but any number of dimensions)
514
+ # to a float.
515
+ #
516
+ # Raises an IndexError if the matrix does not have just a single element.
517
+ #
518
+ # FIXME: Does this actually happen? Matrices should not have just one element.
519
+ def to_f
520
+ raise IndexError, 'to_f only valid for matrices with a single element' unless shape.all? { |e| e == 1 }
521
+ self[*Array.new(shape.size, 0)]
522
+ end
523
+
524
+ ##
525
+ # call-seq:
526
+ # map() -> Enumerator
527
+ # map() { |elem| block } -> NMatrix
528
+ #
529
+ # @see Enumerable#map
530
+ #
531
+ def map(&bl)
532
+ return enum_for(:map) unless block_given?
533
+ cp = self.dup
534
+ cp.map! &bl
535
+ cp
536
+ end
537
+
538
+ ##
539
+ # call-seq:
540
+ # map!() -> Enumerator
541
+ # map!() { |elem| block } -> NMatrix
542
+ #
543
+ # Maps in place.
544
+ # @see #map
545
+ #
546
+ def map!
547
+ return enum_for(:map!) unless block_given?
548
+ self.each_stored_with_indices do |e, *i|
549
+ self[*i] = (yield e)
550
+ end
551
+ self
552
+ end
553
+
554
+
555
+ #
556
+ # call-seq:
557
+ # each_row -> ...
558
+ #
559
+ # Iterate through each row, referencing it as an NVector.
560
+ def each_row(get_by=:reference, &block)
561
+ (0...self.shape[0]).each do |i|
562
+ yield self.row(i, get_by)
563
+ end
564
+ self
565
+ end
566
+
567
+ #
568
+ # call-seq:
569
+ # each_column -> ...
570
+ #
571
+ # Iterate through each column, referencing it as an NVector.
572
+ def each_row(get_by=:reference, &block)
573
+ (0...self.shape[0]).each do |i|
574
+ yield self.row(i, get_by)
575
+ end
576
+ self
577
+ end
578
+
579
+
295
580
  class << self
296
581
  #
297
582
  # call-seq:
@@ -305,9 +590,37 @@ class NMatrix
305
590
  def load_file(file_path)
306
591
  NMatrix::IO::Mat5Reader.new(File.open(file_path, 'rb')).to_ruby
307
592
  end
593
+
594
+ ##
595
+ # call-seq:
596
+ # ones_like(nm) -> NMatrix
597
+ #
598
+ # Creates a new matrix of ones with the same dtype and shape as the
599
+ # provided matrix.
600
+ #
601
+ # @param [NMatrix] nm the nmatrix whose dtype and shape will be used
602
+ # @return [NMatrix] a new nmatrix filled with ones.
603
+ #
604
+ def ones_like(nm)
605
+ NMatrix.ones(nm.shape, nm.dtype)
606
+ end
607
+
608
+ ##
609
+ # call-seq:
610
+ # zeros_like(nm) -> NMatrix
611
+ #
612
+ # Creates a new matrix of zeros with the same stype, dtype, and shape
613
+ # as the provided matrix.
614
+ #
615
+ # @param [NMatrix] nm the nmatrix whose stype, dtype, and shape will be used
616
+ # @return [NMatrix] a new nmatrix filled with zeros.
617
+ #
618
+ def zeros_like(nm)
619
+ NMatrix.zeros(nm.stype, nm.shape, nm.dtype)
620
+ end
308
621
  end
309
622
 
310
- protected
623
+ protected
311
624
  def inspect_helper #:nodoc:
312
625
  ary = []
313
626
  ary << "shape:[#{shape.join(',')}]" << "dtype:#{dtype}" << "stype:#{stype}"
@@ -28,151 +28,232 @@
28
28
 
29
29
  # This is a specific type of NMatrix in which only one dimension is not 1.
30
30
  # Although it is stored as a dim-2, n x 1, matrix, it acts as a dim-1 vector
31
- # of size n. If the @orientation flag is set to :row, it is stored as 1 x n
32
- # instead of n x 1.
31
+ # of size n. If the @orientation flag is set to :column, it is stored as n x 1
32
+ # instead of 1 x n.
33
33
  class NVector < NMatrix
34
34
  #
35
35
  # call-seq:
36
- # new(length) -> NVector
37
- # new(length, values) -> NVector
38
- # new(length, values, dtype) -> NVector
39
- #
40
- # Creates a new NVector.
36
+ # new(shape) -> NVector
37
+ # new(stype, shape) -> NVector
38
+ # new(shape, init) -> NVector
39
+ # new(:dense, shape, init) -> NVector
40
+ # new(:list, shape, init) -> NVector
41
+ # new(shape, init, dtype) -> NVector
42
+ # new(stype, shape, init, dtype) -> NVector
43
+ # new(stype, shape, dtype) -> NVector
44
+ #
45
+ # Creates a new NVector. See also NMatrix#initialize for a more detailed explanation of
46
+ # the arguments.
41
47
  #
42
48
  # * *Arguments* :
43
- # - +length+ -> Size of the vector.
44
- # - +values+ -> (optional) Initial values of the vector. Default is 0.
45
- # - +dtype+ -> (optional) Default is a guess from the +values+.
49
+ # - +stype+ -> (optional) Storage type of the vector (:list, :dense, :yale). Defaults to :dense.
50
+ # - +shape+ -> Shape of the vector. Accepts [n,1], [1,n], or n, where n is a Fixnum.
51
+ # - +init+ -> (optional) Yale: capacity; List: default value (0); Dense: initial value or values (uninitialized by default).
52
+ # - +dtype+ -> (optional if +init+ provided) Data type stored in the vector. For :dense and :list, can be inferred from +init+.
46
53
  # * *Returns* :
47
54
  # -
48
55
  #
49
- def initialize(length, *args)
50
- super(:dense, [length, 1], *args)
51
- orientation
56
+ def initialize(*args)
57
+ stype = args[0].is_a?(Symbol) ? args.shift : :dense
58
+ shape = args[0].is_a?(Array) ? args.shift : [1,args.shift]
59
+
60
+ if shape.size != 2 || !shape.include?(1) || shape == [1,1]
61
+ raise(ArgumentError, "shape must be a Fixnum or an Array of positive Fixnums where exactly one value is 1")
62
+ end
63
+
64
+ super(stype, shape, *args)
52
65
  end
53
66
 
67
+
54
68
  #
55
69
  # call-seq:
56
70
  # orientation -> Symbol
57
71
  #
58
- # Orientation defaults to column (e.g., [3,1] is a column of length 3). It
59
- # may also be row, e.g., for [1,5].
72
+ # Orientation defaults to row (e.g., [1,3] is a row of length 3). It
73
+ # may also be column, e.g., for [5,1].
60
74
  #
61
75
  def orientation
62
- @orientation ||= :column
76
+ shape[0] == 1 ? :row : :column
63
77
  end
64
78
 
79
+ # Override NMatrix#each_row and #each_column
80
+ def each_column(get_by=:reference, &block) #:nodoc:
81
+ shape[0] == 1 ? self.each(&block) : (yield self)
82
+ end
83
+ def each_row(get_by=:reference, &block) #:nodoc:
84
+ shape[0] == 1 ? (yield self) : self.each(&block)
85
+ end
86
+
87
+
88
+
65
89
  #
66
90
  # call-seq:
67
- # transpose -> NVector
91
+ # vector[index] -> element
92
+ # vector[range] -> NVector
68
93
  #
69
- # Returns a transposed copy of the vector.
94
+ # Retrieves an element or return a slice.
70
95
  #
71
- # * *Returns* :
72
- # - NVector containing the transposed vector.
96
+ # Examples:
73
97
  #
74
- def transpose
75
- t = super()
76
- t.flip!
98
+ # u = NVector.new(3, [10, 20, 30])
99
+ # u[0] # => 10
100
+ # u[0] + u[1] # => 30
101
+ # u[0 .. 1].shape # => [2, 1]
102
+ #
103
+ def [](i)
104
+ shape[0] == 1 ? super(0, i) : super(i, 0)
77
105
  end
78
106
 
79
107
  #
80
108
  # call-seq:
81
- # transpose! -> NVector
82
- #
83
- # Transpose the vector in-place.
109
+ # vector[index] = obj -> obj
84
110
  #
85
- # * *Returns* :
86
- # - NVector containing the transposed vector.
111
+ # Stores +value+ at position +index+.
87
112
  #
88
- def transpose!
89
- super()
90
- self.flip!
113
+ def []=(i, val)
114
+ shape[0] == 1 ? super(0, i, val) : super(i, 0, val)
91
115
  end
92
116
 
93
117
  #
94
118
  # call-seq:
95
- # multiply(m) ->
119
+ # dim -> 1
96
120
  #
97
- # ...
121
+ # Returns the dimension of a vector, which is 1.
98
122
  #
99
- # * *Arguments* :
100
- # - ++ ->
101
- # * *Returns* :
102
- # -
123
+ def dim; 1; end
124
+
103
125
  #
104
- def multiply(m)
105
- t = super(m)
106
- t.flip!
126
+ # call-seq:
127
+ # size -> Fixnum
128
+ #
129
+ # Shorthand for the dominant shape component
130
+ def size
131
+ shape[0] > 1 ? shape[0] : shape[1]
107
132
  end
108
133
 
109
134
  #
110
135
  # call-seq:
111
- # multiply!(m) ->
136
+ # max -> Numeric
112
137
  #
113
- # ...
138
+ # Return the maximum element.
139
+ def max
140
+ max_so_far = self[0]
141
+ self.each do |x|
142
+ max_so_far = x if x > max_so_far
143
+ end
144
+ max_so_far
145
+ end
146
+
114
147
  #
115
- # * *Arguments* :
116
- # - ++ ->
117
- # * *Returns* :
118
- # -
148
+ # call-seq:
149
+ # min -> Numeric
119
150
  #
120
- def multiply!(m)
121
- super().flip!
151
+ # Return the minimum element.
152
+ def min
153
+ min_so_far = self[0]
154
+ self.each do |x|
155
+ min_so_far = x if x < min_so_far
156
+ end
157
+ min_so_far
122
158
  end
123
159
 
124
160
  #
125
161
  # call-seq:
126
- # vector[index] -> element
127
- # vector[range] -> NVector
162
+ # absolute_sum -> Numeric
128
163
  #
129
- # Retrieves an element or return a slice.
164
+ # == Arguments
165
+ # - +incx+ -> the skip size (defaults to 1, no skip)
166
+ # - +n+ -> the number of elements to include
130
167
  #
131
- # Examples:
168
+ # Return the sum of the contents of the vector. This is the BLAS asum routine.
169
+ def asum incx=1, n=nil
170
+ NMatrix::BLAS::asum(self, incx, self.size / incx)
171
+ end
172
+ alias :absolute_sum :asum
173
+
132
174
  #
133
- # u = NVector.new(3, [10, 20, 30])
134
- # u[0] # => 10
135
- # u[0] + u[1] # => 30
136
- # u[0 .. 1].shape # => [2, 1]
175
+ # call-seq:
176
+ # norm2 -> Numeric
137
177
  #
138
- def [](i)
139
- case @orientation
140
- when :column; super(i, 0)
141
- when :row; super(0, i)
178
+ # == Arguments
179
+ # - +incx+ -> the skip size (defaults to 1, no skip)
180
+ # - +n+ -> the number of elements to include
181
+ #
182
+ # Return the 2-norm of the vector. This is the BLAS nrm2 routine.
183
+ def nrm2 incx=1, n=nil
184
+ NMatrix::BLAS::nrm2(self, incx, self.size / incx)
185
+ end
186
+ alias :norm2 :nrm2
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 }
142
204
  end
205
+ ary
143
206
  end
144
207
 
145
208
  #
146
209
  # call-seq:
147
- # vector[index] = obj -> obj
210
+ # each_stored_with_index -> Enumerator
148
211
  #
149
- # Stores +value+ at position +index+.
212
+ # Allow iteration across an NVector's stored values. See also NMatrix#each_stored_with_indices
150
213
  #
151
- def []=(i, val)
152
- case @orientation
153
- when :column; super(i, 0, val)
154
- when :row; super(0, i, val)
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)
155
218
  end
219
+ self
156
220
  end
157
221
 
158
222
  #
159
223
  # call-seq:
160
- # dim -> 1
224
+ # shuffle! -> ...
225
+ # shuffle!(random: rng) -> ...
161
226
  #
162
- # Returns the dimension of a vector, which is 1.
227
+ # Re-arranges the contents of an NVector.
163
228
  #
164
- def dim; 1; end
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
165
236
 
166
- # shorthand for the dominant shape component
167
- def size
168
- shape[0] > 1 ? shape[0] : shape[1]
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)
169
249
  end
170
250
 
251
+
171
252
  # TODO: Make this actually pretty.
172
253
  def pretty_print(q = nil) #:nodoc:
173
- dim = @orientation == :row ? 1 : 0
254
+ dimen = shape[0] == 1 ? 1 : 0
174
255
 
175
- arr = (0...shape[dim]).inject(Array.new){ |a, i| a << self[i] }
256
+ arr = (0...shape[dimen]).inject(Array.new){ |a, i| a << self[i] }
176
257
 
177
258
  if q.nil?
178
259
  puts "[" + arr.join("\n") + "]"
@@ -186,27 +267,7 @@ class NVector < NMatrix
186
267
  def inspect #:nodoc:
187
268
  original_inspect = super()
188
269
  original_inspect = original_inspect[0...original_inspect.size-1]
189
- original_inspect.gsub("@orientation=:#{self.orientation}", "orientation:#{self.orientation}") + ">"
270
+ original_inspect += " orientation:#{self.orientation}>"
190
271
  end
191
272
 
192
- protected
193
- # def inspect_helper #:nodoc:
194
- # x = (super() << "orientation:#{self.orientation}") #.gsub(" @orientation=:#{self.orientation}", "")
195
- # binding.pry
196
- # x
197
- # end
198
-
199
- #
200
- # call-seq:
201
- # flip_orientation! -> NVector
202
- #
203
- # Flip the orientation of the vector.
204
- #
205
- # * *Returns* :
206
- # - NVector with orientation changed.
207
- #
208
- def flip_orientation!
209
- returning(self) { @orientation = @orientation == :row ? :column : :row }
210
- end
211
- alias :flip! :flip_orientation!
212
273
  end