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,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