Skip to content
Snippets Groups Projects
Matrix.cpp 48 KiB
Newer Older
#include "MantidKernel/Matrix.h"

#include "MantidKernel/Exception.h"
#include "MantidKernel/make_unique.h"
#include "MantidKernel/MersenneTwister.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/V3D.h"
#include <algorithm>
#include <memory>
#include <sstream>

namespace Mantid {
Stuart Ansell's avatar
Stuart Ansell committed

namespace Kernel {
//
#define fabs(x) std::fabs((x)*1.0)
namespace {
//-------------------------------------------------------------------------
// Utility methods and function objects in anonymous namespace
//-------------------------------------------------------------------------
/**
\class PIndex
\author S. Ansell
\date Aug 2005
\version 1.0
\brief Class  to fill an index with a progressive count
*/
template <typename T> struct PIndex {
private:
  int count; ///< counter
public:
  /// Constructor
  PIndex() : count(0) {}
  /// functional
  std::pair<T, int> operator()(const T &A) {
    return std::pair<T, int>(A, count++);
/**
\class PSep
\author S. Ansell
\date Aug 2005
\version 1.0
\brief Class to access the second object in index pair.
*/
template <typename T> struct PSep {
  /// Functional to the second object
  int operator()(const std::pair<T, int> &A) { return A.second; }
};
Stuart Ansell's avatar
Stuart Ansell committed

/**
* Function to take a vector and sort the vector
* so as to produce an index. Leaves the vector unchanged.
* @param pVec :: Input vector
* @param Index :: Output vector
*/
template <typename T>
void indexSort(const std::vector<T> &pVec, std::vector<int> &Index) {
  Index.resize(pVec.size());
  std::vector<typename std::pair<T, int>> PartList;
  PartList.resize(pVec.size());

  transform(pVec.begin(), pVec.end(), PartList.begin(), PIndex<T>());
  sort(PartList.begin(), PartList.end());
  transform(PartList.begin(), PartList.end(), Index.begin(), PSep<T>());
}
template void indexSort(const std::vector<double> &, std::vector<int> &);
template void indexSort(const std::vector<float> &, std::vector<int> &);
template void indexSort(const std::vector<int> &, std::vector<int> &);
} // End of Anonymous name space
template <typename T> std::vector<T> Matrix<T>::getVector() const {
  std::vector<T> rez(m_numRows * m_numColumns);
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      rez[ic] = m_rawData[i][j];
template <typename T>
Matrix<T>::Matrix(const size_t nrow, const size_t ncol, const bool makeIdentity)
    : m_numRows(0), m_numColumns(0)
/**
  Constructor with pre-set sizes. Matrix is zeroed
  @param nrow :: number of rows
  @param ncol :: number of columns
  @param makeIdentity :: flag for the constructor to return an identity matrix
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  // Note:: m_numRows, m_numColumns zeroed so setMem always works
  setMem(nrow, ncol);
Stuart Ansell's avatar
Stuart Ansell committed
  zeroMatrix();
    identityMatrix();
}

template <typename T>
Matrix<T>::Matrix(const std::vector<T> &A, const std::vector<T> &B)
    : m_numRows(0), m_numColumns(0)
/**
  Constructor to take two vectors and multiply them to
  construct a matrix. (assuming that we have columns x row
  vector.
  @param A :: Column vector to multiply
  @param B :: Row vector to multiply
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  // Note:: m_numRows,m_numColumns zeroed so setMem always works
  setMem(A.size(), B.size());
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      m_rawData[i][j] = A[i] * B[j];
Stuart Ansell's avatar
Stuart Ansell committed
}
template <typename T>
Matrix<T>::Matrix(const std::vector<T> &data)
    : m_numRows(0), m_numColumns(0) {
  size_t numElements = data.size();
  size_t numRows = static_cast<size_t>(sqrt(double(numElements)));
  size_t numRowsSquare = numRows * numRows;
  if (numElements != numRowsSquare) {
    throw(std::invalid_argument(
        "number of elements in input vector have to be square of some value"));
  }

  setMem(numRows, numRows);
  size_t ic(0);
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      m_rawData[i][j] = data[ic];
Matrix<T>::Matrix(const std::vector<T> &data, const size_t nrow,
                  const size_t ncol)
    : m_numRows(0), m_numColumns(0) {
  size_t numel = data.size();
  size_t test = nrow * ncol;
  if (test != numel) {
    throw(std::invalid_argument("number of elements in input vector have is "
                                "incompatible with the number of rows and "
                                "columns"));
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      m_rawData[i][j] = data[ic];
template <typename T>
Matrix<T>::Matrix(const Matrix<T> &A, const size_t nrow, const size_t ncol)
    : m_numRows(A.m_numRows - 1), m_numColumns(A.m_numColumns - 1)
/**
  Constructor with for a missing row/column.
  @param A :: The input matrix
  @param nrow :: number of row to miss
  @param ncol :: number of column to miss
*/
  if (nrow > m_numRows)
    throw Kernel::Exception::IndexError(nrow, A.m_numRows,
                                        "Matrix::Constructor without row");
  if (ncol > m_numColumns)
    throw Kernel::Exception::IndexError(ncol, A.m_numColumns,
                                        "Matrix::Constructor without col");
  setMem(m_numRows, m_numColumns);
  for (size_t i = 0; i <= m_numRows; i++) {
    if (i != nrow) {
      size_t jR(0);
      for (size_t j = 0; j <= m_numColumns; j++) {
        if (j != ncol) {
          m_rawData[iR][jR] = A.m_rawData[i][j];
          jR++;
template <typename T>
Matrix<T>::Matrix(const Matrix<T> &A)
    : m_numRows(0), m_numColumns(0)
/**
  Simple copy constructor
  @param A :: Object to copy
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  // Note:: m_numRows,m_numColumns zeroed so setMem always works
  setMem(A.m_numRows, A.m_numColumns);
  if ((m_numRows * m_numColumns) > 0) {
    for (size_t i = 0; i < m_numRows; i++) {
      for (size_t j = 0; j < m_numColumns; j++) {
        m_rawData[i][j] = A.m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed
    }
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
Matrix<T> &Matrix<T>::operator=(const Matrix<T> &A)
/**
  Simple assignment operator
  @param A :: Object to copy
  @return the copied object
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (&A != this) {
    setMem(A.m_numRows, A.m_numColumns);
    if ((m_numRows * m_numColumns) > 0) {
      for (size_t i = 0; i < m_numRows; i++) {
        for (size_t j = 0; j < m_numColumns; j++) {
          m_rawData[i][j] = A.m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed
    }
Stuart Ansell's avatar
Stuart Ansell committed
  return *this;
}

Matrix<T>::Matrix(Matrix<T> &&other) noexcept
    : m_numRows(other.m_numRows),
      m_numColumns(other.m_numColumns),
      m_rawDataAlloc(std::move(other.m_rawDataAlloc)),
      m_rawData(std::move(other.m_rawData)) {
  other.m_numRows = 0;
  other.m_numColumns = 0;
}

template <typename T>
Matrix<T> &Matrix<T>::operator=(Matrix<T> &&other) noexcept {
  m_numRows = other.m_numRows;
  m_numColumns = other.m_numColumns;
  m_rawData = std::move(other.m_rawData);
  m_rawDataAlloc = std::move(other.m_rawDataAlloc);
  other.m_numRows = 0;
  other.m_numColumns = 0;
template <typename T>
Matrix<T> &Matrix<T>::operator+=(const Matrix<T> &A)
/**
  Matrix addition THIS + A
  If the size is different then 0 is added where appropiate
  Matrix A is not expanded.
  @param A :: Matrix to add
  @return Matrix(this + A)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  const size_t Xpt((m_numRows > A.m_numRows) ? A.m_numRows : m_numRows);
  const size_t Ypt((m_numColumns > A.m_numColumns) ? A.m_numColumns
                                                   : m_numColumns);
  for (size_t i = 0; i < Xpt; i++) {
    for (size_t j = 0; j < Ypt; j++) {
      m_rawData[i][j] += A.m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed

  return *this;
}

template <typename T>
Matrix<T> &Matrix<T>::operator-=(const Matrix<T> &A)
/**
  Matrix subtractoin THIS - A
  If the size is different then 0 is added where appropiate
  Matrix A is not expanded.
  @param A :: Matrix to add
  @return Ma
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  const size_t Xpt((m_numRows > A.m_numRows) ? A.m_numRows : m_numRows);
  const size_t Ypt((m_numColumns > A.m_numColumns) ? A.m_numColumns
                                                   : m_numColumns);
  for (size_t i = 0; i < Xpt; i++) {
    for (size_t j = 0; j < Ypt; j++) {
      m_rawData[i][j] -= A.m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed

  return *this;
}

template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T> &A) const
/**
  Matrix addition THIS + A
  If the size is different then 0 is added where appropiate
  Matrix A is not expanded.
  @param A :: Matrix to add
  @return Matrix(this + A)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  Matrix<T> X(*this);
  return X += A;
}

template <typename T>
Matrix<T> Matrix<T>::operator-(const Matrix<T> &A) const
/**
  Matrix subtraction THIS - A
  If the size is different then 0 is subtracted where
  appropiate. This matrix determines the size
  @param A :: Matrix to add
  @return Matrix(this + A)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  Matrix<T> X(*this);
  return X -= A;
}

template <typename T>
Matrix<T> Matrix<T>::operator*(const Matrix<T> &A) const
/**
  Matrix multiplication THIS * A
  @param A :: Matrix to multiply by  (this->row must == A->columns)
  @throw MisMatch<size_t> if there is a size mismatch.
  @return Matrix(This * A)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (m_numColumns != A.m_numRows)
    throw Kernel::Exception::MisMatch<size_t>(m_numColumns, A.m_numRows,
                                              "Matrix::operator*(Matrix)");
  Matrix<T> X(m_numRows, A.m_numColumns);
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < A.m_numColumns; j++) {
      for (size_t kk = 0; kk < m_numColumns; kk++) {
        X.m_rawData[i][j] += m_rawData[i][kk] * A.m_rawData[kk][j];
Stuart Ansell's avatar
Stuart Ansell committed
  return X;
}

template <typename T>
std::vector<T> Matrix<T>::operator*(const std::vector<T> &Vec) const
/**
  Matrix multiplication THIS * Vec to produce a vec
  @param Vec :: size of vector > this->nrows
  @throw MisMatch<size_t> if there is a size mismatch.
  @return Matrix(This * Vec)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (m_numColumns > Vec.size())
    throw Kernel::Exception::MisMatch<size_t>(m_numColumns, Vec.size(),
                                              "Matrix::operator*(m_rawDataec)");
  std::vector<T> Out(m_numRows);
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      Out[i] += m_rawData[i][j] * Vec[j];
Stuart Ansell's avatar
Stuart Ansell committed
    }
Stuart Ansell's avatar
Stuart Ansell committed
  return Out;
}

Hahn, Steven's avatar
Hahn, Steven committed
/**
  Matrix multiplication THIS * Vec to produce a vec
  @param in :: size of vector > this->nrows
  @param out :: result of Matrix(This * Vec)
  @throw MisMatch<size_t> if there is a size mismatch.
*/
template <typename T>
void Matrix<T>::multiplyPoint(const std::vector<T> &in,
                              std::vector<T> &out) const {
  out.resize(m_numRows);
  std::fill(std::begin(out), std::end(out), static_cast<T>(0.0));
  if (m_numColumns > in.size())
    throw Kernel::Exception::MisMatch<size_t>(m_numColumns, in.size(),
Hahn, Steven's avatar
Hahn, Steven committed
                                              "Matrix::multiplyPoint(in,out)");
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      out[i] += m_rawData[i][j] * in[j];
template <typename T>
V3D Matrix<T>::operator*(const V3D &Vx) const
/**
  Matrix multiplication THIS * V
  @param Vx :: Colunm vector to multiply by
  @throw MisMatch<size_t> if there is a size mismatch.
  @return Matrix(This * A)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (m_numColumns != 3 || m_numRows > 3)
    throw Kernel::Exception::MisMatch<size_t>(m_numColumns, 3,
                                              "Matrix::operator*(m_rawData3D)");
  for (size_t i = 0; i < m_numRows; ++i) {
    v[i] = m_rawData[i][0] * Vx.X() + m_rawData[i][1] * Vx.Y() +
           m_rawData[i][2] * Vx.Z();
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
Matrix<T> Matrix<T>::operator*(const T &Value) const
/**
  Matrix multiplication THIS * Value
  @param Value :: Scalar to multiply by
  @return V * (this)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  Matrix<T> X(*this);
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      X.m_rawData[i][j] *= Value;
Stuart Ansell's avatar
Stuart Ansell committed
  return X;
}

/**
  Matrix multiplication THIS *= A
  Note that we call operator* to avoid the problem
  of changing matrix size.
 @param A :: Matrix to multiply by  (this->row must == A->columns)
 @return This *= A
*/
template <typename T> Matrix<T> &Matrix<T>::operator*=(const Matrix<T> &A) {
  if (m_numColumns != A.m_numRows)
    throw Kernel::Exception::MisMatch<size_t>(m_numColumns, A.m_numRows,
Stuart Ansell's avatar
Stuart Ansell committed
  // This construct to avoid the problem of changing size
  *this = this->operator*(A);
  return *this;
}

template <typename T>
Matrix<T> &Matrix<T>::operator*=(const T &Value)
/**
  Matrix multiplication THIS * Value
  @param Value :: Scalar to multiply matrix by
  @return *this
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      m_rawData[i][j] *= Value;
Stuart Ansell's avatar
Stuart Ansell committed
  return *this;
}

template <typename T>
Matrix<T> &Matrix<T>::operator/=(const T &Value)
/**
  Matrix divishio THIS / Value
  @param Value :: Scalar to multiply matrix by
  @return *this
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      m_rawData[i][j] /= Value;
Stuart Ansell's avatar
Stuart Ansell committed
  return *this;
}

template <typename T>
bool Matrix<T>::operator!=(const Matrix<T> &A) const
Nick Draper's avatar
Nick Draper committed
Element by Element comparison
@param A :: Matrix to check
@return true :: on succees
@return false :: failure
Nick Draper's avatar
Nick Draper committed
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  return !(this->operator==(A));
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
bool Matrix<T>::operator==(const Matrix<T> &A) const
/**
Nick Draper's avatar
Nick Draper committed
Element by element comparison within tolerance.
Tolerance means that the value must be > tolerance
and less than (diff/max)>tolerance
Stuart Ansell's avatar
Stuart Ansell committed

Nick Draper's avatar
Nick Draper committed
Always returns 0 if the Matrix have different sizes
@return true on success
Nick Draper's avatar
Nick Draper committed
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
//---------------------------------------------------------------------------------------
template <typename T>
bool Matrix<T>::equals(const Matrix<T> &A, const double Tolerance) const
/**
Element by element comparison within tolerance.
Tolerance means that the value must be > tolerance
and less than (diff/max)>tolerance

Always returns 0 if the Matrix have different sizes
@param A :: matrix to check.
@param Tolerance :: tolerance in comparing elements
@return true on success
*/
{
  if (&A != this) // this == A == always true
Nick Draper's avatar
Nick Draper committed
  {
    if (A.m_numRows != m_numRows || A.m_numColumns != m_numColumns)
Nick Draper's avatar
Nick Draper committed
      return false;
Stuart Ansell's avatar
Stuart Ansell committed

Nick Draper's avatar
Nick Draper committed
    double maxS(0.0);
    double maxDiff(0.0); // max di
    for (size_t i = 0; i < m_numRows; i++)
      for (size_t j = 0; j < m_numColumns; j++) {
        const T diff = (m_rawData[i][j] - A.m_rawData[i][j]);
        if (fabs(diff) > maxDiff)
          maxDiff = fabs(diff);
        if (fabs(m_rawData[i][j]) > maxS)
          maxS = fabs(m_rawData[i][j]);
Nick Draper's avatar
Nick Draper committed
      }
    if (maxDiff < Tolerance)
      return true;
    if (maxS > 1.0 && (maxDiff / maxS) < Tolerance)
      return true;
    return false;
Nick Draper's avatar
Nick Draper committed
  }
  // this == this is true
Nick Draper's avatar
Nick Draper committed
  return true;
Stuart Ansell's avatar
Stuart Ansell committed
}

//---------------------------------------------------------------------------------------
/** Element by element comparison of <
Always returns false if the Matrix have different sizes
@param A :: matrix to check.
@return true if this < A
*/
template <typename T> bool Matrix<T>::operator<(const Matrix<T> &A) const {
  if (&A == this) // this < A == always false
  if (A.m_numRows != m_numRows || A.m_numColumns != m_numColumns)
  for (size_t i = 0; i < m_numRows; i++)
    for (size_t j = 0; j < m_numColumns; j++) {
      if (m_rawData[i][j] >= A.m_rawData[i][j])
        return false;
    }
  return true;
}

//---------------------------------------------------------------------------------------
/** Element by element comparison of >=
Always returns false if the Matrix have different sizes
@param A :: matrix to check.
@return true if this >= A
*/
template <typename T> bool Matrix<T>::operator>=(const Matrix<T> &A) const {
  if (A.m_numRows != m_numRows || A.m_numColumns != m_numColumns)
  for (size_t i = 0; i < m_numRows; i++)
    for (size_t j = 0; j < m_numColumns; j++) {
      if (m_rawData[i][j] < A.m_rawData[i][j])
/**
  Sets the memory held in matrix
  @param a :: number of rows
  @param b :: number of columns
*/
template <typename T> void Matrix<T>::setMem(const size_t a, const size_t b) {
  if (a == m_numRows && b == m_numColumns && m_rawData != nullptr)
Stuart Ansell's avatar
Stuart Ansell committed

  if (a <= 0 || b <= 0)
Stuart Ansell's avatar
Stuart Ansell committed
    return;

  m_numRows = a;
  m_numColumns = b;
  // Allocate memory first - this has to be a flat 1d array masquerading as a 2d
  // array so we can expose the memory to Python APIs via numpy which expects
  // this
  // style of memory layout.
  auto allocatedMemory = Kernel::make_unique<T[]>((m_numRows * m_numColumns));

  // Next allocate an array of pointers for the rows (X). This partitions
  // the 1D array into a 2D array for callers.
  auto rowPtrs = Kernel::make_unique<T *[]>(m_numRows);
  for (size_t i = 0; i < m_numRows; i++) {
    // Calculate offsets into the allocated memory array (Y)
    rowPtrs[i] = &allocatedMemory[i * m_numColumns];

  m_rawDataAlloc = std::move(allocatedMemory);
  m_rawData = std::move(rowPtrs);

/**
  Swap rows I and J
  @param RowI :: row I to swap
  @param RowJ :: row J to swap
*/
template <typename T>
void Matrix<T>::swapRows(const size_t RowI, const size_t RowJ) {
  if ((m_numRows * m_numColumns > 0) && RowI < m_numRows && RowJ < m_numRows &&
    for (size_t k = 0; k < m_numColumns; k++) {
      T tmp = m_rawData[RowI][k];
      m_rawData[RowI][k] = m_rawData[RowJ][k];
      m_rawData[RowJ][k] = tmp;
Stuart Ansell's avatar
Stuart Ansell committed
    }
Stuart Ansell's avatar
Stuart Ansell committed
}

/**
  Swap columns I and J
  @param colI :: col I to swap
  @param colJ :: col J to swap
*/
template <typename T>
void Matrix<T>::swapCols(const size_t colI, const size_t colJ) {
  if ((m_numRows * m_numColumns) > 0 && colI < m_numColumns &&
      colJ < m_numColumns && colI != colJ) {
    for (size_t k = 0; k < m_numRows; k++) {
      T tmp = m_rawData[k][colI];
      m_rawData[k][colI] = m_rawData[k][colJ];
      m_rawData[k][colJ] = tmp;
Stuart Ansell's avatar
Stuart Ansell committed
    }
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
void Matrix<T>::zeroMatrix()
/**
  Zeros all elements of the matrix
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if ((m_numRows * m_numColumns) > 0) {
    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>(0);
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
void Matrix<T>::identityMatrix()
/**
  Makes the matrix an idenity matrix.
  Zeros all the terms outside of the square
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if ((m_numRows * m_numColumns) > 0) {
    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>(j == i);
Stuart Ansell's avatar
Stuart Ansell committed
}
template <typename T>
void Matrix<T>::setColumn(const size_t nCol, const std::vector<T> &newCol) {
  if (nCol >= this->m_numColumns) {
    throw(std::invalid_argument("nCol requested> nCol availible"));
  }
  size_t m_numRowsM = newCol.size();
  if (m_numRows < m_numRowsM)
    m_numRowsM = m_numRows;
  for (size_t i = 0; i < m_numRowsM; i++) {
    m_rawData[i][nCol] = newCol[i];
template <typename T>
void Matrix<T>::setRow(const size_t nRow, const std::vector<T> &newRow) {
  if (nRow >= this->m_numRows) {
    throw(std::invalid_argument("nRow requested> nRow availible"));
  }
  size_t m_numColumnsM = newRow.size();
  if (m_numColumns < m_numColumnsM)
    m_numColumnsM = m_numColumns;
  for (size_t j = 0; j < m_numColumnsM; j++) {
    m_rawData[nRow][j] = newRow[j];
Stuart Ansell's avatar
Stuart Ansell committed

template <typename T>
void Matrix<T>::rotate(const double tau, const double s, const int i,
                       const int j, const int k, const int m)
/**
  Applies a rotation to a particular point of tan(theta)=tau.
  Note that you need both sin(theta) and tan(theta) because of
  sign preservation.
  @param tau :: tan(theta)
  @param s :: sin(theta)
  @param i ::  first index (xpos)
  @param j ::  first index (ypos)
  @param k ::  second index (xpos)
  @param m ::  second index (ypos)
 */
Stuart Ansell's avatar
Stuart Ansell committed
{
  const T gg = m_rawData[i][j];
  const T hh = m_rawData[k][m];
  m_rawData[i][j] = static_cast<T>(gg - s * (hh + gg * tau));
  m_rawData[k][m] = static_cast<T>(hh + s * (gg - hh * tau));
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
Matrix<T> Matrix<T>::preMultiplyByDiagonal(const std::vector<T> &Dvec) const
  Creates a diagonal matrix D from the given vector Dvec and
  PRE-multiplies the matrix by it (i.e. D * M).
  @param Dvec :: diagonal matrix (just centre points)
  @return D*this
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (Dvec.size() != m_numRows) {
    std::ostringstream cx;
    cx << "Matrix::preMultiplyByDiagonal Size: " << Dvec.size() << " "
       << m_numRows << " " << m_numColumns;
    throw std::runtime_error(cx.str());
  }
  Matrix<T> X(Dvec.size(), m_numColumns);
  for (size_t i = 0; i < Dvec.size(); i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      X.m_rawData[i][j] = Dvec[i] * m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed
  return X;
}

template <typename T>
Matrix<T> Matrix<T>::postMultiplyByDiagonal(const std::vector<T> &Dvec) const
  Creates a diagonal matrix D from the given vector Dvec and
  POST-multiplies the matrix by it (i.e. M * D).
  @param Dvec :: diagonal matrix (just centre points)
  @return this*D
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (Dvec.size() != m_numColumns) {
    std::ostringstream cx;
    cx << "Error Matrix::bDiaognal size:: " << Dvec.size() << " " << m_numRows
       << " " << m_numColumns;
    throw std::runtime_error(cx.str());
  }
Stuart Ansell's avatar
Stuart Ansell committed

  Matrix<T> X(m_numRows, Dvec.size());
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < Dvec.size(); j++) {
      X.m_rawData[i][j] = Dvec[j] * m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed
  return X;
}

template <typename T>
Matrix<T> Matrix<T>::Tprime() const
/**
  Transpose the matrix :
  Has transpose for a square matrix case.
  @return M^T
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if ((m_numRows * m_numColumns) == 0)
Stuart Ansell's avatar
Stuart Ansell committed
    return *this;

  if (m_numRows == m_numColumns) // inplace transpose
  {
    Matrix<T> MT(*this);
    MT.Transpose();
    return MT;
  }
Stuart Ansell's avatar
Stuart Ansell committed

  // irregular matrix
  Matrix<T> MT(m_numColumns, m_numRows);
  for (size_t i = 0; i < m_numRows; i++)
    for (size_t j = 0; j < m_numColumns; j++)
      MT.m_rawData[j][i] = m_rawData[i][j];
Stuart Ansell's avatar
Stuart Ansell committed

  return MT;
}

template <typename T>
Matrix<T> &Matrix<T>::Transpose()
/**
Transpose the matrix :
Has a in place transpose for a square matrix case.
@return this^T
Stuart Ansell's avatar
Stuart Ansell committed
{
  if ((m_numRows * m_numColumns) == 0)
  if (m_numRows == m_numColumns) // in place transpose
    for (size_t i = 0; i < m_numRows; i++) {
      for (size_t j = i + 1; j < m_numColumns; j++) {
        std::swap(m_rawData[i][j], m_rawData[j][i]);
      }
    }
    return *this;
  }

  // irregular matrix
  // get some memory

  auto allocatedMemory = Kernel::make_unique<T[]>((m_numRows * m_numColumns));
  auto transposePtrs = Kernel::make_unique<T *[]>(m_numRows);
  for (size_t i = 0; i < m_numColumns; i++) {
    // Notice how this partitions using Rows (X) instead of Cols(Y)
    transposePtrs[i] = &allocatedMemory[i * m_numRows];
  for (size_t i = 0; i < m_numRows; i++) {
    for (size_t j = 0; j < m_numColumns; j++) {
      transposePtrs[j][i] = m_rawData[i][j];
    }
  }
  // remove old memory
  std::swap(m_numRows, m_numColumns);

  m_rawDataAlloc = std::move(allocatedMemory);
  m_rawData = std::move(transposePtrs);

  return *this;
Stuart Ansell's avatar
Stuart Ansell committed
}

void Matrix<int>::GaussJordan(Kernel::Matrix<int> &)
/**
  Not valid for Integer
  @throw std::invalid_argument
Stuart Ansell's avatar
Stuart Ansell committed
{
  throw std::invalid_argument(
      "Gauss-Jordan inversion not valid for integer matrix");
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
void Matrix<T>::GaussJordan(Matrix<T> &B)
  Invert this matrix in place using Gauss-Jordan elimination.
  Matrix will be replaced by its inverse.
  @param B :: [input, output] Must have same dimensions as A. Returned as
  identity matrix. (?)
  @throw std::invalid_argument on input error
  @throw std::runtime_error if singular
Stuart Ansell's avatar
Stuart Ansell committed
{
  // check for input errors
  if (m_numRows != m_numColumns || B.m_numRows != m_numRows) {
    throw std::invalid_argument("Matrix not square, or sizes do not match");
  }
  std::vector<int> pivoted(m_numRows);
  fill(pivoted.begin(), pivoted.end(), 0);
Stuart Ansell's avatar
Stuart Ansell committed

  std::vector<int> indxcol(m_numRows); // Column index
  std::vector<int> indxrow(m_numRows); // row index
Stuart Ansell's avatar
Stuart Ansell committed

  size_t irow(0), icol(0);
  for (size_t i = 0; i < m_numRows; i++) {
    double bigItem = 0.0; // get point to pivot over
    for (size_t j = 0; j < m_numRows; j++) {
      if (pivoted[j] != 1) // check only non-pivots
        for (size_t k = 0; k < m_numRows; k++) {
          if (!pivoted[k]) {
            if (fabs(m_rawData[j][k]) >= bigItem) {
              bigItem = fabs(m_rawData[j][k]);
              irow = j;
              icol = k;
            }
          }
        }
      } else if (pivoted[j] > 1) {
        throw std::runtime_error("Error doing G-J elem on a singular matrix");
    // Swap in row/col to make a diagonal item
    if (irow != icol) {
      swapRows(irow, icol);
      B.swapRows(irow, icol);
    indxrow[i] = static_cast<int>(irow);
    indxcol[i] = static_cast<int>(icol);

    if (m_rawData[icol][icol] == 0.0) {
      throw std::runtime_error("Error doing G-J elem on a singular matrix");
    const T pivDiv = T(1.0) / m_rawData[icol][icol];
    m_rawData[icol][icol] = 1;
    for (size_t l = 0; l < m_numRows; l++) {
      m_rawData[icol][l] *= pivDiv;
    for (size_t l = 0; l < B.m_numColumns; l++) {
      B.m_rawData[icol][l] *= pivDiv;
Stuart Ansell's avatar
Stuart Ansell committed
    }
    for (size_t ll = 0; ll < m_numRows; ll++) {
      if (ll != icol) {
        const T div_num = m_rawData[ll][icol];
        m_rawData[ll][icol] = 0.0;
        for (size_t l = 0; l < m_numRows; l++) {
          m_rawData[ll][l] -= m_rawData[icol][l] * div_num;
        for (size_t l = 0; l < B.m_numColumns; l++) {
          B.m_rawData[ll][l] -= B.m_rawData[icol][l] * div_num;
Stuart Ansell's avatar
Stuart Ansell committed
  // Un-roll interchanges
  if (m_numRows > 0) {
    for (int l = static_cast<int>(m_numRows) - 1; l >= 0; l--) {
      if (indxrow[l] != indxcol[l]) {
        swapCols(indxrow[l], indxcol[l]);
Stuart Ansell's avatar
Stuart Ansell committed
}

template <typename T>
T Matrix<T>::Invert()
/**
  If the Matrix is square then invert the matrix
  using LU decomposition
  @return Determinant (0 if the matrix is singular)
*/
Stuart Ansell's avatar
Stuart Ansell committed
{
  if (m_numRows != m_numColumns && m_numRows < 1)
Stuart Ansell's avatar
Stuart Ansell committed
    return 0;

  if (m_numRows == 1) {
    T det = m_rawData[0][0];
    if (m_rawData[0][0] != static_cast<T>(0.))
      m_rawData[0][0] = static_cast<T>(1.) / m_rawData[0][0];
  std::vector<int> indx(m_numRows); // Set in lubcmp
  std::vector<double> col(m_numRows);
  int determinant = 0;
Stuart Ansell's avatar
Stuart Ansell committed
  Matrix<T> Lcomp(*this);
  Lcomp.lubcmp(indx.data(), determinant);
  double det = static_cast<double>(determinant);
  for (size_t j = 0; j < m_numRows; j++)
    det *= Lcomp.m_rawData[j][j];
  for (size_t j = 0; j < m_numRows; j++) {
    for (size_t i = 0; i < m_numRows; i++)
      col[i] = 0.0;
    col[j] = 1.0;
    Lcomp.lubksb(indx.data(), col.data());
    for (size_t i = 0; i < m_numRows; i++)
      m_rawData[i][j] = static_cast<T>(col[i]);
Stuart Ansell's avatar
Stuart Ansell committed
  return static_cast<T>(det);
}