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.
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