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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +24 -0
  3. data/ext/g2c_typedefs.h +5 -0
  4. data/ext/lapack/extconf.rb +309 -0
  5. data/ext/lapack/include/BLAS.h +154 -0
  6. data/ext/lapack/include/LAPACK.h +1314 -0
  7. data/ext/lapack/main.c +49 -0
  8. data/ext/lapack/rb_lapack.h +36 -0
  9. data/ext/lapack/rb_lapack_c.c +11614 -0
  10. data/ext/lapack/rb_lapack_d.c +12663 -0
  11. data/ext/lapack/rb_lapack_s.c +12649 -0
  12. data/ext/lapack/rb_lapack_x.c +208 -0
  13. data/ext/lapack/rb_lapack_z.c +11614 -0
  14. data/ext/linalg/dcomplex.c +359 -0
  15. data/ext/linalg/dcomplex.h +40 -0
  16. data/ext/linalg/ddata.c +194 -0
  17. data/ext/linalg/extconf.rb +324 -0
  18. data/ext/linalg/linalg.c +55 -0
  19. data/ext/linalg/linalg.h +21 -0
  20. data/ext/linalg/xdata.c +21 -0
  21. data/ext/linalg/xdata.h +33 -0
  22. data/ext/linalg/xmatrix.c.tmpl +1630 -0
  23. data/ext/linalg/xmatrix.h.tmpl +77 -0
  24. data/ext/linalg/xmatrixc.c.tmpl +138 -0
  25. data/ext/linalg/xmatrixr.c.tmpl +130 -0
  26. data/lib/lapack.rb +87 -0
  27. data/lib/linalg.rb +9 -0
  28. data/lib/linalg/dcomplex.rb +17 -0
  29. data/lib/linalg/dmatrix.rb +29 -0
  30. data/lib/linalg/dmatrix/alias.rb +32 -0
  31. data/lib/linalg/dmatrix/cholesky.rb +52 -0
  32. data/lib/linalg/dmatrix/cond.rb +80 -0
  33. data/lib/linalg/dmatrix/det.rb +36 -0
  34. data/lib/linalg/dmatrix/eigen.rb +153 -0
  35. data/lib/linalg/dmatrix/fit.rb +281 -0
  36. data/lib/linalg/dmatrix/inverse.rb +78 -0
  37. data/lib/linalg/dmatrix/lu.rb +120 -0
  38. data/lib/linalg/dmatrix/main.rb +244 -0
  39. data/lib/linalg/dmatrix/norms.rb +88 -0
  40. data/lib/linalg/dmatrix/nullspace.rb +114 -0
  41. data/lib/linalg/dmatrix/qr.rb +129 -0
  42. data/lib/linalg/dmatrix/schur.rb +88 -0
  43. data/lib/linalg/dmatrix/solve.rb +78 -0
  44. data/lib/linalg/dmatrix/svd.rb +125 -0
  45. data/lib/linalg/exception.rb +32 -0
  46. data/lib/linalg/iterators.rb +221 -0
  47. data/lib/linalg/math.rb +23 -0
  48. data/lib/linalg/scomplex.rb +15 -0
  49. data/lib/linalg/version.rb +3 -0
  50. data/lib/linalg/xdata.rb +123 -0
  51. 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
+