"serialization/tests/TestSerializeQTBIntegrator.cpp" did not exist on "a566a07487053f5eaee59cac0a0938b790697a65"
Commit 52a68c81 authored by Peter Eastman's avatar Peter Eastman
Browse files

Created reference implementation of rigid shake algorithm. Added the JAMA package to OpenMM.

parent 671419fa
......@@ -51,7 +51,7 @@ SUBDIRS (tests)
# The source is organized into subdirectories, but we handle them all from
# this CMakeLists file rather than letting CMake visit them as SUBDIRS.
SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla platforms/reference)
SET(OPENMM_SOURCE_SUBDIRS . openmmapi olla jama platforms/reference)
# The build system will set ARCH64 for 64 bit builds, which require
# use of the lib64/ library directories rather than lib/.
......
#ifndef JAMA_CHOLESKY_H
#define JAMA_CHOLESKY_H
#include "math.h"
/* needed for sqrt() below. */
namespace JAMA
{
using namespace TNT;
/**
<P>
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.
<p>Typical usage looks like:
<pre>
Array2D<double> A(n,n);
Array2D<double> L;
...
Cholesky<double> chol(A);
if (chol.is_spd())
L = chol.getL();
else
cout << "factorization was not complete.\n";
</pre>
<p>
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
*/
template <class Real>
class Cholesky
{
Array2D<Real> L_; // lower triangular factor
int isspd; // 1 if matrix to be factored was SPD
public:
Cholesky();
Cholesky(const Array2D<Real> &A);
Array2D<Real> getL() const;
Array1D<Real> solve(const Array1D<Real> &B);
Array2D<Real> solve(const Array2D<Real> &B);
int is_spd() const;
};
template <class Real>
Cholesky<Real>::Cholesky() : L_(0,0), isspd(0) {}
/**
@return 1, if original matrix to be factored was symmetric
positive-definite (SPD).
*/
template <class Real>
int Cholesky<Real>::is_spd() const
{
return isspd;
}
/**
@return the lower triangular factor, L, such that L*L'=A.
*/
template <class Real>
Array2D<Real> Cholesky<Real>::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 <class Real>
Cholesky<Real>::Cholesky(const Array2D<Real> &A)
{
int m = A.dim1();
int n = A.dim2();
isspd = (m == n);
if (m != n)
{
L_ = Array2D<Real>(0,0);
return;
}
L_ = Array2D<Real>(n,n);
// Main loop.
for (int j = 0; j < n; j++)
{
Real 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 <class Real>
Array1D<Real> Cholesky<Real>::solve(const Array1D<Real> &b)
{
int n = L_.dim1();
if (b.dim1() != n)
return Array1D<Real>();
Array1D<Real> 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 <class Real>
Array2D<Real> Cholesky<Real>::solve(const Array2D<Real> &B)
{
int n = L_.dim1();
if (B.dim1() != n)
return Array2D<Real>();
Array2D<Real> 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<nx; j++)
{
for (int k = n-1; k >= 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
This diff is collapsed.
#ifndef JAMA_LU_H
#define JAMA_LU_H
#include "tnt.h"
#include <algorithm>
//for min(), max() below
using namespace TNT;
using namespace std;
namespace JAMA
{
/** LU Decomposition.
<P>
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.
<P>
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 Real>
class LU
{
/* Array for internal storage of decomposition. */
Array2D<Real> LU_;
int m, n, pivsign;
Array1D<int> piv;
Array2D<Real> permute_copy(const Array2D<Real> &A,
const Array1D<int> &piv, int j0, int j1)
{
int piv_length = piv.dim();
Array2D<Real> 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<Real> permute_copy(const Array1D<Real> &A,
const Array1D<int> &piv)
{
int piv_length = piv.dim();
if (piv_length != A.dim())
return Array1D<Real>();
Array1D<Real> 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<Real> &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<Real> 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<Real> getL () {
Array2D<Real> 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<Real> getU () {
Array2D<Real> 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<int> 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<Real> solve (const Array2D<Real> &B)
{
/* Dimensions: A is mxn, X is nxk, B is mxk */
if (B.dim1() != m) {
return Array2D<Real>(0,0);
}
if (!isNonsingular()) {
return Array2D<Real>(0,0);
}
// Copy right hand side with pivoting
int nx = B.dim2();
Array2D<Real> 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<Real> solve (const Array1D<Real> &b)
{
/* Dimensions: A is mxn, X is nxk, B is mxk */
if (b.dim1() != m) {
return Array1D<Real>();
}
if (!isNonsingular()) {
return Array1D<Real>();
}
Array1D<Real> 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 */
#ifndef JAMA_QR_H
#define JAMA_QR_H
#include "tnt_array1d.h"
#include "tnt_array2d.h"
#include "tnt_math_utils.h"
namespace JAMA
{
/**
<p>
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.
<P>
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).
<p>
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.
<p>
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
*/
template <class Real>
class QR {
/** Array for internal storage of decomposition.
@serial internal array storage.
*/
TNT::Array2D<Real> 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<Real> Rdiag;
public:
/**
Create a QR factorization object for A.
@param A rectangular (m>=n) matrix.
*/
QR(const TNT::Array2D<Real> &A) /* constructor */
{
QR_ = A.copy();
m = A.dim1();
n = A.dim2();
Rdiag = TNT::Array1D<Real>(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<Real> getHouseholder (void) const
{
TNT::Array2D<Real> 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<Real> getR() const
{
TNT::Array2D<Real> 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<Real> getQ() const
{
int i=0, j=0, k=0;
TNT::Array2D<Real> 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<Real> solve(const TNT::Array1D<Real> &b) const
{
if (b.dim1() != m) /* arrays must be conformant */
return TNT::Array1D<Real>();
if ( !isFullRank() ) /* matrix is rank deficient */
{
return TNT::Array1D<Real>();
}
TNT::Array1D<Real> 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<Real> x_(n);
for (int i=0; i<n; i++)
x_[i] = x[i];
return x_;
}
/** Least squares solution of A*X = B
@param B m x k Array (must conform).
@return X n x k Array 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 (0x0) array.
*/
TNT::Array2D<Real> solve(const TNT::Array2D<Real> &B) const
{
if (B.dim1() != m) /* arrays must be conformant */
return TNT::Array2D<Real>(0,0);
if ( !isFullRank() ) /* matrix is rank deficient */
{
return TNT::Array2D<Real>(0,0);
}
int nx = B.dim2();
TNT::Array2D<Real> 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<Real> X_(n,nx);
for (i=0; i<n; i++)
for (j=0; j<nx; j++)
X_[i][j] = X[i][j];
return X_;
}
};
}
// namespace JAMA
#endif
// JAMA_QR__H
#ifndef JAMA_SVD_H
#define JAMA_SVD_H
#include "tnt_array1d.h"
#include "tnt_array1d_utils.h"
#include "tnt_array2d.h"
#include "tnt_array2d_utils.h"
#include "tnt_math_utils.h"
#include <algorithm>
// for min(), max() below
#include <cmath>
// for abs() below
using namespace TNT;
using namespace std;
namespace JAMA
{
/** Singular Value Decomposition.
<P>
For an m-by-n matrix A with m >= n, the singular value decomposition is
an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
an n-by-n orthogonal matrix V so that A = U*S*V'.
<P>
The singular values, sigma[k] = S[k][k], are ordered so that
sigma[0] >= sigma[1] >= ... >= sigma[n-1].
<P>
The singular value decompostion always exists, so the constructor will
never fail. The matrix condition number and the effective numerical
rank can be computed from this decomposition.
<p>
(Adapted from JAMA, a Java Matrix Library, developed by jointly
by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
*/
template <class Real>
class SVD
{
Array2D<Real> U, V;
Array1D<Real> s;
int m, n;
public:
SVD (const Array2D<Real> &Arg) {
m = Arg.dim1();
n = Arg.dim2();
int nu = min(m,n);
s = Array1D<Real>(min(m+1,n));
U = Array2D<Real>(m, nu, Real(0));
V = Array2D<Real>(n,n);
Array1D<Real> e(n);
Array1D<Real> work(m);
Array2D<Real> A(Arg.copy());
int wantu = 1; /* boolean */
int wantv = 1; /* boolean */
int i=0, j=0, k=0;
// Reduce A to bidiagonal form, storing the diagonal elements
// in s and the super-diagonal elements in e.
int nct = min(m-1,n);
int nrt = max(0,min(n-2,m));
for (k = 0; k < max(nct,nrt); k++) {
if (k < nct) {
// Compute the transformation for the k-th column and
// place the k-th diagonal in s[k].
// Compute 2-norm of k-th column without under/overflow.
s[k] = 0;
for (i = k; i < m; i++) {
s[k] = hypot(s[k],A[i][k]);
}
if (s[k] != 0.0) {
if (A[k][k] < 0.0) {
s[k] = -s[k];
}
for (i = k; i < m; i++) {
A[i][k] /= s[k];
}
A[k][k] += 1.0;
}
s[k] = -s[k];
}
for (j = k+1; j < n; j++) {
if ((k < nct) && (s[k] != 0.0)) {
// Apply the transformation.
Real t(0.0);
for (i = k; i < m; i++) {
t += A[i][k]*A[i][j];
}
t = -t/A[k][k];
for (i = k; i < m; i++) {
A[i][j] += t*A[i][k];
}
}
// Place the k-th row of A into e for the
// subsequent calculation of the row transformation.
e[j] = A[k][j];
}
if (wantu & (k < nct)) {
// Place the transformation in U for subsequent back
// multiplication.
for (i = k; i < m; i++) {
U[i][k] = A[i][k];
}
}
if (k < nrt) {
// Compute the k-th row transformation and place the
// k-th super-diagonal in e[k].
// Compute 2-norm without under/overflow.
e[k] = 0;
for (i = k+1; i < n; i++) {
e[k] = hypot(e[k],e[i]);
}
if (e[k] != 0.0) {
if (e[k+1] < 0.0) {
e[k] = -e[k];
}
for (i = k+1; i < n; i++) {
e[i] /= e[k];
}
e[k+1] += 1.0;
}
e[k] = -e[k];
if ((k+1 < m) & (e[k] != 0.0)) {
// Apply the transformation.
for (i = k+1; i < m; i++) {
work[i] = 0.0;
}
for (j = k+1; j < n; j++) {
for (i = k+1; i < m; i++) {
work[i] += e[j]*A[i][j];
}
}
for (j = k+1; j < n; j++) {
Real t(-e[j]/e[k+1]);
for (i = k+1; i < m; i++) {
A[i][j] += t*work[i];
}
}
}
if (wantv) {
// Place the transformation in V for subsequent
// back multiplication.
for (i = k+1; i < n; i++) {
V[i][k] = e[i];
}
}
}
}
// Set up the final bidiagonal matrix or order p.
int p = min(n,m+1);
if (nct < n) {
s[nct] = A[nct][nct];
}
if (m < p) {
s[p-1] = 0.0;
}
if (nrt+1 < p) {
e[nrt] = A[nrt][p-1];
}
e[p-1] = 0.0;
// If required, generate U.
if (wantu) {
for (j = nct; j < nu; j++) {
for (i = 0; i < m; i++) {
U[i][j] = 0.0;
}
U[j][j] = 1.0;
}
for (k = nct-1; k >= 0; k--) {
if (s[k] != 0.0) {
for (j = k+1; j < nu; j++) {
Real t(0.0);
for (i = k; i < m; i++) {
t += U[i][k]*U[i][j];
}
t = -t/U[k][k];
for (i = k; i < m; i++) {
U[i][j] += t*U[i][k];
}
}
for (i = k; i < m; i++ ) {
U[i][k] = -U[i][k];
}
U[k][k] = 1.0 + U[k][k];
for (i = 0; i < k-1; i++) {
U[i][k] = 0.0;
}
} else {
for (i = 0; i < m; i++) {
U[i][k] = 0.0;
}
U[k][k] = 1.0;
}
}
}
// If required, generate V.
if (wantv) {
for (k = n-1; k >= 0; k--) {
if ((k < nrt) & (e[k] != 0.0)) {
for (j = k+1; j < nu; j++) {
Real t(0.0);
for (i = k+1; i < n; i++) {
t += V[i][k]*V[i][j];
}
t = -t/V[k+1][k];
for (i = k+1; i < n; i++) {
V[i][j] += t*V[i][k];
}
}
}
for (i = 0; i < n; i++) {
V[i][k] = 0.0;
}
V[k][k] = 1.0;
}
}
// Main iteration loop for the singular values.
int pp = p-1;
int iter = 0;
Real eps(pow(2.0,-52.0));
while (p > 0) {
int k=0;
int kase=0;
// Here is where a test for too many iterations would go.
// This section of the program inspects for
// negligible elements in the s and e arrays. On
// completion the variables kase and k are set as follows.
// kase = 1 if s(p) and e[k-1] are negligible and k<p
// kase = 2 if s(k) is negligible and k<p
// kase = 3 if e[k-1] is negligible, k<p, and
// s(k), ..., s(p) are not negligible (qr step).
// kase = 4 if e(p-1) is negligible (convergence).
for (k = p-2; k >= -1; k--) {
if (k == -1) {
break;
}
if (abs(e[k]) <= eps*(abs(s[k]) + abs(s[k+1]))) {
e[k] = 0.0;
break;
}
}
if (k == p-2) {
kase = 4;
} else {
int ks;
for (ks = p-1; ks >= k; ks--) {
if (ks == k) {
break;
}
Real t( (ks != p ? abs(e[ks]) : 0.) +
(ks != k+1 ? abs(e[ks-1]) : 0.));
if (abs(s[ks]) <= eps*t) {
s[ks] = 0.0;
break;
}
}
if (ks == k) {
kase = 3;
} else if (ks == p-1) {
kase = 1;
} else {
kase = 2;
k = ks;
}
}
k++;
// Perform the task indicated by kase.
switch (kase) {
// Deflate negligible s(p).
case 1: {
Real f(e[p-2]);
e[p-2] = 0.0;
for (j = p-2; j >= k; j--) {
Real t( hypot(s[j],f));
Real cs(s[j]/t);
Real sn(f/t);
s[j] = t;
if (j != k) {
f = -sn*e[j-1];
e[j-1] = cs*e[j-1];
}
if (wantv) {
for (i = 0; i < n; i++) {
t = cs*V[i][j] + sn*V[i][p-1];
V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
V[i][j] = t;
}
}
}
}
break;
// Split at negligible s(k).
case 2: {
Real f(e[k-1]);
e[k-1] = 0.0;
for (j = k; j < p; j++) {
Real t(hypot(s[j],f));
Real cs( s[j]/t);
Real sn(f/t);
s[j] = t;
f = -sn*e[j];
e[j] = cs*e[j];
if (wantu) {
for (i = 0; i < m; i++) {
t = cs*U[i][j] + sn*U[i][k-1];
U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
U[i][j] = t;
}
}
}
}
break;
// Perform one qr step.
case 3: {
// Calculate the shift.
Real scale = max(max(max(max(
abs(s[p-1]),abs(s[p-2])),abs(e[p-2])),
abs(s[k])),abs(e[k]));
Real sp = s[p-1]/scale;
Real spm1 = s[p-2]/scale;
Real epm1 = e[p-2]/scale;
Real sk = s[k]/scale;
Real ek = e[k]/scale;
Real b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
Real c = (sp*epm1)*(sp*epm1);
Real shift = 0.0;
if ((b != 0.0) || (c != 0.0)) {
shift = sqrt(b*b + c);
if (b < 0.0) {
shift = -shift;
}
shift = c/(b + shift);
}
Real f = (sk + sp)*(sk - sp) + shift;
Real g = sk*ek;
// Chase zeros.
for (j = k; j < p-1; j++) {
Real t = hypot(f,g);
Real cs = f/t;
Real sn = g/t;
if (j != k) {
e[j-1] = t;
}
f = cs*s[j] + sn*e[j];
e[j] = cs*e[j] - sn*s[j];
g = sn*s[j+1];
s[j+1] = cs*s[j+1];
if (wantv) {
for (i = 0; i < n; i++) {
t = cs*V[i][j] + sn*V[i][j+1];
V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
V[i][j] = t;
}
}
t = hypot(f,g);
cs = f/t;
sn = g/t;
s[j] = t;
f = cs*e[j] + sn*s[j+1];
s[j+1] = -sn*e[j] + cs*s[j+1];
g = sn*e[j+1];
e[j+1] = cs*e[j+1];
if (wantu && (j < m-1)) {
for (i = 0; i < m; i++) {
t = cs*U[i][j] + sn*U[i][j+1];
U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
U[i][j] = t;
}
}
}
e[p-2] = f;
iter = iter + 1;
}
break;
// Convergence.
case 4: {
// Make the singular values positive.
if (s[k] <= 0.0) {
s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
if (wantv) {
for (i = 0; i <= pp; i++) {
V[i][k] = -V[i][k];
}
}
}
// Order the singular values.
while (k < pp) {
if (s[k] >= s[k+1]) {
break;
}
Real t = s[k];
s[k] = s[k+1];
s[k+1] = t;
if (wantv && (k < n-1)) {
for (i = 0; i < n; i++) {
t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
}
}
if (wantu && (k < m-1)) {
for (i = 0; i < m; i++) {
t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
}
}
k++;
}
iter = 0;
p--;
}
break;
}
}
}
void getU (Array2D<Real> &A)
{
int minm = min(m+1,n);
A = Array2D<Real>(m, minm);
for (int i=0; i<m; i++)
for (int j=0; j<minm; j++)
A[i][j] = U[i][j];
}
/* Return the right singular vectors */
void getV (Array2D<Real> &A)
{
A = V;
}
/** Return the one-dimensional array of singular values */
void getSingularValues (Array1D<Real> &x)
{
x = s;
}
/** Return the diagonal matrix of singular values
@return S
*/
void getS (Array2D<Real> &A) {
A = Array2D<Real>(n,n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
A[i][j] = 0.0;
}
A[i][i] = s[i];
}
}
/** Two norm (max(S)) */
Real norm2 () {
return s[0];
}
/** Two norm of condition number (max(S)/min(S)) */
Real cond () {
return s[0]/s[min(m,n)-1];
}
/** Effective numerical matrix rank
@return Number of nonnegligible singular values.
*/
int rank ()
{
Real eps = pow(2.0,-52.0);
Real tol = max(m,n)*s[0]*eps;
int r = 0;
for (int i = 0; i < s.dim(); i++) {
if (s[i] > tol) {
r++;
}
}
return r;
}
};
}
#endif
// JAMA_SVD_H
/*
*
* Template Numerical Toolkit (TNT): Linear Algebra Module
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_H
#define TNT_H
//---------------------------------------------------------------------
// Define this macro if you want TNT to track some of the out-of-bounds
// indexing. This can encur a small run-time overhead, but is recommended
// while developing code. It can be turned off for production runs.
//
// #define TNT_BOUNDS_CHECK
//---------------------------------------------------------------------
//
//#define TNT_BOUNDS_CHECK
#include "tnt_version.h"
#include "tnt_math_utils.h"
#include "tnt_array1d.h"
#include "tnt_array2d.h"
#include "tnt_array3d.h"
#include "tnt_array1d_utils.h"
#include "tnt_array2d_utils.h"
#include "tnt_array3d_utils.h"
#include "tnt_fortran_array1d.h"
#include "tnt_fortran_array2d.h"
#include "tnt_fortran_array3d.h"
#include "tnt_fortran_array1d_utils.h"
#include "tnt_fortran_array2d_utils.h"
#include "tnt_fortran_array3d_utils.h"
#include "tnt_sparse_matrix_csr.h"
#include "tnt_stopwatch.h"
#include "tnt_subscript.h"
#include "tnt_vec.h"
#include "tnt_cmat.h"
#endif
// TNT_H
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_ARRAY1D_H
#define TNT_ARRAY1D_H
//#include <cstdlib>
#include <iostream>
#ifdef TNT_BOUNDS_CHECK
#include <assert.h>
#endif
#include "tnt_i_refvec.h"
namespace TNT
{
template <class T>
class Array1D
{
private:
/* ... */
i_refvec<T> v_;
int n_;
T* data_; /* this normally points to v_.begin(), but
* could also point to a portion (subvector)
* of v_.
*/
void copy_(T* p, const T* q, int len) const;
void set_(T* begin, T* end, const T& val);
public:
typedef T value_type;
Array1D();
explicit Array1D(int n);
Array1D(int n, const T &a);
Array1D(int n, T *a);
inline Array1D(const Array1D &A);
inline operator T*();
inline operator const T*();
inline Array1D & operator=(const T &a);
inline Array1D & operator=(const Array1D &A);
inline Array1D & ref(const Array1D &A);
Array1D copy() const;
Array1D & inject(const Array1D & A);
inline T& operator[](int i);
inline const T& operator[](int i) const;
inline int dim1() const;
inline int dim() const;
~Array1D();
/* ... extended interface ... */
inline int ref_count() const;
inline Array1D<T> subarray(int i0, int i1);
};
template <class T>
Array1D<T>::Array1D() : v_(), n_(0), data_(0) {}
template <class T>
Array1D<T>::Array1D(const Array1D<T> &A) : v_(A.v_), n_(A.n_),
data_(A.data_)
{
#ifdef TNT_DEBUG
std::cout << "Created Array1D(const Array1D<T> &A) \n";
#endif
}
template <class T>
Array1D<T>::Array1D(int n) : v_(n), n_(n), data_(v_.begin())
{
#ifdef TNT_DEBUG
std::cout << "Created Array1D(int n) \n";
#endif
}
template <class T>
Array1D<T>::Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
{
#ifdef TNT_DEBUG
std::cout << "Created Array1D(int n, const T& val) \n";
#endif
set_(data_, data_+ n, val);
}
template <class T>
Array1D<T>::Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
{
#ifdef TNT_DEBUG
std::cout << "Created Array1D(int n, T* a) \n";
#endif
}
template <class T>
inline Array1D<T>::operator T*()
{
return &(v_[0]);
}
template <class T>
inline Array1D<T>::operator const T*()
{
return &(v_[0]);
}
template <class T>
inline T& Array1D<T>::operator[](int i)
{
#ifdef TNT_BOUNDS_CHECK
assert(i>= 0);
assert(i < n_);
#endif
return data_[i];
}
template <class T>
inline const T& Array1D<T>::operator[](int i) const
{
#ifdef TNT_BOUNDS_CHECK
assert(i>= 0);
assert(i < n_);
#endif
return data_[i];
}
template <class T>
Array1D<T> & Array1D<T>::operator=(const T &a)
{
set_(data_, data_+n_, a);
return *this;
}
template <class T>
Array1D<T> Array1D<T>::copy() const
{
Array1D A( n_);
copy_(A.data_, data_, n_);
return A;
}
template <class T>
Array1D<T> & Array1D<T>::inject(const Array1D &A)
{
if (A.n_ == n_)
copy_(data_, A.data_, n_);
return *this;
}
template <class T>
Array1D<T> & Array1D<T>::ref(const Array1D<T> &A)
{
if (this != &A)
{
v_ = A.v_; /* operator= handles the reference counting. */
n_ = A.n_;
data_ = A.data_;
}
return *this;
}
template <class T>
Array1D<T> & Array1D<T>::operator=(const Array1D<T> &A)
{
return ref(A);
}
template <class T>
inline int Array1D<T>::dim1() const { return n_; }
template <class T>
inline int Array1D<T>::dim() const { return n_; }
template <class T>
Array1D<T>::~Array1D() {}
/* ............................ exented interface ......................*/
template <class T>
inline int Array1D<T>::ref_count() const
{
return v_.ref_count();
}
template <class T>
inline Array1D<T> Array1D<T>::subarray(int i0, int i1)
{
if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
{
Array1D<T> X(*this); /* create a new instance of this array. */
X.n_ = i1-i0+1;
X.data_ += i0;
return X;
}
else
{
return Array1D<T>();
}
}
/* private internal functions */
template <class T>
void Array1D<T>::set_(T* begin, T* end, const T& a)
{
for (T* p=begin; p<end; p++)
*p = a;
}
template <class T>
void Array1D<T>::copy_(T* p, const T* q, int len) const
{
T *end = p + len;
while (p<end )
*p++ = *q++;
}
} /* namespace TNT */
#endif
/* TNT_ARRAY1D_H */
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_ARRAY1D_UTILS_H
#define TNT_ARRAY1D_UTILS_H
#include <cstdlib>
#include <cassert>
namespace TNT
{
template <class T>
std::ostream& operator<<(std::ostream &s, const Array1D<T> &A)
{
int N=A.dim1();
#ifdef TNT_DEBUG
s << "addr: " << (void *) &A[0] << "\n";
#endif
s << N << "\n";
for (int j=0; j<N; j++)
{
s << A[j] << "\n";
}
s << "\n";
return s;
}
template <class T>
std::istream& operator>>(std::istream &s, Array1D<T> &A)
{
int N;
s >> N;
Array1D<T> B(N);
for (int i=0; i<N; i++)
s >> B[i];
A = B;
return s;
}
template <class T>
Array1D<T> operator+(const Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() != n )
return Array1D<T>();
else
{
Array1D<T> C(n);
for (int i=0; i<n; i++)
{
C[i] = A[i] + B[i];
}
return C;
}
}
template <class T>
Array1D<T> operator-(const Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() != n )
return Array1D<T>();
else
{
Array1D<T> C(n);
for (int i=0; i<n; i++)
{
C[i] = A[i] - B[i];
}
return C;
}
}
template <class T>
Array1D<T> operator*(const Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() != n )
return Array1D<T>();
else
{
Array1D<T> C(n);
for (int i=0; i<n; i++)
{
C[i] = A[i] * B[i];
}
return C;
}
}
template <class T>
Array1D<T> operator/(const Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() != n )
return Array1D<T>();
else
{
Array1D<T> C(n);
for (int i=0; i<n; i++)
{
C[i] = A[i] / B[i];
}
return C;
}
}
template <class T>
Array1D<T>& operator+=(Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() == n)
{
for (int i=0; i<n; i++)
{
A[i] += B[i];
}
}
return A;
}
template <class T>
Array1D<T>& operator-=(Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() == n)
{
for (int i=0; i<n; i++)
{
A[i] -= B[i];
}
}
return A;
}
template <class T>
Array1D<T>& operator*=(Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() == n)
{
for (int i=0; i<n; i++)
{
A[i] *= B[i];
}
}
return A;
}
template <class T>
Array1D<T>& operator/=(Array1D<T> &A, const Array1D<T> &B)
{
int n = A.dim1();
if (B.dim1() == n)
{
for (int i=0; i<n; i++)
{
A[i] /= B[i];
}
}
return A;
}
} // namespace TNT
#endif
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_ARRAY2D_H
#define TNT_ARRAY2D_H
#include <cstdlib>
#include <iostream>
#ifdef TNT_BOUNDS_CHECK
#include <assert.h>
#endif
#include "tnt_array1d.h"
namespace TNT
{
template <class T>
class Array2D
{
private:
Array1D<T> data_;
Array1D<T*> v_;
int m_;
int n_;
public:
typedef T value_type;
Array2D();
Array2D(int m, int n);
Array2D(int m, int n, T *a);
Array2D(int m, int n, const T &a);
inline Array2D(const Array2D &A);
inline operator T**();
inline operator const T**();
inline Array2D & operator=(const T &a);
inline Array2D & operator=(const Array2D &A);
inline Array2D & ref(const Array2D &A);
Array2D copy() const;
Array2D & inject(const Array2D & A);
inline T* operator[](int i);
inline const T* operator[](int i) const;
inline int dim1() const;
inline int dim2() const;
~Array2D();
/* extended interface (not part of the standard) */
inline int ref_count();
inline int ref_count_data();
inline int ref_count_dim1();
Array2D subarray(int i0, int i1, int j0, int j1);
};
template <class T>
Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {}
template <class T>
Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_),
m_(A.m_), n_(A.n_) {}
template <class T>
Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n)
{
if (m>0 && n>0)
{
T* p = &(data_[0]);
for (int i=0; i<m; i++)
{
v_[i] = p;
p += n;
}
}
}
template <class T>
Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m),
m_(m), n_(n)
{
if (m>0 && n>0)
{
data_ = val;
T* p = &(data_[0]);
for (int i=0; i<m; i++)
{
v_[i] = p;
p += n;
}
}
}
template <class T>
Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n)
{
if (m>0 && n>0)
{
T* p = &(data_[0]);
for (int i=0; i<m; i++)
{
v_[i] = p;
p += n;
}
}
}
template <class T>
inline T* Array2D<T>::operator[](int i)
{
#ifdef TNT_BOUNDS_CHECK
assert(i >= 0);
assert(i < m_);
#endif
return v_[i];
}
template <class T>
inline const T* Array2D<T>::operator[](int i) const
{
#ifdef TNT_BOUNDS_CHECK
assert(i >= 0);
assert(i < m_);
#endif
return v_[i];
}
template <class T>
Array2D<T> & Array2D<T>::operator=(const T &a)
{
/* non-optimzied, but will work with subarrays in future verions */
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
v_[i][j] = a;
return *this;
}
template <class T>
Array2D<T> Array2D<T>::copy() const
{
Array2D A(m_, n_);
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
A[i][j] = v_[i][j];
return A;
}
template <class T>
Array2D<T> & Array2D<T>::inject(const Array2D &A)
{
if (A.m_ == m_ && A.n_ == n_)
{
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
v_[i][j] = A[i][j];
}
return *this;
}
template <class T>
Array2D<T> & Array2D<T>::ref(const Array2D<T> &A)
{
if (this != &A)
{
v_ = A.v_;
data_ = A.data_;
m_ = A.m_;
n_ = A.n_;
}
return *this;
}
template <class T>
Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A)
{
return ref(A);
}
template <class T>
inline int Array2D<T>::dim1() const { return m_; }
template <class T>
inline int Array2D<T>::dim2() const { return n_; }
template <class T>
Array2D<T>::~Array2D() {}
template <class T>
inline Array2D<T>::operator T**()
{
return &(v_[0]);
}
template <class T>
inline Array2D<T>::operator const T**()
{
return &(v_[0]);
}
/* ............... extended interface ............... */
/**
Create a new view to a subarray defined by the boundaries
[i0][i0] and [i1][j1]. The size of the subarray is
(i1-i0) by (j1-j0). If either of these lengths are zero
or negative, the subarray view is null.
*/
template <class T>
Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1)
{
Array2D<T> A;
int m = i1-i0+1;
int n = j1-j0+1;
/* if either length is zero or negative, this is an invalide
subarray. return a null view.
*/
if (m<1 || n<1)
return A;
A.data_ = data_;
A.m_ = m;
A.n_ = n;
A.v_ = Array1D<T*>(m);
T* p = &(data_[0]) + i0 * n_ + j0;
for (int i=0; i<m; i++)
{
A.v_[i] = p + i*n_;
}
return A;
}
template <class T>
inline int Array2D<T>::ref_count()
{
return ref_count_data();
}
template <class T>
inline int Array2D<T>::ref_count_data()
{
return data_.ref_count();
}
template <class T>
inline int Array2D<T>::ref_count_dim1()
{
return v_.ref_count();
}
} /* namespace TNT */
#endif
/* TNT_ARRAY2D_H */
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_ARRAY2D_UTILS_H
#define TNT_ARRAY2D_UTILS_H
#include <cstdlib>
#include <cassert>
namespace TNT
{
template <class T>
std::ostream& operator<<(std::ostream &s, const Array2D<T> &A)
{
int M=A.dim1();
int N=A.dim2();
s << M << " " << N << "\n";
for (int i=0; i<M; i++)
{
for (int j=0; j<N; j++)
{
s << A[i][j] << " ";
}
s << "\n";
}
return s;
}
template <class T>
std::istream& operator>>(std::istream &s, Array2D<T> &A)
{
int M, N;
s >> M >> N;
Array2D<T> B(M,N);
for (int i=0; i<M; i++)
for (int j=0; j<N; j++)
{
s >> B[i][j];
}
A = B;
return s;
}
template <class T>
Array2D<T> operator+(const Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() != m || B.dim2() != n )
return Array2D<T>();
else
{
Array2D<T> C(m,n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
C[i][j] = A[i][j] + B[i][j];
}
return C;
}
}
template <class T>
Array2D<T> operator-(const Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() != m || B.dim2() != n )
return Array2D<T>();
else
{
Array2D<T> C(m,n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
C[i][j] = A[i][j] - B[i][j];
}
return C;
}
}
template <class T>
Array2D<T> operator*(const Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() != m || B.dim2() != n )
return Array2D<T>();
else
{
Array2D<T> C(m,n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
C[i][j] = A[i][j] * B[i][j];
}
return C;
}
}
template <class T>
Array2D<T> operator/(const Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() != m || B.dim2() != n )
return Array2D<T>();
else
{
Array2D<T> C(m,n);
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
C[i][j] = A[i][j] / B[i][j];
}
return C;
}
}
template <class T>
Array2D<T>& operator+=(Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() == m || B.dim2() == n )
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
A[i][j] += B[i][j];
}
}
return A;
}
template <class T>
Array2D<T>& operator-=(Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() == m || B.dim2() == n )
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
A[i][j] -= B[i][j];
}
}
return A;
}
template <class T>
Array2D<T>& operator*=(Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() == m || B.dim2() == n )
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
A[i][j] *= B[i][j];
}
}
return A;
}
template <class T>
Array2D<T>& operator/=(Array2D<T> &A, const Array2D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
if (B.dim1() == m || B.dim2() == n )
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
A[i][j] /= B[i][j];
}
}
return A;
}
/**
Matrix Multiply: compute C = A*B, where C[i][j]
is the dot-product of row i of A and column j of B.
@param A an (m x n) array
@param B an (n x k) array
@return the (m x k) array A*B, or a null array (0x0)
if the matrices are non-conformant (i.e. the number
of columns of A are different than the number of rows of B.)
*/
template <class T>
Array2D<T> matmult(const Array2D<T> &A, const Array2D<T> &B)
{
if (A.dim2() != B.dim1())
return Array2D<T>();
int M = A.dim1();
int N = A.dim2();
int K = B.dim2();
Array2D<T> C(M,K);
for (int i=0; i<M; i++)
for (int j=0; j<K; j++)
{
T sum = 0;
for (int k=0; k<N; k++)
sum += A[i][k] * B [k][j];
C[i][j] = sum;
}
return C;
}
} // namespace TNT
#endif
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_ARRAY3D_H
#define TNT_ARRAY3D_H
#include <cstdlib>
#include <iostream>
#ifdef TNT_BOUNDS_CHECK
#include <assert.h>
#endif
#include "tnt_array1d.h"
#include "tnt_array2d.h"
namespace TNT
{
template <class T>
class Array3D
{
private:
Array1D<T> data_;
Array2D<T*> v_;
int m_;
int n_;
int g_;
public:
typedef T value_type;
Array3D();
Array3D(int m, int n, int g);
Array3D(int m, int n, int g, T val);
Array3D(int m, int n, int g, T *a);
inline operator T***();
inline operator const T***();
inline Array3D(const Array3D &A);
inline Array3D & operator=(const T &a);
inline Array3D & operator=(const Array3D &A);
inline Array3D & ref(const Array3D &A);
Array3D copy() const;
Array3D & inject(const Array3D & A);
inline T** operator[](int i);
inline const T* const * operator[](int i) const;
inline int dim1() const;
inline int dim2() const;
inline int dim3() const;
~Array3D();
/* extended interface */
inline int ref_count(){ return data_.ref_count(); }
Array3D subarray(int i0, int i1, int j0, int j1,
int k0, int k1);
};
template <class T>
Array3D<T>::Array3D() : data_(), v_(), m_(0), n_(0) {}
template <class T>
Array3D<T>::Array3D(const Array3D<T> &A) : data_(A.data_),
v_(A.v_), m_(A.m_), n_(A.n_), g_(A.g_)
{
}
template <class T>
Array3D<T>::Array3D(int m, int n, int g) : data_(m*n*g), v_(m,n),
m_(m), n_(n), g_(g)
{
if (m>0 && n>0 && g>0)
{
T* p = & (data_[0]);
int ng = n_*g_;
for (int i=0; i<m_; i++)
{
T* ping = p+ i*ng;
for (int j=0; j<n; j++)
v_[i][j] = ping + j*g_;
}
}
}
template <class T>
Array3D<T>::Array3D(int m, int n, int g, T val) : data_(m*n*g, val),
v_(m,n), m_(m), n_(n), g_(g)
{
if (m>0 && n>0 && g>0)
{
T* p = & (data_[0]);
int ng = n_*g_;
for (int i=0; i<m_; i++)
{
T* ping = p+ i*ng;
for (int j=0; j<n; j++)
v_[i][j] = ping + j*g_;
}
}
}
template <class T>
Array3D<T>::Array3D(int m, int n, int g, T* a) :
data_(m*n*g, a), v_(m,n), m_(m), n_(n), g_(g)
{
if (m>0 && n>0 && g>0)
{
T* p = & (data_[0]);
int ng = n_*g_;
for (int i=0; i<m_; i++)
{
T* ping = p+ i*ng;
for (int j=0; j<n; j++)
v_[i][j] = ping + j*g_;
}
}
}
template <class T>
inline T** Array3D<T>::operator[](int i)
{
#ifdef TNT_BOUNDS_CHECK
assert(i >= 0);
assert(i < m_);
#endif
return v_[i];
}
template <class T>
inline const T* const * Array3D<T>::operator[](int i) const
{ return v_[i]; }
template <class T>
Array3D<T> & Array3D<T>::operator=(const T &a)
{
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
for (int k=0; k<g_; k++)
v_[i][j][k] = a;
return *this;
}
template <class T>
Array3D<T> Array3D<T>::copy() const
{
Array3D A(m_, n_, g_);
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
for (int k=0; k<g_; k++)
A.v_[i][j][k] = v_[i][j][k];
return A;
}
template <class T>
Array3D<T> & Array3D<T>::inject(const Array3D &A)
{
if (A.m_ == m_ && A.n_ == n_ && A.g_ == g_)
for (int i=0; i<m_; i++)
for (int j=0; j<n_; j++)
for (int k=0; k<g_; k++)
v_[i][j][k] = A.v_[i][j][k];
return *this;
}
template <class T>
Array3D<T> & Array3D<T>::ref(const Array3D<T> &A)
{
if (this != &A)
{
m_ = A.m_;
n_ = A.n_;
g_ = A.g_;
v_ = A.v_;
data_ = A.data_;
}
return *this;
}
template <class T>
Array3D<T> & Array3D<T>::operator=(const Array3D<T> &A)
{
return ref(A);
}
template <class T>
inline int Array3D<T>::dim1() const { return m_; }
template <class T>
inline int Array3D<T>::dim2() const { return n_; }
template <class T>
inline int Array3D<T>::dim3() const { return g_; }
template <class T>
Array3D<T>::~Array3D() {}
template <class T>
inline Array3D<T>::operator T***()
{
return v_;
}
template <class T>
inline Array3D<T>::operator const T***()
{
return v_;
}
/* extended interface */
template <class T>
Array3D<T> Array3D<T>::subarray(int i0, int i1, int j0,
int j1, int k0, int k1)
{
/* check that ranges are valid. */
if (!( 0 <= i0 && i0 <= i1 && i1 < m_ &&
0 <= j0 && j0 <= j1 && j1 < n_ &&
0 <= k0 && k0 <= k1 && k1 < g_))
return Array3D<T>(); /* null array */
Array3D<T> A;
A.data_ = data_;
A.m_ = i1-i0+1;
A.n_ = j1-j0+1;
A.g_ = k1-k0+1;
A.v_ = Array2D<T*>(A.m_,A.n_);
T* p = &(data_[0]) + i0*n_*g_ + j0*g_ + k0;
for (int i=0; i<A.m_; i++)
{
T* ping = p + i*n_*g_;
for (int j=0; j<A.n_; j++)
A.v_[i][j] = ping + j*g_ ;
}
return A;
}
} /* namespace TNT */
#endif
/* TNT_ARRAY3D_H */
#ifndef TNT_ARRAY3D_UTILS_H
#define TNT_ARRAY3D_UTILS_H
#include <cstdlib>
#include <cassert>
namespace TNT
{
template <class T>
std::ostream& operator<<(std::ostream &s, const Array3D<T> &A)
{
int M=A.dim1();
int N=A.dim2();
int K=A.dim3();
s << M << " " << N << " " << K << "\n";
for (int i=0; i<M; i++)
{
for (int j=0; j<N; j++)
{
for (int k=0; k<K; k++)
s << A[i][j][k] << " ";
s << "\n";
}
s << "\n";
}
return s;
}
template <class T>
std::istream& operator>>(std::istream &s, Array3D<T> &A)
{
int M, N, K;
s >> M >> N >> K;
Array3D<T> B(M,N,K);
for (int i=0; i<M; i++)
for (int j=0; j<N; j++)
for (int k=0; k<K; k++)
s >> B[i][j][k];
A = B;
return s;
}
template <class T>
Array3D<T> operator+(const Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
return Array3D<T>();
else
{
Array3D<T> C(m,n,p);
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
C[i][j][k] = A[i][j][k] + B[i][j][k];
return C;
}
}
template <class T>
Array3D<T> operator-(const Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
return Array3D<T>();
else
{
Array3D<T> C(m,n,p);
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
C[i][j][k] = A[i][j][k] - B[i][j][k];
return C;
}
}
template <class T>
Array3D<T> operator*(const Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
return Array3D<T>();
else
{
Array3D<T> C(m,n,p);
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
C[i][j][k] = A[i][j][k] * B[i][j][k];
return C;
}
}
template <class T>
Array3D<T> operator/(const Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
return Array3D<T>();
else
{
Array3D<T> C(m,n,p);
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
C[i][j][k] = A[i][j][k] / B[i][j][k];
return C;
}
}
template <class T>
Array3D<T>& operator+=(Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
{
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
A[i][j][k] += B[i][j][k];
}
return A;
}
template <class T>
Array3D<T>& operator-=(Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
{
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
A[i][j][k] -= B[i][j][k];
}
return A;
}
template <class T>
Array3D<T>& operator*=(Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
{
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
A[i][j][k] *= B[i][j][k];
}
return A;
}
template <class T>
Array3D<T>& operator/=(Array3D<T> &A, const Array3D<T> &B)
{
int m = A.dim1();
int n = A.dim2();
int p = A.dim3();
if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
{
for (int i=0; i<m; i++)
for (int j=0; j<n; j++)
for (int k=0; k<p; k++)
A[i][j][k] /= B[i][j][k];
}
return A;
}
} // namespace TNT
#endif
/*
*
* Template Numerical Toolkit (TNT)
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing
//
#ifndef TNT_CMAT_H
#define TNT_CMAT_H
#include "tnt_subscript.h"
#include "tnt_vec.h"
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <sstream>
namespace TNT
{
template <class T>
class Matrix
{
public:
typedef Subscript size_type;
typedef T value_type;
typedef T element_type;
typedef T* pointer;
typedef T* iterator;
typedef T& reference;
typedef const T* const_iterator;
typedef const T& const_reference;
Subscript lbound() const { return 1;}
protected:
Subscript m_;
Subscript n_;
Subscript mn_; // total size
T* v_;
T** row_;
T* vm1_ ; // these point to the same data, but are 1-based
T** rowm1_;
// internal helper function to create the array
// of row pointers
void initialize(Subscript M, Subscript N)
{
mn_ = M*N;
m_ = M;
n_ = N;
v_ = new T[mn_];
row_ = new T*[M];
rowm1_ = new T*[M];
assert(v_ != NULL);
assert(row_ != NULL);
assert(rowm1_ != NULL);
T* p = v_;
vm1_ = v_ - 1;
for (Subscript i=0; i<M; i++)
{
row_[i] = p;
rowm1_[i] = p-1;
p += N ;
}
rowm1_ -- ; // compensate for 1-based offset
}
void copy(const T* v)
{
Subscript N = m_ * n_;
Subscript i;
#ifdef TNT_UNROLL_LOOPS
Subscript Nmod4 = N & 3;
Subscript N4 = N - Nmod4;
for (i=0; i<N4; i+=4)
{
v_[i] = v[i];
v_[i+1] = v[i+1];
v_[i+2] = v[i+2];
v_[i+3] = v[i+3];
}
for (i=N4; i< N; i++)
v_[i] = v[i];
#else
for (i=0; i< N; i++)
v_[i] = v[i];
#endif
}
void set(const T& val)
{
Subscript N = m_ * n_;
Subscript i;
#ifdef TNT_UNROLL_LOOPS
Subscript Nmod4 = N & 3;
Subscript N4 = N - Nmod4;
for (i=0; i<N4; i+=4)
{
v_[i] = val;
v_[i+1] = val;
v_[i+2] = val;
v_[i+3] = val;
}
for (i=N4; i< N; i++)
v_[i] = val;
#else
for (i=0; i< N; i++)
v_[i] = val;
#endif
}
void destroy()
{
/* do nothing, if no memory has been previously allocated */
if (v_ == NULL) return ;
/* if we are here, then matrix was previously allocated */
if (v_ != NULL) delete [] (v_);
if (row_ != NULL) delete [] (row_);
/* return rowm1_ back to original value */
rowm1_ ++;
if (rowm1_ != NULL ) delete [] (rowm1_);
}
public:
operator T**(){ return row_; }
operator T**() const { return row_; }
Subscript size() const { return mn_; }
// constructors
Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {};
Matrix(const Matrix<T> &A)
{
initialize(A.m_, A.n_);
copy(A.v_);
}
Matrix(Subscript M, Subscript N, const T& value = T())
{
initialize(M,N);
set(value);
}
Matrix(Subscript M, Subscript N, const T* v)
{
initialize(M,N);
copy(v);
}
Matrix(Subscript M, Subscript N, const char *s)
{
initialize(M,N);
//std::istrstream ins(s);
std::istringstream ins(s);
Subscript i, j;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
ins >> row_[i][j];
}
// destructor
//
~Matrix()
{
destroy();
}
// reallocating
//
Matrix<T>& newsize(Subscript M, Subscript N)
{
if (num_rows() == M && num_cols() == N)
return *this;
destroy();
initialize(M,N);
return *this;
}
// assignments
//
Matrix<T>& operator=(const Matrix<T> &A)
{
if (v_ == A.v_)
return *this;
if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
copy(A.v_);
else
{
destroy();
initialize(A.m_, A.n_);
copy(A.v_);
}
return *this;
}
Matrix<T>& operator=(const T& scalar)
{
set(scalar);
return *this;
}
Subscript dim(Subscript d) const
{
#ifdef TNT_BOUNDS_CHECK
assert( d >= 1);
assert( d <= 2);
#endif
return (d==1) ? m_ : ((d==2) ? n_ : 0);
}
Subscript num_rows() const { return m_; }
Subscript num_cols() const { return n_; }
inline T* operator[](Subscript i)
{
#ifdef TNT_BOUNDS_CHECK
assert(0<=i);
assert(i < m_) ;
#endif
return row_[i];
}
inline const T* operator[](Subscript i) const
{
#ifdef TNT_BOUNDS_CHECK
assert(0<=i);
assert(i < m_) ;
#endif
return row_[i];
}
inline reference operator()(Subscript i)
{
#ifdef TNT_BOUNDS_CHECK
assert(1<=i);
assert(i <= mn_) ;
#endif
return vm1_[i];
}
inline const_reference operator()(Subscript i) const
{
#ifdef TNT_BOUNDS_CHECK
assert(1<=i);
assert(i <= mn_) ;
#endif
return vm1_[i];
}
inline reference operator()(Subscript i, Subscript j)
{
#ifdef TNT_BOUNDS_CHECK
assert(1<=i);
assert(i <= m_) ;
assert(1<=j);
assert(j <= n_);
#endif
return rowm1_[i][j];
}
inline const_reference operator() (Subscript i, Subscript j) const
{
#ifdef TNT_BOUNDS_CHECK
assert(1<=i);
assert(i <= m_) ;
assert(1<=j);
assert(j <= n_);
#endif
return rowm1_[i][j];
}
};
/* *************************** I/O ********************************/
template <class T>
std::ostream& operator<<(std::ostream &s, const Matrix<T> &A)
{
Subscript M=A.num_rows();
Subscript N=A.num_cols();
s << M << " " << N << "\n";
for (Subscript i=0; i<M; i++)
{
for (Subscript j=0; j<N; j++)
{
s << A[i][j] << " ";
}
s << "\n";
}
return s;
}
template <class T>
std::istream& operator>>(std::istream &s, Matrix<T> &A)
{
Subscript M, N;
s >> M >> N;
if ( !(M == A.num_rows() && N == A.num_cols() ))
{
A.newsize(M,N);
}
for (Subscript i=0; i<M; i++)
for (Subscript j=0; j<N; j++)
{
s >> A[i][j];
}
return s;
}
// *******************[ basic matrix algorithms ]***************************
template <class T>
Matrix<T> operator+(const Matrix<T> &A,
const Matrix<T> &B)
{
Subscript M = A.num_rows();
Subscript N = A.num_cols();
assert(M==B.num_rows());
assert(N==B.num_cols());
Matrix<T> tmp(M,N);
Subscript i,j;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
tmp[i][j] = A[i][j] + B[i][j];
return tmp;
}
template <class T>
Matrix<T> operator-(const Matrix<T> &A,
const Matrix<T> &B)
{
Subscript M = A.num_rows();
Subscript N = A.num_cols();
assert(M==B.num_rows());
assert(N==B.num_cols());
Matrix<T> tmp(M,N);
Subscript i,j;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
tmp[i][j] = A[i][j] - B[i][j];
return tmp;
}
template <class T>
Matrix<T> mult_element(const Matrix<T> &A,
const Matrix<T> &B)
{
Subscript M = A.num_rows();
Subscript N = A.num_cols();
assert(M==B.num_rows());
assert(N==B.num_cols());
Matrix<T> tmp(M,N);
Subscript i,j;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
tmp[i][j] = A[i][j] * B[i][j];
return tmp;
}
template <class T>
Matrix<T> transpose(const Matrix<T> &A)
{
Subscript M = A.num_rows();
Subscript N = A.num_cols();
Matrix<T> S(N,M);
Subscript i, j;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
S[j][i] = A[i][j];
return S;
}
template <class T>
inline Matrix<T> matmult(const Matrix<T> &A,
const Matrix<T> &B)
{
#ifdef TNT_BOUNDS_CHECK
assert(A.num_cols() == B.num_rows());
#endif
Subscript M = A.num_rows();
Subscript N = A.num_cols();
Subscript K = B.num_cols();
Matrix<T> tmp(M,K);
T sum;
for (Subscript i=0; i<M; i++)
for (Subscript k=0; k<K; k++)
{
sum = 0;
for (Subscript j=0; j<N; j++)
sum = sum + A[i][j] * B[j][k];
tmp[i][k] = sum;
}
return tmp;
}
template <class T>
inline Matrix<T> operator*(const Matrix<T> &A,
const Matrix<T> &B)
{
return matmult(A,B);
}
template <class T>
inline int matmult(Matrix<T>& C, const Matrix<T> &A,
const Matrix<T> &B)
{
assert(A.num_cols() == B.num_rows());
Subscript M = A.num_rows();
Subscript N = A.num_cols();
Subscript K = B.num_cols();
C.newsize(M,K);
T sum;
const T* row_i;
const T* col_k;
for (Subscript i=0; i<M; i++)
for (Subscript k=0; k<K; k++)
{
row_i = &(A[i][0]);
col_k = &(B[0][k]);
sum = 0;
for (Subscript j=0; j<N; j++)
{
sum += *row_i * *col_k;
row_i++;
col_k += K;
}
C[i][k] = sum;
}
return 0;
}
template <class T>
Vector<T> matmult(const Matrix<T> &A, const Vector<T> &x)
{
#ifdef TNT_BOUNDS_CHECK
assert(A.num_cols() == x.dim());
#endif
Subscript M = A.num_rows();
Subscript N = A.num_cols();
Vector<T> tmp(M);
T sum;
for (Subscript i=0; i<M; i++)
{
sum = 0;
const T* rowi = A[i];
for (Subscript j=0; j<N; j++)
sum = sum + rowi[j] * x[j];
tmp[i] = sum;
}
return tmp;
}
template <class T>
inline Vector<T> operator*(const Matrix<T> &A, const Vector<T> &x)
{
return matmult(A,x);
}
} // namespace TNT
#endif
// CMAT_H
This diff is collapsed.
This diff is collapsed.
/*
*
* Template Numerical Toolkit (TNT): Two-dimensional Fortran numerical array
*
* Mathematical and Computational Sciences Division
* National Institute of Technology,
* Gaithersburg, MD USA
*
*
* This software was developed at the National Institute of Standards and
* Technology (NIST) by employees of the Federal Government in the course
* of their official duties. Pursuant to title 17 Section 105 of the
* United States Code, this software is not subject to copyright protection
* and is in the public domain. NIST assumes no responsibility whatsoever for
* its use by other parties, and makes no guarantees, expressed or implied,
* about its quality, reliability, or any other characteristic.
*
*/
#ifndef TNT_FORTRAN_ARRAY2D_H
#define TNT_FORTRAN_ARRAY2D_H
#include <cstdlib>
#include <iostream>
#ifdef TNT_BOUNDS_CHECK
#include <assert.h>
#endif
#include "tnt_i_refvec.h"
namespace TNT
{
template <class T>
class Fortran_Array2D
{
private:
i_refvec<T> v_;
int m_;
int n_;
T* data_;
void initialize_(int n);
void copy_(T* p, const T* q, int len);
void set_(T* begin, T* end, const T& val);
public:
typedef T value_type;
Fortran_Array2D();
Fortran_Array2D(int m, int n);
Fortran_Array2D(int m, int n, T *a);
Fortran_Array2D(int m, int n, const T &a);
inline Fortran_Array2D(const Fortran_Array2D &A);
inline Fortran_Array2D & operator=(const T &a);
inline Fortran_Array2D & operator=(const Fortran_Array2D &A);
inline Fortran_Array2D & ref(const Fortran_Array2D &A);
Fortran_Array2D copy() const;
Fortran_Array2D & inject(const Fortran_Array2D & A);
inline T& operator()(int i, int j);
inline const T& operator()(int i, int j) const ;
inline int dim1() const;
inline int dim2() const;
~Fortran_Array2D();
/* extended interface */
inline int ref_count() const;
};
template <class T>
Fortran_Array2D<T>::Fortran_Array2D() : v_(), m_(0), n_(0), data_(0) {}
template <class T>
Fortran_Array2D<T>::Fortran_Array2D(const Fortran_Array2D<T> &A) : v_(A.v_),
m_(A.m_), n_(A.n_), data_(A.data_) {}
template <class T>
Fortran_Array2D<T>::Fortran_Array2D(int m, int n) : v_(m*n), m_(m), n_(n),
data_(v_.begin()) {}
template <class T>
Fortran_Array2D<T>::Fortran_Array2D(int m, int n, const T &val) :
v_(m*n), m_(m), n_(n), data_(v_.begin())
{
set_(data_, data_+m*n, val);
}
template <class T>
Fortran_Array2D<T>::Fortran_Array2D(int m, int n, T *a) : v_(a),
m_(m), n_(n), data_(v_.begin()) {}
template <class T>
inline T& Fortran_Array2D<T>::operator()(int i, int j)
{
#ifdef TNT_BOUNDS_CHECK
assert(i >= 1);
assert(i <= m_);
assert(j >= 1);
assert(j <= n_);
#endif
return v_[ (j-1)*m_ + (i-1) ];
}
template <class T>
inline const T& Fortran_Array2D<T>::operator()(int i, int j) const
{
#ifdef TNT_BOUNDS_CHECK
assert(i >= 1);
assert(i <= m_);
assert(j >= 1);
assert(j <= n_);
#endif
return v_[ (j-1)*m_ + (i-1) ];
}
template <class T>
Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const T &a)
{
set_(data_, data_+m_*n_, a);
return *this;
}
template <class T>
Fortran_Array2D<T> Fortran_Array2D<T>::copy() const
{
Fortran_Array2D B(m_,n_);
B.inject(*this);
return B;
}
template <class T>
Fortran_Array2D<T> & Fortran_Array2D<T>::inject(const Fortran_Array2D &A)
{
if (m_ == A.m_ && n_ == A.n_)
copy_(data_, A.data_, m_*n_);
return *this;
}
template <class T>
Fortran_Array2D<T> & Fortran_Array2D<T>::ref(const Fortran_Array2D<T> &A)
{
if (this != &A)
{
v_ = A.v_;
m_ = A.m_;
n_ = A.n_;
data_ = A.data_;
}
return *this;
}
template <class T>
Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const Fortran_Array2D<T> &A)
{
return ref(A);
}
template <class T>
inline int Fortran_Array2D<T>::dim1() const { return m_; }
template <class T>
inline int Fortran_Array2D<T>::dim2() const { return n_; }
template <class T>
Fortran_Array2D<T>::~Fortran_Array2D()
{
}
template <class T>
inline int Fortran_Array2D<T>::ref_count() const { return v_.ref_count(); }
template <class T>
void Fortran_Array2D<T>::set_(T* begin, T* end, const T& a)
{
for (T* p=begin; p<end; p++)
*p = a;
}
template <class T>
void Fortran_Array2D<T>::copy_(T* p, const T* q, int len)
{
T *end = p + len;
while (p<end )
*p++ = *q++;
}
} /* namespace TNT */
#endif
/* TNT_FORTRAN_ARRAY2D_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment