// ---------------------------------------------------------------------------- // Description : Matrix handling // ---------------------------------------------------------------------------- // (c) Copyright 2000 by iXiONmedia, all rights reserved. // ---------------------------------------------------------------------------- #include #include #include #include #define EX_DIMEN \ EXGEN_THROW(EC_DIMENSIONMISMATCH) template ixion::matrix::matrix(TSize height,TSize width) { setup(height,width); } template ixion::matrix::matrix(matrix const &src) { setup(src.Height,src.Width); TSize size = getSize(); iterator srcit = src.Data.get(); iterator destit = Data.get(); while (size--) *destit++ = *srcit++; } template ixion::matrix &ixion::matrix::operator=(matrix const &src) { setup(src.Height,src.Width); TSize size = getSize(); const_iterator srcit = src.begin(); iterator destit = begin(); while (size--) *destit++ = *srcit++; return *this; } template ixion::matrix &ixion::matrix::operator+=(matrix const &op2) { if (op2.Width != Width || op2.Height != Height) EX_DIMEN TSize size = getSize(); const_iterator src = op2.begin(); iterator dest = begin(); while (size--) *dest++ += *src++; return *this; } template ixion::matrix &ixion::matrix::operator-=(matrix const &op2) { if (op2.Width != Width || op2.Height != Height) EX_DIMEN TSize size = getSize(); const_iterator src = op2.begin(); iterator dest = begin(); while (size--) *dest++ -= *src++; return *this; } template ixion::matrix &ixion::matrix::operator*=(scalar_type scalar) { TSize size = getSize(); iterator dest = begin(); while (size--) *dest++ *= scalar; return *this; } template ixion::matrix ixion::matrix::operator*(matrix const &op2) const { if (Width != op2.Height) EX_DIMEN matrix target(Height,op2.Width); for (TIndex x = 0;x < op2.Width;x++) for (TIndex y = 0;y < Height;y++) { entry_type value = traits_type::zero; for (TIndex i = 0;i < Width;i++) value += operator()(y,i)*op2(i,x); target(y,x) = value; } return target; } template ixion::matrix ixion::matrix::extract(TIndex row,TIndex col,TSize height,TSize width) const { matrix target(height,width); for (TIndex x = 0;x < width;x++) for (TIndex y = 0;y < height;y++) target(y,x) = operator()(y+row,x+col); return target; } template ixion::matrix &ixion::matrix::set(TIndex row,TIndex col,matrix const &src) { for (TIndex x = 0;x < src.Width;x++) for (TIndex y = 0;y < src.Height;y++) operator()(y+row,x+col) = src(y,x); return *this; } template ixion::matrix &ixion::matrix::add(TIndex row,TIndex col,matrix const &src,entry_type factor) { for (TIndex x = 0;x < src.Width;x++) for (TIndex y = 0;y < src.Height;y++) operator()(y+row,x+col) += src(y,x)*factor; return *this; } template ixion::matrix &ixion::matrix::addRowSelf(TIndex to,TIndex from,entry_type factor,TIndex startcol) { for (TIndex x = startcol;x < Width;x++) operator()(to,x) += operator()(from,x)*factor; return *this; } template ixion::matrix &ixion::matrix::addColumnSelf(TIndex to,TIndex from,entry_type factor,TIndex startrow) { for (TIndex y = startrow;y < Height;y++) operator()(y,to) += operator()(y,from)*factor; return *this; } template ixion::matrix &ixion::matrix::multiplyRowSelf(TIndex row,entry_type factor,TIndex startcol) { for (TIndex x = startcol;x < Width;x++) operator()(row,x) *= factor; return *this; } template ixion::matrix &ixion::matrix::multiplyColumnSelf(TIndex column,entry_type factor,TIndex startrow) { for (TIndex y = startrow;y < Height;y++) operator()(y,column) *= factor; return *this; } template ixion::matrix &ixion::matrix::swapRowSelf(TIndex row1,TIndex row2) { for (TIndex x = 0;x < Width;x++) { entry_type temp = operator()(row1,x); operator()(row1,x) = operator()(row2,x); operator()(row2,x) = temp; } return *this; } template ixion::matrix &ixion::matrix::swapColumnSelf(TIndex col1,TIndex col2) { for (TIndex y = 0;y < Height;y++) { entry_type temp = operator()(y,col1); operator()(y,col1) = operator()(y,col2); operator()(y,col2) = temp; } return *this; } template ixion::matrix::entry_type ixion::matrix::det() const { if (Width != Height) EX_DIMEN try { TSize swaps; matrix temp = getGaussElim(0,&swaps); entry_type factor = 1; if (swaps % 2) factor = -1; return factor*temp.diagonalProduct(); } catch (...) { return 0; } } template ixion::matrix::entry_type ixion::matrix::norm(TMatrixNorm norm) const { entry_type result,sum,entry; switch (norm) { case NORM_TOTAL: // the total norm can only be applied to symmetrical matrices if (Width != Height) EX_DIMEN result = 0; for (TIndex i = 0;i < Height;i++) for (TIndex j = 0;j < Width;j++) result = NUM_MAX(result,traits_type::norm(operator()(i,j))); return Width*result; case NORM_ROW_SUM: result = 0; for (TIndex i = 0;i < Height;i++) { sum = 0; for (TIndex j = 0;j < Width;j++) sum += traits_type::norm(operator()(i,j)); result = NUM_MAX(result,sum); } return result; case NORM_COLUMN_SUM: result = 0; for (TIndex i = 0;i < Height;i++) { sum = 0; for (TIndex j = 0;j < Width;j++) sum += traits_type::norm(operator()(j,i)); result = NUM_MAX(result,sum); } return result; case NORM_SCHUR: result = 0; for (TIndex i = 0;i < Height;i++) for (TIndex j = 0;j < Width;j++) { entry = traits_type::norm(operator()(j,i)); result += entry*entry; } return traits_type::sqrt(result); default: EXGEN_NYI } } template ixion::matrix::entry_type ixion::matrix::trace() const { if (Width != Height) EX_DIMEN entry_type result = 0; for (TIndex i = 0;i ixion::matrix::entry_type ixion::matrix::diagonalProduct() const { if (Width != Height) EX_DIMEN entry_type result = 1; for (TIndex i = 0;i ixion::matrix ixion::matrix::transposed() const { matrix target(Width,Height); for (TIndex x = 0;x ixion::matrix ixion::matrix::inverted() const { if (Width != Height) EX_DIMEN matrix temp(Height,Width*2); temp.set(0,0,*this); for (TIndex x = 0;x ixion::matrix ixion::matrix::gauss(scalar_type pivot_threshold,TSize *swapcount) const { matrix target(*this); if (swapcount) *swapcount = 0; TSize steps = NUM_MIN(Width,Height); for (TIndex step = 0;step < steps;step++) { // column pivot search TIndex pivot = step; scalar_type pmax = traits_type::norm(target(step,step)); for (TIndex row = step+1;row pmax) { pivot = row; pmax = traits_type::norm(target(row,step)); } if (pmax < pivot_threshold) EXGEN_THROW(EC_CANCELLED) if (pivot != step) { target.swapRowSelf(pivot,step); if (swapcount) (*swapcount)++; } entry_type diag = target(step,step); // zero out trailing rows for (TIndex row = step+1;row ixion::matrix ixion::matrix::gaussJordan(scalar_type pivot_threshold,TSize *swapcount) const { matrix target(*this); if (swapcount) *swapcount = 0; TSize steps = NUM_MIN(Width,Height); for (TIndex step = 0;step < steps;step++) { // column pivot search TIndex pivot = step; scalar_type pmax = traits_type::norm(target(step,step)); for (TIndex row = step+1;row pmax) { pivot = row; pmax = traits_type::norm(target(row,step)); } if (pmax < pivot_threshold) EXGEN_THROW(EC_CANCELLED) if (pivot != step) { target.swapRowSelf(pivot,step); if (swapcount) (*swapcount)++; } entry_type diag = target(step,step); // zero out preceding rows for (TIndex row = 0;row ixion::matrix ixion::matrix::linearSolve(matrix const &vec,scalar_type pivot_threshold) const { if (vec.Width != 1 || Height != vec.Height || Width != Height) EX_DIMEN matrix backpack(Height,Width+1); backpack.set(0,0,*this); backpack.set(0,Width,vec); matrix gaussed = backpack.getGaussJordan(pivot_threshold).normalize(); return gaussed.extract(0,0,Height,Width).upperTriangleSolve(gaussed.extract(0,Width,Height,1)); } template ixion::matrix ixion::matrix::cholesky() const { if (Width != Height) EX_DIMEN matrix result(Height,Width); result.wipe(); for (TIndex x = 0;x void ixion::matrix::decomposeLR(matrix &l,matrix &r) const { if (Width != Height) EX_DIMEN l.setDimension(Height,Height); r.setDimension(Height,Width); l.wipe(); r.wipe(); for (TIndex x = 0;x r for (TIndex y = 0;y < x;y++) { sum = traits_type::zero; for (TIndex i = 0;i < y;i++) sum += l(y,i)*r(i,x); // the corresponding l element is 1 anyway r(y,x) = operator()(y,x)-sum; } // elements on diagonal sum = traits_type::zero; for (TIndex i = 0;i l for (TIndex y = x+1;y < Height;y++) { sum = traits_type::zero; for (TIndex i = 0;i < x;i++) sum += l(y,i)*r(i,x); l(y,x) = (operator()(y,x)-sum)/r(x,x); } } } template ixion::matrix &ixion::matrix::normalize() { for (TIndex i = 0;i ixion::matrix ixion::matrix::upperTriangleSolve(matrix const &vec) const { if (vec.Width != 1 || Height != vec.Height || Width != Height) EX_DIMEN matrix result(Width,1); if (Width == 0) return result; bool exit = false; for (TIndex i = Width-1;!exit;i--) { entry_type value = vec(i,0); for (TIndex x = i+1;x ixion::matrix ixion::matrix::lowerTriangleSolve(matrix const &vec) const { if (vec.Width != 1 || Height != vec.Height || Width != Height) EX_DIMEN matrix result(Width,1); if (Width == 0) return result; for (TIndex i = 0;i void ixion::matrix::wipe(entry_type value) { TSize size = getSize(); iterator dest = begin(); while (size--) *dest++ = value; } template void ixion::matrix::setDimension(TSize height,TSize width) { setup(height,width); } template void ixion::matrix::outMatrix(std::ostream &ostr,void (*item_formatter)(std::ostream &os,bool first,bool last)) const { ostr << Height << 'x' << Width << endl; for (TIndex y = 0;y < Height;y++) { for (TIndex x = 0;x < Width;x++) { if (item_formatter) item_formatter(ostr,x == 0,x void ixion::matrix::setup(TSize height,TSize width) { Data.allocate(width*height); Width = width; Height = height; } #undef EX_DIMEN