ruby-gsl-ngx 0.2.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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