stick 1.3.2 → 1.3.3

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.
@@ -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