ruby-gsl-ngx 0.2.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/plotting.cpp ADDED
@@ -0,0 +1,22 @@
1
+ #include <gsl/gsl_matrix.h>
2
+ #include <unistd.h>
3
+ #include <iostream>
4
+ using namespace std;
5
+
6
+ extern "C" int gsl_matrix_putdata(gsl_matrix* m, int fd) {
7
+ size_t bytes = m->size1 * m->size2 * sizeof(double);
8
+ long ret = write(fd, m->data, bytes);
9
+ if (ret == -1 || (unsigned long)ret < bytes) {
10
+ if (errno == EINTR) {
11
+ cout << "retrying write" << endl;
12
+ long written;
13
+ if (ret == -1) written = 0;
14
+ else written = ret;
15
+
16
+ ret = write(fd, m->data + written, bytes - written);
17
+ if (ret == -1 || (unsigned long)ret < (bytes - written)) return errno;
18
+ else return 0;
19
+ }
20
+ }
21
+ else return 0;
22
+ }
@@ -0,0 +1,14 @@
1
+ #
2
+ # Convenience extensions for core array
3
+ #
4
+ class Array
5
+
6
+ def to_v
7
+ GSLng::Vector.from_array self
8
+ end
9
+
10
+ def to_m
11
+ GSLng::Matrix.from_array self
12
+ end
13
+
14
+ end
data/lib/gslng.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'gslng/backend'
2
+
3
+ require 'gslng/plotter'
4
+ require 'gslng/vector'
5
+ require 'gslng/vector_view'
6
+ require 'gslng/matrix'
7
+ require 'gslng/matrix_view'
8
+ require 'gslng/rng/rng'
9
+ require 'gslng/special'
10
+
11
+ require 'core_extensions/array'
@@ -0,0 +1,23 @@
1
+ require 'ffi'
2
+
3
+ module GSLng
4
+ # Anonymous module: avoids exposing this internal module when doing "include GSLng" at the top-level.
5
+ # If ruby had "private" modules I wouldn't have to do this.
6
+ @backend = Module.new do
7
+ extend FFI::Library
8
+ ffi_lib(FFI::CURRENT_PROCESS)
9
+ end
10
+
11
+ # Returns the internal backend module
12
+ def GSLng.backend # @private
13
+ @backend
14
+ end
15
+ end
16
+
17
+ require 'gslng_extensions'
18
+ require 'gslng/backend_components/vector'
19
+ require 'gslng/backend_components/matrix'
20
+ require 'gslng/backend_components/error_handling'
21
+ require 'gslng/backend_components/rng'
22
+ require 'gslng/backend_components/special'
23
+ require 'gslng/backend_components/stats'
@@ -0,0 +1,12 @@
1
+ module GSLng
2
+ backend.instance_eval do
3
+ # All of this raises an exception when GSL registers an error
4
+ callback :error_handler_callback, [ :string, :string, :int, :int ], :void
5
+ attach_function :gsl_set_error_handler, [ :error_handler_callback ], :error_handler_callback
6
+
7
+ ErrorHandlerCallback = Proc.new {|reason, file, line, errno|
8
+ raise RuntimeError, "#{reason} (errno: #{errno})", caller[2..-1]
9
+ }
10
+ gsl_set_error_handler(ErrorHandlerCallback)
11
+ end
12
+ end
@@ -0,0 +1,83 @@
1
+ module GSLng
2
+
3
+ class GSLmatrix < FFI::Struct
4
+ layout :size1, :size_t,
5
+ :size2, :size_t,
6
+ :tda, :size_t,
7
+ :data, :pointer,
8
+ :block, :pointer,
9
+ :owner, :int
10
+ end
11
+
12
+ backend.instance_eval do
13
+
14
+ # memory handling
15
+ attach_function :gsl_matrix_alloc, [ :size_t, :size_t ], :pointer
16
+ attach_function :gsl_matrix_calloc, [ :size_t, :size_t ], :pointer
17
+ attach_function :gsl_matrix_free, [ :pointer ], :void
18
+
19
+ # initializing
20
+ attach_function :gsl_matrix_set_all, [ :pointer, :double ], :void
21
+ attach_function :gsl_matrix_set_zero, [ :pointer ], :void
22
+ attach_function :gsl_matrix_set_identity, [ :pointer ], :void
23
+
24
+ # copying
25
+ attach_function :gsl_matrix_memcpy, [ :pointer, :pointer ], :int
26
+
27
+ # operations
28
+ attach_function :gsl_matrix_add, [ :pointer, :pointer ], :int
29
+ attach_function :gsl_matrix_sub, [ :pointer, :pointer ], :int
30
+ attach_function :gsl_matrix_mul_elements, [ :pointer, :pointer ], :int
31
+ attach_function :gsl_matrix_div_elements, [ :pointer, :pointer ], :int
32
+ attach_function :gsl_matrix_scale, [ :pointer, :double ], :int
33
+ attach_function :gsl_matrix_add_constant, [ :pointer, :double ], :int
34
+
35
+ # copy rows/columns into
36
+ attach_function :gsl_matrix_get_row, [ :pointer, :pointer, :size_t ], :int
37
+ attach_function :gsl_matrix_get_col, [ :pointer, :pointer, :size_t ], :int
38
+ attach_function :gsl_matrix_set_row, [ :pointer, :size_t, :pointer ], :int
39
+ attach_function :gsl_matrix_set_col, [ :pointer, :size_t, :pointer ], :int
40
+
41
+ # element access
42
+ attach_function :gsl_matrix_get, [ :pointer, :size_t, :size_t ], :double
43
+ attach_function :gsl_matrix_set, [ :pointer, :size_t, :size_t, :double ], :void
44
+
45
+ # properties
46
+ attach_function :gsl_matrix_isnull, [ :pointer ], :int
47
+ attach_function :gsl_matrix_ispos, [ :pointer ], :int
48
+ attach_function :gsl_matrix_isneg, [ :pointer ], :int
49
+ attach_function :gsl_matrix_isnonneg, [ :pointer ], :int
50
+
51
+ # max and min
52
+ attach_function :gsl_matrix_max, [ :pointer ], :double
53
+ attach_function :gsl_matrix_min, [ :pointer ], :double
54
+ attach_function :gsl_matrix_minmax, [ :pointer, :buffer_out, :buffer_out ], :void
55
+ attach_function :gsl_matrix_max_index, [ :pointer, :buffer_out, :buffer_out ], :void
56
+ attach_function :gsl_matrix_min_index, [ :pointer, :buffer_out, :buffer_out ], :void
57
+ attach_function :gsl_matrix_minmax_index, [ :pointer, :buffer_out, :buffer_out, :buffer_out, :buffer_out ], :void
58
+
59
+ # exchange elements
60
+ attach_function :gsl_matrix_swap_rows, [ :pointer, :size_t, :size_t ], :int
61
+ attach_function :gsl_matrix_swap_columns, [ :pointer, :size_t, :size_t ], :int
62
+ attach_function :gsl_matrix_swap_rowcol, [ :pointer, :size_t, :size_t ], :int
63
+ attach_function :gsl_matrix_transpose_memcpy, [ :pointer, :pointer ], :int
64
+ attach_function :gsl_matrix_transpose, [ :pointer ], :int
65
+
66
+ # From local extension
67
+ # views
68
+ attach_function :gsl_matrix_submatrix2, [ :pointer, :size_t, :size_t, :size_t, :size_t ], :pointer
69
+ attach_function :gsl_matrix_row_view, [ :pointer, :size_t, :size_t, :size_t ], :pointer
70
+ attach_function :gsl_matrix_column_view, [ :pointer, :size_t, :size_t, :size_t ], :pointer
71
+
72
+ # slide
73
+ attach_function :gsl_matrix_slide, [ :pointer, :ssize_t, :ssize_t ], :void
74
+
75
+ # BLAS interface
76
+ enum :cblas_transpose_t, [ :no_transpose, 111, :transpose, :conjugate_transpose ]
77
+ attach_function :gsl_blas_dgemv, [ :cblas_transpose_t, :double, :pointer, :pointer, :double, :pointer ], :int
78
+ attach_function :gsl_blas_dgemm, [ :cblas_transpose_t, :cblas_transpose_t, :double, :pointer, :pointer, :double, :pointer ], :int
79
+
80
+ # communication to gnuplot
81
+ attach_function :gsl_matrix_putdata, [ :pointer, :int ], :int
82
+ end
83
+ end
@@ -0,0 +1,22 @@
1
+ module GSLng
2
+ backend.instance_eval do
3
+ # memory handling
4
+ attach_function :gsl_rng_alloc, [ :pointer ], :pointer
5
+ attach_function :gsl_rng_free, [ :pointer ], :void
6
+
7
+ # RNG types
8
+ algorithms = %w(mt19937 ranlxs0 ranlxs1 ranlxs2 ranlxd1 ranlxd2 ranlux ranlux389 cmrg mrg taus taus2 gfsr4)
9
+ algorithms.each do |alg|
10
+ attach_variable :"gsl_rng_#{alg}", :pointer
11
+ end
12
+
13
+ # Uniform
14
+ attach_function :gsl_ran_flat, [ :pointer, :double, :double ], :double
15
+ attach_function :gsl_ran_flat_pdf, [ :double, :double, :double ], :double
16
+
17
+ # Gaussian
18
+ attach_function :gsl_ran_gaussian, [ :pointer, :double ], :double
19
+ attach_function :gsl_ran_gaussian_ziggurat, [ :pointer, :double ], :double
20
+ attach_function :gsl_ran_gaussian_ratio_method, [ :pointer, :double ], :double
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ module GSLng
2
+ backend.instance_eval do
3
+ # trigonometric
4
+ attach_function :gsl_sf_angle_restrict_symm, [ :double ], :double
5
+ attach_function :gsl_sf_angle_restrict_pos, [ :double ], :double
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ module GSLng
2
+ backend.instance_eval do
3
+ # mean, sd and variance
4
+ attach_function :gsl_stats_mean, [ :pointer, :size_t, :size_t ], :double
5
+ attach_function :gsl_stats_median_from_sorted_data, [ :pointer, :size_t, :size_t ], :double
6
+ attach_function :gsl_stats_variance, [ :pointer, :size_t, :size_t ], :double
7
+ attach_function :gsl_stats_variance_m, [ :pointer, :size_t, :size_t, :double ], :double
8
+ attach_function :gsl_stats_sd, [ :pointer, :size_t, :size_t ], :double
9
+ attach_function :gsl_stats_sd_m, [ :pointer, :size_t, :size_t, :double ], :double
10
+ attach_function :gsl_stats_tss, [ :pointer, :size_t, :size_t ], :double
11
+ attach_function :gsl_stats_tss_m, [ :pointer, :size_t, :size_t, :double ], :double
12
+ attach_function :gsl_stats_variance_with_fixed_mean, [ :pointer, :size_t, :size_t, :double ], :double
13
+ attach_function :gsl_stats_sd_with_fixed_mean, [ :pointer, :size_t, :size_t, :double ], :double
14
+
15
+ # absolute deviation
16
+ attach_function :gsl_stats_absdev, [ :pointer, :size_t, :size_t ], :double
17
+ attach_function :gsl_stats_absdev_m, [ :pointer, :size_t, :size_t, :double ], :double
18
+
19
+ # skewness and kurtosis
20
+ attach_function :gsl_stats_skew, [ :pointer, :size_t, :size_t ], :double
21
+ attach_function :gsl_stats_skew_m_sd, [ :pointer, :size_t, :size_t, :double, :double ], :double
22
+ attach_function :gsl_stats_kurtosis, [ :pointer, :size_t, :size_t ], :double
23
+ attach_function :gsl_stats_kurtosis_m_sd, [ :pointer, :size_t, :size_t, :double, :double ], :double
24
+
25
+ # autocorrelation
26
+ attach_function :gsl_stats_lag1_autocorrelation, [ :pointer, :size_t, :size_t ], :double
27
+ attach_function :gsl_stats_lag1_autocorrelation_m, [ :pointer, :size_t, :size_t, :double ], :double
28
+
29
+ # covariance
30
+ attach_function :gsl_stats_covariance, [ :pointer, :size_t, :pointer, :size_t, :size_t ], :double
31
+ attach_function :gsl_stats_covariance_m, [ :pointer, :size_t, :pointer, :size_t, :size_t, :double, :double ], :double
32
+
33
+ # correlation
34
+ attach_function :gsl_stats_correlation, [ :pointer, :size_t, :pointer, :size_t, :size_t ], :double
35
+ end
36
+ end
@@ -0,0 +1,64 @@
1
+ module GSLng
2
+ backend.instance_eval do
3
+ # memory handling
4
+ attach_function :gsl_vector_alloc, [ :size_t ], :pointer
5
+ attach_function :gsl_vector_calloc, [ :size_t ], :pointer
6
+ attach_function :gsl_vector_free, [ :pointer ], :void
7
+
8
+ # initializing
9
+ attach_function :gsl_vector_set_all, [ :pointer, :double ], :void
10
+ attach_function :gsl_vector_set_zero, [ :pointer ], :void
11
+ attach_function :gsl_vector_set_basis, [ :pointer, :size_t ], :int
12
+
13
+ # operations
14
+ attach_function :gsl_vector_add, [ :pointer, :pointer ], :int
15
+ attach_function :gsl_vector_sub, [ :pointer, :pointer ], :int
16
+ attach_function :gsl_vector_mul, [ :pointer, :pointer ], :int
17
+ attach_function :gsl_vector_div, [ :pointer, :pointer ], :int
18
+ attach_function :gsl_vector_scale, [ :pointer, :double ], :int
19
+ attach_function :gsl_vector_add_constant, [ :pointer, :double ], :int
20
+
21
+ # element access
22
+ attach_function :gsl_vector_get, [ :pointer, :size_t ], :double
23
+ attach_function :gsl_vector_set, [ :pointer, :size_t, :double ], :void
24
+
25
+ # properties
26
+ attach_function :gsl_vector_isnull, [ :pointer ], :int
27
+ attach_function :gsl_vector_ispos, [ :pointer ], :int
28
+ attach_function :gsl_vector_isneg, [ :pointer ], :int
29
+ attach_function :gsl_vector_isnonneg, [ :pointer ], :int
30
+
31
+ # max and min
32
+ attach_function :gsl_vector_max, [ :pointer ], :double
33
+ attach_function :gsl_vector_min, [ :pointer ], :double
34
+ attach_function :gsl_vector_minmax, [ :pointer, :buffer_out, :buffer_out ], :void
35
+ attach_function :gsl_vector_max_index, [ :pointer ], :size_t
36
+ attach_function :gsl_vector_min_index, [ :pointer ], :size_t
37
+ attach_function :gsl_vector_minmax_index, [ :pointer, :buffer_out, :buffer_out ], :void
38
+
39
+ # copying
40
+ attach_function :gsl_vector_memcpy, [ :pointer, :pointer ], :int
41
+
42
+ # exchanging elements
43
+ attach_function :gsl_vector_swap_elements, [ :pointer, :size_t, :size_t ], :int
44
+ attach_function :gsl_vector_reverse, [ :pointer ], :int
45
+
46
+ # BLAS functions
47
+ attach_function :gsl_blas_ddot, [ :pointer, :pointer, :buffer_out ], :int
48
+ attach_function :gsl_blas_dnrm2, [ :pointer ], :double
49
+ attach_function :gsl_blas_dasum, [ :pointer ], :double
50
+ #attach_function :gsl_blas_idamax, [ :pointer ], clbas_index??
51
+ #attach_function :gsl_blas_dcopy, use this instead of memcpy?
52
+ attach_function :gsl_blas_daxpy, [ :double, :pointer, :pointer ], :int
53
+ attach_function :gsl_blas_dscal, [ :double, :pointer ], :void
54
+
55
+ # Sorting
56
+ attach_function :gsl_sort_vector, [ :pointer ], :void
57
+
58
+ # From local extension
59
+ # views
60
+ attach_function :gsl_vector_subvector2, [ :pointer, :size_t, :size_t ], :pointer
61
+ attach_function :gsl_vector_subvector_with_stride2, [ :pointer, :size_t, :size_t, :size_t ], :pointer
62
+ attach_function :gsl_vector_as_array, [ :pointer ], :pointer
63
+ end
64
+ end
@@ -0,0 +1,528 @@
1
+ module GSLng
2
+ # A fixed-size MxN matrix.
3
+ #
4
+ # =Notes
5
+ # See Vector notes. Everything applies with the following *differences/additions*:
6
+ # * The {#*} operator performs actual matrix-matrix and matrix-vector products. To perform element-by-element
7
+ # multiplication use the {#^} operator (or {#multiply} method) instead. The rest of the operators work element-by-element.
8
+ # * Operators can handle matrix-matrix, matrix-vector and matrix-scalar (also in reversed order). See {#coerce}.
9
+ # * The {#[]} and {#[]=} operators can handle a "wildcard" value for any dimension, just like MATLAB's colon (:).
10
+ class Matrix
11
+ attr_reader :m, :n
12
+ attr_reader :ptr # @private
13
+ attr_reader :ptr_value # @private
14
+
15
+ alias_method :height, :m
16
+ alias_method :width, :n
17
+ alias_method :rows, :m
18
+ alias_method :columns, :n
19
+
20
+ # Shorthand for [{#rows},{#columns}]
21
+ def size; [ @m, @n ] end
22
+
23
+ # @group Constructors
24
+
25
+ # Create a Matrix of m-by-n (rows and columns). If zero is true, the Matrix is initialized with zeros.
26
+ # Otherwise, the Matrix will contain garbage.
27
+ # You can optionally pass a block, in which case {#map_index!} will be called with it (i.e.: it works like Array.new).
28
+ def initialize(m, n, zero = false)
29
+ @backend = GSLng.backend
30
+ ptr = zero ? @backend.gsl_matrix_calloc(m, n) : @backend.gsl_matrix_alloc(m, n)
31
+ @ptr = FFI::AutoPointer.new(ptr, Matrix.method(:release))
32
+ @ptr_value = @ptr.to_i
33
+ @m,@n = m,n
34
+ if (block_given?) then self.map_index!(Proc.new) end
35
+ end
36
+
37
+ def initialize_copy(other) # @private
38
+ @backend = GSLng.backend
39
+ ptr = @backend.gsl_matrix_alloc(other.m, other.n)
40
+ @ptr = FFI::AutoPointer.new(ptr, Matrix.method(:release))
41
+ @ptr_value = @ptr.to_i
42
+
43
+ @m,@n = other.size
44
+ @backend.gsl_matrix_memcpy(@ptr, other.ptr)
45
+ end
46
+
47
+ def Matrix.release(ptr) # @private
48
+ GSLng.backend.gsl_matrix_free(ptr)
49
+ end
50
+
51
+ # Same as Matrix.new(m, n, true)
52
+ def Matrix.zero(m, n); Matrix.new(m, n, true) end
53
+
54
+ # Create a matrix from an Array
55
+ # @see Matrix::[]
56
+ def Matrix.from_array(array)
57
+ if (array.empty?) then raise "Can't create empty matrix" end
58
+
59
+ if (Numeric === array[0])
60
+ m = Matrix.new(1, array.size)
61
+ GSLng.backend.gsl_matrix_from_array(m.ptr_value, [ array ])
62
+ return m
63
+ elsif (Array === array[0])
64
+ m = Matrix.new(array.size, array[0].size)
65
+ GSLng.backend.gsl_matrix_from_array(m.ptr_value, array)
66
+ return m
67
+ else
68
+ Matrix.new(array.size, array[0].to_a.size) {|i,j| array[i].to_a[j]}
69
+ end
70
+ end
71
+
72
+ # Create a Matrix from an Array/Array of Arrays/Range
73
+ # @example
74
+ # Matrix[[1,2],[3,4]] => [1.0 2.0; 3.0 4.0]:Matrix
75
+ # Matrix[1,2,3] => [1.0 2.0 3.0]:Matrix
76
+ # Matrix[[1..3],[5..7]] => [1.0 2.0 3.0; 5.0 6.0 7.0]:Matrix
77
+ # @see Matrix::from_array
78
+ def Matrix.[](*args)
79
+ Matrix.from_array(args)
80
+ end
81
+
82
+ # Generates a Matrix of m by n, of random numbers between 0 and 1.
83
+ # NOTE: This simply uses {Kernel::rand}
84
+ def Matrix.random(m, n)
85
+ Matrix.new(m, n).map!{|x| Kernel::rand}
86
+ end
87
+ class << self; alias_method :rand, :random end
88
+
89
+ # @group Setting/getting values
90
+
91
+ # Access the element (i,j), which means (row,column).
92
+ # Symbols :* or :all can be used as wildcards for both dimensions.
93
+ # @example If +m = Matrix[[1,2],[3,4]]+
94
+ # m[0,0] => 1.0
95
+ # m[0,:*] => [1.0, 2.0]:Matrix
96
+ # m[:*,0] => [1.0, 3.0]:Matrix
97
+ # m[:*,:*] => [1.0, 2.0; 3.0, 4.0]:Matrix
98
+ # @raise [RuntimeError] if out-of-bounds
99
+ # @return [Numeric,Matrix] the element/sub-matrix
100
+ def [](i, j = :*)
101
+ if (Integer === i && Integer === j)
102
+ @backend.gsl_matrix_get_operator(@ptr_value, i, j)
103
+ else
104
+ if (Symbol === i && Symbol === j) then return self
105
+ elsif (Symbol === i)
106
+ col = Vector.new(@m)
107
+ @backend.gsl_matrix_get_col(col.ptr, @ptr, j)
108
+ return col.to_matrix
109
+ elsif (Symbol === j)
110
+ row = Vector.new(@n)
111
+ @backend.gsl_matrix_get_row(row.ptr, @ptr, i)
112
+ return row.to_matrix
113
+ end
114
+ end
115
+ end
116
+
117
+ # Set the element (i,j), which means (row,column).
118
+ # @param [Numeric,Vector,Matrix] value depends on indexing
119
+ # @raise [RuntimeError] if out-of-bounds
120
+ # @see #[]
121
+ def []=(i, j, value)
122
+ if (Symbol === i && Symbol === j) then
123
+ if (Numeric === value) then self.fill!(value)
124
+ else
125
+ x,y = self.coerce(value)
126
+ @backend.gsl_matrix_memcpy(@ptr, x.ptr)
127
+ end
128
+ elsif (Symbol === i)
129
+ col = Vector.new(@m)
130
+ x,y = col.coerce(value)
131
+ @backend.gsl_matrix_set_col(@ptr, j, x.ptr)
132
+ return col
133
+ elsif (Symbol === j)
134
+ row = Vector.new(@n)
135
+ x,y = row.coerce(value)
136
+ @backend.gsl_matrix_set_row(@ptr, i, x.ptr)
137
+ return row
138
+ else
139
+ @backend.gsl_matrix_set_operator(@ptr_value, i, j, value)
140
+ end
141
+
142
+ return self
143
+ end
144
+
145
+ # Set all values to _v_
146
+ def all!(v); @backend.gsl_matrix_set_all(@ptr, v); return self end
147
+ alias_method :set!, :all!
148
+ alias_method :fill!, :all!
149
+
150
+ # Set all values to zero
151
+ def zero!; @backend.gsl_matrix_set_zero(@ptr); return self end
152
+
153
+ # Set the identity matrix values
154
+ def identity; @backend.gsl_matrix_set_identity(@ptr); return self end
155
+
156
+ # Copy matrix values from +other+ to +self+
157
+ def set(other); @backend.gsl_matrix_memcpy(@ptr, other.ptr); return self end
158
+
159
+ # @group Views
160
+
161
+ # Create a {Matrix::View} from this Matrix.
162
+ # If either _m_ or _n_ are nil, they're computed from _x_, _y_ and the Matrix's {#size}
163
+ # @return [Matrix::View]
164
+ def view(x = 0, y = 0, m = nil, n = nil)
165
+ View.new(self, x, y, (m or @m - x), (n or @n - y))
166
+ end
167
+ alias_method :submatrix_view, :view
168
+
169
+ # Shorthand for #submatrix_view(..).to_matrix.
170
+ # @return [Matrix]
171
+ def submatrix(*args); self.submatrix_view(*args).to_matrix end
172
+
173
+ # Creates a {Matrix::View} for the i-th column
174
+ # @return [Matrix::View]
175
+ def column_view(i, offset = 0, size = nil); self.view(offset, i, (size or (@m - offset)), 1) end
176
+
177
+ # Analogous to {#submatrix}
178
+ # @return [Matrix]
179
+ def column(*args); self.column_view(*args).to_matrix end
180
+
181
+ # Creates a {Matrix::View} for the i-th row
182
+ # @return [Matrix::View]
183
+ def row_view(i, offset = 0, size = nil); self.view(i, offset, 1, (size or (@n - offset))) end
184
+
185
+ # Analogous to {#submatrix}
186
+ # @return [Matrix]
187
+ def row(*args); self.row_view(*args).to_matrix end
188
+
189
+ # Same as {#row_view}, but returns a {Vector::View}
190
+ # @return [Vector::View]
191
+ def row_vecview(i, offset = 0, size = nil)
192
+ size = (@n - offset) if size.nil?
193
+ ptr = @backend.gsl_matrix_row_view(@ptr, i, offset, size)
194
+ Vector::View.new(ptr, self, size)
195
+ end
196
+
197
+ # Same as {#column_view}, but returns a {Vector::View}
198
+ # @return [Vector::View]
199
+ def column_vecview(i, offset = 0, size = nil)
200
+ size = (@m - offset) if size.nil?
201
+ ptr = @backend.gsl_matrix_column_view(@ptr, i, offset, size)
202
+ Vector::View.new(ptr, self, size, self.columns)
203
+ end
204
+
205
+
206
+ # @group Operators
207
+
208
+ # Add other to self
209
+ # @return [Matrix] self
210
+ def add!(other)
211
+ case other
212
+ when Numeric; @backend.gsl_matrix_add_constant(@ptr, other.to_f)
213
+ when Matrix; @backend.gsl_matrix_add(@ptr, other.ptr)
214
+ else
215
+ x,y = other.coerce(self)
216
+ x.add!(y)
217
+ end
218
+ return self
219
+ end
220
+
221
+ # Substract other from self
222
+ # @return [Matrix] self
223
+ def substract!(other)
224
+ case other
225
+ when Numeric; @backend.gsl_matrix_add_constant(@ptr, -other.to_f)
226
+ when Matrix; @backend.gsl_matrix_sub(@ptr, other.ptr)
227
+ else
228
+ x,y = other.coerce(self)
229
+ x.substract!(y)
230
+ end
231
+ return self
232
+ end
233
+ alias_method :sub!, :substract!
234
+
235
+ # Multiply (element-by-element) other with self
236
+ # @return [Matrix] self
237
+ def multiply!(other)
238
+ case other
239
+ when Numeric; @backend.gsl_matrix_scale(@ptr, other.to_f)
240
+ when Matrix; @backend.gsl_matrix_mul_elements(@ptr, other.ptr)
241
+ else
242
+ x,y = other.coerce(self)
243
+ x.multiply!(y)
244
+ end
245
+ return self
246
+ end
247
+ alias_method :mul!, :multiply!
248
+
249
+ # Divide (element-by-element) self by other
250
+ # @return [Matrix] self
251
+ def divide!(other)
252
+ case other
253
+ when Numeric; @backend.gsl_matrix_scale(@ptr, 1.0 / other)
254
+ when Matrix; @backend.gsl_matrix_div_elements(@ptr, other.ptr)
255
+ else
256
+ x,y = other.coerce(self)
257
+ x.divide!(y)
258
+ end
259
+ return self
260
+ end
261
+ alias_method :div!, :divide!
262
+
263
+ # Element-by-element addition
264
+ def +(other); self.dup.add!(other) end
265
+
266
+ # Element-by-element substraction
267
+ def -(other); self.dup.substract!(other) end
268
+
269
+ # Element-by-element division
270
+ def /(other); self.dup.divide!(other) end
271
+
272
+ # Element-by-element product. Both matrices should have same dimensions.
273
+ def ^(other); self.dup.multiply!(other) end
274
+ alias_method :multiply, :^
275
+ alias_method :mul, :^
276
+
277
+ # Matrix Product. self.n should equal other.m (or other.size, if a Vector).
278
+ # @example
279
+ # Matrix[[1,2],[2,3]] * 2 => [2.0 4.0; 4.0 6.0]:Matrix
280
+ # @todo some cases could be optimized when doing Matrix-Matrix, by using dgemv
281
+ def *(other)
282
+ case other
283
+ when Numeric
284
+ self.multiply(other)
285
+ when Vector
286
+ matrix = Matrix.new(self.m, other.size)
287
+ @backend.gsl_blas_dgemm(:no_transpose, :no_transpose, 1, @ptr, other.to_matrix.ptr, 0, matrix.ptr)
288
+ return matrix
289
+ when Matrix
290
+ matrix = Matrix.new(self.m, other.n)
291
+ @backend.gsl_blas_dgemm(:no_transpose, :no_transpose, 1, @ptr, other.ptr, 0, matrix.ptr)
292
+ return matrix
293
+ else
294
+ x,y = other.coerce(self)
295
+ x * y
296
+ end
297
+ end
298
+
299
+ # @group Row/column swapping
300
+
301
+ # Transposes in-place. Only for square matrices
302
+ def transpose!; @backend.gsl_matrix_transpose(@ptr); return self end
303
+
304
+ # Returns the transpose of self, in a new matrix
305
+ def transpose; matrix = Matrix.new(@n, @m); @backend.gsl_matrix_transpose_memcpy(matrix.ptr, @ptr); return matrix end
306
+
307
+ # Swap the i-th and j-th columnos
308
+ def swap_columns(i, j); @backend.gsl_matrix_swap_columns(@ptr, i, j); return self end
309
+
310
+ # Swap the i-th and j-th rows
311
+ def swap_rows(i, j); @backend.gsl_matrix_swap_rows(@ptr, i, j); return self end
312
+
313
+ # Swap the i-th row with the j-th column. The Matrix must be square.
314
+ def swap_rowcol(i, j); @backend.gsl_matrix_swap_rowcol(@ptr, i, j); return self end
315
+
316
+ # Discards rows and columns as necessary (fill them with zero), to "slide" the values of the matrix
317
+ # @param [Integer] i If > 0, slides all values to the bottom (adds +i+ rows of zeros at the top). If < 0,
318
+ # slides all values to the top and adds zeros in the bottom.
319
+ # @param [Integer] j Analogous to parameter +i+, in this case a value < 0 adds zeros to the right (slides to the left),
320
+ # and a value > 0 adds zeros to the left (slides to the right).
321
+ def slide(i, j); @backend.gsl_matrix_slide(@ptr, i, j); return self end
322
+
323
+ # @group Predicate methods
324
+
325
+ # if all elements are zero
326
+ def zero?; @backend.gsl_matrix_isnull(@ptr) == 1 ? true : false end
327
+
328
+ # if all elements are strictly positive (>0)
329
+ def positive?; @backend.gsl_matrix_ispos(@ptr) == 1 ? true : false end
330
+
331
+ #if all elements are strictly negative (<0)
332
+ def negative?; @backend.gsl_matrix_isneg(@ptr) == 1 ? true : false end
333
+
334
+ # if all elements are non-negative (>=0)
335
+ def nonnegative?; @backend.gsl_matrix_isnonneg(@ptr) == 1 ? true : false end
336
+
337
+ # If this is a column Matrix
338
+ def column?; self.columns == 1 end
339
+
340
+ # @group Minimum/maximum
341
+
342
+ # Maximum element of the Matrix
343
+ def max; @backend.gsl_matrix_max(@ptr) end
344
+
345
+ # Minimum element of the Matrix
346
+ def min; @backend.gsl_matrix_min(@ptr) end
347
+
348
+ # Same as {Array#minmax}
349
+ def minmax
350
+ min = FFI::Buffer.new(:double)
351
+ max = FFI::Buffer.new(:double)
352
+ @backend.gsl_matrix_minmax(@ptr, min, max)
353
+ return [min[0].get_float64(0),max[0].get_float64(0)]
354
+ end
355
+
356
+ # Same as {#minmax}, but returns the indices to the i-th and j-th min, and i-th and j-th max.
357
+ def minmax_index
358
+ i_min = FFI::Buffer.new(:size_t)
359
+ j_min = FFI::Buffer.new(:size_t)
360
+ i_max = FFI::Buffer.new(:size_t)
361
+ j_max = FFI::Buffer.new(:size_t)
362
+ @backend.gsl_matrix_minmax_index(@ptr, i_min, j_min, i_max, j_max)
363
+ #return [min[0].get_size_t(0),max[0].get_size_t(0)]
364
+ return [i_min[0].get_ulong(0),j_min[0].get_ulong(0),i_max[0].get_ulong(0),j_max[0].get_ulong(0)]
365
+ end
366
+
367
+ # Same as {#min}, but returns the indices to the i-th and j-th minimum elements
368
+ def min_index
369
+ i_min = FFI::Buffer.new(:size_t)
370
+ j_min = FFI::Buffer.new(:size_t)
371
+ @backend.gsl_matrix_min_index(@ptr, i_min, j_min)
372
+ return [i_min[0].get_ulong(0), j_min[0].get_ulong(0)]
373
+ end
374
+
375
+ # Same as {#max}, but returns the indices to the i-th and j-th maximum elements
376
+ def max_index
377
+ i_max = FFI::Buffer.new(:size_t)
378
+ j_max = FFI::Buffer.new(:size_t)
379
+ @backend.gsl_matrix_max_index(@ptr, i_max, j_max)
380
+ return [i_max[0].get_ulong(0), j_max[0].get_ulong(0)]
381
+ end
382
+
383
+ # @group High-order methods
384
+
385
+ # Yields the specified block for each element going row-by-row
386
+ # @yield [elem]
387
+ def each
388
+ @m.times {|i| @n.times {|j| yield(self[i,j]) } }
389
+ end
390
+
391
+ # Yields the specified block for each element going row-by-row
392
+ # @yield [elem, i, j]
393
+ def each_with_index
394
+ @m.times {|i| @n.times {|j| yield(self[i,j], i, j) } }
395
+ end
396
+
397
+ # Calls the block on each element of the matrix
398
+ # @yield [elem]
399
+ # @return [void]
400
+ def each(block = Proc.new)
401
+ @backend.gsl_matrix_each(@ptr_value, &block)
402
+ end
403
+
404
+ # @see #each
405
+ # @yield [elem,i,j]
406
+ def each_with_index(block = Proc.new)
407
+ @backend.gsl_matrix_each_with_index(@ptr_value, &block)
408
+ end
409
+
410
+ # Yields the block for each row *view* ({Matrix::View}).
411
+ # @yield [view]
412
+ def each_row; self.rows.times {|i| yield(row_view(i))} end
413
+
414
+ # Same as {#each_row}, but yields {Vector::View}'s
415
+ # @yield [vector_view]
416
+ def each_vec_row; self.rows.times {|i| yield(row_vecview(i))} end
417
+
418
+ # Same as #each_column, but yields {Vector::View}'s
419
+ # @yield [vector_view]
420
+ def each_vec_column; self.columns.times {|i| yield(column_vecview(i))} end
421
+
422
+ # Yields the block for each column *view* ({Matrix::View}).
423
+ # @yield [view]
424
+ def each_column; self.columns.times {|i| yield(column_view(i))} end
425
+
426
+ # Efficient {#map!} implementation
427
+ # @yield [elem]
428
+ def map!(block = Proc.new); @backend.gsl_matrix_map!(@ptr_value, &block); return self end
429
+
430
+ # Alternate version of {#map!}, in this case the block receives the index (row, column) as a parameter.
431
+ # @yield [i,j]
432
+ def map_index!(block = Proc.new); @backend.gsl_matrix_map_index!(@ptr_value, &block); return self end
433
+
434
+ # Similar to {#map_index!}, in this case it receives both the element and the index to it
435
+ # @yield [elem,i,j]
436
+ def map_with_index!(block = Proc.new); @backend.gsl_matrix_map_with_index!(@ptr_value, &block); return self end
437
+
438
+ # @see #map!
439
+ # @return [Matrix]
440
+ # @yield [elem]
441
+ def map(block = Proc.new); self.dup.map!(block) end
442
+
443
+ # @see #map
444
+ # @return [Array]
445
+ # @yield [elem]
446
+ def map_array(block = Proc.new); @backend.gsl_matrix_map_array(@ptr_value, &block) end
447
+
448
+ # @group Type conversions
449
+
450
+ # Same as {Array#join}
451
+ # @example
452
+ # Matrix[[1,2],[2,3]].join => "1.0 2.0 2.0 3.0"
453
+ def join(sep = $,)
454
+ s = ''
455
+ self.each do |e|
456
+ s += (s.empty?() ? e.to_s : "#{sep}#{e}")
457
+ end
458
+ return s
459
+ end
460
+
461
+ # Converts the matrix to a String, separating each element with a space and each row with a ';' and a newline.
462
+ # @example
463
+ # Matrix[[1,2],[2,3]] => "[1.0 2.0;\n 2.0 3.0]"
464
+ def to_s
465
+ s = '['
466
+ @m.times do |i|
467
+ s += ' ' unless i == 0
468
+ @n.times do |j|
469
+ s += (j == 0 ? self[i,j].to_s : ' ' + self[i,j].to_s)
470
+ end
471
+ s += (i == (@m-1) ? ']' : ";\n")
472
+ end
473
+
474
+ return s
475
+ end
476
+
477
+ # Converts the matrix to an Array (of Arrays).
478
+ # @example
479
+ # Matrix[[1,2],[2,3]] => [[1.0,2.0],[2.0,3.0]]
480
+ def to_a
481
+ @backend.gsl_matrix_to_a(@ptr_value)
482
+ end
483
+
484
+ def inspect # @private
485
+ "#{self}:Matrix"
486
+ end
487
+
488
+ # Coerces _other_ to be of Matrix class.
489
+ # If _other_ is a scalar (Numeric) a Matrix filled with _other_ values is created.
490
+ # Vectors are coerced using {Vector#to_matrix} (which results in a row matrix).
491
+ def coerce(other)
492
+ case other
493
+ when Matrix
494
+ [ other, self ]
495
+ when Numeric
496
+ [ Matrix.new(@m, @n).fill!(other), self ]
497
+ when Vector
498
+ [ other.to_matrix, self ]
499
+ else
500
+ raise TypeError, "Can't coerce #{other.class} into #{self.class}"
501
+ end
502
+ end
503
+
504
+ # @group Equality
505
+
506
+ # Element-by-element comparison.
507
+ def ==(other)
508
+ if (self.m != other.m || self.n != other.n) then return false end
509
+
510
+ @m.times do |i|
511
+ @n.times do |j|
512
+ if (self[i,j] != other[i,j]) then return false end
513
+ end
514
+ end
515
+
516
+ return true
517
+ end
518
+
519
+ # @group FFI
520
+
521
+ # Returns the FFI::Pointer to the underlying C data memory; can be used to
522
+ # pass the data directly to/from other FFI libraries, without needing
523
+ # to go through Ruby conversion
524
+ def data_ptr
525
+ GSLmatrix.new(ptr)[:data]
526
+ end
527
+ end
528
+ end