stick 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ require 'e2mmap'
2
+
3
+ module Stick
4
+
5
+ class Matrix
6
+
7
+ module Exceptions # :nodoc:
8
+ extend Exception2MessageMapper
9
+
10
+ def_e2message(TypeError, "wrong argument type %s (expected %s)")
11
+ def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
12
+
13
+ def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
14
+ def_exception("ErrNotRegular", "Not Regular Matrix")
15
+ def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
16
+ end
17
+
18
+ # extend Exception2MessageMapper
19
+ include Exceptions
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,59 @@
1
+ module Stick
2
+
3
+ class Matrix
4
+
5
+ module Givens
6
+
7
+ # Returns the values "c and s" of a Given rotation
8
+ # MC, Golub, pg 216, Alghorithm 5.1.3
9
+
10
+ def Givens.givens(a, b)
11
+ if b == 0
12
+ c = 0; s = 0
13
+ else
14
+ if b.abs > a.abs
15
+ tau = Float(-a)/b; s = 1/Math.sqrt(1+tau**2); c = s * tau
16
+ else
17
+ tau = Float(-b)/a; c = 1/Math.sqrt(1+tau**2); s = c * tau
18
+ end
19
+ end
20
+ return c, s
21
+ end
22
+
23
+ # a QR factorization using Givens rotation
24
+ # Computes the upper triangular matrix R and the orthogonal matrix Q
25
+ # where Q^t A = R (MC, Golub, p227 algorithm 5.2.2)
26
+
27
+ def Givens.QR(mat)
28
+ r = mat.clone
29
+ m = r.row_size
30
+ n = r.column_size
31
+ q = Matrix.I(m)
32
+ n.times{|j|
33
+ m-1.downto(j+1){|i|
34
+ c, s = givens(r[i - 1, j], r[i, j])
35
+ qt = Matrix.I(m); qt[i-1..i, i-1..i] = Matrix[[c, s],[-s, c]]
36
+ q *= qt
37
+ r[i-1..i, j..n-1] = Matrix[[c, -s],[s, c]] * r[i-1..i, j..n-1]}}
38
+ return r, q
39
+ end
40
+
41
+ end
42
+
43
+ # Returns the upper triunghiular matrix R of a Givens QR factorization
44
+
45
+ def givensR
46
+ Givens.QR(self)[0]
47
+ end
48
+
49
+ # Returns the orthogonal matrix Q of Givens QR factorization.
50
+ # Q = G_1 * ... * G_t where G_j is the j'th Givens rotation
51
+ # and 't' is the total number of rotations
52
+
53
+ def givensQ
54
+ Givens.QR(self)[1]
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,63 @@
1
+ require 'stick/matrix/householder'
2
+
3
+ module Stick
4
+
5
+ class Matrix
6
+
7
+ module Hessenberg
8
+
9
+ # The matrix must be an upper R^(n x n) Hessenberg matrix
10
+
11
+ def Hessenberg.QR(mat)
12
+ r = mat.clone
13
+ n = r.row_size
14
+ q = Matrix.I(n)
15
+ for j in (0...n-1)
16
+ c, s = Givens.givens(r[j,j], r[j+1, j])
17
+ cs = Matrix[[c, s], [-s, c]]
18
+ q *= Matrix.diag(Matrix.I(j), cs, Matrix.I(n - j - 2))
19
+ r[j..j+1, j..n-1] = cs.t * r[j..j+1, j..n-1]
20
+ end
21
+ return q, r
22
+ end
23
+ end
24
+
25
+ # Returns the orthogonal matrix Q of Hessenberg QR factorization
26
+ # Q = G_1 *...* G_(n-1) where G_j is the Givens rotation G_j = G(j, j+1, omega_j)
27
+
28
+ def hessenbergQ
29
+ Hessenberg.QR(self)[0]
30
+ end
31
+
32
+ # Returns the upper triunghiular matrix R of a Hessenberg QR factorization
33
+
34
+ def hessenbergR
35
+ Hessenberg.QR(self)[1]
36
+ end
37
+
38
+ # Return an upper Hessenberg matrix obtained with Householder reduction to Hessenberg Form algorithm
39
+
40
+ def hessenberg_form_H
41
+ Householder.toHessenberg(self)[0]
42
+ end
43
+
44
+ # The real Schur decomposition.
45
+ # The eigenvalues are aproximated in diagonal elements of the real Schur decomposition matrix
46
+
47
+ def realSchur(eps = 1.0e-10, steps = 100)
48
+ h = self.hessenberg_form_H
49
+ h1 = Matrix[]
50
+ i = 0
51
+ loop do
52
+ h1 = h.hessenbergR * h.hessenbergQ
53
+ break if Matrix.diag_in_delta?(h1, h, eps) or steps <= 0
54
+ h = h1.clone
55
+ steps -= 1
56
+ i += 1
57
+ end
58
+ h1
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,106 @@
1
+ module Stick
2
+
3
+ class Matrix
4
+
5
+ module Householder
6
+
7
+ # a QR factorization that uses Householder transformation
8
+ # Q^T * A = R
9
+ # MC, Golub & van Loan, pg 224, 5.2.1 Householder QR
10
+
11
+ def Householder.QR(mat)
12
+ h = []
13
+ a = mat.clone
14
+ m = a.row_size
15
+ n = a.column_size
16
+ n.times{|j|
17
+ v, beta = a[j..m - 1, j].house
18
+
19
+ h[j] = Matrix.diag(Matrix.I(j), Matrix.I(m-j)- beta * (v * v.t))
20
+
21
+ a[j..m-1, j..n-1] = (Matrix.I(m-j) - beta * (v * v.t)) * a[j..m-1, j..n-1]
22
+ a[(j+1)..m-1,j] = v[2..(m-j)] if j < m - 1 }
23
+ h
24
+ end
25
+
26
+ # From the essential part of Householder vector
27
+ # it returns the coresponding upper(U_j)/lower(V_j) matrix
28
+
29
+ def Householder.bidiagUV(essential, dim, beta)
30
+ v = Vector.concat(Vector[1], essential)
31
+ dimv = v.size
32
+ Matrix.diag(Matrix.I(dim - dimv), Matrix.I(dimv) - beta * (v * v.t) )
33
+ end
34
+
35
+ # Householder Bidiagonalization algorithm. MC, Golub, pg 252, Algorithm 5.4.2
36
+ # Returns the matrices U_B and V_B such that: U_B^T * A * V_B = B,
37
+ # where B is upper bidiagonal.
38
+
39
+ def Householder.bidiag(mat)
40
+ a = mat.clone
41
+ m = a.row_size
42
+ n = a.column_size
43
+ ub = Matrix.I(m)
44
+ vb = Matrix.I(n)
45
+ n.times{|j|
46
+ v, beta = a[j..m-1,j].house
47
+ a[j..m-1, j..n-1] = (Matrix.I(m-j) - beta * (v * v.t)) * a[j..m-1, j..n-1]
48
+ a[j+1..m-1, j] = v[1..(m-j-1)]
49
+ ub *= bidiagUV(a[j+1..m-1,j], m, beta) #Ub = U_1 * U_2 * ... * U_n
50
+ if j < n - 2
51
+ v, beta = (a[j, j+1..n-1]).house
52
+ a[j..m-1, j+1..n-1] = a[j..m-1, j+1..n-1] * (Matrix.I(n-j-1) - beta * (v * v.t))
53
+ a[j, j+2..n-1] = v[1..n-j-2]
54
+ vb *= bidiagUV(a[j, j+2..n-1], n, beta) #Vb = V_1 * U_2 * ... * V_n-2
55
+ end }
56
+ return ub, vb
57
+ end
58
+
59
+ # Householder Reduction to Hessenberg Form
60
+
61
+ def Householder.toHessenberg(mat)
62
+ h = mat.clone
63
+ n = h.row_size
64
+ u0 = Matrix.I(n)
65
+ for k in (0...n - 2)
66
+ v, beta = h[k+1..n-1, k].house #the householder matrice part
67
+ houseV = Matrix.I(n-k-1) - beta * (v * v.t)
68
+ u0 *= Matrix.diag(Matrix.I(k+1), houseV)
69
+ h[k+1..n-1, k..n-1] = houseV * h[k+1..n-1, k..n-1]
70
+ h[0..n-1, k+1..n-1] = h[0..n-1, k+1..n-1] * houseV
71
+ end
72
+ return h, u0
73
+ end
74
+
75
+ end #end of Householder module
76
+
77
+ # Returns the upper bidiagonal matrix obtained with Householder Bidiagonalization algorithm
78
+
79
+ def bidiagonal
80
+ ub, vb = Householder.bidiag(self)
81
+ ub.t * self * vb
82
+ end
83
+
84
+ # Returns the orthogonal matrix Q of Householder QR factorization
85
+ # where Q = H_1 * H_2 * H_3 * ... * H_n,
86
+
87
+ def houseQ
88
+ h = Householder.QR(self)
89
+ q = h[0]
90
+ (1...h.size).each{|i| q *= h[i]}
91
+ q
92
+ end
93
+
94
+ # Returns the matrix R of Householder QR factorization
95
+ # R = H_n * H_n-1 * ... * H_1 * A is an upper triangular matrix
96
+
97
+ def houseR
98
+ h = Householder.QR(self)
99
+ r = self.clone
100
+ h.size.times{|i| r = h[i] * r}
101
+ r
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,106 @@
1
+ module Stick
2
+
3
+ class Matrix
4
+
5
+ module Jacobi
6
+
7
+ # Returns the nurm of the off-diagonal element
8
+
9
+ def Jacobi.off(a)
10
+ n = a.row_size
11
+ sum = 0
12
+ n.times{|i| n.times{|j| sum += a[i, j]**2 if j != i}}
13
+ Math.sqrt(sum)
14
+ end
15
+
16
+ # Returns the index pair (p, q) with 1<= p < q <= n and A[p, q] is the maximum in absolute value
17
+
18
+ def Jacobi.max(a)
19
+ n = a.row_size
20
+ max = 0
21
+ p = 0
22
+ q = 0
23
+ n.times{|i|
24
+ ((i+1)...n).each{|j|
25
+ val = a[i, j].abs
26
+ if val > max
27
+ max = val
28
+ p = i
29
+ q = j
30
+ end }}
31
+ return p, q
32
+ end
33
+
34
+ # Compute the cosine-sine pair (c, s) for the element A[p, q]
35
+
36
+ def Jacobi.sym_schur2(a, p, q)
37
+ if a[p, q] != 0
38
+ tau = Float(a[q, q] - a[p, p])/(2 * a[p, q])
39
+ if tau >= 0
40
+ t = 1./(tau + Math.sqrt(1 + tau ** 2))
41
+ else
42
+ t = -1./(-tau + Math.sqrt(1 + tau ** 2))
43
+ end
44
+ c = 1./Math.sqrt(1 + t ** 2)
45
+ s = t * c
46
+ else
47
+ c = 1
48
+ s = 0
49
+ end
50
+ return c, s
51
+ end
52
+
53
+ # Returns the Jacobi rotation matrix
54
+
55
+ def Jacobi.J(p, q, c, s, n)
56
+ j = Matrix.I(n)
57
+ j[p,p] = c; j[p, q] = s
58
+ j[q,p] = -s; j[q, q] = c
59
+ j
60
+ end
61
+
62
+ end
63
+
64
+ # Classical Jacobi 8.4.3 Golub & van Loan
65
+
66
+ def cJacobi(tol = 1.0e-10)
67
+ a = self.clone
68
+ n = row_size
69
+ v = Matrix.I(n)
70
+ eps = tol * a.normF
71
+ while Jacobi.off(a) > eps
72
+ p, q = Jacobi.max(a)
73
+ c, s = Jacobi.sym_schur2(a, p, q)
74
+ #print "\np:#{p} q:#{q} c:#{c} s:#{s}\n"
75
+ j = Jacobi.J(p, q, c, s, n)
76
+ a = j.t * a * j
77
+ v = v * j
78
+ end
79
+ return a, v
80
+ end
81
+
82
+ # Returns the aproximation matrix computed with Classical Jacobi algorithm.
83
+ # The aproximate eigenvalues values are in the diagonal of the matrix A.
84
+
85
+ def cJacobiA(tol = 1.0e-10)
86
+ cJacobi(tol)[0]
87
+ end
88
+
89
+ # Returns a Vector with the eigenvalues aproximated values.
90
+ # The eigenvalues are computed with the Classic Jacobi Algorithm.
91
+
92
+ def eigenvaluesJacobi
93
+ a = cJacobiA
94
+ Vector[*(0...row_size).collect{|i| a[i, i]}]
95
+ end
96
+
97
+ # Returns the orthogonal matrix obtained with the Jacobi eigenvalue algorithm.
98
+ # The columns of V are the eigenvector.
99
+
100
+ def cJacobiV(tol = 1.0e-10)
101
+ cJacobi(tol)[1]
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,60 @@
1
+ module Stick
2
+
3
+ class Matrix
4
+
5
+ module LU
6
+
7
+ # Return the Gauss vector, MC, Golub, 3.2.1 Gauss Transformation, p94
8
+
9
+ def LU.gauss_vector(mat, k)
10
+ t = mat.column2matrix(k)
11
+ tk = t[k, 0]
12
+ (0..k).each{|i| t[i, 0] = 0}
13
+ return t if tk == 0
14
+ (k+1...mat.row_size).each{|i| t[i, 0] = t[i, 0].to_f / tk}
15
+ t
16
+ end
17
+
18
+ # Return the Gauss transformation matrix: M_k = I - tau * e_k^T
19
+
20
+ def LU.gauss(mat, k)
21
+ i = Matrix.I(mat.column_size)
22
+ tau = gauss_vector(mat, k)
23
+ e = i.row2matrix(k)
24
+ i - tau * e
25
+ end
26
+
27
+ # LU factorization: A = LU
28
+ # where L is lower triangular and U is upper triangular
29
+
30
+ def LU.factorization(mat)
31
+ u = mat.clone
32
+ n = u.column_size
33
+ i = Matrix.I(n)
34
+ l = i.clone
35
+ (n-1).times {|k|
36
+ mk = gauss(u, k)
37
+ u = mk * u # M_{n-1} * ... * M_1 * A = U
38
+ l += i - mk # L = M_1^{-1} * ... * M_{n-1}^{-1} = I + sum_{k=1}^{n-1} tau * e
39
+ }
40
+ return l, u
41
+ end
42
+ end
43
+
44
+ # Return the upper triangular matrix of LU factorization
45
+ # M_{n-1} * ... * M_1 * A = U
46
+
47
+ def U
48
+ LU.factorization(self)[1]
49
+ end
50
+
51
+ # Return the lower triangular matrix of LU factorization
52
+ # L = M_1^{-1} * ... * M_{n-1}^{-1} = I + sum_{k=1}^{n-1} tau * e
53
+
54
+ def L
55
+ LU.factorization(self)[0]
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -3,7 +3,7 @@
3
3
  # Quaternion
