linalg 1.0.2
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 +7 -0
- data/LICENSE +24 -0
- data/ext/g2c_typedefs.h +5 -0
- data/ext/lapack/extconf.rb +309 -0
- data/ext/lapack/include/BLAS.h +154 -0
- data/ext/lapack/include/LAPACK.h +1314 -0
- data/ext/lapack/main.c +49 -0
- data/ext/lapack/rb_lapack.h +36 -0
- data/ext/lapack/rb_lapack_c.c +11614 -0
- data/ext/lapack/rb_lapack_d.c +12663 -0
- data/ext/lapack/rb_lapack_s.c +12649 -0
- data/ext/lapack/rb_lapack_x.c +208 -0
- data/ext/lapack/rb_lapack_z.c +11614 -0
- data/ext/linalg/dcomplex.c +359 -0
- data/ext/linalg/dcomplex.h +40 -0
- data/ext/linalg/ddata.c +194 -0
- data/ext/linalg/extconf.rb +324 -0
- data/ext/linalg/linalg.c +55 -0
- data/ext/linalg/linalg.h +21 -0
- data/ext/linalg/xdata.c +21 -0
- data/ext/linalg/xdata.h +33 -0
- data/ext/linalg/xmatrix.c.tmpl +1630 -0
- data/ext/linalg/xmatrix.h.tmpl +77 -0
- data/ext/linalg/xmatrixc.c.tmpl +138 -0
- data/ext/linalg/xmatrixr.c.tmpl +130 -0
- data/lib/lapack.rb +87 -0
- data/lib/linalg.rb +9 -0
- data/lib/linalg/dcomplex.rb +17 -0
- data/lib/linalg/dmatrix.rb +29 -0
- data/lib/linalg/dmatrix/alias.rb +32 -0
- data/lib/linalg/dmatrix/cholesky.rb +52 -0
- data/lib/linalg/dmatrix/cond.rb +80 -0
- data/lib/linalg/dmatrix/det.rb +36 -0
- data/lib/linalg/dmatrix/eigen.rb +153 -0
- data/lib/linalg/dmatrix/fit.rb +281 -0
- data/lib/linalg/dmatrix/inverse.rb +78 -0
- data/lib/linalg/dmatrix/lu.rb +120 -0
- data/lib/linalg/dmatrix/main.rb +244 -0
- data/lib/linalg/dmatrix/norms.rb +88 -0
- data/lib/linalg/dmatrix/nullspace.rb +114 -0
- data/lib/linalg/dmatrix/qr.rb +129 -0
- data/lib/linalg/dmatrix/schur.rb +88 -0
- data/lib/linalg/dmatrix/solve.rb +78 -0
- data/lib/linalg/dmatrix/svd.rb +125 -0
- data/lib/linalg/exception.rb +32 -0
- data/lib/linalg/iterators.rb +221 -0
- data/lib/linalg/math.rb +23 -0
- data/lib/linalg/scomplex.rb +15 -0
- data/lib/linalg/version.rb +3 -0
- data/lib/linalg/xdata.rb +123 -0
- metadata +94 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'linalg'
|
8
|
+
|
9
|
+
require 'linalg/exception'
|
10
|
+
require 'linalg/math'
|
11
|
+
require 'linalg/iterators'
|
12
|
+
require 'linalg/xdata'
|
13
|
+
|
14
|
+
require 'linalg/dmatrix/main'
|
15
|
+
require 'linalg/dmatrix/qr'
|
16
|
+
require 'linalg/dmatrix/cholesky'
|
17
|
+
require 'linalg/dmatrix/fit'
|
18
|
+
require 'linalg/dmatrix/schur'
|
19
|
+
require 'linalg/dmatrix/svd'
|
20
|
+
require 'linalg/dmatrix/lu'
|
21
|
+
require 'linalg/dmatrix/cond'
|
22
|
+
require 'linalg/dmatrix/nullspace'
|
23
|
+
require 'linalg/dmatrix/solve'
|
24
|
+
require 'linalg/dmatrix/eigen'
|
25
|
+
require 'linalg/dmatrix/inverse'
|
26
|
+
require 'linalg/dmatrix/norms'
|
27
|
+
require 'linalg/dmatrix/det'
|
28
|
+
require 'linalg/dmatrix/alias'
|
29
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
module Linalg
|
8
|
+
class DMatrix
|
9
|
+
alias_method :mul!, :postmul!
|
10
|
+
alias_method :t, :transpose
|
11
|
+
alias_method :inv, :inverse
|
12
|
+
alias_method :det, :determinant
|
13
|
+
alias_method :col, :column
|
14
|
+
alias_method :svd, :singular_value_decomposition
|
15
|
+
alias_method :sv, :singular_values
|
16
|
+
alias_method :chol, :cholesky
|
17
|
+
alias_method :nrow, :vsize
|
18
|
+
alias_method :num_rows, :vsize
|
19
|
+
alias_method :ncol, :hsize
|
20
|
+
alias_method :num_columns, :hsize
|
21
|
+
alias_method :pinv, :pseudo_inverse
|
22
|
+
alias_method :orth, :rankspace
|
23
|
+
alias_method :norm, :norm_2
|
24
|
+
alias_method :column_norm, :norm_1
|
25
|
+
alias_method :row_norm, :norm_inf
|
26
|
+
alias_method :frobenius_norm, :norm_f
|
27
|
+
|
28
|
+
private :symmetric_private
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
module Linalg
|
9
|
+
class DMatrix
|
10
|
+
#
|
11
|
+
# call-seq:
|
12
|
+
# cholesky => u
|
13
|
+
# cholesky { |u| ... } => block result
|
14
|
+
#
|
15
|
+
# Given a symmetric positive definite matrix +m+, gives
|
16
|
+
# an upper-triangular matrix +u+ such that
|
17
|
+
# u.t * u
|
18
|
+
# is equal to +m+.
|
19
|
+
#
|
20
|
+
# Only the upper-triangular portion of +m+ is considered
|
21
|
+
# for the algorithm.
|
22
|
+
#
|
23
|
+
# Raises +Diverged+ if +m+ was not positive definite.
|
24
|
+
#
|
25
|
+
def cholesky # :yields: u
|
26
|
+
raise DimensionError unless square?
|
27
|
+
uplo = Char.new "U"
|
28
|
+
n = XInteger.new vsize
|
29
|
+
a = self.clone
|
30
|
+
lda = n
|
31
|
+
info = XInteger.new
|
32
|
+
|
33
|
+
Lapack.dpotrf(uplo,
|
34
|
+
n,
|
35
|
+
a,
|
36
|
+
lda,
|
37
|
+
info)
|
38
|
+
|
39
|
+
raise Diverged unless info.value == 0
|
40
|
+
|
41
|
+
a.zero_lower
|
42
|
+
|
43
|
+
if block_given?
|
44
|
+
yield a
|
45
|
+
else
|
46
|
+
a
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
module Linalg
|
9
|
+
class DMatrix
|
10
|
+
#
|
11
|
+
# The condition number. Ratio of the largest singular value to
|
12
|
+
# the smallest.
|
13
|
+
#
|
14
|
+
def cond
|
15
|
+
s = singular_values
|
16
|
+
begin
|
17
|
+
c = s[0]/s[s.vsize-1]
|
18
|
+
c.nan? ? 1.0/0.0 : c
|
19
|
+
rescue SingularMatrix
|
20
|
+
1.0/0.0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Estimate the condition number using the
|
26
|
+
# 1-norm. Seems to be within an order of magnitude.
|
27
|
+
#
|
28
|
+
def cond_est_1
|
29
|
+
begin
|
30
|
+
1.0/rcond_private(:col)
|
31
|
+
rescue SingularMatrix
|
32
|
+
1.0/0.0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Estimate the condition number using the
|
38
|
+
# infinity-norm. Seems to be within an order of magnitude.
|
39
|
+
#
|
40
|
+
def cond_est_inf
|
41
|
+
begin
|
42
|
+
1.0/rcond_private(:row)
|
43
|
+
rescue SingularMatrix
|
44
|
+
1.0/0.0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def rcond_private(which)
|
51
|
+
raise DimensionError unless square?
|
52
|
+
|
53
|
+
norm = (which == :col) ? Char.new("1") : Char.new("I")
|
54
|
+
n = XInteger.new vsize
|
55
|
+
a = self.clone
|
56
|
+
a.lu!
|
57
|
+
lda = n
|
58
|
+
anorm = DData.new(1) {
|
59
|
+
(which == :col) ? a.column_norm : a.row_norm
|
60
|
+
}
|
61
|
+
rcond = DReal.new
|
62
|
+
work = DData.new(4*n.value)
|
63
|
+
iwork = IData.new(n.value)
|
64
|
+
info = XInteger.new
|
65
|
+
|
66
|
+
Lapack.dgecon(norm,
|
67
|
+
n,
|
68
|
+
a,
|
69
|
+
lda,
|
70
|
+
anorm,
|
71
|
+
rcond,
|
72
|
+
work,
|
73
|
+
iwork,
|
74
|
+
info)
|
75
|
+
rcond[0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
module Linalg
|
9
|
+
class DMatrix
|
10
|
+
|
11
|
+
#
|
12
|
+
# Returns the determinant of the matrix. Raises
|
13
|
+
# +DimensionError+ if the matrix is not square.
|
14
|
+
#
|
15
|
+
def determinant
|
16
|
+
raise DimensionError unless square?
|
17
|
+
begin
|
18
|
+
a = self.clone
|
19
|
+
ipiv = a.lu!
|
20
|
+
res = 1.0
|
21
|
+
sign = 1
|
22
|
+
vsize.times { |i|
|
23
|
+
res *= a[i,i]
|
24
|
+
|
25
|
+
# 1-based fortran
|
26
|
+
if ipiv[i] != i + 1
|
27
|
+
sign *= -1
|
28
|
+
end
|
29
|
+
}
|
30
|
+
res*sign
|
31
|
+
rescue SingularMatrix
|
32
|
+
0.0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Linalg
|
10
|
+
class DMatrix
|
11
|
+
|
12
|
+
#
|
13
|
+
# call-seq:
|
14
|
+
# eigensystem => [eigvs, real, imag]
|
15
|
+
# eigensystem { |eigvs, real, imag| ... } => block result
|
16
|
+
#
|
17
|
+
# Find the eigenvectors and eigenvalues of the matrix.
|
18
|
+
#
|
19
|
+
# The columns of +eigvs+ hold the eigenvectors; the column vectors
|
20
|
+
# +real+ and +imag+ hold the eigenvalues.
|
21
|
+
#
|
22
|
+
# Stepping through the eigenvalues in succession starting from the
|
23
|
+
# beginning, one will encounter either a real eigenvalue or a complex
|
24
|
+
# conjugate pair. That is, either the imaginary part will be exactly
|
25
|
+
# equal to zero
|
26
|
+
#
|
27
|
+
# imag[n] == 0.0
|
28
|
+
#
|
29
|
+
# or there will be a conjugate pair with the following exactly equal,
|
30
|
+
#
|
31
|
+
# real[n] == real[n+1]
|
32
|
+
# imag[n] == -imag[n+1]
|
33
|
+
#
|
34
|
+
# In the former case, the real eigenvector
|
35
|
+
#
|
36
|
+
# eigvs.column(n)
|
37
|
+
#
|
38
|
+
# corresponds to the real eigenvalue
|
39
|
+
#
|
40
|
+
# real[n]
|
41
|
+
#
|
42
|
+
# In the latter case, the complex eigenvector
|
43
|
+
#
|
44
|
+
# eigvs.column(n) + i*eigvs.column(n+1)
|
45
|
+
#
|
46
|
+
# corresponds to the complex eigenvalue
|
47
|
+
#
|
48
|
+
# real[n] + i*imag[n]
|
49
|
+
#
|
50
|
+
# and the conjugate eigenvector
|
51
|
+
#
|
52
|
+
# eigvs.column(n) - i*eigvs.column(n+1)
|
53
|
+
#
|
54
|
+
# corresponds to the conjugate eigenvalue
|
55
|
+
#
|
56
|
+
# real[n] - i*imag[n]
|
57
|
+
#
|
58
|
+
# for <tt>i = sqrt(-1)</tt>.
|
59
|
+
#
|
60
|
+
# The eigenvectors are each given unit length with largest component
|
61
|
+
# real.
|
62
|
+
#
|
63
|
+
# Raises +DimensionError+ if the given matrix is not square. May
|
64
|
+
# raise +Diverged+.
|
65
|
+
#
|
66
|
+
def eigensystem(&b)
|
67
|
+
eigen_private(true, &b)
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# call-seq:
|
72
|
+
# eigenvalues => [real, imag]
|
73
|
+
# eigenvalues { |real, imag| ... } => block result
|
74
|
+
#
|
75
|
+
# Returns the eigenvalues. See DMatrix#eigensystem for the format in
|
76
|
+
# which eigenvalues are returned.
|
77
|
+
#
|
78
|
+
def eigenvalues(&b)
|
79
|
+
eigen_private(false, &b)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def eigen_private(vecs)
|
85
|
+
raise DimensionError unless square?
|
86
|
+
|
87
|
+
jobvl = Char.new("N")
|
88
|
+
jobvr = Char.new(vecs ? "V" : "N")
|
89
|
+
n = XInteger.new(vsize)
|
90
|
+
a = self.clone
|
91
|
+
lda = XInteger.new(n.value)
|
92
|
+
wr = DMatrix.reserve(n.value, 1)
|
93
|
+
wi = DMatrix.reserve(n.value, 1)
|
94
|
+
vl = XData::NULL
|
95
|
+
ldvl = XInteger.new(1)
|
96
|
+
vr = DMatrix.reserve(n.value, n.value)
|
97
|
+
ldvr = XInteger.new(n.value)
|
98
|
+
work = DReal.new # query
|
99
|
+
lwork = XInteger.new(-1) # query
|
100
|
+
info = XInteger.new
|
101
|
+
|
102
|
+
# query
|
103
|
+
Lapack.dgeev(jobvl,
|
104
|
+
jobvr,
|
105
|
+
n,
|
106
|
+
a,
|
107
|
+
lda,
|
108
|
+
wr,
|
109
|
+
wi,
|
110
|
+
vl,
|
111
|
+
ldvl,
|
112
|
+
vr,
|
113
|
+
ldvr,
|
114
|
+
work,
|
115
|
+
lwork,
|
116
|
+
info)
|
117
|
+
|
118
|
+
raise Diverged unless info.value == 0
|
119
|
+
lwork = XInteger.new(work.value.to_i)
|
120
|
+
work = DData.new(lwork.value)
|
121
|
+
|
122
|
+
Lapack.dgeev(jobvl,
|
123
|
+
jobvr,
|
124
|
+
n,
|
125
|
+
a,
|
126
|
+
lda,
|
127
|
+
wr,
|
128
|
+
wi,
|
129
|
+
vl,
|
130
|
+
ldvl,
|
131
|
+
vr,
|
132
|
+
ldvr,
|
133
|
+
work,
|
134
|
+
lwork,
|
135
|
+
info)
|
136
|
+
|
137
|
+
raise Diverged unless info.value == 0
|
138
|
+
|
139
|
+
if vecs
|
140
|
+
res = [vr, wr, wi]
|
141
|
+
else
|
142
|
+
res = [wr, wi]
|
143
|
+
end
|
144
|
+
|
145
|
+
if block_given?
|
146
|
+
yield res
|
147
|
+
else
|
148
|
+
res
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
@@ -0,0 +1,281 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2004-2008 by James M. Lawrence
|
3
|
+
#
|
4
|
+
# See LICENSE
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
module Linalg
|
9
|
+
class DMatrix
|
10
|
+
#
|
11
|
+
# Pseudo-inverse.
|
12
|
+
#
|
13
|
+
# For matrix +m+, find +x+ which minimizes
|
14
|
+
# (m*x - DMatrix.identity(m.vsize)).norm
|
15
|
+
#
|
16
|
+
def pseudo_inverse(epsilon = nil)
|
17
|
+
DMatrix.fit(self, DMatrix.identity(vsize), epsilon)[0]
|
18
|
+
end
|
19
|
+
|
20
|
+
# call-seq:
|
21
|
+
# fit(a, b, epsilon = nil) => x
|
22
|
+
# fit(a, b, epsilon = nil) { |x| ... } => block value
|
23
|
+
#
|
24
|
+
# Least squares minimization using QR factorization.
|
25
|
+
#
|
26
|
+
# Find +x+ for which
|
27
|
+
# (a*x - b).norm_2
|
28
|
+
# is a minimum.
|
29
|
+
#
|
30
|
+
# Assumes a matrix of full rank.
|
31
|
+
#
|
32
|
+
def self.fit(a, b)
|
33
|
+
raise DimensionError unless a.vsize == b.vsize
|
34
|
+
b_in = b
|
35
|
+
|
36
|
+
trans = Char.new("N")
|
37
|
+
m = XInteger.new(a.vsize)
|
38
|
+
n = XInteger.new(a.hsize)
|
39
|
+
nrhs = XInteger.new(b.hsize)
|
40
|
+
a = a.clone
|
41
|
+
lda = XInteger.new(a.vsize)
|
42
|
+
b = DMatrix.new(Math.max(m.value, n.value),
|
43
|
+
nrhs.value).replace_minor(0, 0, b_in)
|
44
|
+
ldb = XInteger.new(b.vsize)
|
45
|
+
work = DReal.new # query
|
46
|
+
lwork = XInteger.new(-1) # query
|
47
|
+
info = XInteger.new
|
48
|
+
|
49
|
+
# query
|
50
|
+
Lapack.dgels(trans,
|
51
|
+
m,
|
52
|
+
n,
|
53
|
+
nrhs,
|
54
|
+
a,
|
55
|
+
lda,
|
56
|
+
b,
|
57
|
+
ldb,
|
58
|
+
work,
|
59
|
+
lwork,
|
60
|
+
info)
|
61
|
+
|
62
|
+
raise Diverged unless info.value == 0
|
63
|
+
lwork = XInteger.new(work.value.to_i)
|
64
|
+
work = DData.new(lwork.value)
|
65
|
+
|
66
|
+
Lapack.dgels(trans,
|
67
|
+
m,
|
68
|
+
n,
|
69
|
+
nrhs,
|
70
|
+
a,
|
71
|
+
lda,
|
72
|
+
b,
|
73
|
+
ldb,
|
74
|
+
work,
|
75
|
+
lwork,
|
76
|
+
info)
|
77
|
+
|
78
|
+
raise Diverged unless info.value == 0
|
79
|
+
|
80
|
+
x = b.minor(0, 0, n.value, nrhs.value)
|
81
|
+
if block_given?
|
82
|
+
yield x
|
83
|
+
else
|
84
|
+
x
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
#
|
91
|
+
# call-seq:
|
92
|
+
# fit(a, b) => [x, sv, rank]
|
93
|
+
# fit(a, b) { |x, sv, rank| ... } => block value
|
94
|
+
#
|
95
|
+
# Least squares minimization using singular value decomposition
|
96
|
+
# in conjunction with householder transformations.
|
97
|
+
# Rank deficiency is allowed.
|
98
|
+
#
|
99
|
+
# Find +x+ for which
|
100
|
+
# (a*x - b).norm
|
101
|
+
# is a minimum. (+norm+ is the 2-norm.)
|
102
|
+
#
|
103
|
+
# Also returns the singular values +sv+ and the +rank+.
|
104
|
+
#
|
105
|
+
# For matrix +m+, a singular value less than or equal to
|
106
|
+
# <tt>m.norm*epsilon</tt> is considered a rank deficiency. An
|
107
|
+
# +epsilon+ of +nil+ (default) specifies machine precision.
|
108
|
+
#
|
109
|
+
# Disabled. Crash from a tester.
|
110
|
+
#
|
111
|
+
def self.fit_svdhh(a, b, epsilon = nil) # :yields: x, sv, rank
|
112
|
+
raise DimensionError unless a.vsize == b.vsize
|
113
|
+
b_in = b
|
114
|
+
|
115
|
+
m = XInteger.new(a.vsize)
|
116
|
+
n = XInteger.new(a.hsize)
|
117
|
+
nrhs = XInteger.new(b.hsize)
|
118
|
+
a = a.clone
|
119
|
+
lda = XInteger.new(a.vsize)
|
120
|
+
b = nil
|
121
|
+
ldb = XInteger.new(Math.max(m.value, n.value))
|
122
|
+
b = DMatrix.new(ldb.value, nrhs.value)
|
123
|
+
b.replace_minor(0, 0, b_in)
|
124
|
+
s = DMatrix.new(Math.min(m.value, n.value), 1)
|
125
|
+
rcond = DReal.new(epsilon ? epsilon : -1.0)
|
126
|
+
rank = XInteger.new
|
127
|
+
work = DReal.new # query
|
128
|
+
lwork = XInteger.new(-1) # query
|
129
|
+
# iwork defined below
|
130
|
+
info = XInteger.new
|
131
|
+
|
132
|
+
###################################
|
133
|
+
# ilaenv
|
134
|
+
###################################
|
135
|
+
ary_name = "dgelsd".split("")
|
136
|
+
|
137
|
+
ispec = XInteger.new(9)
|
138
|
+
name = CharData.new(ary_name.size) { |i| ary_name[i] }
|
139
|
+
opts = Char.new("N")
|
140
|
+
nX = XInteger.new(0)
|
141
|
+
smlsiz = Lapack.ilaenv(ispec,
|
142
|
+
name,
|
143
|
+
opts,
|
144
|
+
nX,
|
145
|
+
nX,
|
146
|
+
nX,
|
147
|
+
nX)
|
148
|
+
raise "ilaenv: bad parameter #{-smlsiz}" if smlsiz < 0
|
149
|
+
|
150
|
+
###################################
|
151
|
+
# iwork
|
152
|
+
###################################
|
153
|
+
minmn = Math.min(m.value, n.value)
|
154
|
+
nlvl = Math.max(0, (Math.log2(minmn.to_f/(smlsiz + 1))).to_i + 1)
|
155
|
+
iwork = IData.new(3*minmn*nlvl + 11*minmn)
|
156
|
+
|
157
|
+
###################################
|
158
|
+
# dgesld
|
159
|
+
###################################
|
160
|
+
|
161
|
+
# query
|
162
|
+
Lapack.dgelsd(m,
|
163
|
+
n,
|
164
|
+
nrhs,
|
165
|
+
a,
|
166
|
+
lda,
|
167
|
+
b,
|
168
|
+
ldb,
|
169
|
+
s,
|
170
|
+
rcond,
|
171
|
+
rank,
|
172
|
+
work,
|
173
|
+
lwork,
|
174
|
+
iwork,
|
175
|
+
info)
|
176
|
+
|
177
|
+
raise Diverged unless info.value == 0
|
178
|
+
lwork = XInteger.new(work.value.to_i)
|
179
|
+
work = DData.new(lwork.value)
|
180
|
+
|
181
|
+
Lapack.dgelsd(m,
|
182
|
+
n,
|
183
|
+
nrhs,
|
184
|
+
a,
|
185
|
+
lda,
|
186
|
+
b,
|
187
|
+
ldb,
|
188
|
+
s,
|
189
|
+
rcond,
|
190
|
+
rank,
|
191
|
+
work,
|
192
|
+
lwork,
|
193
|
+
iwork,
|
194
|
+
info)
|
195
|
+
|
196
|
+
raise Diverged unless info.value == 0
|
197
|
+
|
198
|
+
res = [b.minor(0, 0, n.value, nrhs.value), s, rank.value]
|
199
|
+
if block_given?
|
200
|
+
yield res
|
201
|
+
else
|
202
|
+
res
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# call-seq:
|
208
|
+
# fit_svd(a, b) => [x, sv, rank]
|
209
|
+
# fit_svd(a, b) { |x, sv, rank| ... } => block value
|
210
|
+
#
|
211
|
+
# Least squares minimization with posible rank deficiency.
|
212
|
+
# Uses singular value decomposition.
|
213
|
+
#
|
214
|
+
# Disabled. Crash for unknown reason.
|
215
|
+
#
|
216
|
+
def self.fit_svd2(a, b)
|
217
|
+
raise DimensionError unless a.vsize == b.vsize
|
218
|
+
b_in = b
|
219
|
+
|
220
|
+
m = XInteger.new a.vsize
|
221
|
+
n = XInteger.new a.hsize
|
222
|
+
nrhs = XInteger.new b.hsize
|
223
|
+
a = a.clone
|
224
|
+
lda = XInteger.new a.vsize
|
225
|
+
# b
|
226
|
+
ldb = XInteger.new Math.max(m.value, n.value)
|
227
|
+
b = DMatrix.new(ldb.value, nrhs.value)
|
228
|
+
b.replace_minor(0, 0, b_in)
|
229
|
+
s = DMatrix.new(Math.min(m.value, n.value), 1)
|
230
|
+
rcond = DReal.new(-1.0) # use machine precision
|
231
|
+
rank = XInteger.new
|
232
|
+
work = DReal.new # query
|
233
|
+
lwork = XInteger.new(-1) # query
|
234
|
+
info = XInteger.new
|
235
|
+
|
236
|
+
# query
|
237
|
+
Lapack.dgelss(m,
|
238
|
+
n,
|
239
|
+
nrhs,
|
240
|
+
a,
|
241
|
+
lda,
|
242
|
+
b,
|
243
|
+
ldb,
|
244
|
+
s,
|
245
|
+
rcond,
|
246
|
+
rank,
|
247
|
+
work,
|
248
|
+
lwork,
|
249
|
+
info)
|
250
|
+
|
251
|
+
raise Diverged unless info.value == 0
|
252
|
+
lwork = XInteger.new(work.value.to_i)
|
253
|
+
work = DData.new(lwork.value)
|
254
|
+
|
255
|
+
Lapack.dgelss(m,
|
256
|
+
n,
|
257
|
+
nrhs,
|
258
|
+
a,
|
259
|
+
lda,
|
260
|
+
b,
|
261
|
+
ldb,
|
262
|
+
s,
|
263
|
+
rcond,
|
264
|
+
rank,
|
265
|
+
work,
|
266
|
+
lwork,
|
267
|
+
info)
|
268
|
+
|
269
|
+
raise Diverged unless info.value == 0
|
270
|
+
|
271
|
+
res = [b.minor(0, 0, a.hsize, b.hsize), s, rank.value]
|
272
|
+
if block_given?
|
273
|
+
yield res
|
274
|
+
else
|
275
|
+
res
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|