Matrix.h
#ifndef _MATRIX_H
#define _MATRIX_H
#if defined(DEBUG) || defined(_DEBUG)
#define RANGE_CHECK_
#endif
#if defined(max) || defined(min)
#undef max
#undef min
#endif
#if defined(abs)
#undef abs
#endif
#include <cmath>
#include <valarray>
#include <complex>
#include <limits>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#ifndef MAX_MATRIX_CACHE
#define MAX_MATRIX_CACHE 4
#endif
namespace techsoft {
using std::istream;
using std::ostream;
using std::valarray;
using std::
complex;
using std::numeric_limits;
using std::slice;
using std::slice_array;
using std::
abs;
using std::
sqrt;
using std::swap;
using std::setw;
#ifdef RANGE_CHECK_
using std::out_of_range;
using std::invalid_argument;
using std::runtime_error;
using std::exception;
#endif
#if defined(_MSC_VER)
using ::
ceil;
using ::
floor;
using ::srand;
using ::rand;
using ::
sqrt;
using ::sqrtl;
#else
using std::
ceil;
using std::
floor;
using std::srand;
using std::rand;
using std::size_t;
#endif
class mslice;
class gmslice;
template <
class T>
class Mref;
template <
class T>
class Cmat_iter;
template <
class T>
class Mat_iter;
template <
class T>
class mslice_matrix;
template <
class T>
class gmslice_matrix;
enum MatArrayType { C_ARRAY, FORTRAN_ARRAY };
template <
class T>
class matrix
{
public:
typedef T value_type;
typedef valarray<T> array_type;
matrix ();
matrix (size_t nRow, size_t nCol);
matrix (size_t nRow, size_t nCol,
const T& e);
matrix (size_t nRow, size_t nCol,
const T* Array, MatArrayType aType = C_ARRAY);
matrix (size_t nRow, size_t nCol,
const valarray<T>& vec);
~matrix ();
matrix (
const matrix<T>& m);
matrix (
const mslice_matrix<T>& sm);
matrix (
const gmslice_matrix<T>& sm);
#ifndef _TS_NO_MEMBER_TEMPLATES
template <
class X> matrix (
const matrix<X>& m);
#endif
matrix<T>&
operator= (
const matrix<T>& m);
matrix<T>&
operator= (
const mslice_matrix<T>& sm);
matrix<T>&
operator= (
const gmslice_matrix<T>& sm);
matrix<T>&
operator= (
const T& e);
#ifndef _TS_NO_MEMBER_TEMPLATES
template <
class X> matrix<T>&
operator= (
const matrix<X>& m);
#endif
size_t size ()
const throw() {
return mPtr->nrow * mPtr->ncol; }
size_t typesize ()
const throw() {
return sizeof(T); }
size_t colsize ()
const throw() {
return mPtr->nrow; }
size_t rowsize ()
const throw() {
return mPtr->ncol; }
size_t rowno ()
const throw() {
return mPtr->nrow; }
size_t colno ()
const throw() {
return mPtr->ncol; }
void resize (size_t nRow, size_t nCol,
const T& dval = T(
0));
void free ();
Mat_iter<T> row (size_t i);
Cmat_iter<T> row (size_t i)
const;
Mat_iter<T> column (size_t i);
Cmat_iter<T> column (size_t i)
const;
Mat_iter<T> diag (
int i=
0);
Cmat_iter<T> diag (
int i=
0)
const;
T trace (
int i=
0)
const;
Mat_iter<T>
operator[] (size_t i) {
return row(i); }
Cmat_iter<T>
operator[] (size_t i)
const {
return row(i); }
Mat_iter<T>
operator[] (
int i) {
return row(i); }
Cmat_iter<T>
operator[] (
int i)
const {
return row(i); }
Mat_iter<T>
operator() (size_t i) {
return column(i); }
Cmat_iter<T>
operator() (size_t i)
const {
return column(i); }
Mat_iter<T>
operator() (
int i) {
return column(i); }
Cmat_iter<T>
operator() (
int i)
const {
return column(i); }
Mref<T>
operator() (size_t i, size_t j);
const T&
operator() (size_t i, size_t j)
const;
mslice_matrix<T>
operator[] (mslice ms);
gmslice_matrix<T>
operator[] (gmslice gm);
const matrix<T>
operator[] (mslice ms)
const;
const matrix<T>
operator[] (gmslice gm)
const;
matrix<T>
operator+ ()
const {
return *
this; }
matrix<T>
operator- ()
const;
matrix<T>
operator~ ()
const;
matrix<T>
operator! ()
const;
matrix<T>&
operator+= (
const matrix<T>& m);
matrix<T>&
operator-= (
const matrix<T>& m);
matrix<T>&
operator*= (
const matrix<T>& m);
matrix<T>&
operator/= (
const matrix<T>& m);
matrix<T>&
operator*= (
const T& x);
matrix<T>&
operator/= (
const T& x);
void null ();
void unit ();
void rand (
int rmin=-
1,
int rmax=
1,
int rseed=
0);
T sum ()
const {
return mPtr->val.sum(); }
T min ()
const {
return mPtr->val.min(); }
T max ()
const {
return mPtr->val.max(); }
matrix<T> apply (T (*fn)(T))
const;
matrix<T> apply (T (*fn)(
const T&))
const;
matrix<T> apply (T (*fn)(size_t,size_t,T))
const;
matrix<T> apply (T (*fn)(size_t,size_t,
const T&))
const;
bool solve (
const valarray<T>& v, valarray<T>& s)
const;
bool solve (
const matrix<T>& v, matrix<T>& s)
const;
matrix<T> adj ()
const;
T cofact (size_t row, size_t col)
const;
T det ()
const;
T cond ()
const;
size_t rank ()
const;
T norm1 ()
const;
T norm2 ()
const;
T normI ()
const;
T normF ()
const;
bool lud (valarray<size_t>& ri, T* pDet = NULL);
void lubksb (
const valarray<size_t>& ri,
const valarray<T>& v, valarray<T>& s)
const;
void lumpove (
const matrix<T>& ludm,
const valarray<size_t>& ri,
const valarray<T>& v, valarray<T>& s)
const;
bool solve_lu (
const valarray<T>& v, valarray<T>& s)
const {
return solve( v, s); }
bool inv ();
bool inv_lu ();
bool inv_sv ();
bool inv_qr ();
bool svd (matrix<T>& vc, valarray<T>& w);
void svbksb (
const matrix<T>& vc,
const valarray<T>& w,
const valarray<T>& b, valarray<T>& x)
const;
bool solve_sv (
const valarray<T>& v, valarray<T>& s)
const;
void qrd (matrix<T>& r);
void qrbksb (
const matrix<T>& r,
const valarray<T>& v, valarray<T>& s)
const;
bool solve_qr (
const valarray<T>& v, valarray<T>& s)
const;
bool chold ();
void cholbksb (
const valarray<T>& v, valarray<T>& s)
const;
bool solve_chol (
const valarray<T>& v, valarray<T>& s)
const;
bool eigen (valarray<T>& eival)
const;
bool eigen (valarray<T>& eival, matrix<T>& eivec)
const;
bool eigen (valarray<T>& rev, valarray<T>& iev)
const;
bool eigen (valarray<T>& rev, valarray<T>& iev, matrix<T>& eivec)
const;
bool isSquare ()
const throw() {
return (mPtr->nrow == mPtr->ncol); }
bool isSingular ()
const;
bool isDiagonal ()
const;
bool isScalar ()
const;
bool isUnit ()
const throw();
bool isNull ()
const throw();
bool isSymmetric ()
const;
bool isSkewSymmetric ()
const;
bool isUpperTriangular ()
const;
bool isLowerTriangular ()
const;
bool isRowOrthogonal ()
const;
bool isColOrthogonal ()
const;
private:
struct base_mat
{
valarray<T> val;
size_t nrow, ncol;
int refcnt;
base_mat (size_t row, size_t col)
: nrow( row), ncol( col), val( row * col) { refcnt =
1; }
base_mat (
const T& v, size_t row, size_t col)
: nrow( row), ncol( col), val( v, row * col) { refcnt =
1; }
base_mat (
const T* v, size_t row, size_t col)
: nrow( row), ncol( col), val( v, row * col) { refcnt =
1; }
base_mat (size_t row, size_t col,
const valarray<T>& v)
: nrow( row), ncol( col), val( v) { refcnt =
1; }
~base_mat () {;}
};
base_mat *mPtr;
enum AllocType { Allocate, Free, Record };
bool shared () {
return (mPtr->refcnt >
1); }
void clone ();
base_mat *allocator (AllocType bOpt, size_t nrow =
0, size_t ncol =
0);
void tred2 (valarray<T>& d, valarray<T>& e,
bool eivec);
bool tql2 (valarray<T>& d, valarray<T>& e,
bool eivec);
void balanc (matrix<T>& v,
bool eivec);
bool hqr2 (valarray<T>& d, valarray<T>& e, matrix<T>& v,
bool eivec);
friend class Mat_iter<T>;
friend class Cmat_iter<T>;
friend class Mref<T>;
};
template <
class T> matrix<T>
operator+ (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T> matrix<T>
operator- (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T> matrix<T>
operator* (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T> matrix<T>
operator* (
const matrix<T>& m,
const T& el);
template <
class T> matrix<T>
operator* (
const T& el,
const matrix<T>& m);
template <
class T> matrix<T>
operator/ (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T> matrix<T>
operator/ (
const matrix<T>& m,
const T& el);
template <
class T> matrix<T>
operator/ (
const T& el,
const matrix<T>& m);
template <
class T> valarray<T>
operator* (
const matrix<T>& m,
const valarray<T>& v);
template <
class T> valarray<T>
operator* (
const valarray<T>& v,
const matrix<T>& m);
template <
class T> valarray<T>
operator/ (
const matrix<T>& m,
const valarray<T>& v);
template <
class T> valarray<T>
operator/ (
const valarray<T>& v,
const matrix<T>& m);
template <
class T>
bool operator== (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T>
bool operator!= (
const matrix<T>& m1,
const matrix<T>& m2);
template <
class T> matrix<T>
pow (
const matrix<T>& m, size_t n);
template <
class T> matrix<T>
abs (
const matrix<T>& m);
template <
class T> matrix<T>
floor (
const matrix<T>& m);
template <
class T> matrix<T>
ceil (
const matrix<T>& m);
template <
class T>
void mswap (
const Mref<T>& x,
const Mref<T>& y);
template <
class T>
void mswap (
const Mat_iter<T>& x,
const Mat_iter<T>& y);
template <
class T>
void mswap (matrix<T>& x, matrix<T>& y);
template <
class T> istream&
operator>> (istream& is, Mref<T> el);
template <
class T> istream&
operator>> (istream& is, valarray<T>& v);
template <
class T> istream&
operator>> (istream& is, Mat_iter<T> v);
template <
class T> istream&
operator>> (istream& is, matrix<T>& m);
template <
class T> ostream&
operator<< (ostream& os,
const Mref<T>& el);
template <
class T> ostream&
operator<< (ostream &os,
const valarray<T>& v);
template <
class T> ostream&
operator<< (ostream& os,
const Mat_iter<T>& v);
template <
class T> ostream&
operator<< (ostream& os,
const Cmat_iter<T>& v);
template <
class T> ostream&
operator<< (ostream &os,
const matrix<T>& m);
float epsilon (
complex<
float> v);
double epsilon (
complex<
double> v);
long double epsilon (
complex<
long double> v);
template <
class T> T epsilon (
const T& v);
template <
class T>
bool isVecEq (
const valarray<T>& v1,
const valarray<T>& v2);
template <
class T>
class Mref
{
public:
Mref (matrix<T>& mm, size_t ii) : m(mm), i(ii) {;}
operator T ()
const {
return m.mPtr->val[i]; }
T*
operator& ()
const {
if (m.shared()) m.clone();
return &m.mPtr->val[i]; }
T&
operator= (
const Mref<T>& e)
const {
if (m.shared()) m.clone(); T te = e;
return m.mPtr->val[i] = te; }
T&
operator= (
const T& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] = e; }
T&
operator+= (
const T& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] += e; }
T&
operator-= (
const T& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] -= e; }
T&
operator*= (
const T& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] *= e; }
T&
operator/= (
const T& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] /= e; }
#ifndef _TS_NO_MEMBER_TEMPLATES
template <
class X> T&
operator= (
const X& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] = e; }
template <
class X> T&
operator+= (
const X& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] += e; }
template <
class X> T&
operator-= (
const X& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] -= e; }
template <
class X> T&
operator*= (
const X& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] *= e; }
template <
class X> T&
operator/= (
const X& e)
const {
if (m.shared()) m.clone();
return m.mPtr->val[i] /= e; }
template <
class X> T
operator+ (
const X& e) { T y = *
this;
return y += e; }
template <
class X> T
operator- (
const X& e) { T y = *
this;
return y -= e; }
template <
class X> T
operator* (
const X& e) { T y = *
this;
return y *= e; }
template <
class X> T
operator/ (
const X& e) { T y = *
this;
return y /= e; }
#endif
T
operator++ () {
if (m.shared()) m.clone();
return ++m.mPtr->val[i]; }
T
operator++ (
int) {
if (m.shared()) m.clone();
return m.mPtr->val[i]++; }
T
operator-- () {
if (m.shared()) m.clone();
return --m.mPtr->val[i]; }
T
operator-- (
int) {
if (m.shared()) m.clone();
return m.mPtr->val[i]--; }
T
operator+ () {
return m.mPtr->val[i]; }
T
operator- () {
return -m.mPtr->val[i]; }
Mref (
const Mref& mr) : m(mr.m), i(mr.i) {;}
private:
Mref ();
matrix<T>& m;
size_t i;
};
template <
class T>
class Cmat_iter
{
public:
Cmat_iter (
const matrix<T>& mm,
const slice& ss) : m(mm), s(ss) {;}
const T&
operator[] (size_t i)
const;
operator valarray<T> ()
const {
return m.mPtr->val[s]; }
size_t size ()
const {
return s.size(); }
Cmat_iter(
const Cmat_iter& mi) : m(mi.m), s(mi.s) {;}
private:
Cmat_iter();
Cmat_iter&
operator= (
const Cmat_iter&);
const matrix<T>& m;
slice s;
};
template <
class T>
class Mat_iter
{
public:
Mat_iter (matrix<T>& mm,
const slice& ss) : m(mm), s(ss) {;}
Mref<T>
operator[] (size_t i)
const;
operator valarray<T>()
const {
return m.mPtr->val[s]; }
void operator= (
const valarray<T>& v)
const;
void operator= (
const T& e)
const;
void operator*= (
const valarray<T>& v)
const;
void operator/= (
const valarray<T>& v)
const;
void operator+= (
const valarray<T>& v)
const;
void operator-= (
const valarray<T>& v)
const;
size_t size ()
const {
return s.size(); }
Mat_iter(
const Mat_iter& mi) : m(mi.m), s(mi.s) {;}
private:
Mat_iter();
Mat_iter<T>&
operator= (
const Mat_iter<T>& mat);
matrix<T>& m;
slice s;
};
class mslice
{
public:
mslice (size_t sRow, size_t sCol, size_t nRow, size_t nCol)
: srow_(sRow), scol_(sCol), nrow_(nRow), ncol_(nCol) {;}
mslice (
const mslice& ms)
: srow_(ms.srow_), scol_(ms.scol_),
nrow_(ms.nrow_), ncol_(ms.ncol_) {;}
size_t size ()
const {
return nrow_ * ncol_; }
size_t start (size_t colno)
const {
return srow_*colno+scol_; }
size_t end (size_t colno)
const {
return (srow_+nrow_-
1)*colno+(scol_+ncol_); }
size_t colsize ()
const {
return nrow_; }
size_t rowsize ()
const {
return ncol_; }
size_t rowno ()
const {
return nrow_; }
size_t colno ()
const {
return ncol_; }
private:
mslice ();
size_t srow_,scol_, nrow_, ncol_;
};
template <
class T>
class mslice_matrix
{
public:
typedef T value_type;
mslice_matrix (matrix<T>& mm,
const mslice& ss)
: s(ss), m(mm) {;}
const mslice& get_slice()
const {
return s; }
matrix<T>& get_ref_mat ()
const {
return m; }
void operator= (
const matrix<T>& m2)
const;
void operator= (
const T& e)
const;
void operator+= (
const matrix<T>& m2)
const;
void operator-= (
const matrix<T>& m2)
const;
void operator*= (
const T& e)
const;
void operator/= (
const T& e)
const;
mslice_matrix (
const mslice_matrix& ms) : s(ms.s), m(ms.m) {;}
private:
mslice_matrix ();
mslice_matrix&
operator= (
const mslice_matrix&);
mslice s;
matrix<T>& m;
};
enum MATIRX_TYPE { GENERAL, DIAGONAL, TRIDIAGONAL, UTRIANG, LTRIANG };
class gmslice
{
public:
gmslice (MATIRX_TYPE mtype)
: MType_(mtype), ncol_(
0) {;}
gmslice (size_t nCol,
const valarray<size_t>& sRow,
const valarray<size_t>& nRow)
: MType_(GENERAL), ncol_(nCol), srow_(sRow), rsize_(nRow) {;}
gmslice (
const gmslice& gm)
: MType_(gm.MType_), ncol_(gm.ncol_),
srow_(gm.srow_), rsize_(gm.rsize_) {;}
size_t size ()
const {
return srow_.size() * ncol_; }
size_t start (size_t rowno)
const {
return srow_[rowno]; }
size_t end (size_t rowno)
const {
return srow_[rowno]+rsize_[rowno]; }
size_t colsize ()
const {
return srow_.size(); }
size_t rowsize ()
const {
return ncol_; }
size_t rowno ()
const {
return srow_.size(); }
size_t colno ()
const {
return ncol_; }
MATIRX_TYPE getype() {
return MType_; }
size_t ncol_;
valarray<size_t> srow_,rsize_;
private:
gmslice();
MATIRX_TYPE MType_;
};
template <
class T>
class gmslice_matrix
{
public:
typedef T value_type;
gmslice_matrix (matrix<T>& mm,
const gmslice& ss)
: s(ss), m(mm) {;}
const gmslice& get_slice()
const {
return s; }
matrix<T>& get_ref_mat ()
const {
return m; }
void operator= (
const matrix<T>& m2)
const;
void operator= (
const T& e)
const;
void operator+= (
const matrix<T>& m2)
const;
void operator-= (
const matrix<T>& m2)
const;
void operator*= (
const T& e)
const;
void operator/= (
const T& e)
const;
gmslice_matrix (
const gmslice_matrix& ms) : s(ms.s), m(ms.m) {;}
private:
gmslice_matrix ();
gmslice_matrix&
operator= (
const gmslice_matrix&);
gmslice s;
matrix<T>& m;
};
}
#endif
Matrix.cpp
#ifndef _MATRIX_CPP
#define _MATRIX_CPP
#include"matrix.h"
namespace techsoft {
template<
class T>
inline
const T& max (
const T& x,
const T& y)
{
return (x < y) ? y : x;
}
template<
class T>
inline
const T& min (
const T& x,
const T& y)
{
return (y < x) ? y : x;
}
template <
class T>
inline
void mswap (
const Mref<T>& x,
const Mref<T>& y)
{
T z = x;
x = y;
y = z;
}
template <
class T>
inline
void mswap (
const Mat_iter<T>& x,
const Mat_iter<T>& y)
{
size_t n = min( x.size(), y.size());
for (size_t i=
0; i < n; i++)
{
T z = x[i];
x[i] = y[i];
y[i] = z;
}
}
template <
class T>
inline
void mswap (matrix<T>& x, matrix<T>& y)
{
matrix<T> z = x;
x = y;
y = z;
}
inline float epsilon (
complex<
float>)
{
return std::numeric_limits<
float>::epsilon() *
100.0f;
}
inline double epsilon (
complex<
double>)
{
return std::numeric_limits<
double>::epsilon() *
1e4;
}
inline long double epsilon (
complex<
long double>)
{
return std::numeric_limits<
long double>::epsilon() *
1e4;
}
inline double epsilon (
const double& v)
{
double ep =
std::numeric_limits<
double>::epsilon() *
1e4;
return v >
1.0 ? v * ep : ep;
}
inline long double epsilon (
const long double& v)
{
long double ep =
std::numeric_limits<
long double>::epsilon() *
1e4;
return v >
1.0 ? v * ep : ep;
}
template <
class T>
inline
T epsilon (
const T& v)
{
T e =
std::numeric_limits<T>::epsilon() *
100;
return v > T(
1) ? v * e : e;
}
template <
class T>
inline const T&
Cmat_iter<T>::
operator[] (size_t i)
const
{
#ifdef RANGE_CHECK_
if (i >= s.size())
throw out_of_range(
"matrix<T>::operator[][]: Subscript out of range!");
#endif
return m.mPtr->val[s.start()+i*s.stride()];
}
template <
class T>
inline Mref<T>
Mat_iter<T>::
operator[] (size_t i)
const
{
#ifdef RANGE_CHECK_
if (i >= s.size())
throw out_of_range(
"matrix<T>::operator[][]: Subscript out of range!");
#endif
return Mref<T>( m, s.start()+i*s.stride());
}
template <
class T>
inline void
Mat_iter<T>::
operator= (
const valarray<T>& v)
const
{
#ifdef RANGE_CHECK_
if (size() != v.size())
throw invalid_argument(
"matrix<T>::operator[]: size mismatch in assignment operation!");
#endif
if (m.shared())
m.clone();
m.mPtr->val[s] = v;
}
template <
class T>
inline void
Mat_iter<T>::
operator= (
const T& e)
const
{
if (m.shared())
m.clone();
m.mPtr->val[s] = e;
}
template <
class T>
inline void
Mat_iter<T>::
operator*= (
const valarray<T>& v)
const
{
#ifdef RANGE_CHECK_
if (size() != v.size())
throw invalid_argument(
"matrix<T>::operator*=: size mismatch!");
#endif
if (m.shared())
m.clone();
m.mPtr->val[s] *= v;
}
template <
class T>
inline void
Mat_iter<T>::
operator/= (
const valarray<T>& v)
const
{
#ifdef RANGE_CHECK_
if (size() != v.size())
throw invalid_argument(
"matrix<T>::operator/=: size mismatch!");
#endif
if (m.shared())
m.clone();
m.mPtr->val[s] /= v;
}
template <
class T>
inline void
Mat_iter<T>::
operator+= (
const valarray<T>& v)
const
{
#ifdef RANGE_CHECK_
if (size() != v.size())
throw invalid_argument(
"matrix<T>::operator+=: size mismatch!");
#endif
if (m.shared())
m.clone();
m.mPtr->val[s] += v;
}
template <
class T>
inline void
Mat_iter<T>::
operator-= (
const valarray<T>& v)
const
{
#ifdef RANGE_CHECK_
if (size() != v.size())
throw invalid_argument(
"matrix<T>::operator-=: size mismatch!");
#endif
if (m.shared())
m.clone();
m.mPtr->val[s] -= v;
}
template <
class T>
void mslice_matrix<T>::
operator= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>operator= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] = m2(i,j);
}
}
template <
class T>
void mslice_matrix<T>::
operator+= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>::operator+= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] += m2(i,j);
}
}
template <
class T>
void mslice_matrix<T>::
operator-= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>::operator+= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] -= m2(i,j);
}
}
template <
class T>
void mslice_matrix<T>::
operator= (
const T& e)
const
{
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] = e;
}
}
template <
class T>
void mslice_matrix<T>::
operator*= (
const T& e)
const
{
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] *= e;
}
}
template <
class T>
void mslice_matrix<T>::
operator/= (
const T& e)
const
{
T *pv = &m(
0,
0);
size_t start = s.start( m.colno());
for (size_t i=
0; i < s.rowno(); i++)
{
size_t ipos = m.colno() * i;
for (size_t j=
0; j < s.colno(); j++)
pv[start+ipos+j] /= e;
}
}
template <
class T>
void gmslice_matrix<T>::
operator= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>operator= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
const T *pm = &m2(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
{
size_t jpos = ipos+j;
pv[jpos] = pm[jpos];
}
}
template <
class T>
void gmslice_matrix<T>::
operator+= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>::operator+= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
const T *pm = &m2(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
{
size_t jpos = ipos+j;
pv[jpos] += pm[jpos];
}
}
template <
class T>
void gmslice_matrix<T>::
operator-= (
const matrix<T>& m2)
const
{
#ifdef RANGE_CHECK_
if (s.rowno() != m2.rowno() || s.colno() != m2.colno())
throw out_of_range(
"mslice_matrix<T>::operator+= Non-conforming matrix size!");
#endif
T *pv = &m(
0,
0);
const T *pm = &m2(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
{
size_t jpos = ipos+j;
pv[jpos] -= pm[jpos];
}
}
template <
class T>
void gmslice_matrix<T>::
operator= (
const T& e)
const
{
T *pv = &m(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
pv[ipos+j] = e;
}
template <
class T>
void gmslice_matrix<T>::
operator*= (
const T& e)
const
{
T *pv = &m(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
pv[ipos+j] *= e;
}
template <
class T>
void gmslice_matrix<T>::
operator/= (
const T& e)
const
{
T *pv = &m(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
pv[ipos+j] /= e;
}
template <
class T>
inline
matrix<T>::matrix ()
{
mPtr = allocator( Allocate,
0,
0);
}
template <
class T>
inline
matrix<T>::matrix (size_t nRow, size_t nCol)
{
mPtr = allocator( Allocate, nRow, nCol);
}
template <
class T>
matrix<T>::matrix (size_t nRow, size_t nCol,
const T& e)
{
mPtr =
new base_mat( e, nRow, nCol);
allocator( Record);
}
template <
class T>
matrix<T>::matrix (size_t nRow, size_t nCol,
const valarray<T>& vec)
{
mPtr =
new base_mat( nRow, nCol, vec);
allocator( Record);
}
template <
class T>
matrix<T>::matrix (size_t row, size_t col,
const T* val, MatArrayType aType)
{
if (aType == C_ARRAY)
{
mPtr =
new base_mat( val, row, col);
allocator( Record);
}
else
{
mPtr = allocator( Allocate, row, col);
T *pv = &mPtr->val[
0];
for (size_t k=
0, j=
0; j < col; j++)
for (size_t i=
0; i < row; i++)
pv[i*col+j] = val[k++];
}
}
template <
class T>
inline
matrix<T>::matrix (
const matrix<T>& m)
{
mPtr = m.mPtr;
mPtr->refcnt++;
}
template <
class T>
matrix<T>::matrix (
const mslice_matrix<T>& sm)
{
const mslice& s = sm.get_slice();
matrix<T>& m = sm.get_ref_mat();
mPtr = allocator( Allocate, s.rowno(), s.colno());
for (size_t i=
0; i < s.rowno(); i++)
for (size_t j=
0; j < s.colno(); j++)
mPtr->val[i*s.colno()+j] = m.mPtr->val[s.start(m.colno())+i*m.colno()+j];
}
template <
class T>
matrix<T>::matrix (
const gmslice_matrix<T>& sm)
{
const gmslice& s = sm.get_slice();
const matrix<T>& m = sm.get_ref_mat();
mPtr = allocator( Allocate, s.rowno(), s.colno());
mPtr->val = T(
0);
T *pv = &mPtr->val[
0];
const T *pm = &m.mPtr->val[
0];
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
{
size_t jpos = ipos+j;
pv[jpos] = pm[jpos];
}
}
#ifndef _TS_NO_MEMBER_TEMPLATES
template <
class T>
template <
class X>
matrix<T>::matrix (
const matrix<X>& m)
{
mPtr = allocator( Allocate, m.rowno(), m.colno());
for (size_t i=
0; i < rowno(); i++)
for (size_t j=
0; j < colno(); j++)
{
X x = m(i,j);
mPtr->val[i*colno()+j] = x;
}
}
#endif
template <
class T>
void matrix<T>::clone ()
{
if (mPtr->refcnt ==
1)
return;
base_mat *mp = allocator( Allocate, mPtr->nrow, mPtr->ncol);
mp->val = mPtr->val;
mPtr->refcnt--;
mPtr = mp;
}
template <
class T>
#if defined(__MWERKS__) || defined(_MSC_VER) || defined(__GNUC__)
typename
#endif
matrix<T>::base_mat*
matrix<T>::allocator (AllocType bOpt, size_t nrow, size_t ncol)
{
static base_mat *mlist[MAX_MATRIX_CACHE+
1];
static int instCount =
0;
static volatile int semCount =
0;
static bool first =
true;
if (first)
{
first =
false;
for (
int k=
0; k <= MAX_MATRIX_CACHE; k++)
mlist[k] = NULL;
}
switch (bOpt)
{
case Record:
instCount++;
return NULL;
case Allocate:
instCount++;
base_mat *mp;
if (++semCount ==
1)
for (
int i=
0; i < MAX_MATRIX_CACHE; i++)
if (mlist[i] != NULL && mlist[i]->nrow == nrow && mlist[i]->ncol == ncol)
{
mp = mlist[i];
mlist[i] = NULL;
--semCount;
mp->refcnt =
1;
return mp;
}
--semCount;
mp =
new base_mat( nrow, ncol);
return mp;
case Free:
if (--instCount)
{
if (++semCount ==
1)
for (
int i=
0; i < MAX_MATRIX_CACHE; i++)
{
swap( mlist[i], mPtr);
if (mPtr == NULL)
{
--semCount;
return NULL;
}
}
--semCount;
}
else
{
++semCount;
for (
int i=
0; i < MAX_MATRIX_CACHE; i++)
if (mlist[i] != NULL)
{
delete mlist[i];
mlist[i] = NULL;
}
--semCount;
}
delete mPtr;
mPtr = NULL;
break;
}
return NULL;
}
template <
class T>
inline
matrix<T>::~matrix ()
{
if (--mPtr->refcnt ==
0)
allocator( Free);
}
template <
class T>
void
matrix<T>::resize (size_t nRow, size_t nCol,
const T& dval)
{
if (mPtr->nrow == nRow && mPtr->ncol == nCol)
return;
base_mat *mp = allocator( Allocate, nRow, nCol);
for (size_t i=
0; i < nRow; i++)
for (size_t j=
0; j < nCol; j++)
mp->val[i*nCol+j] = (i >= mPtr->nrow || j >= mPtr->ncol) ?
dval : mPtr->val[i*mPtr->ncol+j];
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = mp;
}
template <
class T>
void
matrix<T>::
free ()
{
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = allocator( Allocate,
0,
0);
}
template <
class T>
inline mslice_matrix<T>
matrix<T>::
operator[] (mslice ms)
{
#ifdef RANGE_CHECK_
if (ms.end( colno()-
1) > size())
throw invalid_argument(
"matrix<T>::operator[]: sub-matrix is out of range!");
#endif
return mslice_matrix<T>( *
this, ms);
}
template <
class T>
inline gmslice_matrix<T>
matrix<T>::
operator[] (gmslice gm)
{
#ifdef RANGE_CHECK_
if (gm.size() > size())
throw invalid_argument(
"matrix<T>::operator[]: sub-matrix is out of range!");
#endif
if (gm.getype() != GENERAL)
{
gm.ncol_ = mPtr->ncol;
gm.srow_.resize( mPtr->nrow);
gm.rsize_.resize( mPtr->nrow);
}
size_t i;
switch(gm.getype())
{
case DIAGONAL:
gm.rsize_ =
1;
for (i=
0; i < gm.ncol_; ++i)
gm.srow_[i] = i;
break;
case TRIDIAGONAL:
gm.rsize_ =
3;
gm.rsize_[
0] =
2;
gm.rsize_[gm.ncol_-
1] =
2;
gm.srow_[
0] =
0;
for (i=
1; i < gm.ncol_; ++i)
gm.srow_[i] = i-
1;
break;
case UTRIANG:
for (i=
0; i < gm.ncol_; ++i)
{
gm.srow_[i] = i;
gm.rsize_[i] = gm.ncol_-i;
}
break;
case LTRIANG:
gm.srow_ =
0;
for (i=
0; i < gm.ncol_; ++i)
gm.rsize_[i] = i+
1;
break;
}
return gmslice_matrix<T>( *
this, gm);
}
template <
class T>
inline matrix<T>&
matrix<T>::
operator= (
const matrix<T>& m)
{
m.mPtr->refcnt++;
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = m.mPtr;
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator= (
const mslice_matrix<T>& sm)
{
const mslice& s = sm.get_slice();
matrix<T>& m = sm.get_ref_mat();
base_mat *mp = allocator( Allocate, s.rowno(), s.colno());
T *pv = &mp->val[
0];
const T *pm = &m.mPtr->val[
0];
for (size_t i=
0; i < s.rowno(); i++)
for (size_t j=
0; j < s.colno(); j++)
pv[i*s.colno()+j] = pm[s.start(m.colno())+i*m.colno()+j];
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = mp;
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator= (
const gmslice_matrix<T>& sm)
{
const gmslice& s = sm.get_slice();
const matrix<T>& m = sm.get_ref_mat();
base_mat *mp = allocator( Allocate, s.rowno(), s.colno());
mp->val = T(
0);
T *pv = &mp->val[
0];
const T *pm = &m(
0,
0);
for (size_t i=
0,ipos=
0; i < s.rowno(); ++i,ipos+=s.colno())
for (size_t j=s.start(i); j < s.end(i); j++)
{
size_t jpos = ipos+j;
pv[jpos] = pm[jpos];
}
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = mp;
return *
this;
}
template <
class T>
matrix<T>& matrix<T>::
operator= (
const T& el)
{
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
mPtr->val = el;
return *
this;
}
#ifndef _TS_NO_MEMBER_TEMPLATES
template <
class T>
template <
class X>
matrix<T>& matrix<T>::
operator= (
const matrix<X>& m)
{
if (--mPtr->refcnt ==
0)
allocator( Free);
mPtr = allocator( Allocate, m.rowno(), m.colno());
const X *pm = &m(
0,
0);
T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
pv[i] = pm[i];
return *
this;
}
#endif
template <
class T>
const matrix<T>
matrix<T>::
operator[] (mslice ms)
const
{
#ifdef RANGE_CHECK_
if (ms.end( colno()-
1) > size())
throw invalid_argument(
"matrix<T>::operator[]: sub-matrix is out of range!");
#endif
matrix<T> tm(ms.rowno(),ms.colno());
for (size_t i=
0; i < tm.rowno(); i++)
for (size_t j=
0; j < tm.colno(); j++)
tm.mPtr->val[i*tm.colno()+j] = mPtr->val[ms.start(colno())+i*colno()+j];
return tm;
}
template <
class T>
const matrix<T>
matrix<T>::
operator[] (gmslice gm)
const
{
#ifdef RANGE_CHECK_
if (gm.size() > size())
throw invalid_argument(
"matrix<T>::operator[]: sub-matrix is out of range!");
#endif
if (gm.getype() != GENERAL)
{
gm.ncol_ = mPtr->ncol;
gm.srow_.resize( mPtr->nrow);
gm.rsize_.resize( mPtr->nrow);
}
size_t k;
switch(gm.getype())
{
case DIAGONAL:
gm.rsize_ =
1;
for (k=
0; k < gm.ncol_; ++k)
gm.srow_[k] = k;
break;
case TRIDIAGONAL:
gm.rsize_ =
3;
gm.rsize_[
0] =
2;
gm.rsize_[gm.ncol_-
1] =
2;
gm.srow_[
0] =
0;
for (k=
1; k < gm.ncol_; ++k)
gm.srow_[k] = k-
1;
break;
case UTRIANG:
for (k=
0; k < gm.ncol_; ++k)
{
gm.srow_[k] = k;
gm.rsize_[k] = gm.ncol_-k;
}
break;
case LTRIANG:
gm.srow_ =
0;
for (k=
0; k < gm.ncol_; ++k)
gm.rsize_[k] = k+
1;
break;
}
matrix<T> tm(gm.rowno(), gm.colno(), T(
0));
const T *pv = &mPtr->val[
0];
T *pm = &tm.mPtr->val[
0];
for (size_t i=
0,ipos=
0; i < gm.rowno(); ++i,ipos+=gm.colno())
for (size_t j=gm.start(i); j < gm.end(i); j++)
{
size_t jpos = ipos+j;
pm[jpos] = pv[jpos];
}
return tm;
}
template <
class T>
inline Mat_iter<T>
matrix<T>::row (size_t i)
{
#ifdef RANGE_CHECK_
if (i >= mPtr->nrow)
throw out_of_range(
"matrix<T>::row: subscript is out of range!");
#endif
return Mat_iter<T>( *
this, slice( i * mPtr->ncol, mPtr->ncol,
1));
}
template <
class T>
inline Cmat_iter<T>
matrix<T>::row (size_t i)
const
{
#ifdef RANGE_CHECK_
if (i >= mPtr->nrow)
throw out_of_range(
"matrix<T>::row: subscript is out of range!");
#endif
return Cmat_iter<T>( *
this, slice( i * mPtr->ncol, mPtr->ncol,
1));
}
template <
class T>
inline Mat_iter<T>
matrix<T>::column (size_t i)
{
#ifdef RANGE_CHECK_
if (i >= mPtr->ncol)
throw out_of_range(
"matrix<T>::column: subscript is out of range!");
#endif
return Mat_iter<T>( *
this, slice( i, mPtr->nrow, mPtr->ncol));
}
template <
class T>
inline Cmat_iter<T>
matrix<T>::column (size_t i)
const
{
#ifdef RANGE_CHECK_
if (i >= mPtr->ncol)
throw out_of_range(
"matrix<T>::column: subscript is out of range!");
#endif
return Cmat_iter<T>( *
this, slice( i, mPtr->nrow, mPtr->ncol));
}
template <
class T>
inline Mat_iter<T>
matrix<T>::diag (
int i)
{
#ifdef RANGE_CHECK_
if (i >=
int(mPtr->ncol) ||
int(mPtr->nrow)+i <
1)
throw out_of_range(
"matrix<T>::diag: subscript is out of range!");
#endif
size_t st,sz;
if (i >=
0)
{
st = i;
sz = mPtr->ncol - i;
if (sz > mPtr->nrow)
sz = mPtr->nrow;
}
else
{
st = -i *
int(mPtr->ncol);
sz =
int(mPtr->nrow) + i;
if (sz > mPtr->ncol)
sz = mPtr->ncol;
}
return Mat_iter<T>( *
this, slice( st, sz, mPtr->ncol+
1));
}
template <
class T>
inline Cmat_iter<T>
matrix<T>::diag (
int i)
const
{
#ifdef RANGE_CHECK_
if (i >=
int(mPtr->ncol) ||
int(mPtr->nrow)+i <
1)
throw out_of_range(
"matrix<T>::diag: subscript is out of range!");
#endif
size_t st,sz;
if (i >=
0)
{
st = i;
sz = mPtr->ncol - i;
if (sz > mPtr->nrow)
sz = mPtr->nrow;
}
else
{
st = -i *
int(mPtr->ncol);
sz =
int(mPtr->nrow) + i;
if (sz > mPtr->ncol)
sz = mPtr->ncol;
}
return Cmat_iter<T>( *
this, slice( st, sz, mPtr->ncol+
1));
}
template <
class T>
inline Mref<T>
matrix<T>::
operator() (size_t i, size_t j)
{
#ifdef RANGE_CHECK_
if (i >= mPtr->nrow || j >= mPtr->ncol)
throw out_of_range(
"matrix<T>::operator(): subscript is out of range!");
#endif
return Mref<T>( *
this, i * mPtr->ncol + j);
}
template <
class T>
inline const T&
matrix<T>::
operator() (size_t i, size_t j)
const
{
#ifdef RANGE_CHECK_
if (i >= mPtr->nrow || j >= mPtr->ncol)
throw out_of_range(
"matrix<T>::operator(): subscript is out of range!");
#endif
return mPtr->val[i*mPtr->ncol+j];
}
template <
class T> matrix<T>&
matrix<T>::
operator+= (
const matrix<T>& m)
{
#ifdef RANGE_CHECK_
if (rowno() != m.rowno() || colno() != m.colno())
throw invalid_argument(
"matrix<T>::operator+=: Inconsistent matrix size in addition!");
#endif
base_mat *mp;
if (shared())
mp = allocator( Allocate, mPtr->nrow, mPtr->ncol);
else
mp = mPtr;
const T *pm = &m(
0,
0);
const T *pv = &mPtr->val[
0];
T *pv2 = &mp->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
pv2[i] = pv[i] + pm[i];
if (shared())
{
--mPtr->refcnt;
mPtr = mp;
}
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator-= (
const matrix<T>& m)
{
#ifdef RANGE_CHECK_
if (rowno() != m.rowno() || colno() != m.colno())
throw invalid_argument(
"matrix<T>::operator-=: Inconsistent matrix size in addition!");
#endif
base_mat *mp;
if (shared())
mp = allocator( Allocate, mPtr->nrow, mPtr->ncol);
else
mp = mPtr;
const T *pm = &m(
0,
0);
const T *pv = &mPtr->val[
0];
T *pv2 = &mp->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
pv2[i] = pv[i] - pm[i];
if (shared())
{
--mPtr->refcnt;
mPtr = mp;
}
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator*= (
const T& x)
{
base_mat *mp;
if (shared())
mp = allocator( Allocate, mPtr->nrow, mPtr->ncol);
else
mp = mPtr;
const T *pv = &mPtr->val[
0];
T *pv2 = &mp->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
pv2[i] = pv[i] * x;
if (shared())
{
--mPtr->refcnt;
mPtr = mp;
}
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator*= (
const matrix<T>& m)
{
size_t nr1 = mPtr->nrow;
size_t nc1 = mPtr->ncol;
size_t nc2 = m.mPtr->ncol;
#ifdef RANGE_CHECK_
size_t nr2 = m.mPtr->nrow;
if (nc1 != nr2)
throw invalid_argument(
"matrix<T>::operator*=: Inconsistent matrix size in multiplication!");
#endif
matrix<T> tm( nr1, nc2);
const T *pm1 = &mPtr->val[
0];
const T *pm2 = &m(
0,
0);
T *pm = &tm.mPtr->val[
0];
for (size_t i=
0; i < nr1; i++)
for (size_t j=
0; j < nc2; j++)
{
pm[i*nc2+j] = T(
0);
for (size_t k=
0; k < nc1; k++)
pm[i*nc2+j] += pm1[i*nc1+k] * pm2[k*nc2+j];
}
*
this = tm;
return *
this;
}
template <
class T>
inline matrix<T>&
matrix<T>::
operator/= (
const T& x)
{
*
this *=
1/x;
return *
this;
}
template <
class T> matrix<T>&
matrix<T>::
operator/= (
const matrix<T>& m)
{
*
this *= !m;
return *
this;
}
template <
class T> matrix<T>
matrix<T>::
operator- ()
const
{
matrix<T> m( mPtr->nrow, mPtr->ncol);
T *pv2 = &m.mPtr->val[
0];
const T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
pv2[i] = -pv[i];
return m;
}
template <
class T>
matrix<T> matrix<T>::
operator~ ()
const
{
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
matrix<T> tm( n, m);
const T *pm = &mPtr->val[
0];
T *ptm = &tm.mPtr->val[
0];
for (size_t i=
0; i < m; i++)
for (size_t j=
0; j < n; j++)
ptm[j*m+i] = pm[i*n+j];
return tm;
}
template <
class T>
inline matrix<T> matrix<T>::
operator! ()
const
{
matrix<T> m = *
this;
if (!m.inv())
m.null();
return m;
}
template <
class T>
inline matrix<T>
operator+ (
const matrix<T>& m1,
const matrix<T>& m2)
{
matrix<T> m = m1;
return m += m2;
}
template <
class T>
inline matrix<T>
operator- (
const matrix<T>& m1,
const matrix<T>& m2)
{
matrix<T> m = m1;
return m -= m2;
}
template <
class T>
inline matrix<T>
operator* (
const matrix<T>& m1,
const matrix<T>& m2)
{
matrix<T> m = m1;
return m *= m2;
}
template <
class T>
inline matrix<T>
operator* (
const matrix<T>& m,
const T& el)
{
matrix<T> m2 = m;
return m2 *= el;
}
template <
class T>
inline matrix<T>
operator* (
const T& el,
const matrix<T>& m)
{
return m * el;
}
template <
class T> valarray<T>
operator* (
const matrix<T>& m,
const valarray<T>& v)
{
#ifdef RANGE_CHECK_
if (m.rowsize() != v.size())
throw invalid_argument(
"matrix<T>::operator*: Inconsistent matrix size!");
#endif
valarray<T> vt( m.rowno());
for (size_t i=
0; i < m.rowno(); i++)
{
vt[i] = T(
0);
for (size_t j=
0; j < m.colno(); j++)
{
T el = m(i,j);
vt[i] += el * v[j];
}
}
return vt;
}
template <
class T> valarray<T>
operator* (
const valarray<T>& v,
const matrix<T>& m)
{
#ifdef RANGE_CHECK_
if (v.size() != m.rowno())
throw invalid_argument(
"matrix<T>::operator*: Inconsistent matrix size!");
#endif
valarray<T> vt( m.colno());
for (size_t i=
0; i < m.colno(); i++)
{
vt[i] = T(
0);
for (size_t j=
0; j < v.size(); ++j)
{
T el = m(j,i);
vt[i] += el * v[j];
}
}
return vt;
}
template <
class T>
inline matrix<T>
operator/ (
const matrix<T>& m1,
const matrix<T>& m2)
{
matrix<T> m = m1;
return m *= !m2;
}
template <
class T>
inline matrix<T>
operator/ (
const matrix<T>& m,
const T& el)
{
matrix<T> m2 = m;
return m2 *=
1/el;
}
template <
class T>
inline matrix<T>
operator/ (
const T& el,
const matrix<T>& m)
{
matrix<T> m2 = !m;
return m2 *= el;
}
template <
class T>
inline valarray<T>
operator/ (
const matrix<T>& m,
const valarray<T>& v)
{
valarray<T> v2 = T(
1) / v;
return m * v2;
}
template <
class T>
inline valarray<T>
operator/ (
const valarray<T>& v,
const matrix<T>& m)
{
return v * !m;
}
template <
class T>
bool
operator== (
const matrix<T>& m1,
const matrix<T>& m2)
{
if (m1.rowno() != m2.rowno() || m1.colno() != m2.colno())
return false;
size_t n = m1.size();
const T *pm1 = &m1(
0,
0);
const T *pm2 = &m2(
0,
0);
for (size_t i=
0; i < n; i++)
if (
abs( pm1[i] - pm2[i]) > epsilon( pm1[i]))
return false;
return true;
}
template <
class T>
inline bool
operator!= (
const matrix<T>& m1,
const matrix<T>& m2)
{
return !(m1 == m2);
}
template <
class T>
bool
isVecEq (
const valarray<T>& v1,
const valarray<T>& v2)
{
if (v1.size() != v2.size())
return false;
for (size_t i=
0; i < v1.size(); i++)
{
T d = v1[i] - v2[i];
if (
abs( d) > epsilon( v1[i]))
return false;
}
return true;
}
template <
class T>
inline void
matrix<T>::unit ()
{
null();
diag(
0) = T(
1);
}
template <
class T>
inline void
matrix<T>::null ()
{
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
mPtr->val = T(
0);
}
inline int rand_ () {
return rand(); }
template <
class T>
void
matrix<T>::rand (
int rmin,
int rmax,
int rseed)
{
if (!rmin && !rmax)
{
rmin = -
1;
rmax =
1;
}
if (rmin > rmax)
{
int tmp = rmin;
rmin = rmax;
rmax = tmp;
}
int rdiff = rmax - rmin;
if (rseed)
srand( rseed);
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; i++)
{
int rn = rand_();
if (rdiff >
1)
{
rn %= rdiff;
pv[i] = T(rn) - T(rdiff) / T(
2);
if (rdiff >
1)
{
T f = ((T)rand_()) / T(RAND_MAX);
if (rn > rdiff)
pv[i] -= f;
else
pv[i] += f;
}
}
else
pv[i] = T(rn) / T(RAND_MAX);
}
}
template <
class T> matrix<T>
pow (
const matrix<T>& m, size_t n)
{
#ifdef RANGE_CHECK_
if (m.colno() != m.rowno() || m.rowno() ==
0)
throw invalid_argument(
"pow(): Non-square matrix!");
#endif
matrix<T> x(m.rowno(), m.colno());
if (n ==
0)
{
x.unit();
return x;
}
matrix<T> m1 = m;
bool first =
true;
while (
1)
{
if (n &
1)
{
if (first)
{
x = m1;
first =
false;
}
else
x *= m1;
}
n >>=
1;
if (n ==
0)
break;
m1 *= m1;
}
return x;
}
template <
class T> matrix<T>
abs (
const matrix<T>& m)
{
matrix<T> a(m.rowno(), m.colno());
T *pa = &a(
0,
0);
const T *pm = &m(
0,
0);
size_t n = m.size();
for (size_t i=
0; i < n; i++)
pa[i] = T(
abs( pm[i]));
return a;
}
template <
class T> matrix<T>
floor (
const matrix<T>& m)
{
matrix<T> a(m.rowno(), m.colno());
T *pa = &a(
0,
0);
const T *pm = &m(
0,
0);
size_t n = m.size();
for (size_t i=
0; i < n; i++)
pa[i] = T(
floor( pm[i]));
return a;
}
template <
class T> matrix<T>
ceil (
const matrix<T>& m)
{
matrix<T> a(m.rowno(), m.colno());
T *pa = &a(
0,
0);
const T *pm = &m(
0,
0);
size_t n = m.size();
for (size_t i=
0; i < n; i++)
pa[i] = T(
ceil( pm[i]));
return a;
}
template <
class T>
inline T
matrix<T>::trace (
int i)
const
{
valarray<T> d = diag( i);
return d.sum();
}
template <
class T>
inline
T hypot (T a, T b)
{
a =
abs( a);
b =
abs( b);
if (a > b)
{
T c = b/a;
return (a *
sqrt( T(
1) + c * c));
}
if (b < epsilon(b))
return T(
0);
T c = a/b;
return (b *
sqrt( T(
1) + c * c));
}
template <
class T>
inline
T sign (T a, T b)
{
return (b >= T(
0) ?
abs(a) : -
abs(a));
}
template <
class T>
bool matrix<T>::lud (valarray<size_t>& ri, T* pDet)
{
size_t i,j,k;
double ta,tb;
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::lud: Non-square matrix!");
#endif
if (mPtr->nrow != ri.size())
ri.resize( mPtr->nrow);
if (shared())
clone();
if (pDet != NULL)
*pDet = T(
1);
size_t n = mPtr->nrow;
T *pv = &mPtr->val[
0];
for (i=
0; i < n; i++)
ri[i] = i;
for (k=
0; k < n-
1; k++)
{
j = k;
ta =
abs( pv[ri[k]*n+k]);
for (i=k+
1; i < n; i++)
if ((tb =
abs( pv[ri[i]*n+k])) > ta)
{
ta = tb;
j = i;
}
if (j != k)
{
swap( ri[j], ri[k]);
if (pDet != NULL)
*pDet = - *pDet;
}
size_t kpos = ri[k] * n;
if (
abs( pv[kpos+k]) < epsilon( pv[kpos+k]))
return false;
if (pDet != NULL)
*pDet *= pv[kpos+k];
for (i=k+
1; i < n; i++)
{
size_t ipos = ri[i] * n;
T a = pv[ipos+k] /= pv[kpos+k];
for (j=k+
1; j < n; j++)
pv[ipos+j] -= a * pv[kpos+j];
}
}
if (pDet != NULL)
*pDet *= pv[ri[k]*n+k];
return true;
}
template <
class T>
void
matrix<T>::lubksb (
const valarray<size_t>& ri,
const valarray<T>& v, valarray<T>& s)
const
{
size_t i,j,k,ip;
bool nonzero =
false;
size_t n = mPtr->nrow;
const T *pv = &mPtr->val[
0];
#ifdef RANGE_CHECK_
if (n != v.size())
throw invalid_argument(
"matrix<T>::lubksb: Invalid vector size!");
#endif
if (n != s.size())
s.resize( n);
for (k=
0,i=
0; i < n; i++)
{
ip = ri[i];
s[i] = v[ip];
if (nonzero)
{
ip *= n;
for (j=k; j < i; j++)
s[i] -= pv[ip+j] * s[j];
}
else if (s[i] != T(
0))
{
k = i;
nonzero =
true;
}
}
for (i=n-
1; ; i--)
{
ip = ri[i] * n;
for (j=i+
1; j < n; j++)
s[i] -= pv[ip+j] * s[j];
s[i] /= pv[ip+i];
if (i ==
0)
break;
}
}
template <
class T>
void
matrix<T>::lumpove (
const matrix<T>& ludm,
const valarray<size_t>& ri,
const valarray<T>& v, valarray<T>& s)
const
{
size_t i,j;
size_t n = mPtr->ncol;
const T *pa = &mPtr->val[
0];
valarray<T> rv(n), rs(n);
for (i=
0; i < n; i++)
{
T tmp = -v[i];
for (j=
0; j < n; j++)
tmp += pa[i*n+j] * s[j];
rv[i] = tmp;
}
ludm.lubksb( ri, rv, rs);
for (i=
0; i < n; i++)
s[i] -= rs[i];
}
template <
class T>
bool
matrix<T>::solve (
const valarray<T>& v, valarray<T>& s)
const
{
matrix<T> tm = *
this;
valarray<size_t> ri( mPtr->nrow);
if (tm.lud( ri))
{
tm.lubksb( ri, v, s);
return true;
}
return false;
}
template <
class T>
bool
matrix<T>::solve_chol (
const valarray<T>& v, valarray<T>& s)
const
{
matrix<T> tm = *
this;
if (tm.chold())
{
tm.cholbksb( v, s);
return true;
}
return false;
}
template <
class T>
bool
matrix<T>::solve_sv (
const valarray<T>& v, valarray<T>& s)
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow < mPtr->ncol)
throw invalid_argument(
"matrix<T>::solve_sv(): No. of rows must be equal or greater than column!");
#endif
matrix<T> vc( mPtr->ncol, mPtr->ncol);
matrix<T> tm = *
this;
valarray<T> w( mPtr->ncol);
if (tm.svd( vc, w))
{
tm.svbksb( vc, w, v, s);
return true;
}
return false;
}
template <
class T>
bool
matrix<T>::solve_qr (
const valarray<T>& v, valarray<T>& s)
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow < mPtr->ncol)
throw invalid_argument(
"matrix<T>::solve_qr(): No. of rows must be equal or greater than column!");
#endif
matrix<T> r( mPtr->ncol, mPtr->ncol);
matrix<T> tm = *
this;
tm.qrd( r);
tm.qrbksb( r, v, s);
return true;
}
template <
class T>
bool
matrix<T>::solve (
const matrix<T>& v, matrix<T>& s)
const
{
size_t n = mPtr->nrow;
#ifdef RANGE_CHECK_
if (n != v.rowno())
throw invalid_argument(
"matrix<T>::operator*: Inconsistent number of vectors in solve!");
#endif
if (v.size() != s.size())
s.resize( v.rowno(), v.colno());
matrix<T> tm = *
this;
valarray<size_t> ri(n);
valarray<T> vt(n), st(n);
if (!tm.lud( ri))
return false;
for (size_t i=
0; i < v.colno(); i++)
{
vt = v.column(i);
tm.lubksb( ri, vt, st);
s.column(i) = st;
}
return true;
}
template <
class T>
bool
matrix<T>::chold ()
{
#ifdef RANGE_CHECK_
if (!isSymmetric())
throw invalid_argument(
"matrix<T>::chold: Non-symmetric matrix!");
#endif
int n =
int(mPtr->nrow);
if (shared())
clone();
T *pa = &mPtr->val[
0];
int i,j;
for (i=
0; i < n; i++)
for (j=i; j < n; j++)
{
T s = pa[i*n+j];
for (
int k=i-
1; k >=
0; k--)
s -= pa[i*n+k] * pa[j*n+k];
if (i == j)
{
if (s <= epsilon(s))
return false;
pa[i*n+i] =
sqrt( s);
}
else
pa[j*n+i] = s / pa[i*n+i];
}
for (j=
1; j < n; j++)
for (i=
0; i < j; i++)
pa[i*n+j] = T(
0);
return true;
}
template <
class T>
void
matrix<T>::cholbksb (
const valarray<T>& v, valarray<T>& s)
const
{
int i,k,n;
T a;
const T *pm = &mPtr->val[
0];
n =
int(mPtr->nrow);
i =
int(s.size());
if (n != i)
s.resize( n);
for (i=
0; i < n; i++)
{
a = v[i];
for (k=i-
1; k >=
0; k--)
a -= pm[i*n+k] * s[k];
s[i] = a / pm[i*n+i];
}
for (i=n-
1; i >=
0; i--)
{
a = s[i];
for (k=i+
1; k < n; k++)
a -= pm[k*n+i] * s[k];
s[i] = a / pm[i*n+i];
}
}
template <
class T>
void
matrix<T>::qrd (matrix<T>& r)
{
size_t i,j,k;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
#ifdef RANGE_CHECK_
if (m < n)
throw invalid_argument(
"matrix<T>::qrd: Inconsistent matrix size!");
#endif
if (shared())
clone();
if (n != r.rowno() || r.rowno() != r.colno())
r.resize( n, n);
T *pa = &mPtr->val[
0];
T *pr = &r(
0,
0);
for (k=
0; k < n; k++)
{
T nrm(
0);
for (i = k; i < m; i++)
nrm = hypot( nrm, pa[i*n+k]);
if (nrm > epsilon(nrm))
{
if (pa[k*n+k] < T(
0))
nrm = -nrm;
for (i = k; i < m; i++)
pa[i*n+k] /= nrm;
pa[k*n+k] += T(
1);
for (j=k+
1; j < n; j++)
{
T s(
0);
for (i=k; i < m; i++)
s += pa[i*n+k] * pa[i*n+j];
s /= -pa[k*n+k];
for (i=k; i < m; i++)
pa[i*n+j] += s * pa[i*n+k];
}
}
pr[k*n+k] = -nrm;
}
for (j=
1; j < n; j++)
for (size_t i=
0; i < j; i++)
{
pr[i*n+j] = pa[i*n+j];
pr[j*n+i] = T(
0);
}
matrix<T> q(m,n);
T *pq = &q(
0,
0);
for (k=n-
1; ; k--)
{
for (i =
0; i < m; i++)
pq[i*n+k] = T(
0);
pq[k*n+k] = T(
1);
for (j=k; j < n; j++)
{
if (pa[k*n+k] != T(
0))
{
T s(
0);
for (i=k; i < m; i++)
s += pa[i*n+k] * pq[i*n+j];
s /= -pa[k*n+k];
for (i = k; i < m; i++)
pq[i*n+j] += s * pa[i*n+k];
}
}
if (k ==
0)
break;
}
*
this = q;
}
template <
class T>
void
matrix<T>::qrbksb (
const matrix<T>& r,
const valarray<T>& v, valarray<T>& s)
const
{
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
size_t i,j;
#ifdef RANGE_CHECK_
if (m != v.size())
throw std::invalid_argument(
"matrix<T>::qrsolve: Inconsistent vector size!");
#endif
if (n != s.size())
s.resize( n);
for (i=
0; i < n; i++)
{
s[i] = T(
0);
for (j=
0; j < m; j++)
s[i] += mPtr->val[j*n+i] * v[j];
}
const T *pr = &r(
0,
0);
for (i=n-
1; ; i--)
{
size_t ip = i * n;
for (j=i+
1; j < n; j++)
s[i] -= pr[ip+j] * s[j];
s[i] /= pr[ip+i];
if (i ==
0)
break;
}
}
template <
class T>
bool
matrix<T>::svd (matrix<T>& vc, valarray<T>& w)
{
size_t flag,i,its,j,jj,k,l,nm;
T c,f,h,s,x,y,z,tmp;
if (shared())
clone();
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
if (vc.rowno() != n || vc.colno() != n)
vc.resize( n, n);
if (w.size() != n)
w.resize( n);
T *a = &mPtr->val[
0];
T *v = &vc(
0,
0);
valarray<T> rv1(n);
T g(
0), scale(
0), anorm(
0);
for (i=
0; i < n; i++)
{
l = i +
1;
rv1[i] = scale * g;
g = s = scale = T(
0);
if (i < m)
{
for (k=i; k < m; k++)
scale +=
abs( a[k*n+i]);
if (scale > epsilon( scale))
{
for (k=i; k < m; k++)
{
tmp = a[k*n+i] /= scale;
s += tmp * tmp;
}
f = a[i*n+i];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+i] = f - g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=i; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = s / h;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (k=i; k < m; k++)
a[k*n+i] *= scale;
}
}
w[i] = scale * g;
g = s = scale = T(
0);
if (i < m && i != n-
1)
{
for (k=l; k < n; k++)
scale +=
abs(a[i*n+k]);
if (scale > epsilon(scale))
{
for (k=l; k < n; k++)
{
tmp = a[i*n+k] /= scale;
s += tmp * tmp;
}
f = a[i*n+l];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+l] = f - g;
for (k=l; k < n; k++)
rv1[k] = a[i*n+k] / h;
for (j=l; j < m; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[j*n+k] * a[i*n+k];
for (k=l; k < n; k++)
a[j*n+k] += s * rv1[k];
}
for (k=l; k < n; k++)
a[i*n+k] *= scale;
}
}
anorm = techsoft::max( anorm,
abs( w[i]) +
abs( rv1[i]) );
}
for (i=n-
1; ; i--)
{
if (i < n-
1)
{
if (
abs(g) > epsilon(g))
{
for (j=l; j < n; j++)
v[j*n+i] = (a[i*n+j] / a[i*n+l]) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[i*n+k] * v[k*n+j];
for (k=l; k < n; k++)
v[k*n+j] += s * v[k*n+i];
}
}
for (j=l; j < n; j++)
v[i*n+j] = v[j*n+i] = T(
0);
}
v[i*n+i] = T(
1);
g = rv1[i];
l = i;
if (i ==
0)
break;
}
for (i=techsoft::min(m,n)-
1; ; i--)
{
l = i +
1;
g = w[i];
for (j=l; j < n; j++)
a[i*n+j] = T(
0);
if (
abs(g) > epsilon(g))
{
g = T(
1) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = (s / a[i*n+i]) * g;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (j=i; j < m; j++)
a[j*n+i] *= g;
}
else
{
for (j=i; j < m; j++)
a[j*n+i] = T(
0);
}
++a[i*n+i];
if (i ==
0)
break;
}
for (k=n-
1; ; k--)
{
for (its=
1; its <=
30; its++)
{
flag =
1;
for (l=k; ; l--)
{
nm = l-
1;
if (
abs( rv1[l]) < epsilon(rv1[l]))
{
flag =
0;
break;
}
if (
abs( w[nm]) < epsilon(w[nm]))
break;
if (l ==
0)
break;
}
if (flag)
{
c = T(
0);
s = T(
1);
for (i=l; i <= k; i++)
{
f = s * rv1[i];
rv1[i] = c * rv1[i];
if (
abs(f) < epsilon(f))
break;
g = w[i];
h = hypot( f, g);
w[i] = h;
h = T(
1) / h;
c = g * h;
s = -f * h;
for (j=
0; j < m; j++)
{
y = a[j*n+nm];
z = a[j*n+i];
a[j*n+nm] = y * c + z * s;
a[j*n+i] = z * c - y * s;
}
}
}
z = w[k];
if (l == k)
{
if (z < T(
0))
{
w[k] = -z;
for (j=
0; j < n; j++)
v[j*n+k] = -v[j*n+k];
}
break;
}
if (its ==
30)
return false;
x = w[l];
nm = k -
1;
y = w[nm];
g = rv1[nm];
h = rv1[k];
f = ((y-z) * (y+z) + (g-h) * (g+h)) / (T(
2) * h * y);
g = hypot( f, T(
1));
f = ((x-z) * (x+z) + h * ((y / (f+sign( g, f))) - h)) / x;
c = s = T(
1);
for (j=l; j <= nm; j++)
{
i = j +
1;
g = rv1[i];
y = w[i];
h = s * g;
g = c * g;
z = hypot( f, h);
rv1[j] = z;
c = f / z;
s = h / z;
f = x * c + g * s;
g = g*c - x*s;
h = y * s;
y *= c;
for (jj=
0; jj < n; jj++)
{
x = v[jj*n+j];
z = v[jj*n+i];
v[jj*n+j] = x * c + z * s;
v[jj*n+i] = z * c - x * s;
}
z = hypot( f, h);
w[j] = z;
if (
abs(z) > epsilon(z))
{
z =
1.0 / z;
c = f * z;
s = h * z;
}
f = c * g + s * y;
x = c * y - s * g;
for (jj=
0; jj < m; jj++)
{
y = a[jj*n+j];
z = a[jj*n+i];
a[jj*n+j] = y * c + z * s;
a[jj*n+i] = z * c - y * s;
}
}
rv1[l] =
0.0;
rv1[k] = f;
w[k] = x;
}
if (k ==
0)
break;
}
return true;
}
template <
class T>
void
matrix<T>::svbksb (
const matrix<T>& vc,
const valarray<T>& w,
const valarray<T>& b, valarray<T>& s)
const
{
size_t i,j,k;
const T *pm;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
valarray<T> tmp(n);
pm = &mPtr->val[
0];
for (j=
0; j < n; j++)
{
T ta(
0);
if (
abs(w[j]) > epsilon(w[j]))
{
for (i=
0; i < m; i++)
ta += pm[i*n+j] * b[i];
ta /= w[j];
}
tmp[j] = ta;
}
pm = &vc.mPtr->val[
0];
for (j=
0; j < n; j++)
{
T ta(
0);
for (k=
0; k < n; k++)
ta += pm[j*n+k] * tmp[k];
s[j] = ta;
}
}
template <
class T> T
matrix<T>::norm1 ()
const
{
T nr(
0);
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t j=
0; j < n; j++)
{
T s(
0);
for (size_t i=
0; i < m; i++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return nr;
}
template <
class T> T
matrix<T>::norm2 ()
const
{
matrix<T> m(*
this);
matrix<T> v(mPtr->ncol,mPtr->ncol);
valarray<T> w(mPtr->ncol);
if (m.svd( v, w))
return w.max();
return T(
0);
}
template <
class T> T
matrix<T>::normI ()
const
{
T nr(
0);
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t i=
0; i < m; i++)
{
T s(
0);
for (size_t j=
0; j < n; j++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return nr;
}
template <
class T> T
matrix<T>::normF ()
const
{
T nr(
0);
size_t n = size();
const T *pm = &mPtr->val[
0];
for (size_t i=
0; i < n; i++)
nr += pm[i] * pm[i];
nr =
sqrt( nr);
return nr;
}
template <
class T> T
matrix<T>::cond ()
const
{
matrix<T> m(*
this);
matrix<T> v(mPtr->ncol,mPtr->ncol);
valarray<T> w(mPtr->ncol);
if (m.svd( v, w))
return w.max()/w.min();
return T(
0);
}
template <
class T> size_t
matrix<T>::rank ()
const
{
matrix<T> m(*
this);
matrix<T> v(mPtr->ncol,mPtr->ncol);
valarray<T> w(mPtr->ncol);
if (!m.svd( v, w))
return 0;
size_t r =
0;
for (size_t i=
0; i < mPtr->ncol; i++)
if (
abs(w[i]) > epsilon( w[i]))
++r;
return r;
}
template <
class T> T
matrix<T>::det ()
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::det: Determinant of a non-square matrix!");
#endif
T d;
matrix<T> m(*
this);
valarray<size_t> ri( mPtr->nrow);
if (!m.lud( ri, &d))
d = T(
0);
return d;
}
template <
class T> T
matrix<T>::cofact (size_t row, size_t col)
const
{
size_t i,i1,j,j1;
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::Cofact(): Cofactor of a non-square matrix!");
if (row >= mPtr->nrow || col >= mPtr->ncol)
throw out_of_range(
"matrix<T>::Cofact(): Index out of range!");
#endif
size_t n = mPtr->nrow;
matrix<T> tm (n-
1,n-
1);
const T *pm = &mPtr->val[
0];
T *ptm = &tm.mPtr->val[
0];
for (i=
0,i1=
0; i < n; i++)
{
if (i == row)
continue;
for (j=
0,j1=
0; j < n; j++)
{
if (j == col)
continue;
ptm[i1*(n-
1)+j1] = pm[i*n+j];
j1++;
}
i1++;
}
T cof = tm.det();
if ((row+col)%
2 ==
1)
cof = -cof;
return cof;
}
template <
class T> matrix<T>
matrix<T>::adj ()
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::adj(): Adjoin of a non-square matrix!");
#endif
size_t n = mPtr->nrow;
matrix<T> tm(n,n);
T *pm = &tm.mPtr->val[
0];
for (size_t i=
0; i < n; i++)
for (size_t j=
0; j < n; j++)
pm[j*n+i] = cofact(i,j);
return tm;
}
template <
class T>
bool matrix<T>::inv ()
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::inv(): Inversion of non-square matrix!");
#endif
if (shared())
clone();
size_t n = mPtr->nrow;
T *pv = &mPtr->val[
0];
size_t i,j,k,ipos,kpos;
valarray<size_t> ri(n);
for (i=
0; i < n; i++)
ri[i] = i;
for (k=
0; k < n; k++)
{
double ta,tb;
T a(
0);
kpos = k * n;
i = k;
ta =
abs( pv[kpos+k]);
for (j=k+
1; j < n; j++)
if ((tb =
abs(pv[j*n+k])) > ta)
{
ta = tb;
i = j;
}
if (ta < epsilon( a))
return false;
if (i != k)
{
swap( ri[k], ri[i]);
for (ipos=i*n,j=
0; j < n; j++)
swap( pv[kpos+j], pv[ipos+j]);
}
a = T(
1) / pv[kpos+k];
pv[kpos+k] = T(
1);
for (j=
0; j < n; j++)
pv[kpos+j] *= a;
for (i=
0; i < n; i++)
{
if (i != k)
{
ipos = i * n;
a = pv[ipos+k];
pv[ipos+k] = T(
0);
for (j=
0; j < n; j++)
pv[ipos+j] -= a * pv[kpos+j];
}
}
}
for (j=
0; j < n; j++)
{
if (j != ri[j])
{
k = j+
1;
while (j != ri[k])
k++;
for (i=
0; i < n; i++)
swap( pv[i*n+j], pv[i*n+k]);
swap( ri[j], ri[k]);
}
}
return true;
}
template <
class T>
bool matrix<T>::inv_lu ()
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::inv_lu(): Inversion of non-square matrix!");
#endif
size_t n = mPtr->nrow;
size_t i,j,k;
valarray<size_t> ri(n);
valarray<T> v(n), s(n);
if (!lud( ri))
return false;
matrix<T> tm(n,n);
T *pv = &tm.mPtr->val[
0];
for (j=
0; j < n; j++)
{
for (i=
0; i < n; i++)
v[i] = T(
0);
v[j] = T(
1);
lubksb( ri, v, s);
for (k=
0,i=
0; i < n; i++,k+=n)
pv[k+j] = s[i];
}
*
this = tm;
return true;
}
template <
class T>
bool matrix<T>::inv_qr ()
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::inv_qr(): Inversion of non-square matrix!");
#endif
size_t n = mPtr->nrow;
size_t i,j,k;
valarray<T> v(n), s(n);
matrix<T> tm(n,n), r(n,n);
qrd( r);
T *pv = &tm.mPtr->val[
0];
for (j=
0; j < n; j++)
{
for (i=
0; i < n; i++)
v[i] = T(
0);
v[j] = T(
1);
qrbksb( r, v, s);
for (k=
0,i=
0; i < n; i++,k+=n)
pv[k+j] = s[i];
}
*
this = tm;
return true;
}
template <
class T>
bool matrix<T>::inv_sv ()
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
throw invalid_argument(
"matrix<T>::inv2(): Inversion of non-square matrix!");
#endif
size_t n = mPtr->ncol;
size_t i,j,k;
valarray<T> w(n), v(n), s(n);
matrix<T> vc(n,n);
if (!svd( vc, w))
return false;
matrix<T> tm(n,n);
T *pv = &tm.mPtr->val[
0];
for (j=
0; j < n; j++)
{
for (i=
0; i < n; i++)
v[i] = T(
0);
v[j] = T(
1);
svbksb( vc, w, v, s);
for (k=
0,i=
0; i < n; i++,k+=n)
pv[k+j] = s[i];
}
*
this = tm;
return true;
}
template <
class T>
inline bool
matrix<T>::isSingular ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
return (
abs( det()) < epsilon(T(
0)));
}
template <
class T>
bool
matrix<T>::isDiagonal ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t i=
0; i < n; i++)
for (size_t j=
0; j < n; j++)
if (i != j &&
abs( pm[i*n+j]) > epsilon( pm[i]))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isScalar ()
const
{
if (!isDiagonal())
return false;
T v = mPtr->val[
0];
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t i=
1; i < n; i++)
if (
abs( pm[i*n+i] - v) > epsilon( v))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isUnit ()
const throw()
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t k=
0; k < n; k++)
if (
abs( pm[k*n+k] - T(
1)) > epsilon( T(
1)))
return false;
for (size_t j=
1; j < n; j++)
for (size_t i=
0; i < j; i++)
if (
abs( pm[i*n+j]) > epsilon( T(
1)) ||
abs( pm[j*n+i]) > epsilon( T(
1)))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isNull ()
const throw()
{
size_t n = size();
const T *pm = &mPtr->val[
0];
for (size_t i=
0; i < n; i++)
if (
abs( pm[i]) > epsilon( pm[i]))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isSymmetric ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t j=
1; j < n; j++)
for (size_t i=
0; i < j; i++)
if (
abs( pm[i*n+j] - pm[j*n+i]) > epsilon( pm[
0]))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isSkewSymmetric ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t j=
1; j < n; j++)
for (size_t i=
0; i < j; i++)
if (
abs( pm[i*n+j] + pm[j*n+i]) > epsilon( pm[
0]))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isUpperTriangular ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t i=
1; i < n; i++)
for (size_t j=
0; j < i-
1; j++)
if (
abs( pm[i*n+j]) > epsilon( pm[
0]))
return false;
return true;
}
template <
class T>
bool
matrix<T>::isLowerTriangular ()
const
{
if (mPtr->nrow != mPtr->ncol)
return false;
size_t n = mPtr->nrow;
const T *pm = &mPtr->val[
0];
for (size_t j=
1; j < n; j++)
for (size_t i=
0; i < j-
1; i++)
if (
abs( pm[i*n+j]) > epsilon( pm[
0]))
return false;
return true;
}
template <
class T>
inline bool
matrix<T>::isRowOrthogonal ()
const
{
matrix<T> tm = *
this * ~(*
this);
return tm.isUnit();
}
template <
class T>
inline bool
matrix<T>::isColOrthogonal ()
const
{
matrix<T> tm = ~(*
this) * (*
this);
return tm.isUnit();
}
template <
class T> matrix<T>
matrix<T>::apply (T (*fn)(T))
const
{
matrix<T> a( mPtr->nrow, mPtr->ncol);
size_t n = a.size();
const T *pm = &mPtr->val[
0];
T *pa = &a.mPtr->val[
0];
for (size_t i=
0; i < n; i++)
pa[i] = fn( pm[i]);
return a;
}
template <
class T> matrix<T>
matrix<T>::apply (T (*fn)(size_t,size_t,T))
const
{
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
matrix<T> a( m, n);
const T *pm = &mPtr->val[
0];
T *pa = &a.mPtr->val[
0];
size_t i,j,im,jn;
for (i=
0,im=
0; i < m; im+=n,i++)
for (j=
0,jn=im; j < n; jn++,j++)
pa[jn] = fn( i, j, pm[jn]);
return a;
}
template <
class T> matrix<T>
matrix<T>::apply (T (*fn)(size_t,size_t,
const T&))
const
{
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
matrix<T> a( m, n);
const T *pm = &mPtr->val[
0];
T *pa = &a.mPtr->val[
0];
size_t i,j,im,jn;
for (i=
0,im=
0; i < m; im+=n,i++)
for (j=
0,jn=im; j < n; jn++,j++)
pa[jn] = fn( i, j, pm[jn]);
return a;
}
template <
class T>
inline matrix<T>
matrix<T>::apply (T (*fn)(
const T&))
const
{
matrix<T> a( mPtr->nrow, mPtr->ncol);
size_t n = a.size();
const T *pm = &mPtr->val[
0];
T *pa = &a.mPtr->val[
0];
for (size_t i=
0; i < n; i++)
pa[i] = fn( pm[i]);
return a;
}
template <
class T>
bool
matrix<T>::eigen (valarray<T>& eival)
const
{
#ifdef RANGE_CHECK_
if (!isSymmetric())
return false;
#endif
if (eival.size() != mPtr->nrow)
eival.resize( mPtr->nrow);
matrix<T> a(*
this);
valarray<T> e(mPtr->nrow);
a.tred2( eival, e,
false);
return a.tql2( eival, e,
false);
}
template <
class T>
bool
matrix<T>::eigen (valarray<T>& eival, matrix<T>& eivec)
const
{
#ifdef RANGE_CHECK_
if (!isSymmetric())
return false;
#endif
valarray<T> e(mPtr->nrow);
if (eival.size() != mPtr->nrow)
eival.resize( mPtr->nrow);
eivec = *
this;
eivec.tred2( eival, e,
true);
return eivec.tql2( eival, e,
true);
}
template <
class T>
bool
matrix<T>::eigen (valarray<T>& rev, valarray<T>& iev)
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
return false;
#endif
if (rev.size() != mPtr->nrow)
rev.resize( mPtr->nrow);
if (iev.size() != mPtr->nrow)
iev.resize( mPtr->nrow);
matrix<T> eivec, m(*
this);
m.balanc( eivec,
false);
return m.hqr2( rev, iev, eivec,
false);
}
template <
class T>
bool
matrix<T>::eigen (valarray<T>& rev, valarray<T>& iev, matrix<T>& eivec)
const
{
#ifdef RANGE_CHECK_
if (mPtr->nrow != mPtr->ncol)
return false;
#endif
if (rev.size() != mPtr->nrow)
rev.resize( mPtr->nrow);
if (iev.size() != mPtr->nrow)
iev.resize( mPtr->nrow);
if (eivec.rowno() != mPtr->nrow || eivec.colno() != mPtr->nrow)
eivec.resize( mPtr->nrow, mPtr->nrow);
matrix<T> m(*
this);
m.balanc( eivec,
true);
return m.hqr2( rev, iev, eivec,
true);
}
template <
class T>
inline
void cdiv (
const T& xr,
const T& xi,
const T& yr,
const T& yi, T& cdivr, T& cdivi)
{
T r,d;
if (
abs( yr) >
abs( yi))
{
r = yi/yr;
d = yr + r*yi;
cdivr = (xr + r*xi)/d;
cdivi = (xi - r*xr)/d;
}
else
{
r = yr/yi;
d = yi + r*yr;
cdivr = (r*xr + xi)/d;
cdivi = (r*xi - xr)/d;
}
}
template <
class T>
bool
matrix<T>::hqr2 (valarray<T>& d, valarray<T>& e, matrix<T>& v,
bool eivec)
{
int i,j,k,l;
int nn =
int(mPtr->ncol);
int n = nn-
1;
int low =
0;
int high = nn-
1;
T exshift(
0);
T p(
0),q(
0),r(
0),s(
0),z(
0),t,w,x,y;
T cdivr, cdivi;
if (shared())
clone();
T *pv, *pm = &mPtr->val[
0];
if (eivec)
pv = &v(
0,
0);
T norm(
0);
for (i=
0; i < nn; i++)
{
if (i < low || i > high)
{
d[i] = pm[i*nn+i];
e[i] = T(
0);
}
for (j = techsoft::max(i-
1,
0); j < nn; j++)
norm +=
abs( pm[i*nn+j]);
}
size_t iter =
0;
while (n >= low)
{
l = n;
while (l > low)
{
s =
abs( pm[(l-
1)*nn+l-
1]) +
abs( pm[l*nn+l]);
if (s < epsilon(s))
s = norm;
if (
abs( pm[l*nn+l-
1]) < epsilon(pm[l*nn+l-
1]) * s)
break;
l--;
}
if (l == n)
{
pm[n*nn+n] += exshift;
d[n] = pm[n*nn+n];
e[n] = T(
0);
n--;
iter =
0;
}
else if (l == n-
1)
{
w = pm[n*nn+n-
1] * pm[(n-
1)*nn+n];
p = (pm[(n-
1)*nn+n-
1] - pm[n*nn+n]) / T(
2);
q = p * p + w;
z =
sqrt(
abs( q));
pm[n*nn+n] += exshift;
pm[(n-
1)*nn+n-
1] += exshift;
x = pm[n*nn+n];
if (q >= T(
0))
{
if (p >= T(
0))
z = p + z;
else
z = p - z;
d[n-
1] = x + z;
d[n] = d[n-
1];
if (z != T(
0))
d[n] = x - w / z;
e[n-
1] = T(
0);
e[n] = T(
0);
x = pm[n*nn+n-
1];
s =
abs( x) +
abs( z);
p = x / s;
q = z / s;
r =
sqrt( p*p + q*q);
p = p / r;
q = q / r;
for (j = n-
1; j < nn; j++)
{
z = pm[(n-
1)*nn+j];
pm[(n-
1)*nn+j] = q * z + p * pm[n*nn+j];
pm[n*nn+j] = q * pm[n*nn+j] - p * z;
}
for (i =
0; i <= n; i++)
{
z = pm[i*nn+n-
1];
pm[i*nn+n-
1] = q * z + p * pm[i*nn+n];
pm[i*nn+n] = q * pm[i*nn+n] - p * z;
}
if (eivec)
for (i = low; i <= high; i++)
{
z = pv[i*nn+n-
1];
pv[i*nn+n-
1] = q * z + p * pv[i*nn+n];
pv[i*nn+n] = q * pv[i*nn+n] - p * z;
}
}
else
{
d[n-
1] = x + p;
d[n] = x + p;
e[n-
1] = z;
e[n] = -z;
}
n = n -
2;
iter =
0;
}
else
{
x = pm[n*nn+n];
y = T(
0);
w = T(
0);
if (l < n)
{
y = pm[(n-
1)*nn+n-
1];
w = pm[n*nn+n-
1] * pm[(n-
1)*nn+n];
}
if (iter ==
10)
{
exshift += x;
for (i = low; i <= n; i++)
pm[i*nn+i] -= x;
s =
abs( pm[n*nn+n-
1]) +
abs( pm[(n-
1)*nn+n-
2]);
x = y =
0.75 * s;
w = -
0.4375 * s * s;
}
if (iter ==
30)
{
s = (y - x) / T(
2);
s = s * s + w;
if (s > T(
0))
{
s =
sqrt( s);
if (y < x)
s = -s;
s = x - w / ((y - x) / T(
2) + s);
for (i = low; i <= n; i++)
pm[i*nn+i] -= s;
exshift += s;
x = y = w =
0.964;
}
}
if (++iter >
250)
return false;
int m = n-
2;
while (m >= l)
{
z = pm[m*nn+m];
r = x - z;
s = y - z;
p = (r * s - w) / pm[(m+
1)*nn+m] + pm[m*nn+m+
1];
q = pm[(m+
1)*nn+m+
1] - z - r - s;
r = pm[(m+
2)*nn+m+
1];
s =
abs( p) +
abs( q) +
abs( r);
p = p / s;
q = q / s;
r = r / s;
if (m == l)
break;
if (
abs( pm[m*nn+m-
1]) * (
abs( q) +
abs( r)) <
epsilon(r) * (
abs( p) * (
abs( pm[(m-
1)*nn+m-
1]) +
abs( z) +
abs( pm[(m+
1)*nn+m+
1])))) {
break;
}
m--;
}
for (i = m+
2; i <= n; i++)
{
pm[i*nn+i-
2] = T(
0);
if (i > m+
2)
pm[i*nn+i-
3] = T(
0);
}
for (k = m; k <= n-
1; k++)
{
bool notlast = (k != n-
1);
if (k != m)
{
p = pm[k*nn+k-
1];
q = pm[(k+
1)*nn+k-
1];
r = notlast ? pm[(k+
2)*nn+k-
1] : T(
0);
x =
abs( p) +
abs( q) +
abs( r);
if (x > epsilon(x))
{
p = p / x;
q = q / x;
r = r / x;
}
}
if (x < epsilon(x))
break;
s =
sqrt( p * p + q * q + r * r);
if (p < T(
0))
s = -s;
if (s != T(
0))
{
if (k != m)
pm[k*nn+k-
1] = -s * x;
else if (l != m)
pm[k*nn+k-
1] = -pm[k*nn+k-
1];
p = p + s;
x = p / s;
y = q / s;
z = r / s;
q = q / p;
r = r / p;
for (j = k; j < nn; j++)
{
p = pm[k*nn+j] + q * pm[(k+
1)*nn+j];
if (notlast)
{
p = p + r * pm[(k+
2)*nn+j];
pm[(k+
2)*nn+j] = pm[(k+
2)*nn+j] - p * z;
}
pm[k*nn+j] = pm[k*nn+j] - p * x;
pm[(k+
1)*nn+j] = pm[(k+
1)*nn+j] - p * y;
}
for (i =
0; i <= techsoft::min( n, k+
3); i++)
{
p = x * pm[i*nn+k] + y * pm[i*nn+k+
1];
if (notlast)
{
p = p + z * pm[i*nn+k+
2];
pm[i*nn+k+
2] = pm[i*nn+k+
2] - p * r;
}
pm[i*nn+k] = pm[i*nn+k] - p;
pm[i*nn+k+
1] = pm[i*nn+k+
1] - p * q;
}
if (eivec)
for (i = low; i <= high; i++)
{
p = x * pv[i*nn+k] + y * pv[i*nn+k+
1];
if (notlast)
{
p += z * pv[i*nn+k+
2];
pv[i*nn+k+
2] -= p * r;
}
pv[i*nn+k] -= p;
pv[i*nn+k+
1] -= p * q;
}
}
}
}
}
if (norm < epsilon(norm))
return true;
for (n = nn-
1; n >=
0; n--)
{
p = d[n];
q = e[n];
if (q == T(
0))
{
int l = n;
pm[n*nn+n] = T(
1);
for (i = n-
1; i >=
0; i--)
{
w = pm[i*nn+i] - p;
r = T(
0);
for (j = l; j <= n; j++)
r += pm[i*nn+j] * pm[j*nn+n];
if (e[i] < T(
0))
{
z = w;
s = r;
}
else
{
l = i;
if (e[i] == T(
0))
{
if (w != T(
0))
pm[i*nn+n] = -r / w;
else
pm[i*nn+n] = -r / (epsilon(norm) * norm);
}
else
{
x = pm[i*nn+i+
1];
y = pm[(i+
1)*nn+i];
q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
t = (x * s - z * r) / q;
pm[i*nn+n] = t;
if (
abs( x) >
abs( z))
pm[(i+
1)*nn+n] = (-r - w * t) / x;
else
pm[(i+
1)*nn+n] = (-s - y * t) / z;
}
t =
abs( pm[i*nn+n]);
if ((epsilon(t) * t) * t > T(
1))
for (j = i; j <= n; j++)
pm[j*nn+n] /= t;
}
}
}
else if (q < T(
0))
{
int l = n-
1;
if (
abs( pm[n*nn+n-
1]) >
abs( pm[(n-
1)*nn+n]))
{
pm[(n-
1)*nn+n-
1] = q / pm[n*nn+n-
1];
pm[(n-
1)*nn+n] = -(pm[n*nn+n] - p) / pm[n*nn+n-
1];
}
else
{
cdiv(
0.0, -pm[(n-
1)*nn+n], pm[(n-
1)*nn+n-
1]-p, q, cdivr, cdivi);
pm[(n-
1)*nn+n-
1] = cdivr;
pm[(n-
1)*nn+n] = cdivi;
}
pm[n*nn+n-
1] = T(
0);
pm[n*nn+n] = T(
1);
for (i = n-
2; i >=
0; i--)
{
T ra(
0),sa(
0),vr,vi;
for (j = l; j <= n; j++)
{
ra += pm[i*nn+j] * pm[j*nn+n-
1];
sa += pm[i*nn+j] * pm[j*nn+n];
}
w = pm[i*nn+i] - p;
if (e[i] < T(
0))
{
z = w;
r = ra;
s = sa;
}
else
{
l = i;
if (e[i] == T(
0))
{
cdiv( -ra, -sa, w, q, pm[i*nn+n-
1], pm[i*nn+n]);
}
else
{
x = pm[i*nn+i+
1];
y = pm[(i+
1)*nn+i];
vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
vi = (d[i] - p) *
2.0 * q;
if (vr == T(
0) && vi == T(
0))
vr = epsilon(norm) * norm * (
abs( w) +
abs(q) +
abs(x) +
abs(y) +
abs(z));
cdiv( x*r - z*ra + q*sa, x*s - z*sa - q*ra, vr, vi, cdivr, cdivi);
pm[i*nn+n-
1] = cdivr;
pm[i*nn+n] = cdivi;
if (
abs(x) > (
abs(z) +
abs(q)))
{
pm[(i+
1)*nn+n-
1] = (-ra - w * pm[i*nn+n-
1] + q * pm[i*nn+n]) / x;
pm[(i+
1)*nn+n] = (-sa - w * pm[i*nn+n] - q * pm[i*nn+n-
1]) / x;
}
else
{
cdiv( -r - y * pm[i*nn+n-
1], -s - y * pm[i*nn+n], z, q, cdivr, cdivi);
pm[(i+
1)*nn+n-
1] = cdivr;
pm[(i+
1)*nn+n] = cdivi;
}
}
t = techsoft::max(
abs( pm[i*nn+n-
1]),
abs( pm[i*nn+n]));
if ((epsilon(t) * t) * t > T(
1))
for (j = i; j <= n; j++)
{
pm[j*nn+n-
1] /= t;
pm[j*nn+n] /= t;
}
}
}
}
}
if (eivec)
{
for (i =
0; i < nn; i++)
if (i < low || i > high)
for (j = i; j < nn; j++)
pv[i*nn+j] = pm[i*nn+j];
for (j = nn-
1; j >= low; j--)
for (i = low; i <= high; i++)
{
z = T(
0);
for (k = low; k <= techsoft::min( j, high); k++)
z += pv[i*nn+k] * pm[k*nn+j];
pv[i*nn+j] = z;
}
}
return true;
}
template <
class T>
void
matrix<T>::balanc (matrix<T>& v,
bool eivec)
{
size_t i,j,lo,hi,m,n;
if (shared())
clone();
n = mPtr->ncol;
lo =
0;
hi = n-
1;
valarray<T> ort(n);
T *pv, *pm = &mPtr->val[
0];
if (eivec)
pv = &v(
0,
0);
for (m=lo+
1; m <= hi-
1; m++)
{
T scale(
0);
for (i=m; i <= hi; i++)
scale +=
abs( pm[i*n+m-
1]);
if (scale > epsilon(scale))
{
T h(
0);
for (i=hi; i >= m; i--)
{
ort[i] = pm[i*n+m-
1] / scale;
h += ort[i] * ort[i];
}
T g =
sqrt( h);
if (ort[m] > T(
0))
g = -g;
h -= ort[m] * g;
ort[m] -= g;
for (j=m; j < n; j++)
{
T f(
0);
for (i = hi; i >= m; i--)
f += ort[i] * pm[i*n+j];
f /= h;
for (i=m; i <= hi; i++)
pm[i*n+j] -= f * ort[i];
}
for (i=
0; i <= hi; i++)
{
T f(
0);
for (j=hi; j >= m; j--)
f += ort[j] * pm[i*n+j];
f /= h;
for (j=m; j <= hi; j++)
pm[i*n+j] -= f * ort[j];
}
ort[m] = scale * ort[m];
pm[m*n+m-
1] = scale * g;
}
}
if (eivec)
for (i=
0; i < n; i++)
for (j =
0; j < n; j++)
pv[i*n+j] = (i == j ? T(
1) : T(
0));
for (m=hi-
1; m >= lo+
1; m--)
{
if (
abs(pm[m*n+m-
1]) > T(
0))
{
for (i=m+
1; i <= hi; i++)
ort[i] = pm[i*n+m-
1];
if (eivec)
for (j=m; j <= hi; j++)
{
T g(
0);
for (i=m; i <= hi; i++)
g += ort[i] * pv[i*n+j];
g = (g / ort[m]) / pm[m*n+m-
1];
for (i=m; i <= hi; i++)
pv[i*n+j] += g * ort[i];
}
}
}
}
template <
class T>
bool
matrix<T>::tql2 (valarray<T>& d, valarray<T>& e,
bool eivec)
{
size_t m,l,iter,i,k;
T s,r,p,g,f,c,b;
size_t n = mPtr->nrow;
T *pm = &mPtr->val[
0];
for (i=
1; i < n; i++)
e[i-
1] = e[i];
e[n-
1] = T(
0);
for (l=
0; l < n; l++)
{
iter=
0;
do
{
for (m=l; m < n-
1; m++)
{
T dd =
abs( d[m]) +
abs( d[m+
1]);
if (
abs( e[m]) <= epsilon(e[m])*dd)
break;
}
if (m != l)
{
if (iter++ ==
30)
return false;
g = (d[l+
1] - d[l]) / (T(
2) * e[l]);
r = hypot( g, T(
1));
g = d[m] - d[l] + e[l] / (g + sign( r, g));
s = c = T(
1);
p = T(
0);
for (i=m-
1; ; i--)
{
f = s * e[i];
b = c * e[i];
r = hypot( f, g);
e[i+
1] = r;
if (r < epsilon(r))
{
d[i+
1] -= p;
e[m] = T(
0);
break;
}
s = f / r;
c = g / r;
g = d[i+
1] - p;
r = (d[i] - g) * s + T(
2) * c * b;
p = s * r;
d[i+
1] = g + p;
g = c * r - b;
if (eivec)
for (k=
0; k < n; k++)
{
f = pm[k*n+i+
1];
pm[k*n+i+
1] = s * pm[k*n+i] + c * f;
pm[k*n+i] = c * pm[k*n+i] - s * f;
}
if (i == l)
break;
}
if (
abs(r) < epsilon(r) && i >= l)
continue;
d[l] -= p;
e[l] = g;
e[m] = T(
0);
}
}
while (m != l);
if (
abs(d[l]) < epsilon(d[l]))
d[l] = T(
0);
}
return true;
}
template <
class T>
void
matrix<T>::tred2 (valarray<T>& d, valarray<T>& e,
bool eivec)
{
size_t i,j,k;
size_t n = mPtr->nrow;
#ifdef RANGE_CHECK_
if (n != mPtr->ncol)
throw std::invalid_argument(
"matrix<T>::tred2: non-square matrix!");
#endif
if (shared())
clone();
T *pm = &mPtr->val[
0];
for (i=n-
1; i >
0; i--)
{
T h(
0), scale(
0);
if (i >
1)
{
for (k=
0; k < i; k++)
scale +=
abs( pm[i*n+k]);
if (scale < epsilon(scale))
e[i] = pm[i*n+i-
1];
else
{
for (k=
0; k < i; k++)
{
pm[i*n+k] /= scale;
T tmp = pm[i*n+k];
h += tmp * tmp;
}
T f = pm[i*n+i-
1];
T g =
sqrt( h);
if (f >= T(
0))
g = -g;
e[i] = scale * g;
h -= f * g;
pm[i*n+i-
1] = f - g;
f = T(
0);
for (j=
0; j < i; j++)
{
if (eivec)
pm[j*n+i] = pm[i*n+j] / h;
g = T(
0);
for (k=
0; k <= j; k++)
g += pm[j*n+k] * pm[i*n+k];
for (k=j+
1; k < i; k++)
g += pm[k*n+j] * pm[i*n+k];
e[j] = g / h;
f += e[j] * pm[i*n+j];
}
T hh = f / (h+h);
for (j=
0; j < i; j++)
{
f = pm[i*n+j];
g = e[j] - hh * f;
e[j] = g;
for (k=
0; k <= j; k++)
pm[j*n+k] -= (f * e[k] + g * pm[i*n+k]);
}
}
}
else
e[i] = pm[i*n+i-
1];
d[i] = h;
}
if (eivec)
d[
0] = T(
0);
e[
0] = T(
0);
for (i=
0; i < n; i++)
{
if (eivec)
{
if (d[i] != T(
0))
{
for (j=
0; j < i; j++)
{
T g(
0);
for (k=
0; k < i; k++)
g += pm[i*n+k] * pm[k*n+j];
for (k=
0; k < i; k++)
pm[k*n+j] -= g * pm[k*n+i];
}
}
d[i] = pm[i*n+i];
pm[i*n+i] = T(
1);
for (j=
0; j < i; j++)
pm[j*n+i] = pm[i*n+j] = T(
0);
}
else
d[i] = pm[i*n+i];
}
}
#ifndef MATRIX_ROW_SEP
#define MATRIX_ROW_SEP ('\n')
#endif
#ifndef MATRIX_COL_SEP
#define MATRIX_COL_SEP ('\t')
#endif
template <
class T>
inline istream&
operator>> (istream& is, Mref<T> el)
{
T x; is >> x; el = x;
return is;
}
template <
class T>
inline ostream&
operator<< (ostream& os,
const Mref<T>& el)
{
const T x = el;
os << x;
return os;
}
template <
class T> ostream&
operator<< (ostream& os,
const Mat_iter<T>& v)
{
int w = os.width();
for (size_t i=
0; i < v.size(); i++)
os << setw( w) << v[i] << MATRIX_COL_SEP;
return os;
}
template <
class T> istream&
operator>> (istream& is, Mat_iter<T> v)
{
for (size_t i=
0; i < v.size(); i++)
is >> v[i];
return is;
}
template <
class T> ostream&
operator<< (ostream& os,
const Cmat_iter<T>& v)
{
int w = os.width();
for (size_t i=
0; i < v.size(); i++)
os << setw( w) << v[i] << MATRIX_COL_SEP;
return os;
}
template <
class T> istream&
operator>> (istream& is, matrix<T>& m)
{
T *pm = &m(
0,
0);
size_t n = m.size();
for (size_t i=
0; i < n; i++)
is >> pm[i];
return is;
}
template <
class T> ostream&
operator<< (ostream &os,
const matrix<T>& m)
{
int w = os.width();
for (size_t i=
0; i < m.rowno(); i++)
for (size_t j=
0; j < m.colno(); j++)
os << setw( w) << m(i,j) << (j == m.colno()-
1 ? MATRIX_ROW_SEP : MATRIX_COL_SEP);
return os;
}
template <
class T> istream&
operator>> (istream& is, valarray<T>& v)
{
for (size_t i=
0; i < v.size(); i++)
is >> v[i];
return is;
}
template <
class T> ostream&
operator<< (ostream& os,
const valarray<T>& v)
{
int w = os.width();
for (size_t i=
0; i < v.size(); i++)
os << setw( w) << v[i] << MATRIX_COL_SEP;
return os;
}
template <>
inline
void matrix<
complex<
float> >::rand (
int rmin,
int rmax,
int rseed)
{
typedef value_type T;
typedef float VT;
if (!rmin && !rmax)
{
rmin = -
1;
rmax =
1;
}
if (rmin > rmax)
{
int tmp = rmin;
rmin = rmax;
rmax = tmp;
}
int rdiff = rmax - rmin;
if (rseed)
srand( rseed);
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; ++i)
{
VT rd[
2];
for (size_t j=
0; j <
2; ++j)
{
int rn = rand_();
if (rdiff >
1)
{
rn %= rdiff;
rd[j] = VT(rn) - VT(rdiff) / VT(
2);
if (rdiff >
1)
{
VT f = ((VT)rand_()) / VT(RAND_MAX);
if (rn > rdiff)
rd[j] -= f;
else
rd[j] += f;
}
}
else
rd[j] = VT(rn) / VT(RAND_MAX);
}
pv[i] = T( rd[
0], rd[
1]);
}
}
template <>
inline
void matrix<
complex<
double> >::rand (
int rmin,
int rmax,
int rseed)
{
typedef value_type T;
typedef double VT;
value_type y = value_type(
1.0);
if (!rmin && !rmax)
{
rmin = -
1;
rmax =
1;
}
if (rmin > rmax)
{
int tmp = rmin;
rmin = rmax;
rmax = tmp;
}
int rdiff = rmax - rmin;
if (rseed)
srand( rseed);
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; ++i)
{
VT rd[
2];
for (size_t j=
0; j <
2; ++j)
{
int rn = rand_();
if (rdiff >
1)
{
rn %= rdiff;
rd[j] = VT(rn) - VT(rdiff) / VT(
2);
if (rdiff >
1)
{
VT f = ((VT)rand_()) / VT(RAND_MAX);
if (rn > rdiff)
rd[j] -= f;
else
rd[j] += f;
}
}
else
rd[j] = VT(rn) / VT(RAND_MAX);
}
pv[i] = T( rd[
0], rd[
1]);
}
}
template <>
inline
void matrix<
complex<
long double> >::rand (
int rmin,
int rmax,
int rseed)
{
typedef value_type T;
typedef long double VT;
if (!rmin && !rmax)
{
rmin = -
1;
rmax =
1;
}
if (rmin > rmax)
{
int tmp = rmin;
rmin = rmax;
rmax = tmp;
}
int rdiff = rmax - rmin;
if (rseed)
srand( rseed);
if (shared())
{
--mPtr->refcnt;
mPtr = allocator( Allocate, mPtr->nrow, mPtr->ncol);
}
T *pv = &mPtr->val[
0];
size_t n = size();
for (size_t i=
0; i < n; ++i)
{
VT rd[
2];
for (size_t j=
0; j <
2; ++j)
{
int rn = rand_();
if (rdiff >
1)
{
rn %= rdiff;
rd[j] = VT(rn) - VT(rdiff) / VT(
2);
if (rdiff >
1)
{
VT f = ((VT)rand_()) / VT(RAND_MAX);
if (rn > rdiff)
rd[j] -= f;
else
rd[j] += f;
}
}
else
rd[j] = VT(rn) / VT(RAND_MAX);
}
pv[i] = T( rd[
0], rd[
1]);
}
}
template <>
inline
complex<
float> sign (
complex<
float> a,
complex<
float> b)
{
if (
abs( a-b) < epsilon( a))
return a;
return (b.real() <
0.0f || b.imag() <
0.0f)? -a : a;
}
template <>
inline
complex<
double> sign (
complex<
double> a,
complex<
double> b)
{
if (
abs( a-b) < epsilon( a))
return a;
return (b.real() <
double(
0) || b.imag() <
double(
0))? -a : a;
}
template <>
inline
complex<
long double> sign (
complex<
long double> a,
complex<
long double> b)
{
if (
abs( a-b) < epsilon( a))
return a;
return (b.real() <
0.0 || b.imag() <
0.0)? -a : a;
}
template <>
inline
bool matrix<
complex<
float> >::svd (matrix<
complex<
float> >& vc, valarray<
complex<
float> >& w)
{
typedef value_type T;
typedef float VT;
size_t flag,i,its,j,jj,k,l,nm;
T c,f,g(
0),h,s,x,y,z,tmp;
if (shared())
clone();
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
if (vc.rowno() != n || vc.colno() != n)
vc.resize( n, n);
if (w.size() != n)
w.resize( n);
T *a = &mPtr->val[
0];
T *v = &vc(
0,
0);
valarray<T> rv1(n);
VT scale(
0), anorm(
0);
for (i=
0; i < n; i++)
{
l = i +
1;
rv1[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m)
{
for (k=i; k < m; k++)
scale +=
abs( a[k*n+i]);
if (scale > epsilon( scale))
{
for (k=i; k < m; k++)
{
a[k*n+i] /= scale;
tmp = a[k*n+i];
s += tmp * tmp;
}
f = a[i*n+i];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+i] = f - g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=i; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = s / h;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (k=i; k < m; k++)
a[k*n+i] *= scale;
}
}
w[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m && i != n-
1)
{
for (k=l; k < n; k++)
scale +=
abs(a[i*n+k]);
if (scale > epsilon(scale))
{
for (k=l; k < n; k++)
{
a[i*n+k] /= scale;
tmp = a[i*n+k];
s += tmp * tmp;
}
f = a[i*n+l];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+l] = f - g;
for (k=l; k < n; k++)
rv1[k] = a[i*n+k] / h;
for (j=l; j < m; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[j*n+k] * a[i*n+k];
for (k=l; k < n; k++)
a[j*n+k] += s * rv1[k];
}
for (k=l; k < n; k++)
a[i*n+k] *= scale;
}
}
anorm = techsoft::max( anorm,
abs( w[i]) +
abs( rv1[i]) );
}
for (i=n-
1; ; i--)
{
if (i < n-
1)
{
if (
abs(g) > epsilon(g))
{
for (j=l; j < n; j++)
v[j*n+i] = (a[i*n+j] / a[i*n+l]) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[i*n+k] * v[k*n+j];
for (k=l; k < n; k++)
v[k*n+j] += s * v[k*n+i];
}
}
for (j=l; j < n; j++)
v[i*n+j] = v[j*n+i] = T(
0);
}
v[i*n+i] = T(
1);
g = rv1[i];
l = i;
if (i ==
0)
break;
}
for (i=techsoft::min(m,n)-
1; ; i--)
{
l = i +
1;
g = w[i];
for (j=l; j < n; j++)
a[i*n+j] = T(
0);
if (
abs(g) > epsilon(g))
{
g = T(
1) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = (s / a[i*n+i]) * g;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (j=i; j < m; j++)
a[j*n+i] *= g;
}
else
{
for (j=i; j < m; j++)
a[j*n+i] = T(
0);
}
a[i*n+i] = a[i*n+i] + T(
1);
if (i ==
0)
break;
}
for (k=n-
1; ; k--)
{
for (its=
1; its <=
30; its++)
{
flag =
1;
for (l=k; ; l--)
{
nm = l-
1;
if (
abs( rv1[l]) < epsilon(rv1[l]))
{
flag =
0;
break;
}
if (
abs( w[nm]) < epsilon(w[nm]))
break;
if (l ==
0)
break;
}
if (flag)
{
c = T(
0);
s = T(
1);
for (i=l; i <= k; i++)
{
f = s * rv1[i];
rv1[i] = c * rv1[i];
if (
abs(f) < epsilon(f))
break;
g = w[i];
h =
sqrt( f * f + g * g);
w[i] = h;
h = VT(
1) / h;
c = g * h;
s = -f * h;
for (j=
0; j < m; j++)
{
y = a[j*n+nm];
z = a[j*n+i];
a[j*n+nm] = y * c + z * s;
a[j*n+i] = z * c - y * s;
}
}
}
z = w[k];
if (l == k)
{
if (z.real() < VT(
0))
{
w[k] = -z;
for (j=
0; j < n; j++)
v[j*n+k] = -v[j*n+k];
}
break;
}
if (its ==
30)
return false;
x = w[l];
nm = k -
1;
y = w[nm];
g = rv1[nm];
h = rv1[k];
f = ((y-z) * (y+z) + (g-h) * (g+h)) / (VT(
2) * h * y);
g =
sqrt( f * f + T(
1) * T(
1));
f = ((x-z) * (x+z) + h * ((y / (f+sign( g, f))) - h)) / x;
c = s = T(
1);
for (j=l; j <= nm; j++)
{
i = j +
1;
g = rv1[i];
y = w[i];
h = s * g;
g = c * g;
z =
sqrt( f * f + h * h);
rv1[j] = z;
c = f / z;
s = h / z;
f = x * c + g * s;
g = g*c - x*s;
h = y * s;
y *= c;
for (jj=
0; jj < n; jj++)
{
x = v[jj*n+j];
z = v[jj*n+i];
v[jj*n+j] = x * c + z * s;
v[jj*n+i] = z * c - x * s;
}
z =
sqrt( f * f + h * h);
w[j] = z;
if (
abs(z) > epsilon(z))
{
z = VT(
1) / z;
c = f * z;
s = h * z;
}
f = c * g + s * y;
x = c * y - s * g;
for (jj=
0; jj < m; jj++)
{
y = a[jj*n+j];
z = a[jj*n+i];
a[jj*n+j] = y * c + z * s;
a[jj*n+i] = z * c - y * s;
}
}
rv1[l] =
0.0;
rv1[k] = f;
w[k] = x;
}
if (k ==
0)
break;
}
return true;
}
template <>
inline
bool matrix<
complex<
double> >::svd (matrix<
complex<
double> >& vc, valarray<
complex<
double> >& w)
{
typedef value_type T;
typedef double VT;
size_t flag,i,its,j,jj,k,l,nm;
T c,f,g(
0),h,s,x,y,z,tmp;
if (shared())
clone();
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
if (vc.rowno() != n || vc.colno() != n)
vc.resize( n, n);
if (w.size() != n)
w.resize( n);
T *a = &mPtr->val[
0];
T *v = &vc(
0,
0);
valarray<T> rv1(n);
VT scale(
0), anorm(
0);
for (i=
0; i < n; i++)
{
l = i +
1;
rv1[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m)
{
for (k=i; k < m; k++)
scale +=
abs( a[k*n+i]);
if (scale > epsilon( scale))
{
for (k=i; k < m; k++)
{
a[k*n+i] /= scale;
tmp = a[k*n+i];
s += tmp * tmp;
}
f = a[i*n+i];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+i] = f - g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=i; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = s / h;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (k=i; k < m; k++)
a[k*n+i] *= scale;
}
}
w[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m && i != n-
1)
{
for (k=l; k < n; k++)
scale +=
abs(a[i*n+k]);
if (scale > epsilon(scale))
{
for (k=l; k < n; k++)
{
a[i*n+k] /= scale;
tmp = a[i*n+k];
s += tmp * tmp;
}
f = a[i*n+l];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+l] = f - g;
for (k=l; k < n; k++)
rv1[k] = a[i*n+k] / h;
for (j=l; j < m; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[j*n+k] * a[i*n+k];
for (k=l; k < n; k++)
a[j*n+k] += s * rv1[k];
}
for (k=l; k < n; k++)
a[i*n+k] *= scale;
}
}
anorm = techsoft::max( anorm,
abs( w[i]) +
abs( rv1[i]) );
}
for (i=n-
1; ; i--)
{
if (i < n-
1)
{
if (
abs(g) > epsilon(g))
{
for (j=l; j < n; j++)
v[j*n+i] = (a[i*n+j] / a[i*n+l]) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[i*n+k] * v[k*n+j];
for (k=l; k < n; k++)
v[k*n+j] += s * v[k*n+i];
}
}
for (j=l; j < n; j++)
v[i*n+j] = v[j*n+i] = T(
0);
}
v[i*n+i] = T(
1);
g = rv1[i];
l = i;
if (i ==
0)
break;
}
for (i=techsoft::min(m,n)-
1; ; i--)
{
l = i +
1;
g = w[i];
for (j=l; j < n; j++)
a[i*n+j] = T(
0);
if (
abs(g) > epsilon(g))
{
g = T(
1) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = (s / a[i*n+i]) * g;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (j=i; j < m; j++)
a[j*n+i] *= g;
}
else
{
for (j=i; j < m; j++)
a[j*n+i] = T(
0);
}
a[i*n+i] = a[i*n+i] + T(
1);
if (i ==
0)
break;
}
for (k=n-
1; ; k--)
{
for (its=
1; its <=
30; its++)
{
flag =
1;
for (l=k; ; l--)
{
nm = l-
1;
if (
abs( rv1[l]) < epsilon(rv1[l]))
{
flag =
0;
break;
}
if (
abs( w[nm]) < epsilon(w[nm]))
break;
if (l ==
0)
break;
}
if (flag)
{
c = T(
0);
s = T(
1);
for (i=l; i <= k; i++)
{
f = s * rv1[i];
rv1[i] = c * rv1[i];
if (
abs(f) < epsilon(f))
break;
g = w[i];
h =
sqrt( f * f + g * g);
w[i] = h;
h = VT(
1) / h;
c = g * h;
s = -f * h;
for (j=
0; j < m; j++)
{
y = a[j*n+nm];
z = a[j*n+i];
a[j*n+nm] = y * c + z * s;
a[j*n+i] = z * c - y * s;
}
}
}
z = w[k];
if (l == k)
{
if (z.real() < VT(
0))
{
w[k] = -z;
for (j=
0; j < n; j++)
v[j*n+k] = -v[j*n+k];
}
break;
}
if (its ==
30)
return false;
x = w[l];
nm = k -
1;
y = w[nm];
g = rv1[nm];
h = rv1[k];
f = ((y-z) * (y+z) + (g-h) * (g+h)) / (VT(
2) * h * y);
g =
sqrt( f * f + T(
1) * T(
1));
f = ((x-z) * (x+z) + h * ((y / (f+sign( g, f))) - h)) / x;
c = s = T(
1);
for (j=l; j <= nm; j++)
{
i = j +
1;
g = rv1[i];
y = w[i];
h = s * g;
g = c * g;
z =
sqrt( f * f + h * h);
rv1[j] = z;
c = f / z;
s = h / z;
f = x * c + g * s;
g = g*c - x*s;
h = y * s;
y *= c;
for (jj=
0; jj < n; jj++)
{
x = v[jj*n+j];
z = v[jj*n+i];
v[jj*n+j] = x * c + z * s;
v[jj*n+i] = z * c - x * s;
}
z =
sqrt( f * f + h * h);
w[j] = z;
if (
abs(z) > epsilon(z))
{
z = VT(
1) / z;
c = f * z;
s = h * z;
}
f = c * g + s * y;
x = c * y - s * g;
for (jj=
0; jj < m; jj++)
{
y = a[jj*n+j];
z = a[jj*n+i];
a[jj*n+j] = y * c + z * s;
a[jj*n+i] = z * c - y * s;
}
}
rv1[l] =
0.0;
rv1[k] = f;
w[k] = x;
}
if (k ==
0)
break;
}
return true;
}
template <>
inline
bool matrix<
complex<
long double> >::svd (matrix<
complex<
long double> >& vc, valarray<
complex<
long double> >& w)
{
typedef value_type T;
typedef long double VT;
size_t flag,i,its,j,jj,k,l,nm;
T c,f,g(
0),h,s,x,y,z,tmp;
if (shared())
clone();
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
if (vc.rowno() != n || vc.colno() != n)
vc.resize( n, n);
if (w.size() != n)
w.resize( n);
T *a = &mPtr->val[
0];
T *v = &vc(
0,
0);
valarray<T> rv1(n);
VT scale(
0), anorm(
0);
for (i=
0; i < n; i++)
{
l = i +
1;
rv1[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m)
{
for (k=i; k < m; k++)
scale +=
abs( a[k*n+i]);
if (scale > epsilon( scale))
{
for (k=i; k < m; k++)
{
a[k*n+i] /= scale;
tmp = a[k*n+i];
s += tmp * tmp;
}
f = a[i*n+i];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+i] = f - g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=i; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = s / h;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (k=i; k < m; k++)
a[k*n+i] *= scale;
}
}
w[i] = scale * g;
scale = VT(
0);
s = T(
0);
g = T(
0);
if (i < m && i != n-
1)
{
for (k=l; k < n; k++)
scale +=
abs(a[i*n+k]);
if (scale > epsilon(scale))
{
for (k=l; k < n; k++)
{
a[i*n+k] /= scale;
tmp = a[i*n+k];
s += tmp * tmp;
}
f = a[i*n+l];
g = -sign(
sqrt(s), f);
h = f * g - s;
a[i*n+l] = f - g;
for (k=l; k < n; k++)
rv1[k] = a[i*n+k] / h;
for (j=l; j < m; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[j*n+k] * a[i*n+k];
for (k=l; k < n; k++)
a[j*n+k] += s * rv1[k];
}
for (k=l; k < n; k++)
a[i*n+k] *= scale;
}
}
anorm = techsoft::max( anorm,
abs( w[i]) +
abs( rv1[i]) );
}
for (i=n-
1; ; i--)
{
if (i < n-
1)
{
if (
abs(g) > epsilon(g))
{
for (j=l; j < n; j++)
v[j*n+i] = (a[i*n+j] / a[i*n+l]) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < n; k++)
s += a[i*n+k] * v[k*n+j];
for (k=l; k < n; k++)
v[k*n+j] += s * v[k*n+i];
}
}
for (j=l; j < n; j++)
v[i*n+j] = v[j*n+i] = T(
0);
}
v[i*n+i] = T(
1);
g = rv1[i];
l = i;
if (i ==
0)
break;
}
for (i=techsoft::min(m,n)-
1; ; i--)
{
l = i +
1;
g = w[i];
for (j=l; j < n; j++)
a[i*n+j] = T(
0);
if (
abs(g) > epsilon(g))
{
g = T(
1) / g;
for (j=l; j < n; j++)
{
for (s=T(
0),k=l; k < m; k++)
s += a[k*n+i] * a[k*n+j];
f = (s / a[i*n+i]) * g;
for (k=i; k < m; k++)
a[k*n+j] += f * a[k*n+i];
}
for (j=i; j < m; j++)
a[j*n+i] *= g;
}
else
{
for (j=i; j < m; j++)
a[j*n+i] = T(
0);
}
a[i*n+i] = a[i*n+i] + T(
1);
if (i ==
0)
break;
}
for (k=n-
1; ; k--)
{
for (its=
1; its <=
30; its++)
{
flag =
1;
for (l=k; ; l--)
{
nm = l-
1;
if (
abs( rv1[l]) < epsilon(rv1[l]))
{
flag =
0;
break;
}
if (
abs( w[nm]) < epsilon(w[nm]))
break;
if (l ==
0)
break;
}
if (flag)
{
c = T(
0);
s = T(
1);
for (i=l; i <= k; i++)
{
f = s * rv1[i];
rv1[i] = c * rv1[i];
if (
abs(f) < epsilon(f))
break;
g = w[i];
h =
sqrt( f * f + g * g);
w[i] = h;
h = VT(
1) / h;
c = g * h;
s = -f * h;
for (j=
0; j < m; j++)
{
y = a[j*n+nm];
z = a[j*n+i];
a[j*n+nm] = y * c + z * s;
a[j*n+i] = z * c - y * s;
}
}
}
z = w[k];
if (l == k)
{
if (z.real() < VT(
0))
{
w[k] = -z;
for (j=
0; j < n; j++)
v[j*n+k] = -v[j*n+k];
}
break;
}
if (its ==
30)
return false;
x = w[l];
nm = k -
1;
y = w[nm];
g = rv1[nm];
h = rv1[k];
f = ((y-z) * (y+z) + (g-h) * (g+h)) / (VT(
2) * h * y);
g =
sqrt( f * f + T(
1) * T(
1));
f = ((x-z) * (x+z) + h * ((y / (f+sign( g, f))) - h)) / x;
c = s = T(
1);
for (j=l; j <= nm; j++)
{
i = j +
1;
g = rv1[i];
y = w[i];
h = s * g;
g = c * g;
z =
sqrt( f * f + h * h);
rv1[j] = z;
c = f / z;
s = h / z;
f = x * c + g * s;
g = g*c - x*s;
h = y * s;
y *= c;
for (jj=
0; jj < n; jj++)
{
x = v[jj*n+j];
z = v[jj*n+i];
v[jj*n+j] = x * c + z * s;
v[jj*n+i] = z * c - x * s;
}
z =
sqrt( f * f + h * h);
w[j] = z;
if (
abs(z) > epsilon(z))
{
z = VT(
1) / z;
c = f * z;
s = h * z;
}
f = c * g + s * y;
x = c * y - s * g;
for (jj=
0; jj < m; jj++)
{
y = a[jj*n+j];
z = a[jj*n+i];
a[jj*n+j] = y * c + z * s;
a[jj*n+i] = z * c - y * s;
}
}
rv1[l] =
0.0;
rv1[k] = f;
w[k] = x;
}
if (k ==
0)
break;
}
return true;
}
template <>
inline
complex<
float> matrix<
complex<
float> >::normF ()
const
{
float nr =
0.0f;
size_t n = size();
for (size_t i=
0; i < n; i++)
{
float e =
abs( mPtr->val[i]);
nr += e * e;
}
nr =
sqrt( nr);
return complex<
float>( nr,
0.0f);
}
template <>
inline
complex<
double> matrix<
complex<
double> >::normF ()
const
{
double nr =
0.0;
size_t n = size();
for (size_t i=
0; i < n; i++)
{
double e =
abs( mPtr->val[i]);
nr += e * e;
}
nr =
sqrt( nr);
return complex<
double>( nr,
0.0);
}
template <>
inline
complex<
long double> matrix<
complex<
long double> >::normF ()
const
{
long double nr =
0.0;
size_t n = size();
for (size_t i=
0; i < n; i++)
{
long double e =
abs( mPtr->val[i]);
nr += e * e;
}
nr =
sqrt( nr);
return complex<
long double>( nr,
0.0);
}
template <>
inline
complex<
float> matrix<
complex<
float> >::norm1 ()
const
{
typedef value_type T;
float nr =
0.0;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t j=
0; j < n; j++)
{
float s =
0.0f;
for (size_t i=
0; i < m; i++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return T( nr,
0.0f);
}
template <>
inline
complex<
double> matrix<
complex<
double> >::norm1 ()
const
{
typedef value_type T;
double nr =
0.0;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t j=
0; j < n; j++)
{
double s =
0.0;
for (size_t i=
0; i < m; i++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return T( nr,
0.0);
}
template <>
inline
complex<
long double> matrix<
complex<
long double> >::norm1 ()
const
{
typedef value_type T;
long double nr =
0.0;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t j=
0; j < n; j++)
{
long double s =
0.0;
for (size_t i=
0; i < m; i++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return T( nr,
0.0);
}
template <>
inline
complex<
float> matrix<
complex<
float> >::norm2 ()
const
{
matrix<
complex<
float> > m(*
this);
matrix<
complex<
float> > v(mPtr->ncol,mPtr->ncol);
size_t i, n = mPtr->ncol;
float nr =
0.0f;
valarray<
complex<
float> > w( n);
if (m.svd( v, w))
for (i=
0; i < n; i++)
nr = techsoft::max( nr,
abs( w[i]));
return complex<
float>( nr,
0.0f);
}
template <>
inline
complex<
double> matrix<
complex<
double> >::norm2 ()
const
{
matrix<
complex<
double> > m(*
this);
matrix<
complex<
double> > v(mPtr->ncol,mPtr->ncol);
size_t i, n = mPtr->ncol;
double nr =
0.0;
valarray<
complex<
double> > w( n);
if (m.svd( v, w))
for (i=
0; i < n; i++)
nr = techsoft::max( nr,
abs( w[i]));
return complex<
double>( nr,
0.0);
}
template <>
inline
complex<
long double> matrix<
complex<
long double> >::norm2 ()
const
{
matrix<
complex<
long double> > m(*
this);
matrix<
complex<
long double> > v(mPtr->ncol,mPtr->ncol);
size_t i, n = mPtr->ncol;
long double nr =
0.0;
valarray<
complex<
long double> > w( n);
if (m.svd( v, w))
for (i=
0; i < n; i++)
nr = techsoft::max( nr,
abs( w[i]));
return complex<
long double>( nr,
0.0);
}
template <>
inline
complex<
float> matrix<
complex<
float> >::normI ()
const
{
typedef value_type T;
float nr =
0.0f;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const T *pm = &mPtr->val[
0];
for (size_t i=
0; i < m; i++)
{
float s =
0.0f;
for (size_t j=
0; j < n; j++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return T( nr,
0.0f);
}
template <>
inline
complex<
double> matrix<
complex<
double> >::normI ()
const
{
typedef value_type Ty;
double nr =
0.0;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const Ty *pm = &mPtr->val[
0];
for (size_t i=
0; i < m; i++)
{
double s =
0.0;
for (size_t j=
0; j < n; j++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return Ty( nr,
0.0);
}
template <>
inline
complex<
long double> matrix<
complex<
long double> >::normI ()
const
{
typedef value_type Ty;
long double nr =
0.0;
size_t m = mPtr->nrow;
size_t n = mPtr->ncol;
const Ty *pm = &mPtr->val[
0];
for (size_t i=
0; i < m; i++)
{
long double s =
0.0;
for (size_t j=
0; j < n; j++)
s +=
abs( pm[i*n+j]);
nr = techsoft::max( nr, s);
}
return Ty( nr,
0.0);
}
}
#endif
Test.cpp
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>
#include"matrix.cpp"
#if defined(__BORLANDC__)
#pragma option -w-aus
#endif
using std::
cout;
using std::endl;
using techsoft::epsilon;
using techsoft::isVecEq;
using std::exception;
#ifdef _MSC_VER
using ::rand;
#else
using std::rand;
using std::size_t;
#endif
typedef techsoft::matrix<
float> fMatrix;
typedef std::valarray<
float> fVector;
typedef techsoft::matrix<
double> dMatrix;
typedef std::valarray<
double> dVector;
typedef techsoft::matrix<
long double> ldMatrix;
typedef std::valarray<
long double> ldVector;
typedef std::
complex<
float> fComplex;
typedef techsoft::matrix<fComplex> cfMatrix;
typedef std::valarray<fComplex> cfVector;
typedef std::
complex<
double> dComplex;
typedef techsoft::matrix<dComplex> cdMatrix;
typedef std::valarray<dComplex> cdVector;
typedef std::
complex<
long double> ldComplex;
typedef techsoft::matrix<ldComplex> cldMatrix;
typedef std::valarray<ldComplex> cldVector;
const char *TestFile =
"test.txt";
void test_const ();
void test_submat ();
void test_op ();
void test_util ();
void test_dcomp ();
void test_eigen ();
void test_io ();
template <
class T> T
mfn (size_t i, size_t j,
const T& v)
{
int k =
int(i+j);
return pow( v, k);
}
int main ()
{
#if !defined(_MSC_VER)
using std::remove;
using std::srand;
#endif
try
{
srand(
0x23657876);
test_const();
test_submat();
test_op();
test_util();
test_dcomp();
test_eigen();
test_io();
remove( TestFile);
}
catch (
const exception& e)
{
cout <<
"Error: " << e.what();
}
return 0;
}
void test_const ()
{
try
{
cout <<
"Testing constructors.....";
dMatrix m(
3,
3);
dMatrix m2(
3,
3,
1.0);
m =
1.0;
if (m != m2)
{
cout <<
"failed!\n";
return;
}
float fv[] = {
1.34f,
2.54f,
8.23f,
7.34f, -
2.3f,
2.45f,
-
1.2f,
4.50f,
7.34f };
fMatrix mf(
3,
3, fv);
fMatrix mf2(
3,
3, fv, techsoft::FORTRAN_ARRAY);
fMatrix mf3 = mf;
fVector vf( fv,
9);
fMatrix mf4(
3,
3,vf);
if (mf != ~mf2 || mf != mf3 || mf != mf4)
{
cout <<
"failed!\n";
return;
}
dMatrix ma[
5];
for (size_t i=
0; i <
5; i++)
{
ma[i].resize(
3,
3);
if (!ma[i].isNull())
{
cout <<
"failed!\n";
return;
}
}
cfMatrix cm(
4,
4);
cm.rand();
cfMatrix cm2 = cm;
#ifndef _TS_NO_MEMBER_TEMPLATES
dMatrix md = mf;
cdMatrix mcd = md;
mcd =
1.0;
mcd = cm;
#endif
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
return;
}
cout <<
"Ok\n";
}
void test_submat ()
{
using techsoft::mslice;
using techsoft::gmslice;
using techsoft::mswap;
using techsoft::
abs;
using techsoft::DIAGONAL;
using techsoft::TRIDIAGONAL;
using techsoft::UTRIANG;
using techsoft::LTRIANG;
try
{
cout <<
"Testing subscript/submatrix.....";
dMatrix m(
3,
3);
m.rand();
const dMatrix m2 = m;
double x,y;
size_t i=
0,j=
0;
x = m2[i][j];
m[i][j] = x;
y = m[i][j];
if (
abs(x-y) > epsilon(x))
{
cout <<
"failed!\n";
return;
}
x = m(i,j)++;
y = ++m(i,j);
if (
abs(y-x-
2.0) > epsilon(y))
{
cout <<
"failed!\n";
return;
}
x = m(i,j)--;
y = --m(i,j);
if (
abs(x-y-
2.0) > epsilon(x))
{
cout <<
"failed!\n";
return;
}
x = m[i][j] * m[i+
1][j+
1];
x = m2[i][j] / m2[i+
1][j+
1];
x = m[i][j] + m2[i+
1][j+
1];
x = m2[i][j] - m[i+
1][j+
1];
y = x * m[i][j];
y = m[i][j] * x;
y = x / m[i][j];
y = m[i][j] / x;
y = x + m[i][j];
y = m[i][j] + x;
y = x - m[i][j];
y = m[i][j] - x;
#if defined(_MSC_VER) && _MSC_VER > 1100
x = m[i][j];
m[i][j] += m[i+
1][j+
1];
m[i][j] -= m[i+
1][j+
1];
m[i][j] *= m[i+
1][j+
1];
m[i][j] /= m[i+
1][j+
1];
y = m[i][j];
if (
abs(y-x) > epsilon(y))
{
cout <<
"failed!\n";
return;
}
#endif
x = -m[i][j];
y = +m[i][j];
if (
abs(y+x) > epsilon(x+y))
{
cout <<
"failed!\n";
return;
}
dMatrix a(
6,
6);
a.rand();
const dMatrix b = a;
dMatrix sa = b[mslice(
1,
1,
3,
3)];
a[mslice(
1,
1,
3,
3)] = sa;
if (a != b)
{
cout <<
"failed!\n";
return;
}
a[mslice(
2,
2,
1,
3)] = b[mslice(
2,
2,
1,
3)];
if (a != b)
{
cout <<
"failed!\n";
return;
}
a[mslice(
1,
0,
2,
3)] *=
10.0;
a[mslice(
1,
0,
2,
3)] /=
10.0;
if (a != b)
{
cout <<
"failed!\n";
return;
}
a[mslice(
1,
0,
2,
3)] += b[mslice(
1,
0,
2,
3)];
a[mslice(
1,
0,
2,
3)] -= b[mslice(
1,
0,
2,
3)];
if (a != b)
{
cout <<
"failed!\n";
return;
}
a[mslice(
0,
0,
6,
6)] =
1.0;
dMatrix c(
6,
6,
1.0);
if (a != c)
{
cout <<
"failed!\n";
return;
}
a.resize(
4,
4);
a.rand();
c = a[mslice(
1,
1,
2,
2)];
c = a[gmslice(DIAGONAL)];
c = a[gmslice(TRIDIAGONAL)];
c = a[gmslice(UTRIANG)];
c = a[gmslice(LTRIANG)];
c =
1.0;
c[gmslice(DIAGONAL)] += a;
c[gmslice(TRIDIAGONAL)] -= a;
c[gmslice(UTRIANG)] *=
12.0;
c[gmslice(LTRIANG)] /=
12.0;
dMatrix cm = a[gmslice(UTRIANG)];
const dMatrix ca = a;
cm = ca[gmslice(UTRIANG)];
dMatrix d(
4,
4), d2(
4,
4);
d.rand();
d2.rand();
mswap( d[
0][
0], d[
1][
1]);
mswap( d[
2], d[
3]);
mswap( d(
1), d(
2));
mswap( d[
0][
0], d2[
0][
0]);
mswap( d[
2], d2[
2]);
mswap( d(
1), d2(
1));
mswap( d, d2);
a = b;
dVector v = b[
5];
a[
5] = v;
v = a(
3);
a(
3) = v;
a[
2] += v;
a[
2] -= v;
a[
4] *= v;
a[
4] /= v;
if (a != b)
{
cout <<
"failed!\n";
return;
}
v = b.diag();
a.diag() = v;
dVector v2 = b.diag(-
2);
a.diag(-
2) = v2;
v2 = b.diag(
2);
a.diag(
2) = v2;
if (a != b)
{
cout <<
"failed!\n";
return;
}
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
return;
}
cout <<
"Ok\n";
}
void test_op ()
{
try
{
cout <<
"Testing operators.....";
dMatrix m(
6,
4);
m.rand();
dMatrix m2 = m;
m2 += m;
m2 -= m;
if (m2 != m)
{
cout <<
"failed!\n";
return;
}
double te(
1.234567f);
m2 *= te;
m2 /= te;
if (m2 != m)
{
cout <<
"failed!\n";
return;
}
dMatrix a(
4,
4);
a.rand();
dMatrix b = !a;
a *= b;
if (!a.isUnit())
{
cout <<
"failed!\n";
return;
}
a.rand();
a /= a;
if (!a.isUnit())
{
cout <<
"failed!\n";
return;
}
a.resize(
5,
3);
a.rand();
b = ~a;
dMatrix c = a * b;
b = ~b;
if (a != b)
{
cout <<
"failed!\n";
return;
}
c = a + b;
b = c - a;
if (a != b)
{
cout <<
"failed!\n";
return;
}
a.resize(
4,
4);
a.rand();
b = !a;
c = a * b;
if (!c.isUnit())
{
cout <<
"failed!\n";
return;
}
double x =
2.045f;
c =
1/x * a * x;
if (a != c)
{
cout <<
"failed!\n";
return;
}
c = x * a / x;
if (a != c)
{
cout <<
"failed!\n";
return;
}
c = x / a;
b = x * !a;
if (b != c)
{
cout <<
"failed!\n";
return;
}
dVector v(
4), v2(
4);
v = b[
0];
a.unit();
v2 = v * a;
v = a * v2;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
v2 = v / a;
v = a / v;
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
return;
}
cout <<
"Ok\n";
}
void test_util ()
{
using techsoft::
pow;
using techsoft::
abs;
using techsoft::
floor;
using techsoft::
ceil;
using techsoft::gmslice;
using techsoft::UTRIANG;
using techsoft::LTRIANG;
try
{
cout <<
"Testing utility methods.....";
dMatrix m(
6,
4);
m.rand();
dMatrix m2 = m;
m.unit();
m.resize(
2,
3);
m.unit();
m.resize(
4,
6);
m.unit();
m.
free();
m.resize(
4,
4);
m.rand();
m2 = m * m * m * m * m * m * m;
if (m2 !=
pow( m,
7))
{
cout <<
"failed!\n";
return;
}
m2 = -m;
m2 =
abs( m2);
m2 =
floor( m2);
if (!m2.isNull() || m2.trace() !=
0.0)
{
cout <<
"failed!\n";
return;
}
m2 =
ceil( m);
double val;
size_t rn;
m.rand();
val = m.norm1();
val = m.norm2();
val = m.normI();
val = m.normF();
val = m.cond();
val = m.det();
rn = m.rank();
val = m.cofact(
0,
0);
m2 = m.adj()/m.det();
if (m2 != !m)
{
cout <<
"failed!\n";
return;
}
m2 = m;
m2.inv_lu();
if (m2 != !m)
{
cout <<
"failed!\n";
return;
}
m2 = m;
m2.inv_sv();
if (m2 != !m)
{
cout <<
"failed!\n";
return;
}
m2 = m;
m2.inv_qr();
if (m2 != !m)
{
cout <<
"failed!\n";
return;
}
cdMatrix cm(
4,
4), cm2(
4,
4);
cm.rand();
cm2 = cm;
cm2.inv_sv();
if (cm2 != !cm)
{
cout <<
"failed!\n";
return;
}
bool bt = m.isSingular();
m =
double(
0);
bt = m.isNull();
m.diag() =
1.0;
bt = m.isUnit();
m.diag() =
3.0;
bt = m.isScalar();
m.diag()[
0] =
7.0;
bt = m.isDiagonal();
m.rand();
m2 = m[gmslice(UTRIANG)];
if (!m2.isUpperTriangular())
{
cout <<
"failed!\n";
return;
}
m2 = m[gmslice(LTRIANG)];
if (!m2.isLowerTriangular())
{
cout <<
"failed!\n";
return;
}
dMatrix m3 = ~m2;
m2[gmslice(UTRIANG)] = m3;
if (!m2.isSymmetric())
{
cout <<
"failed!\n";
return;
}
m2[gmslice(UTRIANG)] = -m3;
if (!m2.isSkewSymmetric())
{
cout <<
"failed!\n";
return;
}
#if defined(_MSC_VER) && _MSC_VER > 1100
m2 = m.apply(
log);
m2 = m.apply( mfn);
#endif
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
}
cout <<
"Ok\n";
}
void test_dcomp ()
{
using techsoft::gmslice;
using techsoft::LTRIANG;
try
{
cout <<
"Testing matrix decomposition.....";
size_t i, n =
4;
dMatrix a(n,n);
dVector v(n),s(n),v2(n), w(n);
std::valarray<size_t> indx(n);
a.rand();
dMatrix b = a;
v = a[
0];
v *=
double(
1.2394f);
b.lud( indx);
b.lubksb( indx, v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.lumpove( b, indx, v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
v /=
double(-
1.7913f);
b.lubksb( indx, v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
dMatrix mv(n,
3), ms(n,
3), mv2(n,
3);
mv.rand();
a.solve( mv, ms);
for (i=
0; i <
3; i++)
{
dVector vx = ms(i);
mv2(i) = a * vx;
}
if (mv != mv2)
{
cout <<
"failed!\n";
return;
}
b = a[gmslice(LTRIANG)];
b *= ~b;
a = b;
b.chold();
b.cholbksb( v, s);
v2 = a * s;
if (a != (b * ~b) || !isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.solve_chol( v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.rand();
b = a;
dMatrix c(n,n);
b.qrd( c);
b.qrbksb( c, v, s);
v2 = a * s;
if (!b.isRowOrthogonal() || a != (b * c) || !isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.solve_qr( v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
b = a;
b.svd( c, w);
b.svbksb( c, w, v, s);
v2 = a * s;
dMatrix d(n,n,
0.0);
d.diag() = w;
if (!b.isColOrthogonal() || !c.isRowOrthogonal()
|| a != (b * d * ~c) || !isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.solve_sv( v, s);
v2 = a * s;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
a.resize( n+
2,n);
a.rand();
b = a;
b.qrd( c);
v.resize( n+
2);
for (i=
0; i < n+
2; i++)
v[i] = ((
double)rand())/RAND_MAX;
b.qrbksb( c, v, s);
v2 = a * s;
if (a != b * c)
{
cout <<
"failed!\n";
return;
}
b = a;
b.svd( c, w);
b.svbksb( c, w, v, s);
d.diag() = w;
if (a != (b * d * ~c)
|| !b.isColOrthogonal() || !c.isRowOrthogonal())
{
cout <<
"failed!\n";
return;
}
cdMatrix ca(n,n);
cdVector cv(n),cs(n),cv2(n);
ca.rand();
for (i=
0; i < n; i++)
{
double ta = ((
double)rand())/RAND_MAX;
double tb = ((
double)rand())/RAND_MAX;
dComplex z(ta,tb);
cv[i] = z;
}
cdMatrix cb = ca;
cdMatrix cd = !ca;
cs = cd * cv;
cv2 = ca * cs;
if (!isVecEq( cv, cv2))
{
cout <<
"failed!\n";
return;
}
cb.lud( indx);
cb.lubksb( indx, cv, cs);
cv2 = ca * cs;
if (!isVecEq( cv, cv2))
{
cout <<
"failed!\n";
return;
}
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
}
cout <<
"Ok\n";
}
void test_eigen ()
{
using techsoft::gmslice;
using techsoft::UTRIANG;
using techsoft::LTRIANG;
try
{
cout <<
"Testing eigen value.....";
size_t n =
4;
dMatrix a(n,n), ev(n,n);
dVector d(n), e(n);
bool ret,ret2;
a.rand();
a = a[gmslice(UTRIANG)];
a[gmslice(LTRIANG)] = ~a;
ret = a.eigen( e);
ret2 = a.eigen( d, ev);
if (!ret || !ret2 || !isVecEq( d, e))
{
cout <<
"failed!\n";
return;
}
dMatrix c(n,n,
0.0);
c.diag() = d;
if ((a * ev) != (ev * c))
{
cout <<
"failed!\n";
return;
}
a.rand();
ret = a.eigen( d, e);
ret2 = a.eigen( d, e, ev);
if (!ret || !ret2)
{
cout <<
"failed!\n";
return;
}
for (size_t i=
0; i < n; i++)
{
c(i,i) = d[i];
if (e[i] >
double(
0) && i < n-
1)
c(i,i+
1) = e[i];
else if (e[i] <
double(
0) && i >
0)
c(i,i-
1) = e[i];
}
if ((a * ev) != (ev * c))
{
cout <<
"failed!\n";
return;
}
}
catch (
const exception& e)
{
cout <<
"failed!\nError: " << e.what() << endl;
}
cout <<
"Ok\n";
}
void test_io ()
{
using techsoft::
abs;
#if !defined(_MSC_VER)
using std::FILE;
using std::fopen;
using std::fclose;
using std::fread;
using std::fwrite;
#endif
size_t i,m=
4,n=
3;
dMatrix a(m,n), b(m,n);
dVector v(m), v2(m);
double tmp;
cout <<
"Testing matrix I/O.....";
a.rand();
std::ofstream outFile( TestFile);
if (!outFile)
{
std::
cerr <<
"\nError opefing test file.";
return;
}
outFile.clear();
std::ifstream inFile( TestFile);
if (!inFile)
{
std::
cerr <<
"\nError opefing test file.";
return;
}
inFile.tie( &outFile);
outFile <<
std::scientific <<
std::setprecision(
18);
outFile << a[
0][
0] << endl;
inFile >> b[
0][
0];
tmp = a[
0][
0] - b[
0][
0];
if (
abs( tmp) > epsilon(tmp))
{
cout <<
"failed!\n" << a[
0][
0] << endl << b[
0][
0] ;
return;
}
const dMatrix c = a;
outFile << c(
1,
1) << endl;
inFile >> b(
1,
1);
tmp = c(
1,
1) - b(
1,
1);
if (
abs( tmp) > epsilon( tmp))
{
cout <<
"failed!\n";
return;
}
v = a(
0);
outFile << a(
0) << endl;
inFile >> a(
0);
v2 = a(
0);
a(
0) = v;
if (!isVecEq( v, v2))
{
cout <<
"failed!\n";
return;
}
outFile << a[
1] << endl;
inFile >> b[
1];
for (i=
0; i < n; i++)
{
tmp = a[
1][i] - b[
1][i];
if (
abs( tmp) > epsilon(tmp))
{
cout <<
"failed!\n";
return;
}
}
outFile << c[
1] << endl;
inFile >> b[
1];
for (i=
0; i < n; i++)
{
tmp = c[
1][i] - b[
1][i];
if (
abs( tmp) > epsilon(tmp))
{
cout <<
"failed!\n";
return;
}
}
outFile << a << endl;
inFile >> b;
if (a != b)
{
cout <<
"failed!\n";
return;
}
outFile.close();
inFile.close();
FILE *fp = fopen( TestFile,
"w+b");
if (fp == NULL)
{
std::
cerr <<
"\nError opefing test file.";
return;
}
a.rand();
fwrite( &a[
0][
0], a.size(), a.typesize(), fp);
rewind( fp);
fread( &b[
0][
0], b.size(), b.typesize(), fp);
fclose( fp);
if (a != b)
{
cout <<
"failed!\n";
return;
}
cout <<
"Ok\n";
}
Makefile
matrix : test.cpp
g++ -o
matrix test.cpp
matrix.cpp
clean:
rm -f
matrix