4
4
  #
5
5
  # Copyright:
6
- #
6
+ #
7
7
  # Copyright (c) 2002 K. Kodama
8
8
  #
9
9
  # Authors:
@@ -23,9 +23,9 @@ require "complex"
23
23
  # NOTE This Quaternion class is still very experimental.
24
24
  #
25
25
  # Quaternions are attributed to Sir William Rowan Hamilton
26
- # who find it in 1843, and published a major analysis in 1844 called
26
+ # who find it in 1843, and published a major analysis in 1844 called
27
27
  # "On a Species of Imaginary Quantities Connected with a Theory of Quaternions"
28
- # in the Proceedings of the Royal Irish Academ. (2, pp 424-434).
28
+ # in the Proceedings of the Royal Irish Academ. (2, pp 424-434).
29
29
  #
30
30
  # Typical quaternion number q is of the form q = r + a i + b j + c k.
31
31
  # Bases i j k behaves as follows:
@@ -42,7 +42,7 @@ require "complex"
42
42
  #
43
43
  # A Quaternion q = r + a i + b j + k c have 1st level polar form such that
44
44
  #
45
- # q = |q|(cos t1 + sin t1 u1) , where u1 is unit vector of u1 = a1 i + b1 j + c1 k.
45
+ # q = |q|(cos t1 + sin t1 u1) , where u1 is unit vector of u1 = a1 i + b1 j + c1 k.
46
46
  #
