linalg 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,78 @@
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
+ # call-seq: inverse
13
+ #
14
+ # Matrix inverse. Raises +SingularMatrix+ if the matrix is
15
+ # singular.
16
+ #
17
+ def inverse
18
+ inverse_private(false)
19
+ end
20
+
21
+ #
22
+ # call-seq: inverse!
23
+ #
24
+ # In-place matrix inverse. Raises +SingularMatrix+ if the matrix is
25
+ # singular.
26
+ #
27
+ # a.object_id == a.inverse!.object_id
28
+ #
29
+ def inverse!
30
+ inverse_private(true)
31
+ end
32
+
33
+ private
34
+
35
+ def inverse_private(inplace)
36
+ raise DimensionError unless square?
37
+
38
+ m = XInteger.new(vsize)
39
+ n = m
40
+ a = inplace ? self : self.clone
41
+ lda = XInteger.new(n.value)
42
+ ipiv = IData.new(n.value)
43
+ info = XInteger.new
44
+
45
+ Lapack.dgetrf(m,
46
+ n,
47
+ a,
48
+ lda,
49
+ ipiv,
50
+ info)
51
+
52
+ raise SingularMatrix unless info.value == 0
53
+ work = DReal.new # query
54
+ lwork = XInteger.new(-1) # query
55
+
56
+ Lapack.dgetri(n,
57
+ a,
58
+ lda,
59
+ ipiv,
60
+ work,
61
+ lwork,
62
+ info)
63
+
64
+ raise SingularMatrix unless info.value == 0
65
+ lwork = XInteger.new(work.value.to_i)
66
+ work = DData.new(lwork.value)
67
+
68
+ Lapack.dgetri(n,
69
+ a,
70
+ lda,
71
+ ipiv,
72
+ work,
73
+ lwork,
74
+ info)
75
+ a
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,120 @@
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
+ # lu => [p, l, u]
13
+ # lu { |p, l, u| ... } => block result
14
+ #
15
+ # Generalized LU decomposition for rectangular matrices.
16
+ # The matrix is decomposed into
17
+ #
18
+ # p * l * u
19
+ #
20
+ # where +p+ is a permutation matrix, +l+ lower-triangular
21
+ # (or lower-trapezoidal), and +u+ is upper-triangular (or
22
+ # upper-trapezoidal).
23
+ #
24
+ def lu # :yields: p, l, u
25
+ res = lu_private(false)
26
+ if block_given?
27
+ yield res
28
+ else
29
+ res
30
+ end
31
+ end
32
+
33
+ #
34
+ # call-seq:
35
+ # lu! => p
36
+ #
37
+ # In-place LU decomposition. The matrix is overwritten with
38
+ # both L and U factors (the diagonal 1's of L are discarded).
39
+ # Returns the vector +p+ of pivots.
40
+ #
41
+ def lu!
42
+ lu_private(true)
43
+ end
44
+
45
+ def zero_lower # :nodoc:
46
+ if vsize > hsize
47
+ hsize
48
+ else
49
+ vsize - 1
50
+ end.times { |j|
51
+ replace_minor(j + 1, j, DMatrix.new(vsize - j - 1, 1))
52
+ }
53
+ self
54
+ end
55
+
56
+ def zero_upper # :nodoc:
57
+ # triangular portion
58
+ (1...Math.min(vsize, hsize)).each { |j|
59
+ replace_minor(0, j, DMatrix.new(j, 1))
60
+ }
61
+
62
+ if hsize > vsize
63
+ # remaining
64
+ replace_minor(0, hsize, hsize - vsize, vsize)
65
+ end
66
+
67
+ self
68
+ end
69
+
70
+ private
71
+
72
+ def lu_private(inplace)
73
+ minsize = Math.min(vsize, hsize)
74
+
75
+ m = XInteger.new vsize
76
+ n = XInteger.new hsize
77
+ a = inplace ? self : self.clone
78
+ lda = m
79
+ ipiv = IData.new minsize
80
+ info = XInteger.new
81
+
82
+ Lapack.dgetrf(m,
83
+ n,
84
+ a,
85
+ lda,
86
+ ipiv,
87
+ info)
88
+
89
+ raise SingularMatrix unless info.value == 0
90
+
91
+ if inplace
92
+ ipiv
93
+ else
94
+ p = DMatrix.identity(vsize)
95
+ if vsize > hsize
96
+ uvsize, uhsize = [minsize, minsize]
97
+ lvsize, lhsize = [vsize, hsize]
98
+ else
99
+ uvsize, uhsize = [vsize, hsize]
100
+ lvsize, lhsize = [minsize, minsize]
101
+ end
102
+
103
+ ipiv.each_with_index { |e, i|
104
+ # 1-based fortran
105
+ if i != e - 1
106
+ p.exchange_columns(i, e - 1)
107
+ end
108
+ }
109
+
110
+ l = a.minor(0, 0, lvsize, lhsize).zero_upper
111
+ minsize.times { |i| l[i, i] = 1.0 }
112
+ u = a.minor(0, 0, uvsize, uhsize).zero_lower
113
+
114
+ [p, l, u]
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+
@@ -0,0 +1,244 @@
1
+ #
2
+ # Copyright (c) 2004-2008 by James M. Lawrence
3
+ #
4
+ # See LICENSE
5
+ #
6
+
7
+ module Linalg
8
+
9
+ class DMatrix
10
+ include Iterators
11
+
12
+ include XData # :nodoc:
13
+ include Linalg::Exception # :nodoc:
14
+
15
+
16
+ ##################################################
17
+ #
18
+ # singleton methods
19
+ #
20
+ ##################################################
21
+
22
+ #
23
+ # Create a matrix by joining together a list of column vectors
24
+ #
25
+ # m == DMatrix.join_columns(m.columns.map { |x| x })
26
+ #
27
+ def self.join_columns(cols)
28
+ col_vsize = cols[0].vsize
29
+ res = DMatrix.reserve(col_vsize, cols.size)
30
+ cols.each_with_index { |col, j|
31
+ unless col.vsize == col_vsize
32
+ raise DimensionError
33
+ end
34
+ res.replace_column(j, col)
35
+ }
36
+ res
37
+ end
38
+
39
+ #
40
+ # Create a matrix by joining together a list of row vectors
41
+ #
42
+ # m == DMatrix.join_rows(m.rows.map { |x| x })
43
+ #
44
+ def self.join_rows(rows)
45
+ row_hsize = rows[0].hsize
46
+ res = DMatrix.reserve(rows.size, row_hsize)
47
+ rows.each_with_index { |row, i|
48
+ unless row.hsize == row_hsize
49
+ raise DimensionError
50
+ end
51
+ res.replace_row(i, row)
52
+ }
53
+ res
54
+ end
55
+
56
+ #
57
+ # calls DMatrix.rows with a splat (*)
58
+ #
59
+ # DMatrix[[1,2,3],[4,5,6]]
60
+ # is equivalent to
61
+ # DMatrix.rows [[1,2,3],[4,5,6]]
62
+ #
63
+ def self.[](*array)
64
+ self.rows(array)
65
+ end
66
+
67
+ #
68
+ # Create a matrix using the elements of +array+ as columns.
69
+ #
70
+ # DMatrix.columns(array)
71
+ # is equivalent to
72
+ # DMatrix.new(array[0].size, array.size) { |i,j| array[j][i] }
73
+ #
74
+ # +DimensionError+ is raised if +array+ is not rectangular.
75
+ #
76
+ def self.columns(array)
77
+ self.rows(array).transpose!
78
+ end
79
+
80
+ class << self
81
+ attr_accessor :default_epsilon
82
+ end
83
+
84
+ #
85
+ # rdoc can you see me?
86
+ #
87
+ self.default_epsilon = 1e-8
88
+
89
+ ##################################################
90
+ #
91
+ # instance methods
92
+ #
93
+ ##################################################
94
+
95
+ #
96
+ # Returns the singleton class of the object. Convenient for
97
+ # setting the +default_epsilon+ on a per-object basis.
98
+ # b = DMatrix.rand(4, 4)
99
+ # a = b.map { |e| e + 0.0001 }
100
+ # a.class.default_epsilon # => 1e-8
101
+ # a =~ b # => false
102
+ # a.singleton_class.default_epsilon = 0.001
103
+ # a =~ b # => true
104
+ #
105
+ def singleton_class
106
+ class << self
107
+ self
108
+ end
109
+ end
110
+
111
+ #
112
+ # True if element-wise identical values.
113
+ #
114
+ def ==(other)
115
+ self.within(0.0, other)
116
+ end
117
+
118
+ #
119
+ # Sum of diagonal elements.
120
+ #
121
+ def trace
122
+ diags.inject(0.0) { |acc, e| acc + e }
123
+ end
124
+
125
+ #
126
+ # Same as to_s but prepended with a newline for nice irb output
127
+ #
128
+ def inspect
129
+ "\n" << self.to_s
130
+ end
131
+
132
+ #
133
+ # Dump to an +eval+-able string
134
+ #
135
+ def inspect2
136
+ res = "#{self.class}["
137
+ vsize.times { |i|
138
+ res << "["
139
+ hsize.times { |j|
140
+ res << self[i,j].to_s << ","
141
+ }
142
+ res.chop!
143
+ res << "],"
144
+ }
145
+ res.chop!
146
+ res << "]"
147
+ end
148
+
149
+ #
150
+ # Dump to a readable string
151
+ #
152
+ def to_s(format = "% 10.6f")
153
+ res = ""
154
+ vsize.times { |i|
155
+ hsize.times { |j|
156
+ res << sprintf(format, self[i,j])
157
+ }
158
+ res << "\n"
159
+ }
160
+ res
161
+ end
162
+
163
+ #
164
+ # Returns <tt>m[0,0]</tt> when +m+ is a 1x1 matrix, otherwise a
165
+ # +TypeError+ is raised.
166
+ #
167
+ def to_f
168
+ if vsize == 1 and hsize == 1
169
+ self[0,0]
170
+ else
171
+ raise TypeError, "to_f called on nonscalar matrix"
172
+ end
173
+ end
174
+
175
+ #
176
+ # Implemented as
177
+ #
178
+ # m.within(epsilon, other)
179
+ #
180
+ # where
181
+ # epsilon =
182
+ # self.singleton_class.default_epsilon ||
183
+ # self.class.default_epsilon
184
+ #
185
+ def =~(other)
186
+ epsilon =
187
+ self.singleton_class.default_epsilon ||
188
+ self.class.default_epsilon
189
+
190
+ self.within(epsilon, other)
191
+ end
192
+
193
+ #
194
+ # Returns
195
+ # self.vsize == self.hsize
196
+ #
197
+ def square?
198
+ self.vsize == self.hsize
199
+ end
200
+
201
+ #
202
+ # Tests whether the matrix is symmetric within +epsilon+
203
+ #
204
+ def symmetric?(epsilon = (self.singleton_class.default_epsilon || self.class.default_epsilon))
205
+ symmetric_private(epsilon)
206
+ end
207
+
208
+ #
209
+ # Exchange the <tt>p</tt>-th row with the <tt>q</tt>-th row
210
+ #
211
+ def exchange_rows(p, q)
212
+ tmp = self.row(p)
213
+ replace_row(p, self.row(q))
214
+ replace_row(q, tmp)
215
+ end
216
+
217
+ #
218
+ # Exchange the <tt>p</tt>-th column with the <tt>q</tt>-th column
219
+ #
220
+ def exchange_columns(p, q)
221
+ tmp = self.column(p)
222
+ replace_column(p, self.column(q))
223
+ replace_column(q, tmp)
224
+ end
225
+
226
+ private
227
+
228
+ #
229
+ # Create a column vector from the array
230
+ #
231
+ def self.column_vector(array)
232
+ self.columns([array])
233
+ end
234
+
235
+ #
236
+ # Create a row vector from the array
237
+ #
238
+ def self.row_vector(array)
239
+ self.rows([array])
240
+ end
241
+
242
+ end
243
+ end
244
+
@@ -0,0 +1,88 @@
1
+ #
2
+ # Copyright (c) 2004-2008 by James M. Lawrence
3
+ #
4
+ # See LICENSE
5
+ #
6
+
7
+ module Linalg
8
+ class DMatrix
9
+ #
10
+ # The 2-norm. The largest singular value.
11
+ #
12
+ def norm_2
13
+ singular_values[0]
14
+ end
15
+
16
+ #
17
+ # call-seq: norm_1
18
+ #
19
+ # The 1-norm. Maximum column absolute sum.
20
+ # For matrix +m+, equivalent to
21
+ #
22
+ # m.columns.map { |col|
23
+ # col.elems.inject(0.0) { |acc, e| acc + e.abs }
24
+ # }.sort[-1]
25
+ #
26
+ def norm_1
27
+ private_norm(Char.new("1"), NULL)
28
+ end
29
+
30
+ #
31
+ # call-seq: norm_inf
32
+ #
33
+ # The infinity-norm. Maximum row absolute sum.
34
+ # For matrix +m+, equivalent to
35
+ #
36
+ # m.rows.map { |row|
37
+ # row.elems.inject(0.0) { |acc, e| acc + e.abs }
38
+ # }.sort[-1]
39
+ #
40
+ def norm_inf
41
+ private_norm(Char.new("I"), DData.new(vsize))
42
+ end
43
+
44
+ #
45
+ # call-seq: norm_f
46
+ #
47
+ #
48
+ # Frobenius norm. Square root of the sum of the squares of the
49
+ # elements.
50
+ #
51
+ # For matrix +m+, equivalent to
52
+ #
53
+ # Math.sqrt(m.elems.inject(0.0) { |acc, e| acc + e*e })
54
+ #
55
+ #
56
+ def norm_f
57
+ private_norm(Char.new("F"), NULL)
58
+ end
59
+
60
+ #
61
+ # call-seq: maxabs
62
+ #
63
+ # The maximum absolute value of the individual matrix elements.
64
+ # For matrix +m+, equivalent to
65
+ #
66
+ # m.elems.map { |e| e.abs }.to_a.flatten.sort[-1]
67
+ #
68
+ # Note +maxabs+ is not a matrix norm.
69
+ #
70
+ #
71
+ def maxabs
72
+ private_norm(Char.new("M"), NULL)
73
+ end
74
+
75
+ private
76
+
77
+ def private_norm(kind, work)
78
+ m = XInteger.new(vsize)
79
+ n = XInteger.new(hsize)
80
+ Lapack.dlange(kind,
81
+ m,
82
+ n,
83
+ self,
84
+ m,
85
+ work)
86
+ end
87
+ end
88
+ end