ruby-gsl-ng 0.1.0 → 0.2.0
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/History.txt +6 -1
- data/Manifest.txt +12 -4
- data/README.txt +5 -2
- data/Rakefile +1 -0
- data/ext/extconf.rb +2 -0
- data/ext/gslng_extensions.cpp +77 -0
- data/lib/gslng/backend.rb +19 -0
- data/lib/gslng/backend_components/error_handling.rb +12 -0
- data/lib/gslng/backend_components/matrix.rb +73 -0
- data/lib/{gsl/backend.rb → gslng/backend_components/vector.rb} +24 -32
- data/lib/gslng/finalizer.rb +5 -0
- data/lib/gslng/matrix.rb +406 -0
- data/lib/gslng/matrix_view.rb +39 -0
- data/lib/gslng/vector.rb +353 -0
- data/lib/gslng/vector_view.rb +39 -0
- data/lib/gslng.rb +11 -0
- data/test/benchmark.rb +49 -0
- data/test/matrix_test.rb +105 -0
- data/test/test_gsl.rb +1 -0
- data/test/vector_test.rb +72 -39
- metadata +17 -9
- data/lib/gsl/finalizer.rb +0 -5
- data/lib/gsl/vector.rb +0 -236
- data/lib/gsl.rb +0 -8
data/lib/gslng/matrix.rb
ADDED
@@ -0,0 +1,406 @@
|
|
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, :ptr
|
12
|
+
|
13
|
+
alias_method :height, :m
|
14
|
+
alias_method :width, :n
|
15
|
+
alias_method :rows, :m
|
16
|
+
alias_method :columns, :n
|
17
|
+
|
18
|
+
# Returns [ #rows, #columns ]
|
19
|
+
def size; [ @m, @n ] end
|
20
|
+
|
21
|
+
#--------------------- constructors -------------------------#
|
22
|
+
|
23
|
+
# Create a Matrix of m-by-n (rows and columns). If zero is true, the Matrix is initialized with zeros.
|
24
|
+
# Otherwise, the Matrix 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(m, n, zero = false)
|
27
|
+
@ptr = (zero ? GSLng.backend::gsl_matrix_calloc(m, n) : GSLng.backend::gsl_matrix_alloc(m, n))
|
28
|
+
GSLng.set_finalizer(self, :gsl_matrix_free, @ptr)
|
29
|
+
|
30
|
+
@m,@n = m,n
|
31
|
+
if (block_given?) then self.map_index!(&Proc.new) end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize_copy(other) #:nodoc:
|
35
|
+
ObjectSpace.undefine_finalizer(self) # TODO: ruby bug?
|
36
|
+
@ptr = GSLng.backend::gsl_matrix_alloc(other.m, other.n)
|
37
|
+
GSLng.set_finalizer(self, :gsl_matrix_free, @ptr)
|
38
|
+
|
39
|
+
@m,@n = other.size
|
40
|
+
GSLng.backend::gsl_matrix_memcpy(@ptr, other.ptr)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Same as Matrix.new(m, n, true)
|
44
|
+
def Matrix.zero(m, n); Matrix.new(m, n, true) end
|
45
|
+
|
46
|
+
# Create a matrix from an Array
|
47
|
+
# If array is unidimensional, a row Matrix is created. If it is multidimensional, each sub-array
|
48
|
+
# corresponds to a row of the resulting Matrix. Also, _array_ can be an Array of Ranges, in which case
|
49
|
+
# each Range will correspond to a row.
|
50
|
+
def Matrix.from_array(array)
|
51
|
+
if (array.empty?) then raise "Can't create empty matrix" end
|
52
|
+
|
53
|
+
if (Numeric === array[0]) then
|
54
|
+
Matrix.new(1, array.size) {|i,j| array[j]}
|
55
|
+
else
|
56
|
+
Matrix.new(array.size, array[0].to_a.size) {|i,j| array[i].to_a[j]}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Create a Matrix from an Array of Arrays/Ranges (see #from_array). For example:
|
61
|
+
# Matrix[[1,2],[3,4]]
|
62
|
+
# Matrix[1,2,3]
|
63
|
+
# Matrix[[1..2],[5..10]]
|
64
|
+
def Matrix.[](*args)
|
65
|
+
Matrix.from_array(args)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Generates a Matrix of m by n, of random numbers between 0 and 1.
|
69
|
+
# NOTE: This simply uses Kernel::rand
|
70
|
+
def Matrix.random(m, n)
|
71
|
+
Matrix.new(m, n).map!{|x| Kernel::rand}
|
72
|
+
end
|
73
|
+
class << self; alias_method :rand, :random end
|
74
|
+
|
75
|
+
#--------------------- setting values -------------------------#
|
76
|
+
|
77
|
+
# Set all values to _v_
|
78
|
+
def all!(v); GSLng.backend::gsl_matrix_set_all(@ptr, v); return self end
|
79
|
+
alias_method :set!, :all!
|
80
|
+
alias_method :fill!, :all!
|
81
|
+
|
82
|
+
# Set all values to zero
|
83
|
+
def zero!; GSLng.backend::gsl_matrix_set_zero(@ptr); return self end
|
84
|
+
|
85
|
+
# Set the identity matrix values
|
86
|
+
def identity; GSLng.backend::gsl_matrix_set_identity(@ptr); return self end
|
87
|
+
|
88
|
+
#--------------------- set/get -------------------------#
|
89
|
+
|
90
|
+
# Access the element (i,j), which means (row,column). *NOTE*: throws exception if out-of-bounds.
|
91
|
+
# If either i or j are :* or :all, it serves as a wildcard for that dimension, returning all rows or columns,
|
92
|
+
# respectively.
|
93
|
+
def [](i, j = :*)
|
94
|
+
if (Symbol === i && Symbol === j) then return self
|
95
|
+
elsif (Symbol === i)
|
96
|
+
col = Vector.new(@m)
|
97
|
+
GSLng.backend::gsl_matrix_get_col(col.ptr, @ptr, j)
|
98
|
+
return col
|
99
|
+
elsif (Symbol === j)
|
100
|
+
row = Vector.new(@n)
|
101
|
+
GSLng.backend::gsl_matrix_get_row(row.ptr, @ptr, i)
|
102
|
+
return row
|
103
|
+
else
|
104
|
+
GSLng.backend::gsl_matrix_get(@ptr, i, j)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Set the element (i,j), which means (row,column). *NOTE*: throws exception if out-of-bounds.
|
109
|
+
# Same indexing options as #[].
|
110
|
+
# _value_ can be a single Numeric, a Vector or a Matrix, depending on the indexing.
|
111
|
+
def []=(i, j, value)
|
112
|
+
if (Symbol === i && Symbol === j) then
|
113
|
+
if (Numeric === value) then self.fill!(value)
|
114
|
+
else
|
115
|
+
x,y = self.coerce(value)
|
116
|
+
GSLng.backend::gsl_matrix_memcpy(@ptr, x.ptr)
|
117
|
+
end
|
118
|
+
elsif (Symbol === i)
|
119
|
+
col = Vector.new(@m)
|
120
|
+
x,y = col.coerce(value)
|
121
|
+
GSLng.backend::gsl_matrix_set_col(@ptr, j, x.ptr)
|
122
|
+
return col
|
123
|
+
elsif (Symbol === j)
|
124
|
+
row = Vector.new(@n)
|
125
|
+
x,y = row.coerce(value)
|
126
|
+
GSLng.backend::gsl_matrix_set_row(@ptr, i, x.ptr)
|
127
|
+
return row
|
128
|
+
else
|
129
|
+
GSLng.backend::gsl_matrix_set(@ptr, i, j, value)
|
130
|
+
end
|
131
|
+
|
132
|
+
return self
|
133
|
+
end
|
134
|
+
|
135
|
+
#--------------------- view -------------------------#
|
136
|
+
|
137
|
+
# Create a Matrix::View from this Matrix.
|
138
|
+
# If either _m_ or _n_ are nil, they're computed from _x_, _y_ and the Matrix's #size
|
139
|
+
def view(x = 0, y = 0, m = nil, n = nil)
|
140
|
+
View.new(self, x, y, (m or @m - x), (n or @n - y))
|
141
|
+
end
|
142
|
+
alias_method :submatrix_view, :view
|
143
|
+
|
144
|
+
# Shorthand for submatrix_view(..).to_matrix.
|
145
|
+
def submatrix(*args); self.submatrix_view(*args).to_matrix end
|
146
|
+
|
147
|
+
# Creates a Matrix::View for the i-th column
|
148
|
+
def column_view(i, offset = 0, size = nil); self.view(offset, i, (size or (self.m - offset)), 1) end
|
149
|
+
|
150
|
+
# Analogous to #submatrix
|
151
|
+
def column(*args); self.column_view(*args).to_matrix end
|
152
|
+
|
153
|
+
# Creates a Matrix::View for the i-th row
|
154
|
+
def row_view(i, offset = 0, size = nil); self.view(i, offset, 1, (size or (self.n - offset))) end
|
155
|
+
|
156
|
+
# Analogous to #submatrix
|
157
|
+
def row(*args); self.row_view(*args).to_matrix end
|
158
|
+
|
159
|
+
#--------------------- operators -------------------------#
|
160
|
+
|
161
|
+
# Add other to self
|
162
|
+
def add!(other)
|
163
|
+
case other
|
164
|
+
when Numeric; GSLng.backend::gsl_matrix_add_constant(self.ptr, other.to_f)
|
165
|
+
when Matrix; GSLng.backend::gsl_matrix_add(self.ptr, other.ptr)
|
166
|
+
else
|
167
|
+
x,y = other.coerce(self)
|
168
|
+
x.add!(y)
|
169
|
+
end
|
170
|
+
return self
|
171
|
+
end
|
172
|
+
|
173
|
+
# Substract other from self
|
174
|
+
def substract!(other)
|
175
|
+
case other
|
176
|
+
when Numeric; GSLng.backend::gsl_matrix_add_constant(self.ptr, -other.to_f)
|
177
|
+
when Matrix; GSLng.backend::gsl_matrix_sub(self.ptr, other.ptr)
|
178
|
+
else
|
179
|
+
x,y = other.coerce(self)
|
180
|
+
x.substract!(y)
|
181
|
+
end
|
182
|
+
return self
|
183
|
+
end
|
184
|
+
alias_method :sub!, :substract!
|
185
|
+
|
186
|
+
# Multiply (element-by-element) other with self
|
187
|
+
def multiply!(other)
|
188
|
+
case other
|
189
|
+
when Numeric; GSLng.backend::gsl_matrix_scale(self.ptr, other.to_f)
|
190
|
+
when Matrix; GSLng.backend::gsl_matrix_mul_elements(self.ptr, other.ptr)
|
191
|
+
else
|
192
|
+
x,y = other.coerce(self)
|
193
|
+
x.multiply!(y)
|
194
|
+
end
|
195
|
+
return self
|
196
|
+
end
|
197
|
+
alias_method :mul!, :multiply!
|
198
|
+
|
199
|
+
# Divide (element-by-element) self by other
|
200
|
+
def divide!(other)
|
201
|
+
case other
|
202
|
+
when Numeric; GSLng.backend::gsl_matrix_scale(self.ptr, 1.0 / other)
|
203
|
+
when Matrix; GSLng.backend::gsl_matrix_div_elements(self.ptr, other.ptr)
|
204
|
+
else
|
205
|
+
x,y = other.coerce(self)
|
206
|
+
x.divide!(y)
|
207
|
+
end
|
208
|
+
return self
|
209
|
+
end
|
210
|
+
alias_method :div!, :divide!
|
211
|
+
|
212
|
+
# Element-by-element addition
|
213
|
+
def +(other); self.dup.add!(other) end
|
214
|
+
|
215
|
+
# Element-by-element substraction
|
216
|
+
def -(other); self.dup.substract!(other) end
|
217
|
+
|
218
|
+
# Element-by-element division
|
219
|
+
def /(other); self.dup.divide!(other) end
|
220
|
+
|
221
|
+
# Element-by-element product. Both matrices should have same dimensions.
|
222
|
+
def ^(other); self.dup.multiply!(other) end
|
223
|
+
alias_method :multiply, :^
|
224
|
+
alias_method :mul, :^
|
225
|
+
|
226
|
+
# Matrix Product. self#n should equal other#m (or other#size, if a Vector).
|
227
|
+
# TODO: some cases could be optimized when doing Matrix-Matrix, by using dgemv
|
228
|
+
def *(other)
|
229
|
+
case other
|
230
|
+
when Numeric
|
231
|
+
self.multiply(other)
|
232
|
+
when Vector
|
233
|
+
matrix = Matrix.new(self.m, other.size)
|
234
|
+
GSLng.backend::gsl_blas_dgemm(:no_transpose, :no_transpose, 1, self.ptr, other.to_matrix.ptr, 0, matrix.ptr)
|
235
|
+
return matrix
|
236
|
+
when Matrix
|
237
|
+
matrix = Matrix.new(self.m, other.n)
|
238
|
+
GSLng.backend::gsl_blas_dgemm(:no_transpose, :no_transpose, 1, self.ptr, other.ptr, 0, matrix.ptr)
|
239
|
+
return matrix
|
240
|
+
else
|
241
|
+
x,y = other.coerce(self)
|
242
|
+
x * y
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
#--------------------- swap rows/columns -------------------------#
|
247
|
+
|
248
|
+
# Transposes in-place. Only for square matrices
|
249
|
+
def transpose!; GSLng.backend::gsl_matrix_transpose(self.ptr); return self end
|
250
|
+
|
251
|
+
# Returns the transpose of self, in a new matrix
|
252
|
+
def transpose; matrix = Matrix.new(@n, @m); GSLng.backend::gsl_matrix_transpose_memcpy(matrix.ptr, self.ptr); return matrix end
|
253
|
+
|
254
|
+
def swap_columns(i, j); GSLng.backend::gsl_matrix_swap_columns(self.ptr, i, j); return self end
|
255
|
+
def swap_rows(i, j); GSLng.backend::gsl_matrix_swap_rows(self.ptr, i, j); return self end
|
256
|
+
|
257
|
+
# Swap the i-th row with the j-th column. The Matrix must be square.
|
258
|
+
def swap_rowcol(i, j); GSLng.backend::gsl_matrix_swap_rowcol(self.ptr, i, j); return self end
|
259
|
+
|
260
|
+
#--------------------- predicate methods -------------------------#
|
261
|
+
|
262
|
+
# if all elements are zero
|
263
|
+
def zero?; GSLng.backend::gsl_matrix_isnull(@ptr) == 1 ? true : false end
|
264
|
+
|
265
|
+
# if all elements are strictly positive (>0)
|
266
|
+
def positive?; GSLng.backend::gsl_matrix_ispos(@ptr) == 1 ? true : false end
|
267
|
+
|
268
|
+
#if all elements are strictly negative (<0)
|
269
|
+
def negative?; GSLng.backend::gsl_matrix_isneg(@ptr) == 1 ? true : false end
|
270
|
+
|
271
|
+
# if all elements are non-negative (>=0)
|
272
|
+
def nonnegative?; GSLng.backend::gsl_matrix_isnonneg(@ptr) == 1 ? true : false end
|
273
|
+
|
274
|
+
# If this is a column Matrix
|
275
|
+
def column?; self.columns == 1 end
|
276
|
+
|
277
|
+
#--------------------- min/max -------------------------#
|
278
|
+
|
279
|
+
# Maximum element of the Matrix
|
280
|
+
def max; GSLng.backend::gsl_matrix_max(self.ptr) end
|
281
|
+
|
282
|
+
# Minimum element of the Matrix
|
283
|
+
def min; GSLng.backend::gsl_matrix_min(self.ptr) end
|
284
|
+
|
285
|
+
# Same as Array#minmax
|
286
|
+
def minmax
|
287
|
+
min = FFI::Buffer.new(:double)
|
288
|
+
max = FFI::Buffer.new(:double)
|
289
|
+
GSLng.backend::gsl_matrix_minmax(self.ptr, min, max)
|
290
|
+
return [min[0].get_float64(0),max[0].get_float64(0)]
|
291
|
+
end
|
292
|
+
|
293
|
+
# Same as #minmax, but returns the indices to the i-th and j-th min, and i-th and j-th max.
|
294
|
+
def minmax_index
|
295
|
+
i_min = FFI::Buffer.new(:size_t)
|
296
|
+
j_min = FFI::Buffer.new(:size_t)
|
297
|
+
i_max = FFI::Buffer.new(:size_t)
|
298
|
+
j_max = FFI::Buffer.new(:size_t)
|
299
|
+
GSLng.backend::gsl_matrix_minmax_index(self.ptr, i_min, j_min, i_max, j_max)
|
300
|
+
#return [min[0].get_size_t(0),max[0].get_size_t(0)]
|
301
|
+
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)]
|
302
|
+
end
|
303
|
+
|
304
|
+
# Same as #min, but returns the indices to the i-th and j-th minimum elements
|
305
|
+
def min_index
|
306
|
+
i_min = FFI::Buffer.new(:size_t)
|
307
|
+
j_min = FFI::Buffer.new(:size_t)
|
308
|
+
GSLng.backend::gsl_matrix_min_index(self.ptr, i_min, j_min)
|
309
|
+
return [i_min[0].get_ulong(0), j_min[0].get_ulong(0)]
|
310
|
+
end
|
311
|
+
|
312
|
+
# Same as #max, but returns the indices to the i-th and j-th maximum elements
|
313
|
+
def max_index
|
314
|
+
i_max = FFI::Buffer.new(:size_t)
|
315
|
+
j_max = FFI::Buffer.new(:size_t)
|
316
|
+
GSLng.backend::gsl_matrix_max_index(self.ptr, i_max, j_max)
|
317
|
+
return [i_max[0].get_ulong(0), j_max[0].get_ulong(0)]
|
318
|
+
end
|
319
|
+
|
320
|
+
#--------------------- block handling -------------------------#
|
321
|
+
|
322
|
+
# Yields the specified block for each element going row-by-row
|
323
|
+
def each # :yields: elem
|
324
|
+
@m.times {|i| @n.times {|j| yield(self[i,j]) } }
|
325
|
+
end
|
326
|
+
|
327
|
+
# Yields the specified block for each element going row-by-row
|
328
|
+
def each_with_index # :yields: elem, i, j
|
329
|
+
@m.times {|i| @n.times {|j| yield(self[i,j], i, j) } }
|
330
|
+
end
|
331
|
+
|
332
|
+
# Same as #each, but faster. The catch is that this method returns nothing.
|
333
|
+
def fast_each(&block) #:yield: elem
|
334
|
+
GSLng.backend::gsl_matrix_each(self.ptr, block)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Efficient map! implementation
|
338
|
+
def map!(&block); GSLng.backend::gsl_matrix_map(@ptr, block); return self end
|
339
|
+
|
340
|
+
# Alternate version of #map!, in this case the block receives the index as a parameter.
|
341
|
+
def map_index!(&block); GSLng.backend::gsl_matrix_map_index(@ptr, block); return self end
|
342
|
+
|
343
|
+
# See #map!. Returns a Matrix.
|
344
|
+
def map(&block); self.dup.map!(block) end
|
345
|
+
|
346
|
+
#--------------------- conversions -------------------------#
|
347
|
+
|
348
|
+
# Same as Array#join, for example:
|
349
|
+
# Matrix[[1,2],[2,3]].join => "1.0 2.0 2.0 3.0"
|
350
|
+
def join(sep = $,)
|
351
|
+
s = ''
|
352
|
+
GSLng.backend::gsl_matrix_each(@ptr, lambda {|e| s += (s.empty?() ? e.to_s : "#{sep}#{e}")})
|
353
|
+
return s
|
354
|
+
end
|
355
|
+
|
356
|
+
# Converts the matrix to a String, separating each element with a space and each row with a ';' and a newline:
|
357
|
+
# Matrix[[1,2],[2,3]] => "[1.0 2.0;\n 2.0 3.0]"
|
358
|
+
def to_s
|
359
|
+
s = '['
|
360
|
+
@m.times do |i|
|
361
|
+
s += ' ' unless i == 0
|
362
|
+
@n.times do |j|
|
363
|
+
s += (j == 0 ? self[i,j].to_s : ' ' + self[i,j].to_s)
|
364
|
+
end
|
365
|
+
s += (i == (@m-1) ? ']' : ";\n")
|
366
|
+
end
|
367
|
+
|
368
|
+
return s
|
369
|
+
end
|
370
|
+
|
371
|
+
def inspect #:nodoc:
|
372
|
+
"#{self}:Matrix"
|
373
|
+
end
|
374
|
+
|
375
|
+
# Coerces _other_ to be of Matrix class.
|
376
|
+
# If _other_ is a scalar (Numeric) a Matrix filled with _other_ values is created.
|
377
|
+
# Vectors are coerced using Vector#to_matrix (which results in a row matrix).
|
378
|
+
def coerce(other)
|
379
|
+
case other
|
380
|
+
when Matrix
|
381
|
+
[ other, self ]
|
382
|
+
when Numeric
|
383
|
+
[ Matrix.new(@m, @n).fill!(other), self ]
|
384
|
+
when Vector
|
385
|
+
[ other.to_matrix, self ]
|
386
|
+
else
|
387
|
+
raise TypeError, "Can't coerce #{other.class} into #{self.class}"
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
#--------------------- equality -------------------------#
|
392
|
+
|
393
|
+
# Element-by-element comparison.
|
394
|
+
def ==(other)
|
395
|
+
if (self.m != other.m || self.n != other.n) then return false end
|
396
|
+
|
397
|
+
@m.times do |i|
|
398
|
+
@n.times do |j|
|
399
|
+
if (self[i,j] != other[i,j]) then return false end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
return true
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
@@ -0,0 +1,39 @@
|
|
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 MatrixView of the sub-matrix starting at (x,y), of size (m,n)
|
13
|
+
def initialize(owner, x, y, m, n) #:nodoc:
|
14
|
+
@owner = owner
|
15
|
+
@m,@n = m,n
|
16
|
+
@ptr = GSLng.backend::gsl_matrix_submatrix2(owner.ptr, x, y, m, n)
|
17
|
+
GSLng.set_finalizer(self, :gsl_matrix_free, @ptr)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a Matrix (*NOT* a View) copied from this view. In other words,
|
21
|
+
# you'll get a Matrix which you can modify without modifying #owner elements.
|
22
|
+
def dup
|
23
|
+
matrix = Matrix.new(@m, @n)
|
24
|
+
GSLng.backend::gsl_matrix_memcpy(matrix.ptr, @ptr)
|
25
|
+
return matrix
|
26
|
+
end
|
27
|
+
alias_method :clone, :dup
|
28
|
+
alias_method :to_matrix, :dup
|
29
|
+
|
30
|
+
def view #:nodoc:
|
31
|
+
raise "Can't create a View from a View"
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect #:nodoc:
|
35
|
+
"#{self}:MatrixView"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|