nmatrix 0.0.4 → 0.0.5

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