2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002-2006 André Wobst <wobsta@users.sourceforge.net>
7 # Copyright (C) 2005 Michael Schindler <m-schindler@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28 return (x
>= 0) and 1 or -1
31 import Numeric
, LinearAlgebra
36 def evrealtrisym(d
, e
):
37 """returns eigenvalues of a tridiagonal real symmetric matrix
39 d are the diagonal elements and e are the subdiagonal elements.
40 len(d) == len(e) + 1; d and e are destroyed
43 assert len(d
) == len(e
) + 1
46 for iter in range(30):
47 for m
in range(l
, n
-1):
48 dd
= abs(d
[m
]) + abs(d
[m
+1])
49 if abs(e
[m
]) + dd
== dd
:
55 g
= (d
[l
+1]-d
[l
]) / (2.0*e
[l
])
56 r
= math
.hypot(g
, 1.0)
58 g
= d
[m
]-d
[l
]+e
[l
]/(g
+abs(r
))
60 g
= d
[m
]-d
[l
]+e
[l
]/(g
-abs(r
))
63 for i
in range(m
, l
, -1):
66 e
[i
] = r
= math
.hypot(f
, g
)
74 r
= (d
[i
-1]-g
)*s
+ 2.0*c
*b
83 raise RuntimeError("Too many iterations in evrealtrisym")
86 def realsymtotrisym(a
):
87 """creates a real tridiagonal matrix out of a real symmetric matrix
89 Eigenvalues are not altered by the transformation; a is the matrix, i.e. a
90 list of lists but only the diagonal and off-diagonal elements left of the
91 diagonal are accessed (the other values don't need to be provided and the
92 lists might be shortend); a is destroyed
98 for i
in range(n
-1, 0, -1):
103 scale
+= abs(a
[i
][k
])
122 for k
in range(j
+1, l
):
131 a
[j
][k
] -= f
*x
[k
] + g
*a
[i
][k
]
140 """returns eigenvalues of a real symmetric matrix
142 a is a real symmetric matrix, i.e. a list of lists but only the diagonal
143 and off-diagonal elements below the diagonal are accessed (other values are
144 not accessed, i.e. the lists might be shortend).
146 # make a copy and ensure floats
147 a
= [[float(x
) for x
in row
] for row
in a
]
148 return evrealtrisym(*realsymtotrisym(a
))
150 def balancerealsquare(a
, radix
=2):
151 """modify a general real square matrix to become balanced
153 This routine replaces the general real square matrix a by a balanced matrix
154 with identical eigenvalues. A symmetric matrix is already balanced and is
155 unaffected by this procedure. The parameter radix should be the machine's
156 floating-point radix to prevent any numerical inaccuracies to be introduced
170 if c
!= 0 and r
!= 0:
189 def hessrealsquare(a
):
190 """modify a general real square matrix to the upper hessenberg form
192 This routine replaces the general real square matrix a by a hessenberg
193 formed matrix with identical eigenvalues.
196 for m
in range(1, n
-1):
199 for j
in range(m
, n
):
200 if (abs(a
[j
][m
-1]) > abs(x
)):
204 for j
in range(m
-1, n
):
205 a
[i
][j
], a
[m
][j
] = a
[m
][j
], a
[i
][j
]
207 a
[j
][i
], a
[j
][m
] = a
[j
][m
], a
[j
][i
]
209 for i
in range(m
+1, n
):
214 for j
in range(m
, n
):
218 for i
in range(2, n
):
222 def evhessrealsquare(a
, realonly
=0):
223 """returns eigenvalues of a real square matrix in upper hessenberg form
225 a is a real square matrix in upper hessenberg form. a is destroyed.
226 The return value is a list containing a mixture of floats and complex
235 anorm
+= abs(a
[i
][j
])
240 while first
or l
< n
-2:
242 for l
in range(n
-1, 0, -1):
243 s
= abs(a
[l
-1][l
-1]) + abs(a
[l
][l
])
246 if abs(a
[l
][l
-1]) + s
== s
:
256 w
= a
[n
-1][n
-2]*a
[n
-2][n
-1]
260 z
= math
.sqrt(abs(q
))
278 raise RuntimeError("Too many iterations in evhessrealsquare")
279 if its
== 10 or its
== 20:
283 s
= abs(a
[n
-1][n
-2]) + abs(a
[n
-2][n
-3])
287 for m
in range(n
-3, l
-1, -1):
291 p
= (r
*s
-w
)/a
[m
+1][m
] + a
[m
][m
+1]
292 q
= a
[m
+1][m
+1]-z
-r
-s
294 s
= abs(p
)+abs(q
)+abs(r
)
300 u
= abs(a
[m
][m
-1])*(abs(q
)+abs(r
))
301 v
= abs(p
) * (abs(a
[m
-1][m
-1]) + abs(z
) + abs(a
[m
+1][m
+1]))
304 for i
in range(m
+2, n
):
308 for k
in range(m
, n
-1):
315 x
= abs(p
) + abs(q
) + abs(r
)
321 s
= math
.sqrt(p
*p
+q
*q
+r
*r
)
323 s
= -math
.sqrt(p
*p
+q
*q
+r
*r
)
327 a
[k
][k
-1] = -a
[k
][k
-1]
336 for j
in range(k
, n
):
337 p
= a
[k
][j
]+q
*a
[k
+1][j
]
344 for i
in range(l
, mmin
+1):
345 p
= x
*a
[i
][k
] + y
*a
[i
][k
+1]
355 def evrealsquare(a
, copy
=1, realonly
=0):
356 """returns eigenvalues of a real square matrix
358 a is a real square matrix, i.e. a list of lists. The return value is a list
359 containing a mixture of floats and complex values.
362 # make a copy and ensure floats
363 a
= [[float(x
) for x
in row
] for row
in a
]
366 return evhessrealsquare(a
, realonly
=realonly
)
368 def realpolyroots(coeffs
, epsilon
=1e-5):
369 """returns the roots of a polynom with given coefficients
371 polynomial with coefficients given in coeffs:
372 0 = \sum_i x^i coeffs[i]
373 The solution is found via an equivalent eigenvalue problem
378 f
= -1.0 / coeffs
[-1]
379 except ZeroDivisionError:
380 return realpolyroots(coeffs
[:-1])
384 a
= Numeric
.zeros((n
, n
), Numeric
.Float
)
388 a
[0][i
] = f
*coeffs
[n
-1-i
]
390 for root
in LinearAlgebra
.eigenvalues(a
):
391 if type(root
) == types
.ComplexType
:
393 roots
.append(root
.real
)
398 a
= [[0.0 for i
in range(n
)] for j
in range(n
)]
402 a
[0][i
] = f
*coeffs
[n
-1-i
]
403 return evrealsquare(a
, copy
=0, realonly
=1)