libjama-1.2.4/ 0000755 0021451 0021451 00000000000 10445756567 013336 5 ustar pbuilder pbuilder libjama-1.2.4/src/ 0000755 0021451 0021451 00000000000 10445756650 014116 5 ustar pbuilder pbuilder libjama-1.2.4/src/jama/ 0000755 0021451 0021451 00000000000 10445756650 015026 5 ustar pbuilder pbuilder libjama-1.2.4/src/jama/jama_cholesky.h 0000644 0021451 0021451 00000012165 10134035777 020010 0 ustar pbuilder pbuilder #ifndef JAMA_CHOLESKY_H
#define JAMA_CHOLESKY_H
#include "math.h"
/* needed for sqrt() below. */
namespace JAMA
{
using namespace TNT;
/**
For a symmetric, positive definite matrix A, this function
computes the Cholesky factorization, i.e. it computes a lower
triangular matrix L such that A = L*L'.
If the matrix is not symmetric or positive definite, the function
computes only a partial decomposition. This can be tested with
the is_spd() flag.
Typical usage looks like:
Array2D A(n,n);
Array2D L;
...
Cholesky chol(A);
if (chol.is_spd())
L = chol.getL();
else
cout << "factorization was not complete.\n";
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
*/
template
class Cholesky
{
Array2D L_; // lower triangular factor
int isspd; // 1 if matrix to be factored was SPD
public:
Cholesky();
Cholesky(const Array2D &A);
Array2D getL() const;
Array1D solve(const Array1D &B);
Array2D solve(const Array2D &B);
int is_spd() const;
};
template
Cholesky::Cholesky() : L_(0,0), isspd(0) {}
/**
@return 1, if original matrix to be factored was symmetric
positive-definite (SPD).
*/
template
int Cholesky::is_spd() const
{
return isspd;
}
/**
@return the lower triangular factor, L, such that L*L'=A.
*/
template
Array2D Cholesky::getL() const
{
return L_;
}
/**
Constructs a lower triangular matrix L, such that L*L'= A.
If A is not symmetric positive-definite (SPD), only a
partial factorization is performed. If is_spd()
evalutate true (1) then the factorizaiton was successful.
*/
template
Cholesky::Cholesky(const Array2D &A)
{
int m = A.dim1();
int n = A.dim2();
isspd = (m == n);
if (m != n)
{
L_ = Array2D(0,0);
return;
}
L_ = Array2D(n,n);
// Main loop.
for (int j = 0; j < n; j++)
{
double d = 0.0;
for (int k = 0; k < j; k++)
{
Real s = 0.0;
for (int i = 0; i < k; i++)
{
s += L_[k][i]*L_[j][i];
}
L_[j][k] = s = (A[j][k] - s)/L_[k][k];
d = d + s*s;
isspd = isspd && (A[k][j] == A[j][k]);
}
d = A[j][j] - d;
isspd = isspd && (d > 0.0);
L_[j][j] = sqrt(d > 0.0 ? d : 0.0);
for (int k = j+1; k < n; k++)
{
L_[j][k] = 0.0;
}
}
}
/**
Solve a linear system A*x = b, using the previously computed
cholesky factorization of A: L*L'.
@param B A Matrix with as many rows as A and any number of columns.
@return x so that L*L'*x = b. If b is nonconformat, or if A
was not symmetric posidtive definite, a null (0x0)
array is returned.
*/
template
Array1D Cholesky::solve(const Array1D &b)
{
int n = L_.dim1();
if (b.dim1() != n)
return Array1D();
Array1D x = b.copy();
// Solve L*y = b;
for (int k = 0; k < n; k++)
{
for (int i = 0; i < k; i++)
x[k] -= x[i]*L_[k][i];
x[k] /= L_[k][k];
}
// Solve L'*X = Y;
for (int k = n-1; k >= 0; k--)
{
for (int i = k+1; i < n; i++)
x[k] -= x[i]*L_[i][k];
x[k] /= L_[k][k];
}
return x;
}
/**
Solve a linear system A*X = B, using the previously computed
cholesky factorization of A: L*L'.
@param B A Matrix with as many rows as A and any number of columns.
@return X so that L*L'*X = B. If B is nonconformat, or if A
was not symmetric posidtive definite, a null (0x0)
array is returned.
*/
template
Array2D Cholesky::solve(const Array2D &B)
{
int n = L_.dim1();
if (B.dim1() != n)
return Array2D();
Array2D X = B.copy();
int nx = B.dim2();
// Cleve's original code
#if 0
// Solve L*Y = B;
for (int k = 0; k < n; k++) {
for (int i = k+1; i < n; i++) {
for (int j = 0; j < nx; j++) {
X[i][j] -= X[k][j]*L_[k][i];
}
}
for (int j = 0; j < nx; j++) {
X[k][j] /= L_[k][k];
}
}
// Solve L'*X = Y;
for (int k = n-1; k >= 0; k--) {
for (int j = 0; j < nx; j++) {
X[k][j] /= L_[k][k];
}
for (int i = 0; i < k; i++) {
for (int j = 0; j < nx; j++) {
X[i][j] -= X[k][j]*L_[k][i];
}
}
}
#endif
// Solve L*y = b;
for (int j=0; j< nx; j++)
{
for (int k = 0; k < n; k++)
{
for (int i = 0; i < k; i++)
X[k][j] -= X[i][j]*L_[k][i];
X[k][j] /= L_[k][k];
}
}
// Solve L'*X = Y;
for (int j=0; j= 0; k--)
{
for (int i = k+1; i < n; i++)
X[k][j] -= X[i][j]*L_[i][k];
X[k][j] /= L_[k][k];
}
}
return X;
}
}
// namespace JAMA
#endif
// JAMA_CHOLESKY_H
libjama-1.2.4/src/jama/jama_eig.h 0000644 0021451 0021451 00000067450 10134035777 016742 0 ustar pbuilder pbuilder #ifndef JAMA_EIG_H
#define JAMA_EIG_H
#include "tnt_array1d.h"
#include "tnt_array2d.h"
#include "tnt_math_utils.h"
#include
// for min(), max() below
#include
// for abs() below
using namespace TNT;
using namespace std;
namespace JAMA
{
/**
Computes eigenvalues and eigenvectors of a real (non-complex)
matrix.
If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
diagonal and the eigenvector matrix V is orthogonal. That is,
the diagonal values of D are the eigenvalues, and
V*V' = I, where I is the identity matrix. The columns of V
represent the eigenvectors in the sense that A*V = V*D.
If A is not symmetric, then the eigenvalue matrix D is block diagonal
with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
eigenvalues look like
u + iv . . . . .
. u - iv . . . .
. . a + ib . . .
. . . a - ib . .
. . . . x .
. . . . . y
then D looks like
u v . . . .
-v u . . . .
. . a b . .
. . -b a . .
. . . . x .
. . . . . y
This keeps V a real matrix in both symmetric and non-symmetric
cases, and A*V = V*D.
The matrix V may be badly
conditioned, or even singular, so the validity of the equation
A = V*D*inverse(V) depends upon the condition number of V.
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
**/
template
class Eigenvalue
{
/** Row and column dimension (square matrix). */
int n;
int issymmetric; /* boolean*/
/** Arrays for internal storage of eigenvalues. */
TNT::Array1D d; /* real part */
TNT::Array1D e; /* img part */
/** Array for internal storage of eigenvectors. */
TNT::Array2D V;
/** Array for internal storage of nonsymmetric Hessenberg form.
@serial internal storage of nonsymmetric Hessenberg form.
*/
TNT::Array2D H;
/** Working storage for nonsymmetric algorithm.
@serial working storage for nonsymmetric algorithm.
*/
TNT::Array1D ort;
// Symmetric Householder reduction to tridiagonal form.
void tred2() {
// This is derived from the Algol procedures tred2 by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
for (int j = 0; j < n; j++) {
d[j] = V[n-1][j];
}
// Householder reduction to tridiagonal form.
for (int i = n-1; i > 0; i--) {
// Scale to avoid under/overflow.
Real scale = 0.0;
Real h = 0.0;
for (int k = 0; k < i; k++) {
scale = scale + abs(d[k]);
}
if (scale == 0.0) {
e[i] = d[i-1];
for (int j = 0; j < i; j++) {
d[j] = V[i-1][j];
V[i][j] = 0.0;
V[j][i] = 0.0;
}
} else {
// Generate Householder vector.
for (int k = 0; k < i; k++) {
d[k] /= scale;
h += d[k] * d[k];
}
Real f = d[i-1];
Real g = sqrt(h);
if (f > 0) {
g = -g;
}
e[i] = scale * g;
h = h - f * g;
d[i-1] = f - g;
for (int j = 0; j < i; j++) {
e[j] = 0.0;
}
// Apply similarity transformation to remaining columns.
for (int j = 0; j < i; j++) {
f = d[j];
V[j][i] = f;
g = e[j] + V[j][j] * f;
for (int k = j+1; k <= i-1; k++) {
g += V[k][j] * d[k];
e[k] += V[k][j] * f;
}
e[j] = g;
}
f = 0.0;
for (int j = 0; j < i; j++) {
e[j] /= h;
f += e[j] * d[j];
}
Real hh = f / (h + h);
for (int j = 0; j < i; j++) {
e[j] -= hh * d[j];
}
for (int j = 0; j < i; j++) {
f = d[j];
g = e[j];
for (int k = j; k <= i-1; k++) {
V[k][j] -= (f * e[k] + g * d[k]);
}
d[j] = V[i-1][j];
V[i][j] = 0.0;
}
}
d[i] = h;
}
// Accumulate transformations.
for (int i = 0; i < n-1; i++) {
V[n-1][i] = V[i][i];
V[i][i] = 1.0;
Real h = d[i+1];
if (h != 0.0) {
for (int k = 0; k <= i; k++) {
d[k] = V[k][i+1] / h;
}
for (int j = 0; j <= i; j++) {
Real g = 0.0;
for (int k = 0; k <= i; k++) {
g += V[k][i+1] * V[k][j];
}
for (int k = 0; k <= i; k++) {
V[k][j] -= g * d[k];
}
}
}
for (int k = 0; k <= i; k++) {
V[k][i+1] = 0.0;
}
}
for (int j = 0; j < n; j++) {
d[j] = V[n-1][j];
V[n-1][j] = 0.0;
}
V[n-1][n-1] = 1.0;
e[0] = 0.0;
}
// Symmetric tridiagonal QL algorithm.
void tql2 () {
// This is derived from the Algol procedures tql2, by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
for (int i = 1; i < n; i++) {
e[i-1] = e[i];
}
e[n-1] = 0.0;
Real f = 0.0;
Real tst1 = 0.0;
Real eps = pow(2.0,-52.0);
for (int l = 0; l < n; l++) {
// Find small subdiagonal element
tst1 = max(tst1,abs(d[l]) + abs(e[l]));
int m = l;
// Original while-loop from Java code
while (m < n) {
if (abs(e[m]) <= eps*tst1) {
break;
}
m++;
}
// If m == l, d[l] is an eigenvalue,
// otherwise, iterate.
if (m > l) {
int iter = 0;
do {
iter = iter + 1; // (Could check iteration count here.)
// Compute implicit shift
Real g = d[l];
Real p = (d[l+1] - g) / (2.0 * e[l]);
Real r = hypot(p,1.0);
if (p < 0) {
r = -r;
}
d[l] = e[l] / (p + r);
d[l+1] = e[l] * (p + r);
Real dl1 = d[l+1];
Real h = g - d[l];
for (int i = l+2; i < n; i++) {
d[i] -= h;
}
f = f + h;
// Implicit QL transformation.
p = d[m];
Real c = 1.0;
Real c2 = c;
Real c3 = c;
Real el1 = e[l+1];
Real s = 0.0;
Real s2 = 0.0;
for (int i = m-1; i >= l; i--) {
c3 = c2;
c2 = c;
s2 = s;
g = c * e[i];
h = c * p;
r = hypot(p,e[i]);
e[i+1] = s * r;
s = e[i] / r;
c = p / r;
p = c * d[i] - s * g;
d[i+1] = h + s * (c * g + s * d[i]);
// Accumulate transformation.
for (int k = 0; k < n; k++) {
h = V[k][i+1];
V[k][i+1] = s * V[k][i] + c * h;
V[k][i] = c * V[k][i] - s * h;
}
}
p = -s * s2 * c3 * el1 * e[l] / dl1;
e[l] = s * p;
d[l] = c * p;
// Check for convergence.
} while (abs(e[l]) > eps*tst1);
}
d[l] = d[l] + f;
e[l] = 0.0;
}
// Sort eigenvalues and corresponding vectors.
for (int i = 0; i < n-1; i++) {
int k = i;
Real p = d[i];
for (int j = i+1; j < n; j++) {
if (d[j] < p) {
k = j;
p = d[j];
}
}
if (k != i) {
d[k] = d[i];
d[i] = p;
for (int j = 0; j < n; j++) {
p = V[j][i];
V[j][i] = V[j][k];
V[j][k] = p;
}
}
}
}
// Nonsymmetric reduction to Hessenberg form.
void orthes () {
// This is derived from the Algol procedures orthes and ortran,
// by Martin and Wilkinson, Handbook for Auto. Comp.,
// Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutines in EISPACK.
int low = 0;
int high = n-1;
for (int m = low+1; m <= high-1; m++) {
// Scale column.
Real scale = 0.0;
for (int i = m; i <= high; i++) {
scale = scale + abs(H[i][m-1]);
}
if (scale != 0.0) {
// Compute Householder transformation.
Real h = 0.0;
for (int i = high; i >= m; i--) {
ort[i] = H[i][m-1]/scale;
h += ort[i] * ort[i];
}
Real g = sqrt(h);
if (ort[m] > 0) {
g = -g;
}
h = h - ort[m] * g;
ort[m] = ort[m] - g;
// Apply Householder similarity transformation
// H = (I-u*u'/h)*H*(I-u*u')/h)
for (int j = m; j < n; j++) {
Real f = 0.0;
for (int i = high; i >= m; i--) {
f += ort[i]*H[i][j];
}
f = f/h;
for (int i = m; i <= high; i++) {
H[i][j] -= f*ort[i];
}
}
for (int i = 0; i <= high; i++) {
Real f = 0.0;
for (int j = high; j >= m; j--) {
f += ort[j]*H[i][j];
}
f = f/h;
for (int j = m; j <= high; j++) {
H[i][j] -= f*ort[j];
}
}
ort[m] = scale*ort[m];
H[m][m-1] = scale*g;
}
}
// Accumulate transformations (Algol's ortran).
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
V[i][j] = (i == j ? 1.0 : 0.0);
}
}
for (int m = high-1; m >= low+1; m--) {
if (H[m][m-1] != 0.0) {
for (int i = m+1; i <= high; i++) {
ort[i] = H[i][m-1];
}
for (int j = m; j <= high; j++) {
Real g = 0.0;
for (int i = m; i <= high; i++) {
g += ort[i] * V[i][j];
}
// Double division avoids possible underflow
g = (g / ort[m]) / H[m][m-1];
for (int i = m; i <= high; i++) {
V[i][j] += g * ort[i];
}
}
}
}
}
// Complex scalar division.
Real cdivr, cdivi;
void cdiv(Real xr, Real xi, Real yr, Real yi) {
Real r,d;
if (abs(yr) > abs(yi)) {
r = yi/yr;
d = yr + r*yi;
cdivr = (xr + r*xi)/d;
cdivi = (xi - r*xr)/d;
} else {
r = yr/yi;
d = yi + r*yr;
cdivr = (r*xr + xi)/d;
cdivi = (r*xi - xr)/d;
}
}
// Nonsymmetric reduction from Hessenberg to real Schur form.
void hqr2 () {
// This is derived from the Algol procedure hqr2,
// by Martin and Wilkinson, Handbook for Auto. Comp.,
// Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
// Initialize
int nn = this->n;
int n = nn-1;
int low = 0;
int high = nn-1;
Real eps = pow(2.0,-52.0);
Real exshift = 0.0;
Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;
// Store roots isolated by balanc and compute matrix norm
Real norm = 0.0;
for (int i = 0; i < nn; i++) {
if ((i < low) || (i > high)) {
d[i] = H[i][i];
e[i] = 0.0;
}
for (int j = max(i-1,0); j < nn; j++) {
norm = norm + abs(H[i][j]);
}
}
// Outer loop over eigenvalue index
int iter = 0;
while (n >= low) {
// Look for single small sub-diagonal element
int l = n;
while (l > low) {
s = abs(H[l-1][l-1]) + abs(H[l][l]);
if (s == 0.0) {
s = norm;
}
if (abs(H[l][l-1]) < eps * s) {
break;
}
l--;
}
// Check for convergence
// One root found
if (l == n) {
H[n][n] = H[n][n] + exshift;
d[n] = H[n][n];
e[n] = 0.0;
n--;
iter = 0;
// Two roots found
} else if (l == n-1) {
w = H[n][n-1] * H[n-1][n];
p = (H[n-1][n-1] - H[n][n]) / 2.0;
q = p * p + w;
z = sqrt(abs(q));
H[n][n] = H[n][n] + exshift;
H[n-1][n-1] = H[n-1][n-1] + exshift;
x = H[n][n];
// Real pair
if (q >= 0) {
if (p >= 0) {
z = p + z;
} else {
z = p - z;
}
d[n-1] = x + z;
d[n] = d[n-1];
if (z != 0.0) {
d[n] = x - w / z;
}
e[n-1] = 0.0;
e[n] = 0.0;
x = H[n][n-1];
s = abs(x) + abs(z);
p = x / s;
q = z / s;
r = sqrt(p * p+q * q);
p = p / r;
q = q / r;
// Row modification
for (int j = n-1; j < nn; j++) {
z = H[n-1][j];
H[n-1][j] = q * z + p * H[n][j];
H[n][j] = q * H[n][j] - p * z;
}
// Column modification
for (int i = 0; i <= n; i++) {
z = H[i][n-1];
H[i][n-1] = q * z + p * H[i][n];
H[i][n] = q * H[i][n] - p * z;
}
// Accumulate transformations
for (int i = low; i <= high; i++) {
z = V[i][n-1];
V[i][n-1] = q * z + p * V[i][n];
V[i][n] = q * V[i][n] - p * z;
}
// Complex pair
} else {
d[n-1] = x + p;
d[n] = x + p;
e[n-1] = z;
e[n] = -z;
}
n = n - 2;
iter = 0;
// No convergence yet
} else {
// Form shift
x = H[n][n];
y = 0.0;
w = 0.0;
if (l < n) {
y = H[n-1][n-1];
w = H[n][n-1] * H[n-1][n];
}
// Wilkinson's original ad hoc shift
if (iter == 10) {
exshift += x;
for (int i = low; i <= n; i++) {
H[i][i] -= x;
}
s = abs(H[n][n-1]) + abs(H[n-1][n-2]);
x = y = 0.75 * s;
w = -0.4375 * s * s;
}
// MATLAB's new ad hoc shift
if (iter == 30) {
s = (y - x) / 2.0;
s = s * s + w;
if (s > 0) {
s = sqrt(s);
if (y < x) {
s = -s;
}
s = x - w / ((y - x) / 2.0 + s);
for (int i = low; i <= n; i++) {
H[i][i] -= s;
}
exshift += s;
x = y = w = 0.964;
}
}
iter = iter + 1; // (Could check iteration count here.)
// Look for two consecutive small sub-diagonal elements
int m = n-2;
while (m >= l) {
z = H[m][m];
r = x - z;
s = y - z;
p = (r * s - w) / H[m+1][m] + H[m][m+1];
q = H[m+1][m+1] - z - r - s;
r = H[m+2][m+1];
s = abs(p) + abs(q) + abs(r);
p = p / s;
q = q / s;
r = r / s;
if (m == l) {
break;
}
if (abs(H[m][m-1]) * (abs(q) + abs(r)) <
eps * (abs(p) * (abs(H[m-1][m-1]) + abs(z) +
abs(H[m+1][m+1])))) {
break;
}
m--;
}
for (int i = m+2; i <= n; i++) {
H[i][i-2] = 0.0;
if (i > m+2) {
H[i][i-3] = 0.0;
}
}
// Double QR step involving rows l:n and columns m:n
for (int k = m; k <= n-1; k++) {
int notlast = (k != n-1);
if (k != m) {
p = H[k][k-1];
q = H[k+1][k-1];
r = (notlast ? H[k+2][k-1] : 0.0);
x = abs(p) + abs(q) + abs(r);
if (x != 0.0) {
p = p / x;
q = q / x;
r = r / x;
}
}
if (x == 0.0) {
break;
}
s = sqrt(p * p + q * q + r * r);
if (p < 0) {
s = -s;
}
if (s != 0) {
if (k != m) {
H[k][k-1] = -s * x;
} else if (l != m) {
H[k][k-1] = -H[k][k-1];
}
p = p + s;
x = p / s;
y = q / s;
z = r / s;
q = q / p;
r = r / p;
// Row modification
for (int j = k; j < nn; j++) {
p = H[k][j] + q * H[k+1][j];
if (notlast) {
p = p + r * H[k+2][j];
H[k+2][j] = H[k+2][j] - p * z;
}
H[k][j] = H[k][j] - p * x;
H[k+1][j] = H[k+1][j] - p * y;
}
// Column modification
for (int i = 0; i <= min(n,k+3); i++) {
p = x * H[i][k] + y * H[i][k+1];
if (notlast) {
p = p + z * H[i][k+2];
H[i][k+2] = H[i][k+2] - p * r;
}
H[i][k] = H[i][k] - p;
H[i][k+1] = H[i][k+1] - p * q;
}
// Accumulate transformations
for (int i = low; i <= high; i++) {
p = x * V[i][k] + y * V[i][k+1];
if (notlast) {
p = p + z * V[i][k+2];
V[i][k+2] = V[i][k+2] - p * r;
}
V[i][k] = V[i][k] - p;
V[i][k+1] = V[i][k+1] - p * q;
}
} // (s != 0)
} // k loop
} // check convergence
} // while (n >= low)
// Backsubstitute to find vectors of upper triangular form
if (norm == 0.0) {
return;
}
for (n = nn-1; n >= 0; n--) {
p = d[n];
q = e[n];
// Real vector
if (q == 0) {
int l = n;
H[n][n] = 1.0;
for (int i = n-1; i >= 0; i--) {
w = H[i][i] - p;
r = 0.0;
for (int j = l; j <= n; j++) {
r = r + H[i][j] * H[j][n];
}
if (e[i] < 0.0) {
z = w;
s = r;
} else {
l = i;
if (e[i] == 0.0) {
if (w != 0.0) {
H[i][n] = -r / w;
} else {
H[i][n] = -r / (eps * norm);
}
// Solve real equations
} else {
x = H[i][i+1];
y = H[i+1][i];
q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
t = (x * s - z * r) / q;
H[i][n] = t;
if (abs(x) > abs(z)) {
H[i+1][n] = (-r - w * t) / x;
} else {
H[i+1][n] = (-s - y * t) / z;
}
}
// Overflow control
t = abs(H[i][n]);
if ((eps * t) * t > 1) {
for (int j = i; j <= n; j++) {
H[j][n] = H[j][n] / t;
}
}
}
}
// Complex vector
} else if (q < 0) {
int l = n-1;
// Last vector component imaginary so matrix is triangular
if (abs(H[n][n-1]) > abs(H[n-1][n])) {
H[n-1][n-1] = q / H[n][n-1];
H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
} else {
cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
H[n-1][n-1] = cdivr;
H[n-1][n] = cdivi;
}
H[n][n-1] = 0.0;
H[n][n] = 1.0;
for (int i = n-2; i >= 0; i--) {
Real ra,sa,vr,vi;
ra = 0.0;
sa = 0.0;
for (int j = l; j <= n; j++) {
ra = ra + H[i][j] * H[j][n-1];
sa = sa + H[i][j] * H[j][n];
}
w = H[i][i] - p;
if (e[i] < 0.0) {
z = w;
r = ra;
s = sa;
} else {
l = i;
if (e[i] == 0) {
cdiv(-ra,-sa,w,q);
H[i][n-1] = cdivr;
H[i][n] = cdivi;
} else {
// Solve complex equations
x = H[i][i+1];
y = H[i+1][i];
vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
vi = (d[i] - p) * 2.0 * q;
if ((vr == 0.0) && (vi == 0.0)) {
vr = eps * norm * (abs(w) + abs(q) +
abs(x) + abs(y) + abs(z));
}
cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
H[i][n-1] = cdivr;
H[i][n] = cdivi;
if (abs(x) > (abs(z) + abs(q))) {
H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
} else {
cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
H[i+1][n-1] = cdivr;
H[i+1][n] = cdivi;
}
}
// Overflow control
t = max(abs(H[i][n-1]),abs(H[i][n]));
if ((eps * t) * t > 1) {
for (int j = i; j <= n; j++) {
H[j][n-1] = H[j][n-1] / t;
H[j][n] = H[j][n] / t;
}
}
}
}
}
}
// Vectors of isolated roots
for (int i = 0; i < nn; i++) {
if (i < low || i > high) {
for (int j = i; j < nn; j++) {
V[i][j] = H[i][j];
}
}
}
// Back transformation to get eigenvectors of original matrix
for (int j = nn-1; j >= low; j--) {
for (int i = low; i <= high; i++) {
z = 0.0;
for (int k = low; k <= min(j,high); k++) {
z = z + V[i][k] * H[k][j];
}
V[i][j] = z;
}
}
}
public:
/** Check for symmetry, then construct the eigenvalue decomposition
@param A Square real (non-complex) matrix
*/
Eigenvalue(const TNT::Array2D &A) {
n = A.dim2();
V = Array2D(n,n);
d = Array1D(n);
e = Array1D(n);
issymmetric = 1;
for (int j = 0; (j < n) && issymmetric; j++) {
for (int i = 0; (i < n) && issymmetric; i++) {
issymmetric = (A[i][j] == A[j][i]);
}
}
if (issymmetric) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
V[i][j] = A[i][j];
}
}
// Tridiagonalize.
tred2();
// Diagonalize.
tql2();
} else {
H = TNT::Array2D(n,n);
ort = TNT::Array1D(n);
for (int j = 0; j < n; j++) {
for (int i = 0; i < n; i++) {
H[i][j] = A[i][j];
}
}
// Reduce to Hessenberg form.
orthes();
// Reduce Hessenberg to real Schur form.
hqr2();
}
}
/** Return the eigenvector matrix
@return V
*/
void getV (TNT::Array2D &V_) {
V_ = V;
return;
}
/** Return the real parts of the eigenvalues
@return real(diag(D))
*/
void getRealEigenvalues (TNT::Array1D &d_) {
d_ = d;
return ;
}
/** Return the imaginary parts of the eigenvalues
in parameter e_.
@pararm e_: new matrix with imaginary parts of the eigenvalues.
*/
void getImagEigenvalues (TNT::Array1D &e_) {
e_ = e;
return;
}
/**
Computes the block diagonal eigenvalue matrix.
If the original matrix A is not symmetric, then the eigenvalue
matrix D is block diagonal with the real eigenvalues in 1-by-1
blocks and any complex eigenvalues,
a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
eigenvalues look like
u + iv . . . . .
. u - iv . . . .
. . a + ib . . .
. . . a - ib . .
. . . . x .
. . . . . y
then D looks like
u v . . . .
-v u . . . .
. . a b . .
. . -b a . .
. . . . x .
. . . . . y
This keeps V a real matrix in both symmetric and non-symmetric
cases, and A*V = V*D.
@param D: upon return, the matrix is filled with the block diagonal
eigenvalue matrix.
*/
void getD (TNT::Array2D &D) {
D = Array2D(n,n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
D[i][j] = 0.0;
}
D[i][i] = d[i];
if (e[i] > 0) {
D[i][i+1] = e[i];
} else if (e[i] < 0) {
D[i][i-1] = e[i];
}
}
}
};
} //namespace JAMA
#endif
// JAMA_EIG_H
libjama-1.2.4/src/jama/jama_lu.h 0000644 0021451 0021451 00000015567 10146452352 016613 0 ustar pbuilder pbuilder #ifndef JAMA_LU_H
#define JAMA_LU_H
#include "tnt.h"
#include
//for min(), max() below
using namespace TNT;
using namespace std;
namespace JAMA
{
/** LU Decomposition.
For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
unit lower triangular matrix L, an n-by-n upper triangular matrix U,
and a permutation vector piv of length m so that A(piv,:) = L*U.
If m < n, then L is m-by-m and U is m-by-n.
The LU decompostion with pivoting always exists, even if the matrix is
singular, so the constructor will never fail. The primary use of the
LU decomposition is in the solution of square systems of simultaneous
linear equations. This will fail if isNonsingular() returns false.
*/
template
class LU
{
/* Array for internal storage of decomposition. */
Array2D LU_;
int m, n, pivsign;
Array1D piv;
Array2D permute_copy(const Array2D &A,
const Array1D &piv, int j0, int j1)
{
int piv_length = piv.dim();
Array2D X(piv_length, j1-j0+1);
for (int i = 0; i < piv_length; i++)
for (int j = j0; j <= j1; j++)
X[i][j-j0] = A[piv[i]][j];
return X;
}
Array1D permute_copy(const Array1D &A,
const Array1D &piv)
{
int piv_length = piv.dim();
if (piv_length != A.dim())
return Array1D();
Array1D x(piv_length);
for (int i = 0; i < piv_length; i++)
x[i] = A[piv[i]];
return x;
}
public :
/** LU Decomposition
@param A Rectangular matrix
@return LU Decomposition object to access L, U and piv.
*/
LU (const Array2D &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()),
piv(A.dim1())
{
// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
for (int i = 0; i < m; i++) {
piv[i] = i;
}
pivsign = 1;
Real *LUrowi = 0;;
Array1D LUcolj(m);
// Outer loop.
for (int j = 0; j < n; j++) {
// Make a copy of the j-th column to localize references.
for (int i = 0; i < m; i++) {
LUcolj[i] = LU_[i][j];
}
// Apply previous transformations.
for (int i = 0; i < m; i++) {
LUrowi = LU_[i];
// Most of the time is spent in the following dot product.
int kmax = min(i,j);
double s = 0.0;
for (int k = 0; k < kmax; k++) {
s += LUrowi[k]*LUcolj[k];
}
LUrowi[j] = LUcolj[i] -= s;
}
// Find pivot and exchange if necessary.
int p = j;
for (int i = j+1; i < m; i++) {
if (abs(LUcolj[i]) > abs(LUcolj[p])) {
p = i;
}
}
if (p != j) {
int k=0;
for (k = 0; k < n; k++) {
double t = LU_[p][k];
LU_[p][k] = LU_[j][k];
LU_[j][k] = t;
}
k = piv[p];
piv[p] = piv[j];
piv[j] = k;
pivsign = -pivsign;
}
// Compute multipliers.
if ((j < m) && (LU_[j][j] != 0.0)) {
for (int i = j+1; i < m; i++) {
LU_[i][j] /= LU_[j][j];
}
}
}
}
/** Is the matrix nonsingular?
@return 1 (true) if upper triangular factor U (and hence A)
is nonsingular, 0 otherwise.
*/
int isNonsingular () {
for (int j = 0; j < n; j++) {
if (LU_[j][j] == 0)
return 0;
}
return 1;
}
/** Return lower triangular factor
@return L
*/
Array2D getL () {
Array2D L_(m,n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i > j) {
L_[i][j] = LU_[i][j];
} else if (i == j) {
L_[i][j] = 1.0;
} else {
L_[i][j] = 0.0;
}
}
}
return L_;
}
/** Return upper triangular factor
@return U portion of LU factorization.
*/
Array2D getU () {
Array2D U_(n,n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i <= j) {
U_[i][j] = LU_[i][j];
} else {
U_[i][j] = 0.0;
}
}
}
return U_;
}
/** Return pivot permutation vector
@return piv
*/
Array1D getPivot () {
return piv;
}
/** Compute determinant using LU factors.
@return determinant of A, or 0 if A is not square.
*/
Real det () {
if (m != n) {
return Real(0);
}
Real d = Real(pivsign);
for (int j = 0; j < n; j++) {
d *= LU_[j][j];
}
return d;
}
/** Solve A*X = B
@param B A Matrix with as many rows as A and any number of columns.
@return X so that L*U*X = B(piv,:), if B is nonconformant, returns
0x0 (null) array.
*/
Array2D solve (const Array2D &B)
{
/* Dimensions: A is mxn, X is nxk, B is mxk */
if (B.dim1() != m) {
return Array2D(0,0);
}
if (!isNonsingular()) {
return Array2D(0,0);
}
// Copy right hand side with pivoting
int nx = B.dim2();
Array2D X = permute_copy(B, piv, 0, nx-1);
// Solve L*Y = B(piv,:)
for (int k = 0; k < n; k++) {
for (int i = k+1; i < n; i++) {
for (int j = 0; j < nx; j++) {
X[i][j] -= X[k][j]*LU_[i][k];
}
}
}
// Solve U*X = Y;
for (int k = n-1; k >= 0; k--) {
for (int j = 0; j < nx; j++) {
X[k][j] /= LU_[k][k];
}
for (int i = 0; i < k; i++) {
for (int j = 0; j < nx; j++) {
X[i][j] -= X[k][j]*LU_[i][k];
}
}
}
return X;
}
/** Solve A*x = b, where x and b are vectors of length equal
to the number of rows in A.
@param b a vector (Array1D> of length equal to the first dimension
of A.
@return x a vector (Array1D> so that L*U*x = b(piv), if B is nonconformant,
returns 0x0 (null) array.
*/
Array1D solve (const Array1D &b)
{
/* Dimensions: A is mxn, X is nxk, B is mxk */
if (b.dim1() != m) {
return Array1D();
}
if (!isNonsingular()) {
return Array1D();
}
Array1D x = permute_copy(b, piv);
// Solve L*Y = B(piv)
for (int k = 0; k < n; k++) {
for (int i = k+1; i < n; i++) {
x[i] -= x[k]*LU_[i][k];
}
}
// Solve U*X = Y;
for (int k = n-1; k >= 0; k--) {
x[k] /= LU_[k][k];
for (int i = 0; i < k; i++)
x[i] -= x[k]*LU_[i][k];
}
return x;
}
}; /* class LU */
} /* namespace JAMA */
#endif
/* JAMA_LU_H */
libjama-1.2.4/src/jama/jama_qr.h 0000644 0021451 0021451 00000016273 10250113571 016601 0 ustar pbuilder pbuilder #ifndef JAMA_QR_H
#define JAMA_QR_H
#include "tnt_array1d.h"
#include "tnt_array2d.h"
#include "tnt_math_utils.h"
namespace JAMA
{
/**
Classical QR Decompisition:
for an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
orthogonal matrix Q and an n-by-n upper triangular matrix R so that
A = Q*R.
The QR decompostion always exists, even if the matrix does not have
full rank, so the constructor will never fail. The primary use of the
QR decomposition is in the least squares solution of nonsquare systems
of simultaneous linear equations. This will fail if isFullRank()
returns 0 (false).
The Q and R factors can be retrived via the getQ() and getR()
methods. Furthermore, a solve() method is provided to find the
least squares solution of Ax=b using the QR factors.
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
*/
template
class QR {
/** Array for internal storage of decomposition.
@serial internal array storage.
*/
TNT::Array2D QR_;
/** Row and column dimensions.
@serial column dimension.
@serial row dimension.
*/
int m, n;
/** Array for internal storage of diagonal of R.
@serial diagonal of R.
*/
TNT::Array1D Rdiag;
public:
/**
Create a QR factorization object for A.
@param A rectangular (m>=n) matrix.
*/
QR(const TNT::Array2D &A) /* constructor */
{
QR_ = A.copy();
m = A.dim1();
n = A.dim2();
Rdiag = TNT::Array1D(n);
int i=0, j=0, k=0;
// Main loop.
for (k = 0; k < n; k++) {
// Compute 2-norm of k-th column without under/overflow.
Real nrm = 0;
for (i = k; i < m; i++) {
nrm = TNT::hypot(nrm,QR_[i][k]);
}
if (nrm != 0.0) {
// Form k-th Householder vector.
if (QR_[k][k] < 0) {
nrm = -nrm;
}
for (i = k; i < m; i++) {
QR_[i][k] /= nrm;
}
QR_[k][k] += 1.0;
// Apply transformation to remaining columns.
for (j = k+1; j < n; j++) {
Real s = 0.0;
for (i = k; i < m; i++) {
s += QR_[i][k]*QR_[i][j];
}
s = -s/QR_[k][k];
for (i = k; i < m; i++) {
QR_[i][j] += s*QR_[i][k];
}
}
}
Rdiag[k] = -nrm;
}
}
/**
Flag to denote the matrix is of full rank.
@return 1 if matrix is full rank, 0 otherwise.
*/
int isFullRank() const
{
for (int j = 0; j < n; j++)
{
if (Rdiag[j] == 0)
return 0;
}
return 1;
}
/**
Retreive the Householder vectors from QR factorization
@returns lower trapezoidal matrix whose columns define the reflections
*/
TNT::Array2D getHouseholder (void) const
{
TNT::Array2D H(m,n);
/* note: H is completely filled in by algorithm, so
initializaiton of H is not necessary.
*/
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i >= j) {
H[i][j] = QR_[i][j];
} else {
H[i][j] = 0.0;
}
}
}
return H;
}
/** Return the upper triangular factor, R, of the QR factorization
@return R
*/
TNT::Array2D getR() const
{
TNT::Array2D R(n,n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i < j) {
R[i][j] = QR_[i][j];
} else if (i == j) {
R[i][j] = Rdiag[i];
} else {
R[i][j] = 0.0;
}
}
}
return R;
}
/**
Generate and return the (economy-sized) orthogonal factor
@param Q the (ecnomy-sized) orthogonal factor (Q*R=A).
*/
TNT::Array2D getQ() const
{
int i=0, j=0, k=0;
TNT::Array2D Q(m,n);
for (k = n-1; k >= 0; k--) {
for (i = 0; i < m; i++) {
Q[i][k] = 0.0;
}
Q[k][k] = 1.0;
for (j = k; j < n; j++) {
if (QR_[k][k] != 0) {
Real s = 0.0;
for (i = k; i < m; i++) {
s += QR_[i][k]*Q[i][j];
}
s = -s/QR_[k][k];
for (i = k; i < m; i++) {
Q[i][j] += s*QR_[i][k];
}
}
}
}
return Q;
}
/** Least squares solution of A*x = b
@param B m-length array (vector).
@return x n-length array (vector) that minimizes the two norm of Q*R*X-B.
If B is non-conformant, or if QR.isFullRank() is false,
the routine returns a null (0-length) vector.
*/
TNT::Array1D solve(const TNT::Array1D &b) const
{
if (b.dim1() != m) /* arrays must be conformant */
return TNT::Array1D();
if ( !isFullRank() ) /* matrix is rank deficient */
{
return TNT::Array1D();
}
TNT::Array1D x = b.copy();
// Compute Y = transpose(Q)*b
for (int k = 0; k < n; k++)
{
Real s = 0.0;
for (int i = k; i < m; i++)
{
s += QR_[i][k]*x[i];
}
s = -s/QR_[k][k];
for (int i = k; i < m; i++)
{
x[i] += s*QR_[i][k];
}
}
// Solve R*X = Y;
for (int k = n-1; k >= 0; k--)
{
x[k] /= Rdiag[k];
for (int i = 0; i < k; i++) {
x[i] -= x[k]*QR_[i][k];
}
}
/* return n x nx portion of X */
TNT::Array1D x_(n);
for (int i=0; i solve(const TNT::Array2D &B) const
{
if (B.dim1() != m) /* arrays must be conformant */
return TNT::Array2D(0,0);
if ( !isFullRank() ) /* matrix is rank deficient */
{
return TNT::Array2D(0,0);
}
int nx = B.dim2();
TNT::Array2D X = B.copy();
int i=0, j=0, k=0;
// Compute Y = transpose(Q)*B
for (k = 0; k < n; k++) {
for (j = 0; j < nx; j++) {
Real s = 0.0;
for (i = k; i < m; i++) {
s += QR_[i][k]*X[i][j];
}
s = -s/QR_[k][k];
for (i = k; i < m; i++) {
X[i][j] += s*QR_[i][k];
}
}
}
// Solve R*X = Y;
for (k = n-1; k >= 0; k--) {
for (j = 0; j < nx; j++) {
X[k][j] /= Rdiag[k];
}
for (i = 0; i < k; i++) {
for (j = 0; j < nx; j++) {
X[i][j] -= X[k][j]*QR_[i][k];
}
}
}
/* return n x nx portion of X */
TNT::Array2D X_(n,nx);
for (i=0; i