Newer
Older
template <typename T>
T Matrix<T>::determinant() const
/**
Calculate the derminant of the matrix
@return Determinant of matrix.
*/
if (m_numRows != m_numColumns)
throw Kernel::Exception::MisMatch<size_t>(
m_numRows, m_numColumns, "Determinant error :: Matrix is not square");
Matrix<T> Mt(*this); // temp copy
T D = Mt.factor();
template <typename T>
T Matrix<T>::factor()
/**
Gauss jordan diagonal factorisation
The diagonal is left as the values,
the lower part is zero.
@return the factored matrix
*/
if (m_numRows != m_numColumns || m_numRows < 1)
throw std::runtime_error("Matrix::factor Matrix is not square");
for (int i = 0; i < static_cast<int>(m_numRows) - 1;
i++) // loop over each row
double Pmax = fabs(m_rawData[i][i]);
for (int j = i + 1; j < static_cast<int>(m_numRows);
j++) // find max in Row i
if (fabs(m_rawData[i][j]) > Pmax) {
Pmax = fabs(m_rawData[i][j]);
jmax = j;
}
}
if (Pmax < 1e-8) // maxtrix signular
{
// std::cerr<<"Matrix Singular"<<'\n';
return 0;
}
// Swap Columns
if (i != jmax) {
swapCols(i, jmax);
deter *= -1; // change sign.
}
// zero all rows below diagonal
Pmax = m_rawData[i][i];
for (int k = i + 1; k < static_cast<int>(m_numRows); k++) // row index
const double scale = m_rawData[k][i] / Pmax;
m_rawData[k][i] = static_cast<T>(0);
for (int q = i + 1; q < static_cast<int>(m_numRows); q++) // column index
m_rawData[k][q] -= static_cast<T>(scale * m_rawData[i][q]);
deter *= m_rawData[m_numRows - 1][m_numRows - 1];
template <typename T>
void Matrix<T>::normVert()
/**
Normalise EigenVectors
Assumes that they have already been calculated
*/
for (size_t i = 0; i < m_numRows; i++) {
for (size_t j = 0; j < m_numColumns; j++) {
sum += m_rawData[i][j] * m_rawData[i][j];
Gigg, Martyn Anthony
committed
}
sum = static_cast<T>(std::sqrt(static_cast<double>(sum)));
for (size_t j = 0; j < m_numColumns; j++) {
m_rawData[i][j] /= sum;
Gigg, Martyn Anthony
committed
}
template <typename T>
T Matrix<T>::compSum() const
/**
Add up each component sums for the matrix
@return \f$ \sum_i \sum_j V_{ij}^2 \f$
*/
for (size_t i = 0; i < m_numRows; i++) {
for (size_t j = 0; j < m_numColumns; j++) {
sum += m_rawData[i][j] * m_rawData[i][j];
Gigg, Martyn Anthony
committed
}
}
template <typename T>
void Matrix<T>::lubcmp(int *rowperm, int &interchange)
/**
Find biggest pivot and move to top row. Then
divide by pivot.
@param interchange :: odd/even nterchange (+/-1)
@param rowperm :: row permutations [m_numRows values]
if (m_numRows != m_numColumns || m_numRows < 2) {
std::cerr << "Error with lubcmp\n";
std::vector<double> result(m_numRows);
for (int i = 0; i < static_cast<int>(m_numRows); i++) {
for (int j = 0; j < static_cast<int>(m_numRows); j++)
if ((temp = fabs(m_rawData[i][j])) > big)
big = temp;
if (big == 0.0) {
for (int j = 0; j < static_cast<int>(m_numRows); j++) {
result[i] = 1.0 / big;
for (int j = 0; j < static_cast<int>(m_numRows); j++) {
sum = m_rawData[i][j];
sum -= m_rawData[i][k] * m_rawData[k][j];
m_rawData[i][j] = static_cast<T>(sum);
}
big = 0.0;
int imax = j;
for (int i = j; i < static_cast<int>(m_numRows); i++) {
sum = m_rawData[i][j];
sum -= m_rawData[i][k] * m_rawData[k][j];
m_rawData[i][j] = static_cast<T>(sum);
if ((dum = result[i] * fabs(sum)) >= big) {
big = dum;
imax = i;
}
}
for (int k = 0; k < static_cast<int>(m_numRows);
k++) { // Interchange rows
dum = m_rawData[imax][k];
m_rawData[imax][k] = m_rawData[j][k];
m_rawData[j][k] = static_cast<T>(dum);
result[imax] = static_cast<T>(result[j]);
if (m_rawData[j][j] == 0.0)
m_rawData[j][j] = static_cast<T>(1e-14);
if (j != static_cast<int>(m_numRows) - 1) {
dum = 1.0 / (m_rawData[j][j]);
for (int i = j + 1; i < static_cast<int>(m_numRows); i++)
m_rawData[i][j] *= static_cast<T>(dum);
template <typename T>
void Matrix<T>::lubksb(const int *rowperm, double *b)
/**
Implements a separation of the Matrix
into a triangular matrix
for (int i = 0; i < static_cast<int>(m_numRows); i++) {
int ip = rowperm[i];
double sum = b[ip];
b[ip] = b[i];
if (ii != -1)
for (int j = ii; j < i; j++)
sum -= m_rawData[i][j] * b[j];
else if (sum != 0.)
ii = i;
b[i] = sum;
}
for (int i = static_cast<int>(m_numRows) - 1; i >= 0; i--) {
double sum = static_cast<T>(b[i]);
for (int j = i + 1; j < static_cast<int>(m_numRows); j++)
sum -= m_rawData[i][j] * b[j];
b[i] = sum / m_rawData[i][i];
template <typename T>
void Matrix<T>::averSymmetric()
/**
Simple function to create an average symmetric matrix
out of the Matrix
*/
const size_t minSize = (m_numRows > m_numColumns) ? m_numColumns : m_numRows;
for (size_t i = 0; i < minSize; i++) {
for (size_t j = i + 1; j < minSize; j++) {
m_rawData[i][j] = (m_rawData[i][j] + m_rawData[j][i]) / 2;
m_rawData[j][i] = m_rawData[i][j];
Gigg, Martyn Anthony
committed
}
}
template <typename T>
std::vector<T> Matrix<T>::Diagonal() const
/**
Returns the diagonal form as a vector
@return Diagonal elements
*/
const size_t Msize = (m_numColumns > m_numRows) ? m_numRows : m_numColumns;
for (size_t i = 0; i < Msize; i++) {
Diag[i] = m_rawData[i][i];
Gigg, Martyn Anthony
committed
}
template <typename T>
T Matrix<T>::Trace() const
/**
Calculates the trace of the matrix
@return Trace of matrix
*/
const size_t Msize = (m_numColumns > m_numRows) ? m_numRows : m_numColumns;
Gigg, Martyn Anthony
committed
T Trx = 0;
for (size_t i = 0; i < Msize; i++) {
Trx += m_rawData[i][i];
Gigg, Martyn Anthony
committed
}
template <typename T>
void Matrix<T>::sortEigen(Matrix<T> &DiagMatrix)
/**
Sorts the eigenvalues into increasing
size. Moves the EigenVectors correspondingly
@param DiagMatrix :: matrix of the EigenValues
*/
if (m_numColumns != m_numRows || m_numRows != DiagMatrix.m_numRows ||
m_numRows != DiagMatrix.m_numColumns) {
std::cerr << "Matrix not Eigen Form\n";
throw(std::invalid_argument(" Matrix is not in an eigenvalue format"));
}
std::vector<T> X = DiagMatrix.Diagonal();
indexSort(X, index);
for (size_t Icol = 0; Icol < m_numRows; Icol++) {
for (size_t j = 0; j < m_numRows; j++) {
m_rawData[j][Icol] = EigenVec[j][index[Icol]];
Gigg, Martyn Anthony
committed
}
DiagMatrix[Icol][Icol] = X[index[Icol]];
Alex Buts
committed
}
template <typename T>
int Matrix<T>::Diagonalise(Matrix<T> &EigenVec, Matrix<T> &DiagMatrix) const
/**
Attempt to diagonalise the matrix IF symmetric
@param EigenVec :: (output) the Eigenvectors matrix
@param DiagMatrix :: the diagonal matrix of eigenvalues
@return :: 1 on success 0 on failure
*/
if (m_numRows != m_numColumns || m_numRows < 1) {
std::cerr << "Matrix not square\n";
for (size_t i = 0; i < m_numRows; i++)
for (size_t j = i + 1; j < m_numRows; j++)
if (fabs(m_rawData[i][j] - m_rawData[j][i]) > 1e-6) {
std::cerr << "Matrix not symmetric\n";
std::cerr << (*this);
return 0;
}
EigenVec.setMem(m_numRows, m_numRows);
DiagMatrix.setMem(m_numRows, m_numRows);
std::vector<double> Diag(m_numRows);
std::vector<double> B(m_numRows);
std::vector<double> ZeroComp(m_numRows);
// set b and d to the diagonal elements o A
for (size_t i = 0; i < m_numRows; i++) {
Diag[i] = B[i] = A.m_rawData[i][i];
int iteration = 0;
for (int i = 0; i < 100; i++) // max 50 iterations
{
double sm = 0.0; // sum of off-diagonal terms
for (size_t ip = 0; ip < m_numRows - 1; ip++)
for (size_t iq = ip + 1; iq < m_numRows; iq++)
sm += fabs(A.m_rawData[ip][iq]);
if (sm == 0.0) // Nothing to do return...
// Make OUTPUT -- D + A
// sort Output::
for (size_t ix = 0; ix < m_numRows; ix++)
DiagMatrix.m_rawData[ix][ix] = static_cast<T>(Diag[ix]);
// Threshold large for first 5 sweeps
(i < 6) ? 0.2 * sm / static_cast<int>(m_numRows * m_numRows) : 0.0;
for (int ip = 0; ip < static_cast<int>(m_numRows) - 1; ip++) {
for (int iq = ip + 1; iq < static_cast<int>(m_numRows); iq++) {
double g = 100.0 * fabs(A.m_rawData[ip][iq]);
// After 4 sweeps skip if off diagonal small
if (i > 6 &&
static_cast<float>(fabs(Diag[ip] + g)) ==
static_cast<float>(fabs(Diag[ip])) &&
static_cast<float>(fabs(Diag[iq] + g)) ==
static_cast<float>(fabs(Diag[iq])))
A.m_rawData[ip][iq] = 0;
else if (fabs(A.m_rawData[ip][iq]) > tresh) {
double tanAngle, cosAngle, sinAngle;
double h = Diag[iq] - Diag[ip];
if (static_cast<float>((fabs(h) + g)) == static_cast<float>(fabs(h)))
tanAngle = A.m_rawData[ip][iq] / h; // tanAngle=1/(2theta)
double theta = 0.5 * h / A.m_rawData[ip][iq];
tanAngle = 1.0 / (fabs(theta) + sqrt(1.0 + theta * theta));
if (theta < 0.0)
tanAngle = -tanAngle;
}
cosAngle = 1.0 / sqrt(1 + tanAngle * tanAngle);
sinAngle = tanAngle * cosAngle;
double tau = sinAngle / (1.0 + cosAngle);
h = tanAngle * A.m_rawData[ip][iq];
ZeroComp[ip] -= h;
ZeroComp[iq] += h;
Diag[ip] -= h;
Diag[iq] += h;
A.m_rawData[ip][iq] = 0;
// Rotations 0<j<p
for (int j = 0; j < ip; j++)
A.rotate(tau, sinAngle, j, ip, j, iq);
for (int j = ip + 1; j < iq; j++)
A.rotate(tau, sinAngle, ip, j, j, iq);
for (int j = iq + 1; j < static_cast<int>(m_numRows); j++)
A.rotate(tau, sinAngle, ip, j, iq, j);
for (int j = 0; j < static_cast<int>(m_numRows); j++)
EigenVec.rotate(tau, sinAngle, j, ip, j, iq);
iteration++;
Gigg, Martyn Anthony
committed
}
for (size_t j = 0; j < m_numRows; j++) {
B[j] += ZeroComp[j];
Diag[j] = B[j];
ZeroComp[j] = 0.0;
std::cerr << "Error :: Iterations are a problem\n";
bool Matrix<T>::isRotation() const
Savici, Andrei T.
committed
/** Check if a matrix represents a proper rotation
@ return :: true/false
*/
{
if (this->m_numRows != this->m_numColumns)
throw(std::invalid_argument("matrix is not square"));
// std::cout << "Matrix determinant-1 is " << (this->determinant()-1) <<
if (fabs(this->determinant() - 1) > 1e-5) {
Savici, Andrei T.
committed
return false;
Matrix<T> prod(m_numRows, m_numColumns),
ident(m_numRows, m_numColumns, true);
prod = this->operator*(this->Tprime());
// std::cout << "Matrix * Matrix' = " << std::endl << prod << '\n';
return prod.equals(ident, 1e-5);
Savici, Andrei T.
committed
}
}
bool Matrix<T>::isOrthogonal() const
/** Check if a matrix is orthogonal. Same as isRotation, but allows determinant
to be -1
Savici, Andrei T.
committed
@ return :: true/false
*/
{
if (this->m_numRows != this->m_numColumns)
throw(std::invalid_argument("matrix is not square"));
if (fabs(fabs(this->determinant()) - 1.) > 1e-5) {
Savici, Andrei T.
committed
return false;
Matrix<T> prod(m_numRows, m_numColumns),
ident(m_numRows, m_numColumns, true);
prod = this->operator*(this->Tprime());
Savici, Andrei T.
committed
return prod.equals(ident, 1e-7);
}
}
template <typename T>
std::vector<T> Matrix<T>::toRotation()
Savici, Andrei T.
committed
/**
Transform the matrix to a rotation matrix, by normalizing each column to 1
@return :: a vector of scaling factors
@throw :: std::invalid_argument if the absolute value of the determinant is
less then 1e-10 or not square matrix
Savici, Andrei T.
committed
*/
{
if (this->m_numRows != this->m_numColumns)
throw(std::invalid_argument("matrix is not square"));
if (fabs(this->determinant()) < 1e-10)
throw(std::invalid_argument("Determinant is too small"));
Savici, Andrei T.
committed
// step 1: orthogonalize the matrix
for (size_t i = 0; i < this->m_numColumns; ++i) {
for (size_t j = 0; j < this->m_numRows; ++j)
spself += (m_rawData[j][i] * m_rawData[j][i]);
for (size_t k = i + 1; k < this->m_numColumns; ++k) {
for (size_t j = 0; j < this->m_numRows; ++j)
spother += (m_rawData[j][i] * m_rawData[j][k]);
for (size_t j = 0; j < this->m_numRows; ++j)
m_rawData[j][k] -= static_cast<T>(m_rawData[j][i] * spother / spself);
Savici, Andrei T.
committed
}
}
// step 2: get scales and rescsale the matrix
std::vector<T> scale(this->m_numRows);
for (size_t i = 0; i < this->m_numColumns; ++i) {
for (size_t j = 0; j < this->m_numRows; ++j)
currentScale += (m_rawData[j][i] * m_rawData[j][i]);
currentScale = static_cast<T>(sqrt(static_cast<double>(currentScale)));
if (currentScale < 1e-10)
throw(std::invalid_argument("Scale is too small"));
scale[i] = currentScale;
}
Matrix<T> scalingMatrix(m_numRows, m_numColumns),
change(m_numRows, m_numColumns, true);
for (size_t i = 0; i < this->m_numColumns; ++i)
scalingMatrix[i][i] = static_cast<T>(1.0 / scale[i]);
Savici, Andrei T.
committed
*this = this->operator*(scalingMatrix);
if (this->determinant() < 0.) {
scale[0] = -scale[0];
change[0][0] = static_cast<T>(-1);
Savici, Andrei T.
committed
*this = this->operator*(change);
}
return scale;
}
template <typename T>
void Matrix<T>::print() const
/**
Simple print out routine
*/
/** set matrix elements ito random values in the range from rMin to rMax*/
template <typename T>
void Matrix<T>::setRandom(size_t seed, double rMin, double rMax) {
MersenneTwister rng(seed, rMin, rMax);
for (size_t i = 0; i < m_numRows; i++) {
for (size_t j = 0; j < m_numColumns; j++) {
m_rawData[i][j] = static_cast<T>(rng.nextValue());
template <typename T>
void Matrix<T>::write(std::ostream &Fh, const int blockCnt) const
/**
Write out function for blocks of 10 Columns
@param Fh :: file stream for output
@param blockCnt :: number of columns per line (0 == full)
*/
std::ios::fmtflags oldFlags = Fh.flags();
Fh.setf(std::ios::floatfield, std::ios::scientific);
const size_t blockNumber((blockCnt > 0) ? blockCnt : m_numColumns);
Gigg, Martyn Anthony
committed
size_t BCnt(0);
do {
const size_t ACnt = BCnt;
BCnt += blockNumber;
if (BCnt > m_numColumns) {
BCnt = m_numColumns;
Fh << " ----- " << ACnt << " " << BCnt << " ------ \n";
for (size_t i = 0; i < m_numRows; i++) {
for (size_t j = ACnt; j < BCnt; j++) {
Fh << std::setw(10) << m_rawData[i][j] << " ";
Gigg, Martyn Anthony
committed
}
} while (BCnt < m_numColumns);
template <typename T>
std::string Matrix<T>::str() const
/**
Convert the matrix into a simple linear string expression
@return String value of output
*/
for (size_t i = 0; i < m_numRows; i++) {
for (size_t j = 0; j < m_numColumns; j++) {
cx << std::setprecision(6) << m_rawData[i][j] << " ";
Gigg, Martyn Anthony
committed
}
}
/**
* Write an object to a stream. Format will be
* Matrix(nrows,ncols)x_00,x_01...,x_10,x_11
* @param os :: output stream
* @param matrix :: Matrix to write out
* @return The output stream (of)
*/
template <typename T>
std::ostream &operator<<(std::ostream &os, const Matrix<T> &matrix) {
dumpToStream(os, matrix, ',');
return os;
}
/**
* Write a Matrix to a stream. Format will be
* Matrix(nrowsSEPncols)x_00SEPx_01...SEPx_10SEPx_11
* @param os :: output stream
* @param matrix :: Matrix to write out
* @param delimiter :: A character to use as delimiter for the string
*/
template <typename T>
void dumpToStream(std::ostream &os, const Kernel::Matrix<T> &matrix,
const char delimiter) {
size_t nrows(matrix.numRows()), ncols(matrix.numCols());
os << "Matrix(" << nrows << delimiter << ncols << ")";
for (size_t i = 0; i < nrows; ++i) {
for (size_t j = 0; j < ncols; ++j) {
os << matrix[i][j];
if (i < nrows - 1 || j < ncols - 1)
os << delimiter;
}
}
}
/**
* Fill an object from a stream. Format should be
* Matrix(nrows,ncols)x_00,x_01...,x_10,x_11
* @param is :: A stream object
* @param in :: An object to fill
* @returns A reference to the stream
*/
template <typename T>
std::istream &operator>>(std::istream &is, Kernel::Matrix<T> &in) {
fillFromStream(is, in, ',');
return is;
}
/**
* Fill a Matrix from a stream using the given separator. Format should be
* Matrix(nrowsSEPncols)x_00SEPx_01...SEPx_10SEPx_11
* where SEP is replaced by the given separator
* @param is :: A stream object
* @param in :: An Matrix object to fill
* @param delimiter :: A single character separator that delimits the entries
*/
template <typename T>
void fillFromStream(std::istream &is, Kernel::Matrix<T> &in,
const char delimiter) {
// Stream should start with Matrix(
char dump;
std::string start(7, ' ');
is >> dump;
start[i] = dump;
if (!is)
throw std::invalid_argument(
"Unexpected character when reading Matrix from stream.");
}
if (start != "Matrix(")
throw std::invalid_argument("Incorrect input format for Matrix stream.");
// Now read a nrows,ncols and )
size_t nrows(0), ncols(0);
is >> nrows;
if (!is)
throw std::invalid_argument("Expected number of rows when reading Matrix "
"from stream, found something else.");
is >> dump;
is >> ncols;
if (!is)
throw std::invalid_argument("Expected number of columns when reading "
"Matrix from stream, found something else.");
is >> dump;
if (dump != ')')
throw std::invalid_argument("Expected closing parenthesis after ncols when "
"reading Matrix from stream, found something "
"else.");
// Resize the matrix
// Use getline with the delimiter set to "," to read
std::string value_str;
size_t row(0), col(0);
while (!is.eof() && std::getline(is, value_str, delimiter)) {
try {
T value = boost::lexical_cast<T>(value_str);
in.m_rawData[row][col] = value;
} catch (boost::bad_lexical_cast &) {
throw std::invalid_argument(
"Unexpected type found while reading Matrix from stream: \"" +
value_str + "\"");
}
++col;
{
col = 0;
++row;
}
}
}
Gigg, Martyn Anthony
committed
// Symbol definitions for common types
Gigg, Martyn Anthony
committed
template class MANTID_KERNEL_DLL Matrix<double>;
// The explicit template instantiation for int does not have an export macro
// since this produces a warning on "gcc: warning: type attributes ignored after
// type is already define" The reason for this is the use of Matrix<int>
// in a template specialization above, causing an implicit sepcialization.
// This, most likely, obtains a visibility setting from the general template
// definition.
template class Matrix<int>;
Gigg, Martyn Anthony
committed
template class MANTID_KERNEL_DLL Matrix<float>;
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
template MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &,
const DblMatrix &);
template MANTID_KERNEL_DLL void dumpToStream(std::ostream &, const DblMatrix &,
const char);
template MANTID_KERNEL_DLL std::istream &operator>>(std::istream &,
DblMatrix &);
template MANTID_KERNEL_DLL void fillFromStream(std::istream &, DblMatrix &,
const char);
template MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &,
const Matrix<float> &);
template MANTID_KERNEL_DLL void dumpToStream(std::ostream &,
const Matrix<float> &, const char);
template MANTID_KERNEL_DLL std::istream &operator>>(std::istream &,
Matrix<float> &);
template MANTID_KERNEL_DLL void fillFromStream(std::istream &, Matrix<float> &,
const char);
template MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &,
const IntMatrix &);
template MANTID_KERNEL_DLL void dumpToStream(std::ostream &, const IntMatrix &,
const char);
template MANTID_KERNEL_DLL std::istream &operator>>(std::istream &,
IntMatrix &);
template MANTID_KERNEL_DLL void fillFromStream(std::istream &, IntMatrix &,
const char);
Gigg, Martyn Anthony
committed
} // namespace Kernel