ruby-gsl-ngx 0.2.6.1

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.
@@ -0,0 +1,47 @@
1
+ module GSLng
2
+ class Matrix
3
+ # A View of a Matrix.
4
+ #
5
+ # Views reference an existing Matrix and can be used to access parts of it without having to copy
6
+ # it entirely. You can treat a View just like a Matrix.
7
+ # But note that modifying elements of a View will modify the elements of the original matrix.
8
+ #
9
+ class View < Matrix
10
+ attr_reader :owner # The Matrix owning the data this View uses
11
+
12
+ # Create a Matrix::View of the sub-matrix starting at (x,y), of size (m,n)
13
+ def initialize(owner, x, y, m, n) # @private
14
+ @owner = owner
15
+ @m,@n = m,n
16
+
17
+ @backend = GSLng.backend
18
+ ptr = GSLng.backend::gsl_matrix_submatrix2(owner.ptr, x, y, m, n)
19
+ @ptr = FFI::AutoPointer.new(ptr, View.method(:release))
20
+ @ptr_value = @ptr.to_i
21
+ end
22
+
23
+ def View.release(ptr)
24
+ GSLng.backend.gsl_matrix_free(ptr)
25
+ end
26
+
27
+ # Returns a Matrix (*NOT* a View) copied from this view. In other words,
28
+ # you'll get a Matrix which you can modify without modifying #owner elements.
29
+ # @return [Matrix]
30
+ def dup
31
+ matrix = Matrix.new(@m, @n)
32
+ GSLng.backend::gsl_matrix_memcpy(matrix.ptr, @ptr)
33
+ return matrix
34
+ end
35
+ alias_method :clone, :dup
36
+ alias_method :to_matrix, :dup
37
+
38
+ def view # @private
39
+ raise "Can't create a View from a View"
40
+ end
41
+
42
+ def inspect # @private
43
+ "#{self}:MatrixView"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,88 @@
1
+ require 'singleton'
2
+ require 'ffi'
3
+
4
+ module GSLng
5
+ # This class encapsulates the communication with the plotting backend: gnuplot.
6
+ #
7
+ # Plot data is always represented as a {Matrix}, so you can use {Matrix#plot} to do a single plot.
8
+ # Otherwise, you can use {Matrix#define_plot} (taking the same parameters as the previous method) which returns a {Plotter::Plot}
9
+ # object. By defining multiple plot objects you can then use {Plotter#plot} passing all plot objects as parameters effectively
10
+ # creating a single output of all plots.
11
+ #
12
+ # This class works as {Singleton}, so when you instantiate it the gnuplot process is started. You can also send arbitrary commands
13
+ # to the gnuplot process by using the {Plotter#<<} operator. Read the gnuplot documentation on what are the possible commands you can send.
14
+ #
15
+ class Plotter
16
+ include Singleton
17
+
18
+ attr_reader :io
19
+
20
+ # Creates the singleton Plotter object
21
+ def initialize
22
+ @io = IO.popen('gnuplot', 'w')
23
+ @io.sync = true
24
+ self << "set datafile nofpe_trap"
25
+ end
26
+
27
+ # Close the pipe. It is desireable to call this in an "ensure" section, to avoid
28
+ # leaving the child gnuplot process there if the main ruby process dies
29
+ def close
30
+ pid = @io.pid
31
+ @io.flush; @io.close; @io = nil
32
+ begin
33
+ Process.kill 'TERM', pid
34
+ rescue Errno::ESRCH
35
+ end
36
+ end
37
+
38
+ # Send a command to the gnuplot process
39
+ # @example Setting the xrange
40
+ # Plotter.instance << "set xrange [0:1]"
41
+ def <<(cmd)
42
+ @io.puts(cmd)
43
+ end
44
+
45
+ # Expects a variable number of {Plot} objects and creates a single plot out of them
46
+ def plot(*plots)
47
+ self << 'plot ' + plots.map(&:command).join(', ')
48
+ plots.each {|p| self.put_data(p.matrix)}
49
+ end
50
+
51
+ def put_data(matrix) # @private
52
+ ret = GSLng.backend.gsl_matrix_putdata(matrix.ptr, @io.to_i)
53
+ if (ret != 0) then raise SystemCallError.new("Problem sending data to gnuplot", ret) end
54
+ end
55
+
56
+ # Yields the given block enabling and disabling multiplot mode, before and after the yield respectively
57
+ def multiplot
58
+ self << 'set multiplot'
59
+ yield(self)
60
+ ensure
61
+ self << 'unset multiplot'
62
+ end
63
+
64
+ # This class holds a "plot" command and the associated matrix
65
+ class Plot < Struct.new(:command, :matrix); end
66
+ end
67
+
68
+ class Matrix
69
+ # Create a single plot out of the data contained in this Matrix
70
+ # @param [String] with The value of the 'with' option in gnuplot's plot command (i.e.: lines, linespoints, image, etc.)
71
+ # @param [String] extra_cmds Other variables/modifiers you can optionally pass to the "plot" command
72
+ def plot(with, extra_cmds = '')
73
+ Plotter.instance.plot(define_plot(with, extra_cmds))
74
+ end
75
+
76
+ # Works the same as {#plot} but returns a {Plotter::Plot} object you can store and then pass (along with other plot objects)
77
+ # to {Plotter#plot} and create a single plot out of them
78
+ # @return [Plot] The plot object you can pass to {Plotter#plot}
79
+ def define_plot(with, extra_cmds = '')
80
+ if (with == 'image')
81
+ cmd = "'-' binary array=(#{self.m},#{self.n}) format='%double' #{extra_cmds} with #{with}"
82
+ else
83
+ cmd = "'-' binary record=(#{self.m}) format=\"#{Array.new(self.n,'%double').join('')}\" #{extra_cmds} with #{with}"
84
+ end
85
+ Plotter::Plot.new(cmd, self)
86
+ end
87
+ end
88
+ end
@@ -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,28 @@
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 = FFI::AutoPointer.new(GSLng.backend.gsl_rng_alloc(type), RNG.method(:release))
14
+ end
15
+
16
+ def self.release(ptr)
17
+ GSLng.backend.gsl_rng_free(ptr)
18
+ end
19
+
20
+ def initialize_copy
21
+ type = GSLng.backend.send(:"gsl_rng_#{@type}")
22
+ @ptr = FFI::AutoPointer.new(GSLng.backend.gsl_rng_alloc(type), RNG.method(:release))
23
+ end
24
+ end
25
+ end
26
+
27
+ require 'gslng/rng/gaussian'
28
+ 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
@@ -0,0 +1,553 @@
1
+ module GSLng
2
+ # A fixed-size n-dimensional vector.
3
+ #
4
+ # =Notes
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
+ #
14
+ class Vector
15
+ include Enumerable
16
+
17
+ attr_reader :size, :stride
18
+ attr_reader :ptr # @private
19
+ attr_reader :ptr_value # @private
20
+
21
+ # @group Constructors
22
+
23
+ # Create a Vector of size n. If zero is true, the vector is initialized with zeros.
24
+ # Otherwise, the vector will contain garbage.
25
+ # You can optionally pass a block, in which case {#map_index!} will be called with it (i.e.: it works like {Array.new}).
26
+ def initialize(n, zero = false)
27
+ @backend = GSLng.backend
28
+ ptr = (zero ? @backend.gsl_vector_calloc(n) : @backend.gsl_vector_alloc(n))
29
+ @ptr = FFI::AutoPointer.new(ptr, Vector.method(:release))
30
+ @ptr_value = @ptr.to_i
31
+ @size = n
32
+ @stride = 1
33
+ if (block_given?) then self.map_index!(Proc.new) end
34
+ end
35
+
36
+ def initialize_copy(other) # @private
37
+ @backend = GSLng.backend
38
+ ptr = @backend.gsl_vector_alloc(other.size)
39
+ @ptr = FFI::AutoPointer.new(ptr, Vector.method(:release))
40
+ @ptr_value = @ptr.to_i
41
+ @size = other.size
42
+ @stride = 1
43
+ @backend.gsl_vector_memcpy(@ptr, other.ptr)
44
+ end
45
+
46
+ def Vector.release(ptr) # @private
47
+ GSLng.backend.gsl_vector_free(ptr)
48
+ end
49
+
50
+ # Same as Vector.new(n, true)
51
+ def Vector.zero(n); Vector.new(n, true) end
52
+
53
+ # Create a vector from an Array.
54
+ def Vector.from_array(array)
55
+ if (array.empty?) then raise "Can't create empty vector" end
56
+ v = Vector.new(array.size)
57
+ GSLng.backend.gsl_vector_from_array(v.ptr_value, array)
58
+ return v
59
+ end
60
+
61
+ # Creates a Vector with linearly distributed values between +start+ and +stop+, separated by +delta+.
62
+ def Vector.linspace(start, stop, delta)
63
+ if (start > stop || delta <= 0) then raise 'Invalid values' end
64
+ Vector.new(((stop - start) / delta).floor.to_i + 1) {|i| start + delta * i}
65
+ end
66
+
67
+ # Creates a Vector from an Array or a Range
68
+ # @see Vector::from_array
69
+ # @example
70
+ # Vector[1,2,3]
71
+ # Vector[1..3]
72
+ def Vector.[](*args)
73
+ array = (args.size == 1 && Range === args[0] ? args[0].to_a : args)
74
+ Vector.from_array(array)
75
+ end
76
+
77
+ # Generates a Vector of n random numbers between 0 and 1.
78
+ # NOTE: This simply uses {Kernel::rand}
79
+ def Vector.random(n)
80
+ Vector.new(n).map!{|x| Kernel::rand}
81
+ end
82
+ class << self; alias_method :rand, :random end
83
+
84
+ # @group Operators
85
+
86
+ # Add (element-by-element) other to self
87
+ # @return [Vector] self
88
+ def add!(other)
89
+ case other
90
+ when Numeric; @backend.gsl_vector_add_constant(@ptr, other.to_f)
91
+ when Vector; @backend.gsl_vector_add(@ptr, other.ptr)
92
+ else
93
+ x,y = other.coerce(self)
94
+ x.add!(y)
95
+ end
96
+ return self
97
+ end
98
+
99
+ # Substract (element-by-element) other from self
100
+ # @return [Vector] self
101
+ def substract!(other)
102
+ case other
103
+ when Numeric; @backend.gsl_vector_add_constant(@ptr, -other.to_f)
104
+ when Vector; @backend.gsl_vector_sub(@ptr, other.ptr)
105
+ else
106
+ x,y = other.coerce(self)
107
+ x.sub!(y)
108
+ end
109
+ return self
110
+ end
111
+ alias_method :sub!, :substract!
112
+
113
+ # Multiply (element-by-element) other with self
114
+ # @return [Vector] self
115
+ def multiply!(other)
116
+ case other
117
+ when Numeric; @backend.gsl_blas_dscal(other.to_f, @ptr)
118
+ when Vector; @backend.gsl_vector_mul(@ptr, other.ptr)
119
+ else
120
+ x,y = other.coerce(self)
121
+ x.mul!(y)
122
+ end
123
+ return self
124
+ end
125
+ alias_method :mul!, :multiply!
126
+
127
+ # Divide (element-by-element) self by other
128
+ # @return [Vector] self
129
+ def divide!(other)
130
+ case other
131
+ when Numeric; @backend.gsl_blas_dscal(1.0 / other, @ptr)
132
+ when Vector; @backend.gsl_vector_div(@ptr, other.ptr)
133
+ else
134
+ x,y = other.coerce(self)
135
+ x.div!(y)
136
+ end
137
+ return self
138
+ end
139
+ alias_method :div!, :divide!
140
+
141
+ # Element-by-element addition
142
+ def +(other); self.dup.add!(other) end
143
+
144
+ # Element-by-element substraction
145
+ def -(other); self.dup.sub!(other) end
146
+
147
+ # Element-by-element product
148
+ # @example
149
+ # Vector[1,2,3] * 2 => [2.0, 4.0, 6.0]:Vector
150
+ # Vector[1,2,3] * Vector[0,1,2] => [0.0, 2.0, 6.0]:Vector
151
+ def *(other)
152
+ case other
153
+ when Numeric; self.dup.mul!(other)
154
+ when Vector; self.dup.mul!(other)
155
+ else
156
+ x,y = other.coerce(self)
157
+ x * y
158
+ end
159
+ end
160
+
161
+ # Element-by-element division
162
+ def /(other); self.dup.div!(other) end
163
+
164
+ # Invert sign on all elements
165
+ def -@; self.map!(&:-@) end
166
+
167
+ # @group Other mathematical operations
168
+
169
+ # Dot product between self and other (uses BLAS's ddot)
170
+ # @return [Float]
171
+ # @example
172
+ # Vector[1,2,3] ^ Vector[0,1,2] => 8.0
173
+ def dot(other)
174
+ out = FFI::Buffer.new(:double)
175
+ @backend.gsl_blas_ddot(@ptr, other.ptr, out)
176
+ return out[0].get_double(0)
177
+ end
178
+ alias_method :^, :dot
179
+
180
+ # Norm 2 of the vector (uses BLAS's dnrm2)
181
+ def norm; @backend.gsl_blas_dnrm2(@ptr) end
182
+ alias_method :length, :norm
183
+
184
+ # Returns the sum of all elements (uses BLAS's dasum)
185
+ def sum; @backend.gsl_blas_dasum(@ptr) end
186
+
187
+ # Optimized version of: self += other * alpha (where alpha is a Numeric). Uses BLAS's daxpy.
188
+ def mul_add(other, alpha); @backend.gsl_blas_daxpy(alpha, other.ptr, @ptr); return self end
189
+
190
+ # @group Miscelaneous methods
191
+
192
+ # Reverse the order of elements
193
+ def reverse!; @backend.gsl_vector_reverse(@ptr); return self end
194
+
195
+ # Swap the i-th element with the j-th element
196
+ def swap(i,j); @backend.gsl_vector_swap_elements(@ptr, i, j); return self end
197
+
198
+ def sort!; @backend.gsl_sort_vector(@ptr); return self end
199
+ def sort; self.dup.sort! end
200
+
201
+ # Copy other's values into self
202
+ def copy(other); @backend.gsl_vector_memcpy(@ptr, other.ptr); return self end
203
+
204
+ # Wraps self into the interval [0,up_to). NOTE: this value must be > 0
205
+ # @param [Vector,Numeric] up_to
206
+ # @return [Vector] a vector of values -1, 1 or 0, if (max-min) was substracted, added to the coordinate,
207
+ # or not modified, respectively.
208
+ # @example Assuming that +v = Vector[-8,2,8]+
209
+ # v.wrap(5) => [1.0 0.0 -1.0]:Vector
210
+ # v => [-3.0 2.0 3.0]:Vector
211
+ def wrap!(up_to)
212
+ delta = Vector.new(self.size)
213
+ self.map_index! do |i|
214
+ a,b = self[i].divmod(up_to)
215
+ delta[i] = -a
216
+ b
217
+ end
218
+ return delta
219
+ end
220
+
221
+ # Compute hash value for this Vector.
222
+ # Note: this may be a bit inefficient for now
223
+ def hash
224
+ self.to_a.hash
225
+ end
226
+
227
+ # @group Setting/getting values
228
+
229
+ # Access the i-th element.
230
+ # If _index_ is negative, it counts from the end (-1 is the last element).
231
+ # @raise [RuntimeError] if out-of-bounds
232
+ # @todo support ranges
233
+ def [](index)
234
+ @backend.gsl_vector_get_operator(@ptr_value, index)
235
+ end
236
+
237
+ # Set the i-th element.
238
+ # If _index_ is negative, it counts from the end (-1 is the last element).
239
+ # @raise [RuntimeError] if out-of-bounds
240
+ # @todo support ranges
241
+ def []=(index, value)
242
+ @backend.gsl_vector_set_operator(@ptr_value, index, value.to_f)
243
+ #@backend.gsl_vector_set(@ptr, (index < 0 ? @size + index : index), value.to_f)
244
+ end
245
+
246
+ # @group Views
247
+
248
+ # Create a {Vector::View} from this Vector.
249
+ # If _size_ is nil, it is computed automatically from _offset_ and _stride_
250
+ def view(offset = 0, size = nil, stride = 1)
251
+ if (stride <= 0) then raise 'stride must be positive' end
252
+
253
+ if (size.nil?)
254
+ size = @size - offset
255
+ k,m = size.divmod(stride)
256
+ size = k + (m == 0 ? 0 : 1)
257
+ end
258
+
259
+ if (stride == 1) then ptr = @backend.gsl_vector_subvector2(@ptr, offset, size)
260
+ else ptr = @backend.gsl_vector_subvector_with_stride2(@ptr, offset, stride, size) end
261
+ View.new(ptr, self, size, stride)
262
+ end
263
+ alias_method :subvector_view, :view
264
+
265
+ # Shorthand for #subvector_view(..).to_vector.
266
+ def subvector(*args); subvector_view(*args).to_vector end
267
+
268
+ # Set all values to v
269
+ def all!(v); @backend.gsl_vector_set_all(@ptr, v); return self end
270
+ alias_method :set!, :all!
271
+ alias_method :fill!, :all!
272
+
273
+ # Set all values to zero
274
+ def zero!; @backend.gsl_vector_set_zero(@ptr); return self end
275
+
276
+ # Set all values to zero, except the i-th element, which is set to 1
277
+ def basis!(i); @backend.gsl_vector_set_basis(@ptr, i); return self end
278
+
279
+ # @group 2D/3D/4D utility vectors
280
+
281
+ # Same as Vector#[0]
282
+ def x; @backend.gsl_vector_get(@ptr, 0) end
283
+ # Same as Vector#[1]
284
+ def y; @backend.gsl_vector_get(@ptr, 1) end
285
+ # Same as Vector#[2]
286
+ def z; @backend.gsl_vector_get(@ptr, 2) end
287
+ # Same as Vector#[3]
288
+ def w; @backend.gsl_vector_get(@ptr, 3) end
289
+
290
+ # Same as Vector#[0]=
291
+ def x=(v); @backend.gsl_vector_set(@ptr, 0, v.to_f) end
292
+ # Same as Vector#[1]=
293
+ def y=(v); @backend.gsl_vector_set(@ptr, 1, v.to_f) end
294
+ # Same as Vector#[2]=
295
+ def z=(v); @backend.gsl_vector_set(@ptr, 2, v.to_f) end
296
+ # Same as Vector#[3]=
297
+ def w=(v); @backend.gsl_vector_set(@ptr, 3, v.to_f) end
298
+
299
+ # @group Predicate methods
300
+
301
+ # if all elements are zero
302
+ def zero?; @backend.gsl_vector_isnull(@ptr) == 1 ? true : false end
303
+
304
+ # if all elements are strictly positive (>0)
305
+ def positive?; @backend.gsl_vector_ispos(@ptr) == 1 ? true : false end
306
+
307
+ #if all elements are strictly negative (<0)
308
+ def negative?; @backend.gsl_vector_isneg(@ptr) == 1 ? true : false end
309
+
310
+ # if all elements are non-negative (>=0)
311
+ def nonnegative?; @backend.gsl_vector_isnonneg(@ptr) == 1 ? true : false end
312
+
313
+ # If each element of self is less than other's elements
314
+ def <(other); (other - self).positive? end
315
+
316
+ # If each element of self is greater than other's elements
317
+ def >(other); (other - self).negative? end
318
+
319
+ # If each element of self is less-or-equal than other's elements
320
+ def <=(other); (other - self).nonnegative? end
321
+
322
+ # If each element of self is less-or-equal than other's elements
323
+ def >=(other); (self - other).nonnegative? end
324
+
325
+ # @group Minimum/Maximum
326
+
327
+ # Return maximum element of vector
328
+ def max; @backend.gsl_vector_max(@ptr) end
329
+
330
+ # Return minimum element of vector
331
+ def min; @backend.gsl_vector_min(@ptr) end
332
+
333
+ # Same as {Array#minmax}
334
+ def minmax
335
+ min = FFI::Buffer.new(:double)
336
+ max = FFI::Buffer.new(:double)
337
+ @backend.gsl_vector_minmax(@ptr, min, max)
338
+ return [min[0].get_float64(0),max[0].get_float64(0)]
339
+ end
340
+
341
+ # Same as {#minmax}, but returns the indices to the elements
342
+ def minmax_index
343
+ min = FFI::Buffer.new(:size_t)
344
+ max = FFI::Buffer.new(:size_t)
345
+ @backend.gsl_vector_minmax_index(@ptr, min, max)
346
+ #return [min[0].get_size_t(0),max[0].get_size_t(0)]
347
+ return [min[0].get_ulong(0),max[0].get_ulong(0)]
348
+ end
349
+
350
+ # Same as {#min}, but returns the index to the element
351
+ def min_index; @backend.gsl_vector_min_index(@ptr) end
352
+
353
+ # Same as {#max}, but returns the index to the element
354
+ def max_index; @backend.gsl_vector_max_index(@ptr) end
355
+
356
+ # @group Statistics
357
+
358
+ # Compute the mean of the vector
359
+ def mean; @backend.gsl_stats_mean(self.as_array, self.stride, self.size) end
360
+
361
+ # Compute the median of the vector
362
+ # *Note* it assumes sorted data!
363
+ def median; @backend.gsl_stats_median_from_sorted_data(self.as_array, self.stride, self.size) end
364
+
365
+ # Compute the median of the vector
366
+ # *Note* it assumes sorted data!
367
+ # @param [Float] f A number between 0 and 1 indicating the percentile
368
+ def quantile(f); @backend.gsl_stats_quantile_from_sorted_data(self.as_array, self.stride, self.size, f) end
369
+
370
+ # Compute the variance of the vector
371
+ # @param [Float] mean Optionally supply the mean if you already computed it previously with {self#mean}
372
+ # @param [Boolean] fixed_mean If true, the passed mean is taken to be known a priori (see GSL documentation)
373
+ def variance(mean = nil, fixed_mean = false)
374
+ if (mean.nil?) then @backend.gsl_stats_variance(self.as_array, self.stride, self.size)
375
+ else
376
+ if (fixed_mean) then @backend.gsl_stats_variance_with_fixed_mean(self.as_array, self.stride, self.size, mean)
377
+ else @backend.gsl_stats_variance_m(self.as_array, self.stride, self.size, mean) end
378
+ end
379
+ end
380
+
381
+ # Compute the standard deviation of the vector
382
+ # @see #variance
383
+ def standard_deviation(mean = nil, fixed_mean = false)
384
+ if (mean.nil?) then @backend.gsl_stats_sd(self.as_array, self.stride, self.size)
385
+ else
386
+ if (fixed_mean) then @backend.gsl_stats_sd_with_fixed_mean(self.as_array, self.stride, self.size, mean)
387
+ else @backend.gsl_stats_sd_m(self.as_array, self.stride, self.size, mean) end
388
+ end
389
+ end
390
+
391
+ # Compute the total sum of squares of the vector
392
+ # @see #variance
393
+ def total_sum_squares(mean = nil)
394
+ if (mean.nil?) then @backend.gsl_stats_tss(self.as_array, self.stride, self.size)
395
+ else @backend.gsl_stats_tss_m(self.as_array, self.stride, self.size, mean) end
396
+ end
397
+
398
+ # Compute the absolute deviation of the vector
399
+ # @see #variance
400
+ def absolute_deviation(mean = nil)
401
+ if (mean.nil?) then @backend.gsl_stats_absdev(self.as_array, self.stride, self.size)
402
+ else @backend.gsl_stats_absdev_m(self.as_array, self.stride, self.size, mean) end
403
+ end
404
+
405
+ # Compute the skewness of the vector. You can optionally provide the mean *and* the standard deviation if you already computed them
406
+ def skew(mean = nil, sd = nil)
407
+ if (mean.nil? || sd.nil?) then @backend.gsl_stats_skew(self.as_array, self.stride, self.size)
408
+ else @backend.gsl_stats_skew_sd_m(self.as_array, self.stride, self.size, mean, sd) end
409
+ end
410
+
411
+ # Compute the kurtosis of the vector
412
+ # @see #skew
413
+ def kurtosis(mean = nil, sd = nil)
414
+ if (mean.nil? || sd.nil?) then @backend.gsl_stats_kurtosis(self.as_array, self.stride, self.size)
415
+ else @backend.gsl_stats_kurtosis_sd_m(self.as_array, self.stride, self.size, mean, sd) end
416
+ end
417
+
418
+ # Compute the autocorrelation of the vector
419
+ # @see #variance
420
+ def autocorrelation(mean = nil)
421
+ if (mean.nil?) then @backend.gsl_stats_lag1_autocorrelation(self.as_array, self.stride, self.size)
422
+ else @backend.gsl_stats_lag1_autocorrelation(self.as_array, self.stride, self.size, mean) end
423
+ end
424
+
425
+ # Compute the covariance between self and other. You can optionally pass the mean of both vectors if you already computed them
426
+ # @see #variance
427
+ def covariance(other, mean1 = nil, mean2 = nil)
428
+ if (mean1.nil? || mean2.nil?) then @backend.gsl_stats_covariance(self.as_array, self.stride, other.as_array, other.stride, self.size)
429
+ else @backend.gsl_stats_covariance(self.as_array, self.stride, other.as_array, other.stride, self.size, mean1, mean2) end
430
+ end
431
+
432
+ # Compute the correlation between self and other
433
+ def correlation(other)
434
+ @backend.gsl_stats_correlation(self.as_array, self.stride, other.as_array, other.stride, self.size)
435
+ end
436
+
437
+ # @group High-order methods
438
+
439
+ # @yield [elem]
440
+ def each(block = Proc.new)
441
+ @backend.gsl_vector_each(@ptr_value, &block)
442
+ end
443
+
444
+ # @see #each
445
+ # @yield [elem,i]
446
+ def each_with_index(block = Proc.new)
447
+ @backend.gsl_vector_each_with_index(@ptr_value, &block)
448
+ end
449
+
450
+ # @see #map
451
+ def map!(block = Proc.new); @backend.gsl_vector_map!(@ptr_value, &block); return self end
452
+
453
+ # Similar to {#map!}, but passes the index to the element instead.
454
+ # @yield [i]
455
+ def map_index!(block = Proc.new); @backend.gsl_vector_map_index!(@ptr_value, &block); return self end
456
+
457
+ # @return [Vector]
458
+ # @see #map_index!
459
+ # @yield [i]
460
+ def map_index(block = Proc.new); self.dup.map_index!(block) end
461
+
462
+ alias_method :map_old, :map
463
+
464
+ # Acts like the normal 'map' method from Enumerator
465
+ # @return [Array]
466
+ # @see #map
467
+ # @yield [i]
468
+ def map_array(block = Proc.new); self.map_old(&block); end
469
+
470
+ # @return [Vector]
471
+ # @yield [elem]
472
+ def map(block = Proc.new); self.dup.map!(block) end
473
+
474
+ # @group Type conversions
475
+
476
+ # @see Array#join
477
+ # @return [String]
478
+ def join(sep = $,)
479
+ s = ''
480
+ self.each do |e|
481
+ s += (s.empty?() ? e.to_s : "#{sep}#{e}")
482
+ end
483
+ return s
484
+ end
485
+
486
+ # Coerces _other_ to be a Vector.
487
+ # @example
488
+ # Vector[1,2].coerce(5) => [[5.0, 5.0]:Vector, [1.0, 2.0]:Vector]
489
+ def coerce(other)
490
+ case other
491
+ when Vector
492
+ [ other, self ]
493
+ when Numeric
494
+ [ Vector.new(@size).set!(other), self ]
495
+ else
496
+ raise TypeError, "Can't coerce #{other.class} into #{self.class}"
497
+ end
498
+ end
499
+
500
+ # @return [String] same format as {Array#to_s}
501
+ # @example
502
+ # Vector[1,2,3].to_s => "[1.0, 2.0, 3.0]"
503
+ def to_s
504
+ "[" + self.join(', ') + "]"
505
+ end
506
+
507
+ def inspect # @private
508
+ "#{self}:Vector"
509
+ end
510
+
511
+ # @return [Array]
512
+ def to_a
513
+ @backend.gsl_vector_to_a(@ptr_value)
514
+ end
515
+
516
+ def as_array # @private
517
+ @backend.gsl_vector_as_array(@ptr)
518
+ end
519
+
520
+ # Create a row matrix from this vector
521
+ # @return [Matrix]
522
+ def to_matrix
523
+ m = Matrix.new(1, @size)
524
+ @backend.gsl_matrix_set_row(m.ptr, 0, @ptr)
525
+ return m
526
+ end
527
+ alias_method :to_row, :to_matrix
528
+
529
+ # Create a column matrix from this vector
530
+ # @return [Matrix]
531
+ def transpose
532
+ m = Matrix.new(@size, 1)
533
+ @backend.gsl_matrix_set_col(m.ptr, 0, @ptr)
534
+ return m
535
+ end
536
+ alias_method :to_column, :transpose
537
+
538
+ # @group Equality test
539
+
540
+ # Element-by-element comparison. Admits comparing to Array.
541
+ def ==(other)
542
+ if (self.size != other.size) then return false end
543
+ self.each_with_index do |elem,i|
544
+ if (elem != other[i]) then return false end
545
+ end
546
+ return true
547
+ end
548
+
549
+ def eql?(other)
550
+ @backend.gsl_vector_eql?(@ptr_value, other.ptr_value)
551
+ end
552
+ end
553
+ end