nmatrix 0.1.0.rc1 → 0.1.0.rc2
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 +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:
|