nmatrix 0.2.3 → 0.2.4
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.
- checksums.yaml +4 -4
- data/ext/nmatrix/data/ruby_object.h +1 -1
- data/ext/nmatrix/math.cpp +274 -33
- data/ext/nmatrix/math/math.h +8 -2
- data/ext/nmatrix/ruby_nmatrix.c +81 -65
- data/lib/nmatrix/blas.rb +6 -2
- data/lib/nmatrix/cruby/math.rb +744 -0
- data/lib/nmatrix/enumerate.rb +3 -2
- data/lib/nmatrix/jruby/decomposition.rb +24 -0
- data/lib/nmatrix/jruby/enumerable.rb +13 -0
- data/lib/nmatrix/jruby/error.rb +4 -0
- data/lib/nmatrix/jruby/math.rb +501 -0
- data/lib/nmatrix/jruby/nmatrix_java.rb +840 -0
- data/lib/nmatrix/jruby/operators.rb +283 -0
- data/lib/nmatrix/jruby/slice.rb +264 -0
- data/lib/nmatrix/math.rb +233 -635
- data/lib/nmatrix/mkmf.rb +6 -9
- data/lib/nmatrix/monkeys.rb +2 -4
- data/lib/nmatrix/nmatrix.rb +62 -32
- data/lib/nmatrix/shortcuts.rb +8 -3
- data/lib/nmatrix/version.rb +1 -1
- data/spec/00_nmatrix_spec.rb +110 -3
- data/spec/01_enum_spec.rb +7 -1
- data/spec/02_slice_spec.rb +19 -1
- data/spec/03_nmatrix_monkeys_spec.rb +2 -0
- data/spec/elementwise_spec.rb +10 -2
- data/spec/homogeneous_spec.rb +1 -0
- data/spec/io_spec.rb +11 -1
- data/spec/math_spec.rb +346 -102
- data/spec/rspec_spec.rb +1 -0
- data/spec/shortcuts_spec.rb +47 -23
- data/spec/slice_set_spec.rb +7 -2
- data/spec/stat_spec.rb +11 -0
- metadata +20 -41
- data/ext/nmatrix/ttable_helper.rb +0 -115
data/lib/nmatrix/enumerate.rb
CHANGED
@@ -71,7 +71,8 @@ class NMatrix
|
|
71
71
|
#
|
72
72
|
def map(&bl)
|
73
73
|
return enum_for(:map) unless block_given?
|
74
|
-
|
74
|
+
# NMatrix-jruby currently supports only doubles
|
75
|
+
cp = jruby? ? self : self.cast(dtype: :object)
|
75
76
|
cp.map!(&bl)
|
76
77
|
cp
|
77
78
|
end
|
@@ -220,7 +221,7 @@ class NMatrix
|
|
220
221
|
|
221
222
|
return enum_for(:inject_rank, dimen, initial, dtype) unless block_given?
|
222
223
|
|
223
|
-
new_shape = shape
|
224
|
+
new_shape = shape.dup
|
224
225
|
new_shape[dimen] = 1
|
225
226
|
|
226
227
|
first_as_acc = false
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class NMatrix
|
2
|
+
|
3
|
+
# discussion in https://github.com/SciRuby/nmatrix/issues/374
|
4
|
+
|
5
|
+
def matrix_solve rhs
|
6
|
+
if rhs.shape[1] > 1
|
7
|
+
nmatrix = NMatrix.new :copy
|
8
|
+
nmatrix.shape = rhs.shape
|
9
|
+
res = []
|
10
|
+
#Solve a matrix and store the vectors in a matrix
|
11
|
+
(0...rhs.shape[1]).each do |i|
|
12
|
+
res << self.solve(rhs.col(i)).s.toArray.to_a
|
13
|
+
end
|
14
|
+
#res is in col major format
|
15
|
+
result = ArrayGenerator.getArrayColMajorDouble res.to_java :double, rhs.shape[0], rhs.shape[1]
|
16
|
+
nmatrix.s = ArrayRealVector.new result
|
17
|
+
|
18
|
+
return nmatrix
|
19
|
+
else
|
20
|
+
return self.solve rhs
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Source: https://github.com/marcandre/backports/blob/master/lib/backports/rails/enumerable.rb
|
2
|
+
module Enumerable
|
3
|
+
# Standard in rails... See official documentation[http://api.rubyonrails.org/classes/Enumerable.html]
|
4
|
+
# Modified from rails 2.3 to not rely on size
|
5
|
+
def sum(identity = 0, &block)
|
6
|
+
if block_given?
|
7
|
+
map(&block).sum(identity)
|
8
|
+
else
|
9
|
+
inject { |sum, element| sum + element } || identity
|
10
|
+
end
|
11
|
+
end unless method_defined? :sum
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,501 @@
|
|
1
|
+
#--
|
2
|
+
# = NMatrix
|
3
|
+
#
|
4
|
+
# A linear algebra library for scientific computation in Ruby.
|
5
|
+
# NMatrix is part of SciRuby.
|
6
|
+
#
|
7
|
+
# NMatrix was originally inspired by and derived from NArray, by
|
8
|
+
# Masahiro Tanaka: http://narray.rubyforge.org
|
9
|
+
#
|
10
|
+
# == Copyright Information
|
11
|
+
#
|
12
|
+
# SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
|
13
|
+
# NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
|
14
|
+
#
|
15
|
+
# Please see LICENSE.txt for additional copyright notices.
|
16
|
+
#
|
17
|
+
# == Contributing
|
18
|
+
#
|
19
|
+
# By contributing source code to SciRuby, you agree to be bound by
|
20
|
+
# our Contributor Agreement:
|
21
|
+
#
|
22
|
+
# * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
23
|
+
#
|
24
|
+
# == math.rb
|
25
|
+
#
|
26
|
+
# Math functionality for NMatrix, along with any NMatrix instance
|
27
|
+
# methods that correspond to ATLAS/BLAS/LAPACK functions (e.g.,
|
28
|
+
# laswp).
|
29
|
+
#++
|
30
|
+
|
31
|
+
class NMatrix
|
32
|
+
|
33
|
+
#
|
34
|
+
# call-seq:
|
35
|
+
# getrf! -> Array
|
36
|
+
#
|
37
|
+
# LU factorization of a general M-by-N matrix +A+ using partial pivoting with
|
38
|
+
# row interchanges. The LU factorization is A = PLU, where P is a row permutation
|
39
|
+
# matrix, L is a lower triangular matrix with unit diagonals, and U is an upper
|
40
|
+
# triangular matrix (note that this convention is different from the
|
41
|
+
# clapack_getrf behavior, but matches the standard LAPACK getrf).
|
42
|
+
# +A+ is overwritten with the elements of L and U (the unit
|
43
|
+
# diagonal elements of L are not saved). P is not returned directly and must be
|
44
|
+
# constructed from the pivot array ipiv. The row indices in ipiv are indexed
|
45
|
+
# starting from 1.
|
46
|
+
# Only works for dense matrices.
|
47
|
+
#
|
48
|
+
# * *Returns* :
|
49
|
+
# - The IPIV vector. The L and U matrices are stored in A.
|
50
|
+
# * *Raises* :
|
51
|
+
# - +StorageTypeError+ -> ATLAS functions only work on dense matrices.
|
52
|
+
#
|
53
|
+
def getrf!
|
54
|
+
ipiv = LUDecomposition.new(self.twoDMat).getPivot.to_a
|
55
|
+
return ipiv
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# call-seq:
|
60
|
+
# geqrf! -> shape.min x 1 NMatrix
|
61
|
+
#
|
62
|
+
# QR factorization of a general M-by-N matrix +A+.
|
63
|
+
#
|
64
|
+
# The QR factorization is A = QR, where Q is orthogonal and R is Upper Triangular
|
65
|
+
# +A+ is overwritten with the elements of R and Q with Q being represented by the
|
66
|
+
# elements below A's diagonal and an array of scalar factors in the output NMatrix.
|
67
|
+
#
|
68
|
+
# The matrix Q is represented as a product of elementary reflectors
|
69
|
+
# Q = H(1) H(2) . . . H(k), where k = min(m,n).
|
70
|
+
#
|
71
|
+
# Each H(i) has the form
|
72
|
+
#
|
73
|
+
# H(i) = I - tau * v * v'
|
74
|
+
#
|
75
|
+
# http://www.netlib.org/lapack/explore-html/d3/d69/dgeqrf_8f.html
|
76
|
+
#
|
77
|
+
# Only works for dense matrices.
|
78
|
+
#
|
79
|
+
# * *Returns* :
|
80
|
+
# - Vector TAU. Q and R are stored in A. Q is represented by TAU and A
|
81
|
+
# * *Raises* :
|
82
|
+
# - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
|
83
|
+
#
|
84
|
+
def geqrf!
|
85
|
+
# The real implementation is in lib/nmatrix/lapacke.rb
|
86
|
+
raise(NotImplementedError, "geqrf! requires the nmatrix-lapacke gem")
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# call-seq:
|
91
|
+
# ormqr(tau) -> NMatrix
|
92
|
+
# ormqr(tau, side, transpose, c) -> NMatrix
|
93
|
+
#
|
94
|
+
# Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization.
|
95
|
+
# +c+ is overwritten with the elements of the result NMatrix if supplied. Q is the orthogonal matrix
|
96
|
+
# represented by tau and the calling NMatrix
|
97
|
+
#
|
98
|
+
# Only works on float types, use unmqr for complex types.
|
99
|
+
#
|
100
|
+
# == Arguments
|
101
|
+
#
|
102
|
+
# * +tau+ - vector containing scalar factors of elementary reflectors
|
103
|
+
# * +side+ - direction of multiplication [:left, :right]
|
104
|
+
# * +transpose+ - apply Q with or without transpose [false, :transpose]
|
105
|
+
# * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity
|
106
|
+
#
|
107
|
+
# * *Returns* :
|
108
|
+
#
|
109
|
+
# - Q * c or c * Q Where Q may be transposed before multiplication.
|
110
|
+
#
|
111
|
+
#
|
112
|
+
# * *Raises* :
|
113
|
+
# - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
|
114
|
+
# - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types
|
115
|
+
# - +TypeError+ -> c must have the same dtype as the calling NMatrix
|
116
|
+
#
|
117
|
+
def ormqr(tau, side=:left, transpose=false, c=nil)
|
118
|
+
# The real implementation is in lib/nmatrix/lapacke.rb
|
119
|
+
raise(NotImplementedError, "ormqr requires the nmatrix-lapacke gem")
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# call-seq:
|
125
|
+
# unmqr(tau) -> NMatrix
|
126
|
+
# unmqr(tau, side, transpose, c) -> NMatrix
|
127
|
+
#
|
128
|
+
# Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization.
|
129
|
+
# +c+ is overwritten with the elements of the result NMatrix if it is supplied. Q is the orthogonal matrix
|
130
|
+
# represented by tau and the calling NMatrix
|
131
|
+
#
|
132
|
+
# Only works on complex types, use ormqr for float types.
|
133
|
+
#
|
134
|
+
# == Arguments
|
135
|
+
#
|
136
|
+
# * +tau+ - vector containing scalar factors of elementary reflectors
|
137
|
+
# * +side+ - direction of multiplication [:left, :right]
|
138
|
+
# * +transpose+ - apply Q as Q or its complex conjugate [false, :complex_conjugate]
|
139
|
+
# * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity
|
140
|
+
#
|
141
|
+
# * *Returns* :
|
142
|
+
#
|
143
|
+
# - Q * c or c * Q Where Q may be transformed to its complex conjugate before multiplication.
|
144
|
+
#
|
145
|
+
#
|
146
|
+
# * *Raises* :
|
147
|
+
# - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
|
148
|
+
# - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types
|
149
|
+
# - +TypeError+ -> c must have the same dtype as the calling NMatrix
|
150
|
+
#
|
151
|
+
def unmqr(tau, side=:left, transpose=false, c=nil)
|
152
|
+
# The real implementation is in lib/nmatrix/lapacke.rb
|
153
|
+
raise(NotImplementedError, "unmqr requires the nmatrix-lapacke gem")
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# call-seq:
|
158
|
+
# potrf!(upper_or_lower) -> NMatrix
|
159
|
+
#
|
160
|
+
# Cholesky factorization of a symmetric positive-definite matrix -- or, if complex,
|
161
|
+
# a Hermitian positive-definite matrix +A+.
|
162
|
+
# The result will be written in either the upper or lower triangular portion of the
|
163
|
+
# matrix, depending on whether the argument is +:upper+ or +:lower+.
|
164
|
+
# Also the function only reads in the upper or lower part of the matrix,
|
165
|
+
# so it doesn't actually have to be symmetric/Hermitian.
|
166
|
+
# However, if the matrix (i.e. the symmetric matrix implied by the lower/upper
|
167
|
+
# half) is not positive-definite, the function will return nonsense.
|
168
|
+
#
|
169
|
+
# This functions requires either the nmatrix-atlas or nmatrix-lapacke gem
|
170
|
+
# installed.
|
171
|
+
#
|
172
|
+
# * *Returns* :
|
173
|
+
# the triangular portion specified by the parameter
|
174
|
+
# * *Raises* :
|
175
|
+
# - +StorageTypeError+ -> ATLAS functions only work on dense matrices.
|
176
|
+
# - +ShapeError+ -> Must be square.
|
177
|
+
# - +NotImplementedError+ -> If called without nmatrix-atlas or nmatrix-lapacke gem
|
178
|
+
#
|
179
|
+
def potrf!(which)
|
180
|
+
# The real implementation is in the plugin files.
|
181
|
+
cholesky = CholeskyDecomposition.new(self.twoDMat)
|
182
|
+
if which == :upper
|
183
|
+
u = create_dummy_nmatrix
|
184
|
+
twoDMat = cholesky.getLT
|
185
|
+
u.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
|
186
|
+
return u
|
187
|
+
else
|
188
|
+
l = create_dummy_nmatrix
|
189
|
+
twoDMat = cholesky.getL
|
190
|
+
l.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
|
191
|
+
return l
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def potrf_upper!
|
196
|
+
potrf! :upper
|
197
|
+
end
|
198
|
+
|
199
|
+
def potrf_lower!
|
200
|
+
potrf! :lower
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
#
|
205
|
+
# call-seq:
|
206
|
+
# factorize_cholesky -> [upper NMatrix, lower NMatrix]
|
207
|
+
#
|
208
|
+
# Calculates the Cholesky factorization of a matrix and returns the
|
209
|
+
# upper and lower matrices such that A=LU and L=U*, where * is
|
210
|
+
# either the transpose or conjugate transpose.
|
211
|
+
#
|
212
|
+
# Unlike potrf!, this makes method requires that the original is matrix is
|
213
|
+
# symmetric or Hermitian. However, it is still your responsibility to make
|
214
|
+
# sure it is positive-definite.
|
215
|
+
def factorize_cholesky
|
216
|
+
# raise "Matrix must be symmetric/Hermitian for Cholesky factorization" unless self.hermitian?
|
217
|
+
cholesky = CholeskyDecomposition.new(self.twoDMat)
|
218
|
+
l = create_dummy_nmatrix
|
219
|
+
twoDMat = cholesky.getL
|
220
|
+
l.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
|
221
|
+
u = create_dummy_nmatrix
|
222
|
+
twoDMat = cholesky.getLT
|
223
|
+
u.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
|
224
|
+
return [u,l]
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# call-seq:
|
229
|
+
# factorize_lu -> ...
|
230
|
+
#
|
231
|
+
# LU factorization of a matrix. Optionally return the permutation matrix.
|
232
|
+
# Note that computing the permutation matrix will introduce a slight memory
|
233
|
+
# and time overhead.
|
234
|
+
#
|
235
|
+
# == Arguments
|
236
|
+
#
|
237
|
+
# +with_permutation_matrix+ - If set to *true* will return the permutation
|
238
|
+
# matrix alongwith the LU factorization as a second return value.
|
239
|
+
#
|
240
|
+
def factorize_lu with_permutation_matrix=nil
|
241
|
+
raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense
|
242
|
+
raise(NotImplementedError, "matrix is not 2-dimensional") unless self.dimensions == 2
|
243
|
+
t = self.clone
|
244
|
+
pivot = create_dummy_nmatrix
|
245
|
+
twoDMat = LUDecomposition.new(self.twoDMat).getP
|
246
|
+
pivot.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
|
247
|
+
return [t,pivot]
|
248
|
+
end
|
249
|
+
|
250
|
+
#
|
251
|
+
# call-seq:
|
252
|
+
# factorize_qr -> [Q,R]
|
253
|
+
#
|
254
|
+
# QR factorization of a matrix without column pivoting.
|
255
|
+
# Q is orthogonal and R is upper triangular if input is square or upper trapezoidal if
|
256
|
+
# input is rectangular.
|
257
|
+
#
|
258
|
+
# Only works for dense matrices.
|
259
|
+
#
|
260
|
+
# * *Returns* :
|
261
|
+
# - Array containing Q and R matrices
|
262
|
+
#
|
263
|
+
# * *Raises* :
|
264
|
+
# - +StorageTypeError+ -> only implemented for desnse storage.
|
265
|
+
# - +ShapeError+ -> Input must be a 2-dimensional matrix to have a QR decomposition.
|
266
|
+
#
|
267
|
+
def factorize_qr
|
268
|
+
|
269
|
+
raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense
|
270
|
+
raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless self.dim == 2
|
271
|
+
qrdecomp = QRDecomposition.new(self.twoDMat)
|
272
|
+
|
273
|
+
qmat = create_dummy_nmatrix
|
274
|
+
qtwoDMat = qrdecomp.getQ
|
275
|
+
qmat.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(qtwoDMat.getData, @shape[0], @shape[1]))
|
276
|
+
|
277
|
+
rmat = create_dummy_nmatrix
|
278
|
+
rtwoDMat = qrdecomp.getR
|
279
|
+
rmat.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(rtwoDMat.getData, @shape[0], @shape[1]))
|
280
|
+
return [qmat,rmat]
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
# Solve the matrix equation AX = B, where A is +self+, B is the first
|
285
|
+
# argument, and X is returned. A must be a nxn square matrix, while B must be
|
286
|
+
# nxm. Only works with dense matrices and non-integer, non-object data types.
|
287
|
+
#
|
288
|
+
# == Arguments
|
289
|
+
#
|
290
|
+
# * +b+ - the right hand side
|
291
|
+
#
|
292
|
+
# == Options
|
293
|
+
#
|
294
|
+
# * +form+ - Signifies the form of the matrix A in the linear system AX=B.
|
295
|
+
# If not set then it defaults to +:general+, which uses an LU solver.
|
296
|
+
# Other possible values are +:lower_tri+, +:upper_tri+ and +:pos_def+ (alternatively,
|
297
|
+
# non-abbreviated symbols +:lower_triangular+, +:upper_triangular+,
|
298
|
+
# and +:positive_definite+ can be used.
|
299
|
+
# If +:lower_tri+ or +:upper_tri+ is set, then a specialized linear solver for linear
|
300
|
+
# systems AX=B with a lower or upper triangular matrix A is used. If +:pos_def+ is chosen,
|
301
|
+
# then the linear system is solved via the Cholesky factorization.
|
302
|
+
# Note that when +:lower_tri+ or +:upper_tri+ is used, then the algorithm just assumes that
|
303
|
+
# all entries in the lower/upper triangle of the matrix are zeros without checking (which
|
304
|
+
# can be useful in certain applications).
|
305
|
+
#
|
306
|
+
#
|
307
|
+
# == Usage
|
308
|
+
#
|
309
|
+
# a = NMatrix.new [2,2], [3,1,1,2], dtype: dtype
|
310
|
+
# b = NMatrix.new [2,1], [9,8], dtype: dtype
|
311
|
+
# a.solve(b)
|
312
|
+
#
|
313
|
+
# # solve an upper triangular linear system more efficiently:
|
314
|
+
# require 'benchmark'
|
315
|
+
# require 'nmatrix/lapacke'
|
316
|
+
# rand_mat = NMatrix.random([10000, 10000], dtype: :float64)
|
317
|
+
# a = rand_mat.triu
|
318
|
+
# b = NMatrix.random([10000, 10], dtype: :float64)
|
319
|
+
# Benchmark.bm(10) do |bm|
|
320
|
+
# bm.report('general') { a.solve(b) }
|
321
|
+
# bm.report('upper_tri') { a.solve(b, form: :upper_tri) }
|
322
|
+
# end
|
323
|
+
# # user system total real
|
324
|
+
# # general 73.170000 0.670000 73.840000 ( 73.810086)
|
325
|
+
# # upper_tri 0.180000 0.000000 0.180000 ( 0.182491)
|
326
|
+
#
|
327
|
+
def solve(b, opts = {})
|
328
|
+
raise(ShapeError, "Must be called on square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1]
|
329
|
+
raise(ShapeError, "number of rows of b must equal number of cols of self") if
|
330
|
+
self.shape[1] != b.shape[0]
|
331
|
+
raise(ArgumentError, "only works with dense matrices") if self.stype != :dense
|
332
|
+
raise(ArgumentError, "only works for non-integer, non-object dtypes") if
|
333
|
+
integer_dtype? or object_dtype? or b.integer_dtype? or b.object_dtype?
|
334
|
+
|
335
|
+
opts = { form: :general }.merge(opts)
|
336
|
+
x = b.clone
|
337
|
+
n = self.shape[0]
|
338
|
+
nrhs = b.shape[1]
|
339
|
+
|
340
|
+
nmatrix = create_dummy_nmatrix
|
341
|
+
case opts[:form]
|
342
|
+
when :general, :upper_tri, :upper_triangular, :lower_tri, :lower_triangular
|
343
|
+
#LU solver
|
344
|
+
solver = LUDecomposition.new(self.twoDMat).getSolver
|
345
|
+
nmatrix.s = solver.solve(b.s)
|
346
|
+
return nmatrix
|
347
|
+
when :pos_def, :positive_definite
|
348
|
+
solver = CholeskyDecomposition.new(self.twoDMat).getSolver
|
349
|
+
nmatrix.s = solver.solve(b.s)
|
350
|
+
return nmatrix
|
351
|
+
else
|
352
|
+
raise(ArgumentError, "#{opts[:form]} is not a valid form option")
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
#
|
358
|
+
# call-seq:
|
359
|
+
# det -> determinant
|
360
|
+
#
|
361
|
+
# Calculate the determinant by way of LU decomposition. This is accomplished
|
362
|
+
# using clapack_getrf, and then by taking the product of the diagonal elements. There is a
|
363
|
+
# risk of underflow/overflow.
|
364
|
+
#
|
365
|
+
# There are probably also more efficient ways to calculate the determinant.
|
366
|
+
# This method requires making a copy of the matrix, since clapack_getrf
|
367
|
+
# modifies its input.
|
368
|
+
#
|
369
|
+
# For smaller matrices, you may be able to use +#det_exact+.
|
370
|
+
#
|
371
|
+
# This function is guaranteed to return the same type of data in the matrix
|
372
|
+
# upon which it is called.
|
373
|
+
#
|
374
|
+
# Integer matrices are converted to floating point matrices for the purposes of
|
375
|
+
# performing the calculation, as xGETRF can't work on integer matrices.
|
376
|
+
#
|
377
|
+
# * *Returns* :
|
378
|
+
# - The determinant of the matrix. It's the same type as the matrix's dtype.
|
379
|
+
# * *Raises* :
|
380
|
+
# - +ShapeError+ -> Must be used on square matrices.
|
381
|
+
#
|
382
|
+
def det
|
383
|
+
raise(ShapeError, "determinant can be calculated only for square matrices") unless self.dim == 2 && self.shape[0] == self.shape[1]
|
384
|
+
self.det_exact2
|
385
|
+
end
|
386
|
+
|
387
|
+
#
|
388
|
+
# call-seq:
|
389
|
+
# complex_conjugate -> NMatrix
|
390
|
+
# complex_conjugate(new_stype) -> NMatrix
|
391
|
+
#
|
392
|
+
# Get the complex conjugate of this matrix. See also complex_conjugate! for
|
393
|
+
# an in-place operation (provided the dtype is already +:complex64+ or
|
394
|
+
# +:complex128+).
|
395
|
+
#
|
396
|
+
# Doesn't work on list matrices, but you can optionally pass in the stype you
|
397
|
+
# want to cast to if you're dealing with a list matrix.
|
398
|
+
#
|
399
|
+
# * *Arguments* :
|
400
|
+
# - +new_stype+ -> stype for the new matrix.
|
401
|
+
# * *Returns* :
|
402
|
+
# - If the original NMatrix isn't complex, the result is a +:complex128+ NMatrix. Otherwise, it's the original dtype.
|
403
|
+
#
|
404
|
+
def complex_conjugate(new_stype = self.stype)
|
405
|
+
self.cast(new_stype, NMatrix::upcast(dtype, :complex64)).complex_conjugate!
|
406
|
+
end
|
407
|
+
|
408
|
+
#
|
409
|
+
# call-seq:
|
410
|
+
# conjugate_transpose -> NMatrix
|
411
|
+
#
|
412
|
+
# Calculate the conjugate transpose of a matrix. If your dtype is already
|
413
|
+
# complex, this should only require one copy (for the transpose).
|
414
|
+
#
|
415
|
+
# * *Returns* :
|
416
|
+
# - The conjugate transpose of the matrix as a copy.
|
417
|
+
#
|
418
|
+
def conjugate_transpose
|
419
|
+
self.transpose.complex_conjugate!
|
420
|
+
end
|
421
|
+
|
422
|
+
#
|
423
|
+
# call-seq:
|
424
|
+
# absolute_sum -> Numeric
|
425
|
+
#
|
426
|
+
# == Arguments
|
427
|
+
# - +incx+ -> the skip size (defaults to 1, no skip)
|
428
|
+
# - +n+ -> the number of elements to include
|
429
|
+
#
|
430
|
+
# Return the sum of the contents of the vector. This is the BLAS asum routine.
|
431
|
+
def asum incx=1, n=nil
|
432
|
+
if self.shape == [1]
|
433
|
+
return self[0].abs unless self.complex_dtype?
|
434
|
+
return self[0].real.abs + self[0].imag.abs
|
435
|
+
end
|
436
|
+
return method_missing(:asum, incx, n) unless vector?
|
437
|
+
NMatrix::BLAS::asum(self, incx, self.size / incx)
|
438
|
+
end
|
439
|
+
alias :absolute_sum :asum
|
440
|
+
|
441
|
+
#
|
442
|
+
# call-seq:
|
443
|
+
# norm2 -> Numeric
|
444
|
+
#
|
445
|
+
# == Arguments
|
446
|
+
# - +incx+ -> the skip size (defaults to 1, no skip)
|
447
|
+
# - +n+ -> the number of elements to include
|
448
|
+
#
|
449
|
+
# Return the 2-norm of the vector. This is the BLAS nrm2 routine.
|
450
|
+
def nrm2 incx=1, n=nil
|
451
|
+
self.twoDMat.getFrobeniusNorm()
|
452
|
+
end
|
453
|
+
alias :norm2 :nrm2
|
454
|
+
|
455
|
+
#
|
456
|
+
# call-seq:
|
457
|
+
# scale! -> NMatrix
|
458
|
+
#
|
459
|
+
# == Arguments
|
460
|
+
# - +alpha+ -> Scalar value used in the operation.
|
461
|
+
# - +inc+ -> Increment used in the scaling function. Should generally be 1.
|
462
|
+
# - +n+ -> Number of elements of +vector+.
|
463
|
+
#
|
464
|
+
# This is a destructive method, modifying the source NMatrix. See also #scale.
|
465
|
+
# Return the scaling result of the matrix. BLAS scal will be invoked if provided.
|
466
|
+
|
467
|
+
def scale!(alpha, incx=1, n=nil)
|
468
|
+
#FIXME
|
469
|
+
# raise(DataTypeError, "Incompatible data type for the scaling factor") unless
|
470
|
+
# NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype
|
471
|
+
raise(DataTypeError, "Incompatible data type for the scaling factor") if
|
472
|
+
self.dtype == :int8
|
473
|
+
@s.mapMultiplyToSelf(alpha)
|
474
|
+
return self
|
475
|
+
end
|
476
|
+
|
477
|
+
#
|
478
|
+
# call-seq:
|
479
|
+
# scale -> NMatrix
|
480
|
+
#
|
481
|
+
# == Arguments
|
482
|
+
# - +alpha+ -> Scalar value used in the operation.
|
483
|
+
# - +inc+ -> Increment used in the scaling function. Should generally be 1.
|
484
|
+
# - +n+ -> Number of elements of +vector+.
|
485
|
+
#
|
486
|
+
# Return the scaling result of the matrix. BLAS scal will be invoked if provided.
|
487
|
+
|
488
|
+
def scale(alpha, incx=1, n=nil)
|
489
|
+
# FIXME
|
490
|
+
# raise(DataTypeError, "Incompatible data type for the scaling factor") unless
|
491
|
+
# NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype
|
492
|
+
raise(DataTypeError, "Incompatible data type for the scaling factor") if
|
493
|
+
self.dtype == :byte || self.dtype == :int8 || self.dtype == :int16 ||
|
494
|
+
self.dtype == :int32 || self.dtype == :int64
|
495
|
+
nmatrix = NMatrix.new :copy
|
496
|
+
nmatrix.shape = @shape.clone
|
497
|
+
nmatrix.s = ArrayRealVector.new(@s.toArray.clone).mapMultiplyToSelf(alpha)
|
498
|
+
return nmatrix
|
499
|
+
end
|
500
|
+
|
501
|
+
end
|