ruby-gsl-ng 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/Manifest +9 -0
- data/Rakefile +9 -5
- data/ext/extconf.rb +2 -2
- data/ext/gslng_extensions.cpp +141 -36
- data/lib/gslng.rb +9 -8
- data/lib/gslng/backend.rb +5 -3
- data/lib/gslng/backend_components/error_handling.rb +11 -11
- data/lib/gslng/backend_components/matrix.rb +66 -75
- data/lib/gslng/backend_components/rng.rb +22 -0
- data/lib/gslng/backend_components/special.rb +7 -0
- data/lib/gslng/backend_components/vector.rb +63 -75
- data/lib/gslng/finalizer.rb +6 -2
- data/lib/gslng/matrix.rb +199 -134
- data/lib/gslng/matrix_view.rb +3 -2
- data/lib/gslng/rng/gaussian.rb +34 -0
- data/lib/gslng/rng/rng.rb +27 -0
- data/lib/gslng/rng/uniform.rb +23 -0
- data/lib/gslng/special.rb +22 -0
- data/lib/gslng/vector.rb +196 -125
- data/lib/gslng/vector_view.rb +5 -3
- data/ruby-gsl-ng.gemspec +6 -6
- data/test/benchmark.rb +61 -14
- data/test/benchmark_results +80 -0
- data/test/matrix_test.rb +11 -8
- data/test/rng_test.rb +27 -0
- data/test/test_special.rb +21 -0
- data/test/vector_test.rb +18 -4
- metadata +21 -4
data/lib/gslng/matrix_view.rb
CHANGED
@@ -9,16 +9,17 @@ module GSLng
|
|
9
9
|
class View < Matrix
|
10
10
|
attr_reader :owner # The Matrix owning the data this View uses
|
11
11
|
|
12
|
-
# Create a
|
12
|
+
# Create a Matrix::View of the sub-matrix starting at (x,y), of size (m,n)
|
13
13
|
def initialize(owner, x, y, m, n) # @private
|
14
14
|
@owner = owner
|
15
15
|
@m,@n = m,n
|
16
16
|
@ptr = GSLng.backend::gsl_matrix_submatrix2(owner.ptr, x, y, m, n)
|
17
|
-
GSLng.
|
17
|
+
GSLng.define_finalizer(self, :gsl_matrix_free, @ptr)
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns a Matrix (*NOT* a View) copied from this view. In other words,
|
21
21
|
# you'll get a Matrix which you can modify without modifying #owner elements.
|
22
|
+
# @return [Matrix]
|
22
23
|
def dup
|
23
24
|
matrix = Matrix.new(@m, @n)
|
24
25
|
GSLng.backend::gsl_matrix_memcpy(matrix.ptr, @ptr)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GSLng
|
2
|
+
class RNG
|
3
|
+
class Gaussian < RNG
|
4
|
+
attr_reader :ptr # @private
|
5
|
+
|
6
|
+
attr_reader :mu, :sigma
|
7
|
+
|
8
|
+
# Creates a new Gaussian distribution
|
9
|
+
# @param [Float] mu mean
|
10
|
+
# @param [Float] sigma standard deviation
|
11
|
+
# @param [Symbol] sample_method The method to use to sample numbers. Can be either :boxmuller, :ziggurat or :ratio_method
|
12
|
+
# @param generator_type (see GSLng::RNG#initialize)
|
13
|
+
# @see http://www.gnu.org/software/gsl/manual/html_node/The-Gaussian-Distribution.html
|
14
|
+
def initialize(mu = 0, sigma = 1, sample_method = :boxmuller, generator_type = nil)
|
15
|
+
super(generator_type)
|
16
|
+
@mu,@sigma = mu,sigma
|
17
|
+
|
18
|
+
case sample_method
|
19
|
+
when :boxmuller; @function = :gsl_ran_gaussian
|
20
|
+
when :ziggurat; @function = :gsl_ran_gaussian_ziggurat
|
21
|
+
when :ratio_method; @function = :gsl_ran_ratio_method
|
22
|
+
else raise "Unsupported method"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Obtain a sample from this distribution
|
27
|
+
# @return [Float]
|
28
|
+
def sample
|
29
|
+
GSLng.backend.send(@function, self.ptr, @sigma) + @mu
|
30
|
+
end
|
31
|
+
alias_method :get, :sample
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GSLng
|
2
|
+
# Random Number Generator class
|
3
|
+
# @abstract You should use any of the descendant classes which implement the {#sample} method.
|
4
|
+
class RNG
|
5
|
+
# Create a Generator of the given type
|
6
|
+
# @param [Symbol] generator_type the algorithm to use (without the +gsl_rng+ prefix). Default is :mt19937.
|
7
|
+
# @see http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html
|
8
|
+
def initialize(generator_type = nil)
|
9
|
+
@type = generator_type
|
10
|
+
if (@type.nil?) then @type = :mt19937 end # update comment above if changed
|
11
|
+
|
12
|
+
type = GSLng.backend.send(:"gsl_rng_#{@type}")
|
13
|
+
@ptr = GSLng.backend.gsl_rng_alloc(type)
|
14
|
+
GSLng.define_finalizer(self, :gsl_rng_free, @ptr)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize_copy
|
18
|
+
ObjectSpace.undefine_finalizer(self)
|
19
|
+
type = GSLng.backend.send(:"gsl_rng_#{@type}")
|
20
|
+
@ptr = GSLng.backend.gsl_rng_alloc(type)
|
21
|
+
GSLng.define_finalizer(self, :gsl_rng_free, @ptr)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'gslng/rng/gaussian'
|
27
|
+
require 'gslng/rng/uniform'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module GSLng
|
2
|
+
class RNG
|
3
|
+
class Uniform < RNG
|
4
|
+
attr_reader :ptr # @private
|
5
|
+
|
6
|
+
# Creates a new Uniform distribution with values in [min,max)
|
7
|
+
# @param [Float] min
|
8
|
+
# @param [Float] max
|
9
|
+
# @param generator_type (see GSLng::RNG#initialize)
|
10
|
+
def initialize(min, max, generator_type = nil)
|
11
|
+
super(generator_type)
|
12
|
+
@min,@max = min,max
|
13
|
+
end
|
14
|
+
|
15
|
+
# Obtain a sample from this distribution
|
16
|
+
# @return [Float]
|
17
|
+
def sample
|
18
|
+
GSLng.backend.gsl_ran_flat(self.ptr, @min, @max)
|
19
|
+
end
|
20
|
+
alias_method :get, :sample
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GSLng
|
2
|
+
# A group of several different special functions.
|
3
|
+
#
|
4
|
+
# =Notes
|
5
|
+
# You can use this module simply by acessing its functions. Optionally, you can also extend the +Math+ standard module
|
6
|
+
# with these methods by doing:
|
7
|
+
# Math.extend(GSLng::Special)
|
8
|
+
#
|
9
|
+
module Special
|
10
|
+
extend self # allow this module to be used as such, and as a mixin
|
11
|
+
|
12
|
+
# Restrict the given angle to the interval (-pi,pi]
|
13
|
+
def angle_restrict_symm(theta)
|
14
|
+
GSLng.backend.gsl_sf_angle_restrict_symm(theta)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Restrict the given angle to the interval (0,2pi]
|
18
|
+
def angle_restrict_pos(theta)
|
19
|
+
GSLng.backend.gsl_sf_angle_restrict_pos(theta)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/gslng/vector.rb
CHANGED
@@ -2,31 +2,31 @@ module GSLng
|
|
2
2
|
# A fixed-size n-dimensional vector.
|
3
3
|
#
|
4
4
|
# =Notes
|
5
|
-
|
6
|
-
|
7
|
-
# *
|
8
|
-
# so they use
|
9
|
-
|
10
|
-
|
11
|
-
# * Operator
|
12
|
-
# * Operands are coerced to vectors so you can do vector + scalar, etc. (see #coerce)
|
5
|
+
# * {#each}, {#map} and similar methods are implemented with C versions which should be fast.
|
6
|
+
# * {#map} returns a Vector, not an Array. Use {#map_array} for that.
|
7
|
+
# * While this class includes Enumerable, certain methods are redefined (like {#max} and {#min})
|
8
|
+
# so they use internal GSL methods.
|
9
|
+
# * Some functions (like {#sum}, {#dot}, and others) use BLAS functions (through GSLng's CBLAS interface).
|
10
|
+
# * In contrary to Array, operators {#[]} and {#[]=} will raise an exception when accessing out-of-bounds elements.
|
11
|
+
# * Operator {#*} multiplies two vectors element-by-element. To perform a dot product use the {#^} operator instead (or the {#dot} alias).
|
12
|
+
# * Operands are coerced to vectors so you can do vector + scalar, etc. (see {#coerce})
|
13
13
|
#
|
14
14
|
class Vector
|
15
15
|
include Enumerable
|
16
|
-
|
17
|
-
attr_reader :
|
18
|
-
attr_reader :
|
16
|
+
|
17
|
+
attr_reader :size
|
18
|
+
attr_reader :ptr # @private
|
19
19
|
|
20
20
|
#--------------------- constructors -------------------------#
|
21
21
|
|
22
22
|
# Create a Vector of size n. If zero is true, the vector is initialized with zeros.
|
23
23
|
# Otherwise, the vector will contain garbage.
|
24
|
-
|
24
|
+
# You can optionally pass a block, in which case {#map_index!} will be called with it (i.e.: it works like {Array.new}).
|
25
25
|
def initialize(n, zero = false)
|
26
26
|
@size = n
|
27
27
|
@ptr = (zero ? GSLng.backend::gsl_vector_calloc(n) : GSLng.backend::gsl_vector_alloc(n))
|
28
|
-
GSLng.
|
29
|
-
|
28
|
+
GSLng.define_finalizer(self, :gsl_vector_free, @ptr)
|
29
|
+
if (block_given?) then self.map_index!(Proc.new) end
|
30
30
|
end
|
31
31
|
|
32
32
|
def initialize_copy(other) # @private
|
@@ -34,41 +34,45 @@ module GSLng
|
|
34
34
|
|
35
35
|
@size = other.size
|
36
36
|
@ptr = GSLng.backend::gsl_vector_alloc(other.size)
|
37
|
-
GSLng.
|
37
|
+
GSLng.define_finalizer(self, :gsl_vector_free, @ptr)
|
38
38
|
|
39
39
|
GSLng.backend::gsl_vector_memcpy(@ptr, other.ptr)
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
# Same as Vector.new(n, true)
|
43
|
+
def Vector.zero(n); Vector.new(n, true) end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
# Create a vector from an Array.
|
46
|
+
def Vector.from_array(array)
|
47
|
+
if (array.empty?) then raise "Can't create empty vector" end
|
48
|
+
v = Vector.new(array.size)
|
49
|
+
GSLng.backend.gsl_vector_from_array(v.ptr.to_i, array)
|
50
|
+
return v
|
51
|
+
end
|
50
52
|
|
51
|
-
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
53
|
+
# Creates a Vector from an Array or a Range
|
54
|
+
# @see Vector::from_array
|
55
|
+
# @example
|
56
|
+
# Vector[1,2,3]
|
57
|
+
# Vector[1..3]
|
58
|
+
def Vector.[](*args)
|
55
59
|
array = (args.size == 1 && Range === args[0] ? args[0].to_a : args)
|
56
|
-
|
57
|
-
|
60
|
+
Vector.from_array(array)
|
61
|
+
end
|
58
62
|
|
59
63
|
# Generates a Vector of n random numbers between 0 and 1.
|
60
|
-
# NOTE: This simply uses Kernel::rand
|
64
|
+
# NOTE: This simply uses {Kernel::rand}
|
61
65
|
def Vector.random(n)
|
62
|
-
|
66
|
+
Vector.new(n).map!{|x| Kernel::rand}
|
63
67
|
end
|
64
|
-
|
68
|
+
class << self; alias_method :rand, :random end
|
65
69
|
|
66
70
|
#--------------------- setting values -------------------------#
|
67
71
|
|
68
72
|
# Set all values to v
|
69
73
|
def all!(v); GSLng.backend::gsl_vector_set_all(self.ptr, v); return self end
|
70
|
-
|
71
|
-
|
74
|
+
alias_method :set!, :all!
|
75
|
+
alias_method :fill!, :all!
|
72
76
|
|
73
77
|
# Set all values to zero
|
74
78
|
def zero!; GSLng.backend::gsl_vector_set_zero(self.ptr); return self end
|
@@ -79,53 +83,57 @@ module GSLng
|
|
79
83
|
#--------------------- operators -------------------------#
|
80
84
|
|
81
85
|
# Add (element-by-element) other to self
|
86
|
+
# @return [Vector] self
|
82
87
|
def add!(other)
|
83
88
|
case other
|
84
89
|
when Numeric; GSLng.backend::gsl_vector_add_constant(self.ptr, other.to_f)
|
85
90
|
when Vector; GSLng.backend::gsl_vector_add(self.ptr, other.ptr)
|
86
91
|
else
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
x,y = other.coerce(self)
|
93
|
+
x.add!(y)
|
94
|
+
end
|
95
|
+
return self
|
91
96
|
end
|
92
97
|
|
93
98
|
# Substract (element-by-element) other from self
|
99
|
+
# @return [Vector] self
|
94
100
|
def substract!(other)
|
95
101
|
case other
|
96
102
|
when Numeric; GSLng.backend::gsl_vector_add_constant(self.ptr, -other.to_f)
|
97
103
|
when Vector; GSLng.backend::gsl_vector_sub(self.ptr, other.ptr)
|
98
104
|
else
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
x,y = other.coerce(self)
|
106
|
+
x.sub!(y)
|
107
|
+
end
|
108
|
+
return self
|
103
109
|
end
|
104
110
|
alias_method :sub!, :substract!
|
105
111
|
|
106
112
|
# Multiply (element-by-element) other with self
|
113
|
+
# @return [Vector] self
|
107
114
|
def multiply!(other)
|
108
115
|
case other
|
109
116
|
when Numeric; GSLng.backend::gsl_blas_dscal(other.to_f, self.ptr)
|
110
117
|
when Vector; GSLng.backend::gsl_vector_mul(self.ptr, other.ptr)
|
111
118
|
else
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
x,y = other.coerce(self)
|
120
|
+
x.mul!(y)
|
121
|
+
end
|
122
|
+
return self
|
116
123
|
end
|
117
124
|
alias_method :mul!, :multiply!
|
118
125
|
|
119
126
|
# Divide (element-by-element) self by other
|
127
|
+
# @return [Vector] self
|
120
128
|
def divide!(other)
|
121
129
|
case other
|
122
130
|
when Numeric; GSLng.backend::gsl_blas_dscal(1.0 / other, self.ptr)
|
123
131
|
when Vector; GSLng.backend::gsl_vector_div(self.ptr, other.ptr)
|
124
132
|
else
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
133
|
+
x,y = other.coerce(self)
|
134
|
+
x.div!(y)
|
135
|
+
end
|
136
|
+
return self
|
129
137
|
end
|
130
138
|
alias_method :div!, :divide!
|
131
139
|
|
@@ -136,14 +144,17 @@ module GSLng
|
|
136
144
|
def -(other); self.dup.sub!(other) end
|
137
145
|
|
138
146
|
# Element-by-element product
|
147
|
+
# @example
|
148
|
+
# Vector[1,2,3] * 2 => [2.0, 4.0, 6.0]:Vector
|
149
|
+
# Vector[1,2,3] * Vector[0,1,2] => [0.0, 2.0, 6.0]:Vector
|
139
150
|
def *(other)
|
140
151
|
case other
|
141
152
|
when Numeric; self.dup.mul!(other)
|
142
153
|
when Vector; self.dup.mul!(other)
|
143
154
|
else
|
144
|
-
|
145
|
-
|
146
|
-
|
155
|
+
x,y = other.coerce(self)
|
156
|
+
x * y
|
157
|
+
end
|
147
158
|
end
|
148
159
|
|
149
160
|
# Element-by-element division
|
@@ -155,6 +166,9 @@ module GSLng
|
|
155
166
|
#--------------------- other math -------------------------#
|
156
167
|
|
157
168
|
# Dot product between self and other (uses BLAS's ddot)
|
169
|
+
# @return [Float]
|
170
|
+
# @example
|
171
|
+
# Vector[1,2,3] ^ Vector[0,1,2] => 8.0
|
158
172
|
def dot(other)
|
159
173
|
out = FFI::Buffer.new(:double)
|
160
174
|
GSLng.backend::gsl_blas_ddot(self.ptr, other.ptr, out)
|
@@ -180,29 +194,54 @@ module GSLng
|
|
180
194
|
# Swap the i-th element with the j-th element
|
181
195
|
def swap(i,j); GSLng.backend::gsl_vector_swap_elements(self.ptr, i, j); return self end
|
182
196
|
|
183
|
-
|
184
|
-
|
197
|
+
def sort!; GSLng.backend::gsl_sort_vector(self.ptr); return self end
|
198
|
+
def sort; self.dup.sort! end
|
185
199
|
|
186
200
|
# Copy other's values into self
|
187
201
|
def copy(other); GSLng.backend::gsl_vector_memcpy(self.ptr, other.ptr); return self end
|
188
202
|
|
203
|
+
# Wraps self into the interval [min,max) by adding or substracting (max-min) to each component as necessary.
|
204
|
+
# Note that wrapping is done only with a single addition/substraction.
|
205
|
+
# @param [Vector,Numeric] min
|
206
|
+
# @param [Vector,Numeric] max
|
207
|
+
# @return [Vector] a vector of values -1, 1 or 0, if (max-min) was substracted, added to the coordinate,
|
208
|
+
# or not modified, respectively.
|
209
|
+
# @example Assuming that +v = Vector[-8,2,8]+
|
210
|
+
# v.wrap(0, 5) => [1.0 0.0 -1.0]:Vector
|
211
|
+
# v => [-3.0 2.0 3.0]:Vector
|
212
|
+
def wrap!(min, max)
|
213
|
+
min,other = self.coerce(min)
|
214
|
+
max,other = self.coerce(max)
|
215
|
+
delta = Vector.new(self.size)
|
216
|
+
range = max - min
|
217
|
+
|
218
|
+
self.map_index! do |i|
|
219
|
+
if (self[i] < min[i]) then delta[i] = 1; self[i] + range[i]
|
220
|
+
elsif (self[i] >= max[i]) then delta[i] = -1; self[i] - range[i]
|
221
|
+
else delta[i] = 0; self[i] end
|
222
|
+
end
|
223
|
+
return delta
|
224
|
+
end
|
225
|
+
|
189
226
|
#--------------------- set/get -------------------------#
|
190
227
|
|
191
|
-
|
192
|
-
|
193
|
-
|
228
|
+
# Access the i-th element.
|
229
|
+
# If _index_ is negative, it counts from the end (-1 is the last element).
|
230
|
+
# @raise [RuntimeError] if out-of-bounds
|
231
|
+
# @todo support ranges
|
194
232
|
def [](index)
|
195
|
-
|
233
|
+
GSLng.backend::gsl_vector_get(self.ptr, (index < 0 ? @size + index : index))
|
196
234
|
end
|
197
235
|
|
198
|
-
|
199
|
-
|
200
|
-
|
236
|
+
# Set the i-th element.
|
237
|
+
# If _index_ is negative, it counts from the end (-1 is the last element).
|
238
|
+
# @raise [RuntimeError] if out-of-bounds
|
239
|
+
# @todo support ranges
|
201
240
|
def []=(index, value)
|
202
|
-
|
241
|
+
GSLng.backend::gsl_vector_set(self.ptr, (index < 0 ? @size + index : index), value.to_f)
|
203
242
|
end
|
204
243
|
|
205
|
-
# Create a Vector::View from this Vector.
|
244
|
+
# Create a {Vector::View} from this Vector.
|
206
245
|
# If _size_ is nil, it is computed automatically from _offset_ and _stride_
|
207
246
|
def view(offset = 0, size = nil, stride = 1)
|
208
247
|
if (stride <= 0) then raise 'stride must be positive' end
|
@@ -223,15 +262,24 @@ module GSLng
|
|
223
262
|
def subvector(*args); subvector_view(*args).to_vector end
|
224
263
|
|
225
264
|
#------------ utility methods for 2D,3D and 4D vectors -----------#
|
265
|
+
|
266
|
+
# Same as Vector#[0]
|
226
267
|
def x; GSLng.backend::gsl_vector_get(self.ptr, 0) end
|
268
|
+
# Same as Vector#[1]
|
227
269
|
def y; GSLng.backend::gsl_vector_get(self.ptr, 1) end
|
228
|
-
|
229
|
-
def
|
270
|
+
# Same as Vector#[2]
|
271
|
+
def z; GSLng.backend::gsl_vector_get(self.ptr, 2) end
|
272
|
+
# Same as Vector#[3]
|
273
|
+
def w; GSLng.backend::gsl_vector_get(self.ptr, 3) end
|
230
274
|
|
275
|
+
# Same as Vector#[0]=
|
231
276
|
def x=(v); GSLng.backend::gsl_vector_set(self.ptr, 0, v.to_f) end
|
277
|
+
# Same as Vector#[1]=
|
232
278
|
def y=(v); GSLng.backend::gsl_vector_set(self.ptr, 1, v.to_f) end
|
279
|
+
# Same as Vector#[2]=
|
233
280
|
def z=(v); GSLng.backend::gsl_vector_set(self.ptr, 2, v.to_f) end
|
234
|
-
|
281
|
+
# Same as Vector#[3]=
|
282
|
+
def w=(v); GSLng.backend::gsl_vector_set(self.ptr, 3, v.to_f) end
|
235
283
|
|
236
284
|
#--------------------- predicate methods -------------------------#
|
237
285
|
|
@@ -243,10 +291,22 @@ module GSLng
|
|
243
291
|
|
244
292
|
#if all elements are strictly negative (<0)
|
245
293
|
def negative?; GSLng.backend::gsl_vector_isneg(self.ptr) == 1 ? true : false end
|
246
|
-
|
294
|
+
|
247
295
|
# if all elements are non-negative (>=0)
|
248
296
|
def nonnegative?; GSLng.backend::gsl_vector_isnonneg(self.ptr) == 1 ? true : false end
|
249
297
|
|
298
|
+
# If each element of self is less than other's elements
|
299
|
+
def <(other); (other - self).positive? end
|
300
|
+
|
301
|
+
# If each element of self is greater than other's elements
|
302
|
+
def >(other); (other - self).negative? end
|
303
|
+
|
304
|
+
# If each element of self is less-or-equal than other's elements
|
305
|
+
def <=(other); (other - self).nonnegative? end
|
306
|
+
|
307
|
+
# If each element of self is less-or-equal than other's elements
|
308
|
+
def >=(other); (self - other).nonnegative? end
|
309
|
+
|
250
310
|
#--------------------- min/max -------------------------#
|
251
311
|
|
252
312
|
# Return maximum element of vector
|
@@ -255,7 +315,7 @@ module GSLng
|
|
255
315
|
# Return minimum element of vector
|
256
316
|
def min; GSLng.backend::gsl_vector_min(self.ptr) end
|
257
317
|
|
258
|
-
|
318
|
+
# Same as {Array#minmax}
|
259
319
|
def minmax
|
260
320
|
min = FFI::Buffer.new(:double)
|
261
321
|
max = FFI::Buffer.new(:double)
|
@@ -263,87 +323,97 @@ module GSLng
|
|
263
323
|
return [min[0].get_float64(0),max[0].get_float64(0)]
|
264
324
|
end
|
265
325
|
|
266
|
-
|
326
|
+
# Same as {#minmax}, but returns the indices to the elements
|
267
327
|
def minmax_index
|
268
328
|
min = FFI::Buffer.new(:size_t)
|
269
329
|
max = FFI::Buffer.new(:size_t)
|
270
330
|
GSLng.backend::gsl_vector_minmax_index(self.ptr, min, max)
|
271
331
|
#return [min[0].get_size_t(0),max[0].get_size_t(0)]
|
272
|
-
|
332
|
+
return [min[0].get_ulong(0),max[0].get_ulong(0)]
|
273
333
|
end
|
274
334
|
|
275
|
-
# Same as #min, but returns the index to the element
|
335
|
+
# Same as {#min}, but returns the index to the element
|
276
336
|
def min_index; GSLng.backend::gsl_vector_min_index(self.ptr) end
|
277
337
|
|
278
|
-
# Same as #max, but returns the index to the element
|
338
|
+
# Same as {#max}, but returns the index to the element
|
279
339
|
def max_index; GSLng.backend::gsl_vector_max_index(self.ptr) end
|
280
340
|
|
281
341
|
#--------------------- block handling -------------------------#
|
282
|
-
|
283
|
-
#
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
# Same as #each, but faster. The catch is that this method returns nothing.
|
289
|
-
def fast_each(block = Proc.new) #:yield: obj
|
290
|
-
GSLng.backend::gsl_vector_each(self.ptr, block)
|
342
|
+
|
343
|
+
# Same as {#each}, but faster. The catch is that this method returns nothing.
|
344
|
+
# @yield [elem]
|
345
|
+
def each(block = Proc.new)
|
346
|
+
GSLng.backend::gsl_vector_each(self.ptr.to_i, &block)
|
291
347
|
end
|
292
348
|
|
293
|
-
|
294
|
-
|
349
|
+
# @see #each
|
350
|
+
# @yield [elem,i]
|
351
|
+
def each_with_index(block = Proc.new)
|
352
|
+
GSLng.backend::gsl_vector_each_with_index(self.ptr.to_i, &block)
|
295
353
|
end
|
296
354
|
|
297
|
-
|
298
|
-
|
355
|
+
# Efficient {#map!} implementation.
|
356
|
+
def map!(block = Proc.new); GSLng.backend::gsl_vector_map!(self.ptr.to_i, &block); return self end
|
299
357
|
|
300
|
-
|
301
|
-
|
358
|
+
# Similar to {#map!}, but passes the index to the element instead.
|
359
|
+
# @yield [i]
|
360
|
+
def map_index!(block = Proc.new); GSLng.backend::gsl_vector_map_index!(self.ptr.to_i, &block); return self end
|
302
361
|
|
303
|
-
|
304
|
-
|
362
|
+
# @return [Vector]
|
363
|
+
# @see map_index!
|
364
|
+
# @yield [i]
|
365
|
+
def map_index(block = Proc.new); self.dup.map_index!(block) end
|
305
366
|
|
306
|
-
|
307
|
-
|
367
|
+
alias_method :map_array, :map
|
368
|
+
|
369
|
+
# @return [Vector]
|
370
|
+
# @yield [elem]
|
371
|
+
def map(block = Proc.new); self.dup.map!(block) end
|
308
372
|
|
309
373
|
#--------------------- conversions -------------------------#
|
310
374
|
|
311
|
-
#
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
375
|
+
# @see Array#join
|
376
|
+
# @return [String]
|
377
|
+
def join(sep = $,)
|
378
|
+
s = ''
|
379
|
+
self.each do |e|
|
380
|
+
s += (s.empty?() ? e.to_s : "#{sep}#{e}")
|
381
|
+
end
|
382
|
+
return s
|
383
|
+
end
|
317
384
|
|
318
|
-
# Coerces _other_ to be a Vector.
|
319
|
-
#
|
320
|
-
|
385
|
+
# Coerces _other_ to be a Vector.
|
386
|
+
# @example
|
387
|
+
# Vector[1,2].coerce(5) => [[5.0, 5.0]:Vector, [1.0, 2.0]:Vector]
|
388
|
+
def coerce(other)
|
321
389
|
case other
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
#
|
390
|
+
when Vector
|
391
|
+
[ other, self ]
|
392
|
+
when Numeric
|
393
|
+
[ Vector.new(@size).set!(other), self ]
|
394
|
+
else
|
395
|
+
raise TypeError, "Can't coerce #{other.class} into #{self.class}"
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# @return [String] same format as {Array#to_s}
|
400
|
+
# @example
|
332
401
|
# Vector[1,2,3].to_s => "[1.0, 2.0, 3.0]"
|
333
|
-
|
334
|
-
|
335
|
-
|
402
|
+
def to_s
|
403
|
+
"[" + self.join(', ') + "]"
|
404
|
+
end
|
336
405
|
|
337
406
|
def inspect # @private
|
338
407
|
"#{self}:Vector"
|
339
408
|
end
|
340
409
|
|
341
|
-
#
|
342
|
-
|
343
|
-
|
344
|
-
|
410
|
+
# @return [Array]
|
411
|
+
def to_a
|
412
|
+
GSLng.backend.gsl_vector_to_a(self.ptr.to_i)
|
413
|
+
end
|
345
414
|
|
346
415
|
# Create a row matrix from this vector
|
416
|
+
# @return [Matrix]
|
347
417
|
def to_matrix
|
348
418
|
m = Matrix.new(1, @size)
|
349
419
|
GSLng.backend::gsl_matrix_set_row(m.ptr, 0, self.ptr)
|
@@ -352,6 +422,7 @@ module GSLng
|
|
352
422
|
alias_method :to_row, :to_matrix
|
353
423
|
|
354
424
|
# Create a column matrix from this vector
|
425
|
+
# @return [Matrix]
|
355
426
|
def transpose
|
356
427
|
m = Matrix.new(@size, 1)
|
357
428
|
GSLng.backend::gsl_matrix_set_col(m.ptr, 0, self.ptr)
|
@@ -361,13 +432,13 @@ module GSLng
|
|
361
432
|
|
362
433
|
#--------------------- equality -------------------------#
|
363
434
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
435
|
+
# Element-by-element comparison. Admits comparing to Array.
|
436
|
+
def ==(other)
|
437
|
+
if (self.size != other.size) then return false end
|
438
|
+
self.each_with_index do |elem,i|
|
439
|
+
if (elem != other[i]) then return false end
|
440
|
+
end
|
441
|
+
return true
|
442
|
+
end
|
372
443
|
end
|
373
444
|
end
|