nmatrix 0.1.0.rc1 → 0.1.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -1
- data/Gemfile +1 -4
- data/History.txt +64 -2
- data/Manifest.txt +6 -4
- data/README.rdoc +8 -5
- data/Rakefile +0 -2
- data/ext/nmatrix/data/data.cpp +2 -1
- data/ext/nmatrix/data/data.h +3 -2
- data/ext/nmatrix/extconf.rb +4 -9
- data/ext/nmatrix/math.cpp +65 -0
- data/ext/nmatrix/math/math.h +1 -0
- data/ext/nmatrix/nmatrix.h +2 -2
- data/ext/nmatrix/ruby_constants.cpp +3 -1
- data/ext/nmatrix/ruby_constants.h +3 -1
- data/ext/nmatrix/ruby_nmatrix.c +153 -8
- data/ext/nmatrix/util/sl_list.cpp +6 -2
- data/lib/nmatrix/io/point_cloud.rb +182 -0
- data/lib/nmatrix/math.rb +35 -5
- data/lib/nmatrix/nmatrix.rb +70 -26
- data/lib/nmatrix/shortcuts.rb +18 -1
- data/lib/nmatrix/version.rb +1 -1
- data/nmatrix.gemspec +2 -2
- data/spec/00_nmatrix_spec.rb +220 -176
- data/spec/01_enum_spec.rb +29 -29
- data/spec/02_slice_spec.rb +85 -85
- data/spec/blas_spec.rb +18 -18
- data/spec/elementwise_spec.rb +44 -44
- data/spec/io_spec.rb +31 -24
- data/spec/lapack_spec.rb +34 -34
- data/spec/math_spec.rb +61 -46
- data/spec/nmatrix_yale_spec.rb +35 -35
- data/spec/rspec_spec.rb +2 -2
- data/spec/shortcuts_spec.rb +66 -48
- data/spec/slice_set_spec.rb +31 -31
- data/spec/stat_spec.rb +40 -40
- data/spec/test.pcd +20 -0
- metadata +5 -2
@@ -49,6 +49,10 @@ namespace nm { namespace list {
|
|
49
49
|
* Macros
|
50
50
|
*/
|
51
51
|
|
52
|
+
#ifndef RHASH_SET_IFNONE
|
53
|
+
#define RHASH_SET_IFNONE(h, v) (RHASH(h)->ifnone = (v))
|
54
|
+
#endif
|
55
|
+
|
52
56
|
/*
|
53
57
|
* Global Variables
|
54
58
|
*/
|
@@ -580,9 +584,9 @@ extern "C" {
|
|
580
584
|
static VALUE empty_list_to_hash(const nm::dtype_t dtype, size_t recursions, VALUE default_value) {
|
581
585
|
VALUE h = rb_hash_new();
|
582
586
|
if (recursions) {
|
583
|
-
|
587
|
+
RHASH_SET_IFNONE(h, empty_list_to_hash(dtype, recursions-1, default_value));
|
584
588
|
} else {
|
585
|
-
|
589
|
+
RHASH_SET_IFNONE(h, default_value);
|
586
590
|
}
|
587
591
|
return h;
|
588
592
|
}
|
@@ -0,0 +1,182 @@
|
|
1
|
+
#--
|
2
|
+
# = NMatrix
|
3
|
+
#
|
4
|
+
# A linear algebra library for scientific computation in Ruby.
|
5
|
+
# NMatrix is part of SciRuby.
|
6
|
+
#
|
7
|
+
# NMatrix was originally inspired by and derived from NArray, by
|
8
|
+
# Masahiro Tanaka: http://narray.rubyforge.org
|
9
|
+
#
|
10
|
+
# == Copyright Information
|
11
|
+
#
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
|
14
|
+
#
|
15
|
+
# Please see LICENSE.txt for additional copyright notices.
|
16
|
+
#
|
17
|
+
# == Contributing
|
18
|
+
#
|
19
|
+
# By contributing source code to SciRuby, you agree to be bound by
|
20
|
+
# our Contributor Agreement:
|
21
|
+
#
|
22
|
+
# * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
23
|
+
#
|
24
|
+
# == io/point_cloud.rb
|
25
|
+
#
|
26
|
+
# Point Cloud Library (PCL) PCD file IO functions.
|
27
|
+
#
|
28
|
+
#++
|
29
|
+
|
30
|
+
# Reader for a PCD file, specified here:
|
31
|
+
#
|
32
|
+
# * http://pointclouds.org/documentation/tutorials/pcd_file_format.php
|
33
|
+
#
|
34
|
+
# Note that this does not take the width or height parameters into account.
|
35
|
+
#
|
36
|
+
module NMatrix::IO::PointCloud
|
37
|
+
|
38
|
+
class MetaReader
|
39
|
+
ENTRIES = [:version, :fields, :size, :type, :count, :width, :height, :viewpoint, :points, :data]
|
40
|
+
ASSIGNS = [:version=, :fields=, :size=, :type=, :count=, :width=, :height=, :viewpoint=, :points=, :data=]
|
41
|
+
CONVERT = [:to_s, :downcase_to_sym, :to_i, :downcase_to_sym, :to_i, :to_i, :to_i, :to_f, :to_i, :downcase_to_sym]
|
42
|
+
|
43
|
+
DTYPE_CONVERT = {:byte => :to_i, :int8 => :to_i, :int16 => :to_i, :int32 => :to_i, :float32 => :to_f, :float64 => :to_f}
|
44
|
+
|
45
|
+
# For UINT, just add 1 to the index.
|
46
|
+
INT_DTYPE_BY_SIZE = {1 => :int8, 2 => :int16, 4 => :int32, 8 => :int64, 16 => :int64}
|
47
|
+
FLOAT_DTYPE_BY_SIZE = {1 => :float32, 2 => :float32, 4 => :float32, 8 => :float64,16 => :float64}
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
# Given a type and a number of bytes, figure out an appropriate dtype
|
52
|
+
def dtype_by_type_and_size t, s #:nodoc:
|
53
|
+
if t == :f
|
54
|
+
FLOAT_DTYPE_BY_SIZE[s]
|
55
|
+
elsif t == :u
|
56
|
+
return :byte if s == 1
|
57
|
+
INT_DTYPE_BY_SIZE[s*2]
|
58
|
+
else
|
59
|
+
INT_DTYPE_BY_SIZE[s]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# call-seq:
|
65
|
+
# PointCloudReader::MetaReader.new(filename) -> MetaReader
|
66
|
+
#
|
67
|
+
# * *Arguments* :
|
68
|
+
# - +filename+ -> String giving the name of the file to be loaded.
|
69
|
+
# * *Raises* :
|
70
|
+
# - +NotImplementedError+ -> only ASCII supported currently
|
71
|
+
# - +IOError+ -> premature end of file
|
72
|
+
#
|
73
|
+
# Open a file and read the metadata at the top; then read the PCD into an
|
74
|
+
# NMatrix.
|
75
|
+
#
|
76
|
+
# In addition to the fields in the PCD file, there will be at least one
|
77
|
+
# additional attribute, :matrix, storing the data.
|
78
|
+
def initialize filename
|
79
|
+
f = File.new(filename, "r")
|
80
|
+
|
81
|
+
ENTRIES.each.with_index do |entry,i|
|
82
|
+
read_entry(f, entry, ASSIGNS[i], CONVERT[i])
|
83
|
+
end
|
84
|
+
|
85
|
+
raise(NotImplementedError, "only ASCII supported currently") unless self.data.first == :ascii
|
86
|
+
|
87
|
+
@matrix = NMatrix.new(self.shape, dtype: self.dtype)
|
88
|
+
|
89
|
+
# Do we want to use to_i or to_f?
|
90
|
+
convert = DTYPE_CONVERT[self.dtype]
|
91
|
+
|
92
|
+
i = 0
|
93
|
+
while line = f.gets
|
94
|
+
@matrix[i,:*] = line.chomp.split.map { |f| f.send(convert) }
|
95
|
+
i += 1
|
96
|
+
end
|
97
|
+
|
98
|
+
raise(IOError, "premature end of file") if i < self.points[0]
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
attr_accessor *ENTRIES
|
103
|
+
attr_reader :matrix
|
104
|
+
|
105
|
+
protected
|
106
|
+
# Read the current entry of the header.
|
107
|
+
def read_entry f, entry, assign=nil, convert=nil #:nodoc:
|
108
|
+
assign ||= (entry.to_s + "=").to_sym
|
109
|
+
|
110
|
+
while line = f.gets
|
111
|
+
next if line =~ /^\s*#/ # ignore comment lines
|
112
|
+
line = line.chomp.split(/\s*#/)[0] # ignore the comments after any data
|
113
|
+
|
114
|
+
# Split, remove the entry name, and convert to the correct type.
|
115
|
+
self.send(assign,
|
116
|
+
line.split.tap { |t| t.shift }.map do |f|
|
117
|
+
if convert.nil?
|
118
|
+
f
|
119
|
+
elsif convert == :downcase_to_sym
|
120
|
+
f.downcase.to_sym
|
121
|
+
else
|
122
|
+
f.send(convert)
|
123
|
+
end
|
124
|
+
end)
|
125
|
+
|
126
|
+
# We don't really want to loop.
|
127
|
+
break
|
128
|
+
end
|
129
|
+
|
130
|
+
self.send(entry)
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Determine the dtype for a matrix based on the types and sizes given in the PCD.
|
135
|
+
# Call this only after read_entry has been called.
|
136
|
+
def dtype #:nodoc:
|
137
|
+
@dtype ||= begin
|
138
|
+
dtypes = self.type.map.with_index do |t,k|
|
139
|
+
MetaReader.dtype_by_type_and_size(t, size[k])
|
140
|
+
end.sort.uniq
|
141
|
+
|
142
|
+
# This could probably save one comparison at most, but we assume that
|
143
|
+
# worst case isn't going to happen very often.
|
144
|
+
while dtypes.size > 1
|
145
|
+
d = NMatrix.upcast(dtypes[0], dtypes[1])
|
146
|
+
dtypes.shift
|
147
|
+
dtypes[0] = d
|
148
|
+
end
|
149
|
+
|
150
|
+
dtypes[0]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Determine the shape of the matrix.
|
155
|
+
def shape
|
156
|
+
@shape ||= [
|
157
|
+
self.points[0],
|
158
|
+
self.fields.size
|
159
|
+
]
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
# For UINT, just add 1 to the index.
|
165
|
+
INT_DTYPE_BY_SIZE = [:int8, :int8, :int16, :int32, :int64, :int64]
|
166
|
+
FLOAT_DTYPE_BY_SIZE = {4 => :float32, 8 => :float64}
|
167
|
+
|
168
|
+
class << self
|
169
|
+
|
170
|
+
#
|
171
|
+
# call-seq:
|
172
|
+
# load(filename) -> NMatrix
|
173
|
+
#
|
174
|
+
# * *Arguments* :
|
175
|
+
# - +filename+ -> String giving the name of the file to be loaded.
|
176
|
+
#
|
177
|
+
# Load a Point Cloud Library PCD file as a matrix.
|
178
|
+
def load(filename)
|
179
|
+
MetaReader.new(filename).matrix
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/lib/nmatrix/math.rb
CHANGED
@@ -33,7 +33,7 @@ class NMatrix
|
|
33
33
|
module NMMath
|
34
34
|
METHODS_ARITY_2 = [:atan2, :ldexp, :hypot]
|
35
35
|
METHODS_ARITY_1 = [:cos, :sin, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh,
|
36
|
-
:asinh, :atanh, :exp, :log2, :log10, :sqrt, :cbrt, :erf, :erfc, :gamma]
|
36
|
+
:asinh, :atanh, :exp, :log2, :log10, :sqrt, :cbrt, :erf, :erfc, :gamma, :-@]
|
37
37
|
end
|
38
38
|
|
39
39
|
#
|
@@ -43,7 +43,8 @@ class NMatrix
|
|
43
43
|
# Use LAPACK to calculate the inverse of the matrix (in-place). Only works on
|
44
44
|
# dense matrices.
|
45
45
|
#
|
46
|
-
# Note: If you don't have LAPACK, e.g., on a Mac, this may not work yet.
|
46
|
+
# Note: If you don't have LAPACK, e.g., on a Mac, this may not work yet. Use
|
47
|
+
# invert instead (which still probably won't work if your matrix is larger than 3x3).
|
47
48
|
#
|
48
49
|
def invert!
|
49
50
|
# Get the pivot array; factor the matrix
|
@@ -59,13 +60,29 @@ class NMatrix
|
|
59
60
|
# call-seq:
|
60
61
|
# invert -> NMatrix
|
61
62
|
#
|
62
|
-
# Make a copy of the matrix, then invert it (requires LAPACK).
|
63
|
+
# Make a copy of the matrix, then invert it (requires LAPACK for matrices larger than 3x3).
|
64
|
+
#
|
65
|
+
#
|
63
66
|
#
|
64
67
|
# * *Returns* :
|
65
68
|
# - A dense NMatrix.
|
66
69
|
#
|
67
70
|
def invert
|
68
|
-
|
71
|
+
if NMatrix.has_clapack?
|
72
|
+
begin
|
73
|
+
self.cast(:dense, self.dtype).invert! # call CLAPACK version
|
74
|
+
rescue NotImplementedError # probably a rational matrix
|
75
|
+
inverse = self.clone_structure
|
76
|
+
__inverse_exact__(inverse)
|
77
|
+
end
|
78
|
+
elsif self.integer_dtype? # FIXME: This check is probably too slow.
|
79
|
+
rational_self = self.cast(dtype: :rational128)
|
80
|
+
inverse = rational_self.clone_structure
|
81
|
+
rational_self.__inverse_exact__(inverse)
|
82
|
+
else
|
83
|
+
inverse = self.clone_structure
|
84
|
+
__inverse_exact__(inverse)
|
85
|
+
end
|
69
86
|
end
|
70
87
|
alias :inverse :invert
|
71
88
|
|
@@ -552,7 +569,7 @@ protected
|
|
552
569
|
|
553
570
|
# These don't actually take an argument -- they're called reverse-polish style on the matrix.
|
554
571
|
# This group always gets casted to float64.
|
555
|
-
[:log2, :log10, :sqrt, :sin, :cos, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh, :asinh, :atanh, :exp, :erf, :erfc, :gamma, :cbrt].each do |ewop|
|
572
|
+
[:log, :log2, :log10, :sqrt, :sin, :cos, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh, :asinh, :atanh, :exp, :erf, :erfc, :gamma, :cbrt].each do |ewop|
|
556
573
|
define_method("__list_unary_#{ewop}__") do
|
557
574
|
self.__list_map_stored__(nil) { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64))
|
558
575
|
end
|
@@ -577,6 +594,19 @@ protected
|
|
577
594
|
self.__dense_map__ { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64))
|
578
595
|
end
|
579
596
|
|
597
|
+
# These are for negating matrix contents using -@
|
598
|
+
def __list_unary_negate__
|
599
|
+
self.__list_map_stored__(nil) { |l| -l }.cast(stype, dtype)
|
600
|
+
end
|
601
|
+
|
602
|
+
def __yale_unary_negate__
|
603
|
+
self.__yale_map_stored__ { |l| -l }.cast(stype, dtype)
|
604
|
+
end
|
605
|
+
|
606
|
+
def __dense_unary_negate__
|
607
|
+
self.__dense_map__ { |l| -l }.cast(stype, dtype)
|
608
|
+
end
|
609
|
+
|
580
610
|
# These take two arguments. One might be a matrix, and one might be a scalar.
|
581
611
|
# See also monkeys.rb, which contains Math module patches to let the first
|
582
612
|
# arg be a scalar
|
data/lib/nmatrix/nmatrix.rb
CHANGED
@@ -49,24 +49,37 @@ class NMatrix
|
|
49
49
|
autoload :Mat5Reader, 'nmatrix/io/mat5_reader'
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
autoload :
|
52
|
+
autoload :Market, 'nmatrix/io/market.rb'
|
53
|
+
autoload :PointCloud, 'nmatrix/io/point_cloud.rb'
|
54
54
|
end
|
55
55
|
|
56
56
|
class << self
|
57
57
|
#
|
58
58
|
# call-seq:
|
59
|
-
#
|
59
|
+
# load_matlab_file(path) -> Mat5Reader
|
60
60
|
#
|
61
61
|
# * *Arguments* :
|
62
|
-
# - +
|
62
|
+
# - +file_path+ -> The path to a version 5 .mat file.
|
63
63
|
# * *Returns* :
|
64
64
|
# - A Mat5Reader object.
|
65
65
|
#
|
66
|
-
def
|
66
|
+
def load_matlab_file(file_path)
|
67
67
|
NMatrix::IO::Mat5Reader.new(File.open(file_path, 'rb')).to_ruby
|
68
68
|
end
|
69
69
|
|
70
|
+
#
|
71
|
+
# call-seq:
|
72
|
+
# load_pcd_file(path) -> PointCloudReader::MetaReader
|
73
|
+
#
|
74
|
+
# * *Arguments* :
|
75
|
+
# - +file_path+ -> The path to a PCL PCD file.
|
76
|
+
# * *Returns* :
|
77
|
+
# - A PointCloudReader::MetaReader object with the matrix stored in its +matrix+ property
|
78
|
+
#
|
79
|
+
def load_pcd_file(file_path)
|
80
|
+
NMatrix::IO::PointCloudReader::MetaReader.new(file_path)
|
81
|
+
end
|
82
|
+
|
70
83
|
#
|
71
84
|
# Calculate the size of an NMatrix of a given shape.
|
72
85
|
def size(shape)
|
@@ -226,7 +239,7 @@ class NMatrix
|
|
226
239
|
|
227
240
|
|
228
241
|
##
|
229
|
-
# call-seq:
|
242
|
+
# call-seq:
|
230
243
|
# integer_dtype?() -> Boolean
|
231
244
|
#
|
232
245
|
# Checks if dtype is an integer type
|
@@ -403,15 +416,45 @@ class NMatrix
|
|
403
416
|
# * *Returns* :
|
404
417
|
# - A copy with a different shape.
|
405
418
|
#
|
406
|
-
def reshape new_shape
|
407
|
-
|
408
|
-
|
419
|
+
def reshape new_shape,*shapes
|
420
|
+
if new_shape.is_a?Fixnum
|
421
|
+
newer_shape = [new_shape]+shapes
|
422
|
+
else # new_shape is an Array
|
423
|
+
newer_shape = new_shape
|
424
|
+
end
|
425
|
+
t = reshape_clone_structure(newer_shape)
|
426
|
+
left_params = [:*]*newer_shape.size
|
427
|
+
puts(left_params)
|
409
428
|
right_params = [:*]*self.shape.size
|
410
429
|
t[*left_params] = self[*right_params]
|
411
430
|
t
|
412
431
|
end
|
413
432
|
|
414
433
|
|
434
|
+
#
|
435
|
+
# call-seq:
|
436
|
+
# reshape!(new_shape) -> NMatrix
|
437
|
+
# reshape! new_shape -> NMatrix
|
438
|
+
#
|
439
|
+
# Reshapes the matrix (in-place) to the desired shape. Note that this function does not do a resize; the product of
|
440
|
+
# the new and old shapes' components must be equal.
|
441
|
+
#
|
442
|
+
# * *Arguments* :
|
443
|
+
# - +new_shape+ -> Array of positive Fixnums.
|
444
|
+
#
|
445
|
+
def reshape! new_shape,*shapes
|
446
|
+
if self.is_ref?
|
447
|
+
raise(ArgumentError, "This operation cannot be performed on reference slices")
|
448
|
+
else
|
449
|
+
if new_shape.is_a?Fixnum
|
450
|
+
shape = [new_shape]+shapes
|
451
|
+
else # new_shape is an Array
|
452
|
+
shape = new_shape
|
453
|
+
end
|
454
|
+
self.reshape_bang(shape)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
415
458
|
#
|
416
459
|
# call-seq:
|
417
460
|
# transpose -> NMatrix
|
@@ -427,7 +470,9 @@ class NMatrix
|
|
427
470
|
# - A copy of the matrix, but transposed.
|
428
471
|
#
|
429
472
|
def transpose(permute = nil)
|
430
|
-
if self.dim
|
473
|
+
if self.dim == 1
|
474
|
+
return self.clone
|
475
|
+
elsif self.dim == 2
|
431
476
|
new_shape = [self.shape[1], self.shape[0]]
|
432
477
|
elsif permute.nil?
|
433
478
|
raise(ArgumentError, "need permutation array of size #{self.dim}")
|
@@ -771,6 +816,21 @@ class NMatrix
|
|
771
816
|
end
|
772
817
|
|
773
818
|
|
819
|
+
#
|
820
|
+
# call-seq:
|
821
|
+
# clone_structure -> NMatrix
|
822
|
+
#
|
823
|
+
# This function is like clone, but it only copies the structure and the default value.
|
824
|
+
# None of the other values are copied. It takes an optional capacity argument. This is
|
825
|
+
# mostly only useful for dense, where you may not want to initialize; for other types,
|
826
|
+
# you should probably use +zeros_like+.
|
827
|
+
#
|
828
|
+
def clone_structure(capacity = nil)
|
829
|
+
opts = {stype: self.stype, default: self.default_value, dtype: self.dtype}
|
830
|
+
opts = {capacity: capacity}.merge(opts) if self.yale?
|
831
|
+
NMatrix.new(self.shape, opts)
|
832
|
+
end
|
833
|
+
|
774
834
|
# This is how you write an individual element-wise operation function:
|
775
835
|
#def __list_elementwise_add__ rhs
|
776
836
|
# self.__list_map_merged_stored__(rhs){ |l,r| l+r }.cast(self.stype, NMatrix.upcast(self.dtype, rhs.dtype))
|
@@ -797,22 +857,6 @@ protected
|
|
797
857
|
end
|
798
858
|
|
799
859
|
|
800
|
-
#
|
801
|
-
# call-seq:
|
802
|
-
# clone_structure -> NMatrix
|
803
|
-
#
|
804
|
-
# This function is like clone, but it only copies the structure and the default value.
|
805
|
-
# None of the other values are copied. It takes an optional capacity argument. This is
|
806
|
-
# mostly only useful for dense, where you may not want to initialize; for other types,
|
807
|
-
# you should probably use +zeros_like+.
|
808
|
-
#
|
809
|
-
def clone_structure(capacity = nil)
|
810
|
-
opts = {stype: self.stype, default: self.default_value, dtype: self.dtype}
|
811
|
-
opts = {capacity: capacity}.merge(opts) if self.yale?
|
812
|
-
NMatrix.new(self.shape, opts)
|
813
|
-
end
|
814
|
-
|
815
|
-
|
816
860
|
# Clone the structure as needed for a reshape
|
817
861
|
def reshape_clone_structure(new_shape) #:nodoc:
|
818
862
|
raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") unless self.size == new_shape.inject(1) { |p,i| p *= i }
|
data/lib/nmatrix/shortcuts.rb
CHANGED
@@ -263,6 +263,7 @@ class NMatrix
|
|
263
263
|
alias :diag :diagonal
|
264
264
|
alias :diagonals :diagonal
|
265
265
|
|
266
|
+
|
266
267
|
#
|
267
268
|
# call-seq:
|
268
269
|
# random(shape) -> NMatrix
|
@@ -270,6 +271,10 @@ class NMatrix
|
|
270
271
|
# Creates a +:dense+ NMatrix with random numbers between 0 and 1 generated
|
271
272
|
# by +Random::rand+. The parameter is the dimension of the matrix.
|
272
273
|
#
|
274
|
+
# If you use an integer dtype, make sure to specify :scale as a parameter, or you'll
|
275
|
+
# only get a matrix of 0s. You may not currently generate random numbers for
|
276
|
+
# a rational matrix.
|
277
|
+
#
|
273
278
|
# * *Arguments* :
|
274
279
|
# - +shape+ -> Array (or integer for square matrix) specifying the dimensions.
|
275
280
|
# * *Returns* :
|
@@ -280,16 +285,28 @@ class NMatrix
|
|
280
285
|
# NMatrix.random([2, 2]) # => 0.4859439730644226 0.1783195585012436
|
281
286
|
# 0.23193766176700592 0.4503345191478729
|
282
287
|
#
|
288
|
+
# NMatrix.random([2, 2], :dtype => :byte, :scale => 255) # => [ [252, 108] [44, 12] ]
|
289
|
+
#
|
283
290
|
def random(shape, opts={})
|
291
|
+
scale = opts.delete(:scale) || 1.0
|
292
|
+
|
293
|
+
raise(NotImplementedError, "does not support rational random number generation") if opts[:dtype].to_s =~ /^rational/
|
294
|
+
|
284
295
|
rng = Random.new
|
285
296
|
|
286
297
|
random_values = []
|
287
298
|
|
299
|
+
|
288
300
|
# Construct the values of the final matrix based on the dimension.
|
289
|
-
|
301
|
+
if opts[:dtype] == :complex64 || opts[:dtype] == :complex128
|
302
|
+
NMatrix.size(shape).times { |i| random_values << Complex(rng.rand(scale), rng.rand(scale)) }
|
303
|
+
else
|
304
|
+
NMatrix.size(shape).times { |i| random_values << rng.rand(scale) }
|
305
|
+
end
|
290
306
|
|
291
307
|
NMatrix.new(shape, random_values, {:dtype => :float64, :stype => :dense}.merge(opts))
|
292
308
|
end
|
309
|
+
alias :rand :random
|
293
310
|
|
294
311
|
#
|
295
312
|
# call-seq:
|