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.
- checksums.yaml +7 -0
- data/History.txt +68 -2
- data/Manifest.txt +1 -0
- data/README.rdoc +8 -7
- data/Rakefile +13 -2
- data/ext/nmatrix/data/complex.h +19 -1
- data/ext/nmatrix/data/data.h +8 -0
- data/ext/nmatrix/data/ruby_object.h +1 -0
- data/ext/nmatrix/extconf.rb +6 -4
- data/ext/nmatrix/nmatrix.cpp +97 -35
- data/ext/nmatrix/nmatrix.h +2 -0
- data/ext/nmatrix/ruby_constants.cpp +11 -1
- data/ext/nmatrix/ruby_constants.h +6 -1
- data/ext/nmatrix/storage/dense.cpp +2 -2
- data/ext/nmatrix/storage/yale.cpp +303 -49
- data/ext/nmatrix/storage/yale.h +3 -0
- data/ext/nmatrix/util/math.cpp +112 -0
- data/ext/nmatrix/util/math.h +372 -72
- data/lib/nmatrix/blas.rb +55 -9
- data/lib/nmatrix/nmatrix.rb +315 -2
- data/lib/nmatrix/nvector.rb +156 -95
- data/lib/nmatrix/version.rb +1 -1
- data/lib/nmatrix/yale_functions.rb +112 -0
- data/spec/blas_spec.rb +11 -0
- data/spec/elementwise_spec.rb +4 -1
- data/spec/io_spec.rb +8 -0
- data/spec/lapack_spec.rb +37 -15
- data/spec/leakcheck.rb +16 -0
- data/spec/math_spec.rb +6 -2
- data/spec/nmatrix_spec.rb +209 -3
- data/spec/nmatrix_yale_spec.rb +55 -0
- data/spec/nvector_spec.rb +33 -14
- data/spec/slice_spec.rb +26 -17
- data/spec/spec_helper.rb +17 -0
- metadata +60 -45
- data/ext/nmatrix/new_extconf.rb +0 -55
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
|
65
|
-
raise
|
66
|
-
raise
|
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
|
137
|
-
raise
|
138
|
-
raise
|
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
|
183
|
-
raise
|
184
|
-
raise
|
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
|
data/lib/nmatrix/nmatrix.rb
CHANGED
@@ -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
|
-
|
623
|
+
protected
|
311
624
|
def inspect_helper #:nodoc:
|
312
625
|
ary = []
|
313
626
|
ary << "shape:[#{shape.join(',')}]" << "dtype:#{dtype}" << "stype:#{stype}"
|
data/lib/nmatrix/nvector.rb
CHANGED
@@ -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 :
|
32
|
-
# instead of
|
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(
|
37
|
-
# new(
|
38
|
-
# new(
|
39
|
-
#
|
40
|
-
#
|
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
|
-
# - +
|
44
|
-
# - +
|
45
|
-
# - +
|
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(
|
50
|
-
|
51
|
-
|
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
|
59
|
-
# may also be
|
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
|
-
|
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
|
-
#
|
91
|
+
# vector[index] -> element
|
92
|
+
# vector[range] -> NVector
|
68
93
|
#
|
69
|
-
#
|
94
|
+
# Retrieves an element or return a slice.
|
70
95
|
#
|
71
|
-
#
|
72
|
-
# - NVector containing the transposed vector.
|
96
|
+
# Examples:
|
73
97
|
#
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
#
|
82
|
-
#
|
83
|
-
# Transpose the vector in-place.
|
109
|
+
# vector[index] = obj -> obj
|
84
110
|
#
|
85
|
-
#
|
86
|
-
# - NVector containing the transposed vector.
|
111
|
+
# Stores +value+ at position +index+.
|
87
112
|
#
|
88
|
-
def
|
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
|
-
#
|
119
|
+
# dim -> 1
|
96
120
|
#
|
97
|
-
#
|
121
|
+
# Returns the dimension of a vector, which is 1.
|
98
122
|
#
|
99
|
-
|
100
|
-
|
101
|
-
# * *Returns* :
|
102
|
-
# -
|
123
|
+
def dim; 1; end
|
124
|
+
|
103
125
|
#
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
#
|
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
|
-
#
|
116
|
-
#
|
117
|
-
# * *Returns* :
|
118
|
-
# -
|
148
|
+
# call-seq:
|
149
|
+
# min -> Numeric
|
119
150
|
#
|
120
|
-
|
121
|
-
|
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
|
-
#
|
127
|
-
# vector[range] -> NVector
|
162
|
+
# absolute_sum -> Numeric
|
128
163
|
#
|
129
|
-
#
|
164
|
+
# == Arguments
|
165
|
+
# - +incx+ -> the skip size (defaults to 1, no skip)
|
166
|
+
# - +n+ -> the number of elements to include
|
130
167
|
#
|
131
|
-
#
|
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
|
-
#
|
134
|
-
#
|
135
|
-
# u[0] + u[1] # => 30
|
136
|
-
# u[0 .. 1].shape # => [2, 1]
|
175
|
+
# call-seq:
|
176
|
+
# norm2 -> Numeric
|
137
177
|
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
#
|
210
|
+
# each_stored_with_index -> Enumerator
|
148
211
|
#
|
149
|
-
#
|
212
|
+
# Allow iteration across an NVector's stored values. See also NMatrix#each_stored_with_indices
|
150
213
|
#
|
151
|
-
def
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
#
|
224
|
+
# shuffle! -> ...
|
225
|
+
# shuffle!(random: rng) -> ...
|
161
226
|
#
|
162
|
-
#
|
227
|
+
# Re-arranges the contents of an NVector.
|
163
228
|
#
|
164
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
254
|
+
dimen = shape[0] == 1 ? 1 : 0
|
174
255
|
|
175
|
-
arr = (0...shape[
|
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
|
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
|