47
47
  # u1 have 2nd level
48
48
  #
@@ -126,7 +126,7 @@ Quaternian::vector(v)
126
126
  Quaternion::rotation(v,t)
127
127
  # t-rotatin along the 3-D vector v
128
128
  q.rotate(r)
129
- rotate by r = q r^(-1)
129
+ rotate by r = q r^(-1)
130
130
  q.rotate_angle
131
131
  # = q.amplitude/2
132
132
 
@@ -189,7 +189,7 @@ q.sinh
189
189
  q.cosh
190
190
  q.tanh
191
191
 
192
- * Trigonometric functions
192
+ * Trigonometric functions
193
193
  q.sin
194
194
  q.cos
195
195
  q.tan
@@ -211,6 +211,7 @@ q.hash
211
211
  q.inspect
212
212
  =end
213
213
 
214
+ module Stick
214
215
 
215
216
  def Quaternion(a=0, b=0,c=0, d=0)
216
217
  if a.kind_of?(Quaternion);
@@ -224,6 +225,8 @@ def Quaternion(a=0, b=0,c=0, d=0)
224
225
  end
225
226
  end
226
227
 
228
+ module_function :Quaternion
229
+
227
230
  class Quaternion < Numeric
228
231
  attr :re
229
232
  attr :im
@@ -549,3 +552,4 @@ class Quaternion < Numeric
549
552
  end
550
553
 
551
554
  end # Quaternion
555
+ end # Stick