/* * SymmetricMatrix, ConstSymmetricMatrixView, SymmetricMatrixView template * classes implement fixed size symmetric matrix; "views" mimic the semantic * of C++ references: any operation performed on a "view" is actually performed * on the "viewed object" * * Authors: * Marco Cecchetti * * Copyright 2009 authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. */ #ifndef _NL_SYMMETRIC_MATRIX_FS_H_ #define _NL_SYMMETRIC_MATRIX_FS_H_ #include <2geom/numeric/vector.h> #include <2geom/numeric/matrix.h> #include <2geom/utils.h> #include <2geom/exception.h> #include #include #include // for std::pair #include // for std::swap, std::copy #include #include namespace Geom { namespace NL { namespace detail { template struct index { static const size_t K = index::K; }; template struct index { static const size_t K = (((I+1) * I) >> 1) + J; }; } // end namespace detail template class ConstBaseSymmetricMatrix; template class BaseSymmetricMatrix; template class SymmetricMatrix; template class ConstSymmetricMatrixView; template class SymmetricMatrixView; // declaration needed for friend clause template bool operator== (ConstBaseSymmetricMatrix const& _smatrix1, ConstBaseSymmetricMatrix const& _smatrix2); template class ConstBaseSymmetricMatrix { public: const static size_t DIM = N; const static size_t DATA_SIZE = ((DIM+1) * DIM) / 2; public: ConstBaseSymmetricMatrix (VectorView const& _data) : m_data(_data) { } double operator() (size_t i, size_t j) const { return m_data[get_index(i,j)]; } template double get() const { BOOST_STATIC_ASSERT ((I < N && J < N)); return m_data[detail::index::K]; } size_t rows() const { return DIM; } size_t columns() const { return DIM; } bool is_zero() const { return m_data.is_zero(); } bool is_positive() const { return m_data.is_positive(); } bool is_negative() const { return m_data.is_negative(); } bool is_non_negative() const { return m_data.is_non_negative(); } double min() const { return m_data.min(); } double max() const { return m_data.max(); } std::pair min_index() const { std::pair indices(0,0); double min_value = m_data[0]; for (size_t i = 1; i < DIM; ++i) { for (size_t j = 0; j <= i; ++j) { if (min_value > (*this)(i,j)) { min_value = (*this)(i,j); indices.first = i; indices.second = j; } } } return indices; } std::pair max_index() const { std::pair indices(0,0); double max_value = m_data[0]; for (size_t i = 1; i < DIM; ++i) { for (size_t j = 0; j <= i; ++j) { if (max_value < (*this)(i,j)) { max_value = (*this)(i,j); indices.first = i; indices.second = j; } } } return indices; } size_t min_on_row_index (size_t i) const { size_t idx = 0; double min_value = (*this)(i,0); for (size_t j = 1; j < DIM; ++j) { if (min_value > (*this)(i,j)) { min_value = (*this)(i,j); idx = j; } } return idx; } size_t max_on_row_index (size_t i) const { size_t idx = 0; double max_value = (*this)(i,0); for (size_t j = 1; j < DIM; ++j) { if (max_value < (*this)(i,j)) { max_value = (*this)(i,j); idx = j; } } return idx; } size_t min_on_column_index (size_t j) const { return min_on_row_index(j); } size_t max_on_column_index (size_t j) const { return max_on_row_index(j); } size_t min_on_diag_index () const { size_t idx = 0; double min_value = (*this)(0,0); for (size_t i = 1; i < DIM; ++i) { if (min_value > (*this)(i,i)) { min_value = (*this)(i,i); idx = i; } } return idx; } size_t max_on_diag_index () const { size_t idx = 0; double max_value = (*this)(0,0); for (size_t i = 1; i < DIM; ++i) { if (max_value < (*this)(i,i)) { max_value = (*this)(i,i); idx = i; } } return idx; } std::string str() const; ConstSymmetricMatrixView main_minor_const_view() const; SymmetricMatrix operator- () const; Vector operator* (ConstVectorView _vector) const { assert (_vector.size() == DIM); Vector result(DIM, 0.0); for (size_t i = 0; i < DIM; ++i) { for (size_t j = 0; j < DIM; ++j) { result[i] += (*this)(i,j) * _vector[j]; } } return result; } protected: static size_t get_index (size_t i, size_t j) { if (i < j) return get_index (j, i); size_t k = (i+1) * i; k >>= 1; k += j; return k; } protected: ConstVectorView get_data() const { return m_data; } friend bool operator== (ConstBaseSymmetricMatrix const& _smatrix1, ConstBaseSymmetricMatrix const& _smatrix2); protected: VectorView m_data; }; //end ConstBaseSymmetricMatrix template class BaseSymmetricMatrix : public ConstBaseSymmetricMatrix { public: typedef ConstBaseSymmetricMatrix base_type; public: BaseSymmetricMatrix (VectorView const& _data) : base_type(_data) { } double operator() (size_t i, size_t j) const { return m_data[base_type::get_index(i,j)]; } double& operator() (size_t i, size_t j) { return m_data[base_type::get_index(i,j)]; } template double& get() { BOOST_STATIC_ASSERT ((I < N && J < N)); return m_data[detail::index::K]; } void set_all (double x) { m_data.set_all(x); } SymmetricMatrixView main_minor_view(); BaseSymmetricMatrix& transpose() const { return (*this); } BaseSymmetricMatrix& translate (double c) { m_data.translate(c); return (*this); } BaseSymmetricMatrix& scale (double c) { m_data.scale(c); return (*this); } BaseSymmetricMatrix& operator+= (base_type const& _smatrix) { m_data += (static_cast(_smatrix).m_data); return (*this); } BaseSymmetricMatrix& operator-= (base_type const& _smatrix) { m_data -= (static_cast(_smatrix).m_data); return (*this); } using base_type::DIM; using base_type::DATA_SIZE; using base_type::m_data; using base_type::operator-; using base_type::operator*; }; //end BaseSymmetricMatrix template class SymmetricMatrix : public BaseSymmetricMatrix { public: typedef BaseSymmetricMatrix base_type; typedef typename base_type::base_type base_base_type; using base_type::DIM; using base_type::DATA_SIZE; using base_type::m_data; public: SymmetricMatrix () : base_type (VectorView(m_adata, DATA_SIZE)) { } explicit SymmetricMatrix (ConstVectorView _data) : base_type (VectorView(m_adata, DATA_SIZE)) { assert (_data.size() == DATA_SIZE); m_data = _data; } explicit SymmetricMatrix (const double _data[DATA_SIZE]) : base_type (VectorView(m_adata, DATA_SIZE)) { std::copy (_data, _data + DATA_SIZE, m_adata); } SymmetricMatrix (SymmetricMatrix const& _smatrix) : base_type (VectorView(m_adata, DATA_SIZE)) { m_data = _smatrix.m_data; } explicit SymmetricMatrix (base_base_type const& _smatrix) : base_type (VectorView(m_adata, DATA_SIZE)) { m_data = static_cast &>(_smatrix).m_data; } explicit SymmetricMatrix (ConstMatrixView const& _matrix) : base_type (VectorView(m_adata, DATA_SIZE)) { assert (_matrix.rows() == N && _matrix.columns() == N); for (size_t i = 0; i < N; ++i) for (size_t j = 0; j <= i ; ++j) (*this)(i,j) = _matrix(i,j); } SymmetricMatrix& operator= (SymmetricMatrix const& _smatrix) { m_data = _smatrix.m_data; return (*this); } SymmetricMatrix& operator= (base_base_type const& _smatrix) { m_data = static_cast &>(_smatrix).m_data; return (*this); } SymmetricMatrix& operator= (ConstMatrixView const& _matrix) { assert (_matrix.rows() == N && _matrix.columns() == N); for (size_t i = 0; i < N; ++i) for (size_t j = 0; j <= i ; ++j) (*this)(i,j) = _matrix(i,j); return (*this); } // needed for accessing m_adata friend class ConstSymmetricMatrixView; friend class SymmetricMatrixView; private: double m_adata[DATA_SIZE]; }; //end SymmetricMatrix template class ConstSymmetricMatrixView : public ConstBaseSymmetricMatrix { public: typedef ConstBaseSymmetricMatrix base_type; using base_type::DIM; using base_type::DATA_SIZE; using base_type::m_data; public: explicit ConstSymmetricMatrixView (ConstVectorView _data) : base_type (const_vector_view_cast(_data)) { assert (_data.size() == DATA_SIZE); } explicit ConstSymmetricMatrixView (const double _data[DATA_SIZE]) : base_type (const_vector_view_cast (ConstVectorView (_data, DATA_SIZE))) { } ConstSymmetricMatrixView (const ConstSymmetricMatrixView & _smatrix) : base_type (_smatrix.m_data) { } ConstSymmetricMatrixView (const base_type & _smatrix) : base_type (static_cast(_smatrix).m_data) { } }; //end SymmetricMatrix // declaration needed for friend clause template void swap_view(SymmetricMatrixView & m1, SymmetricMatrixView & m2); template class SymmetricMatrixView : public BaseSymmetricMatrix { public: typedef BaseSymmetricMatrix base_type; typedef typename base_type::base_type base_base_type; using base_type::DIM; using base_type::DATA_SIZE; using base_type::m_data; public: explicit SymmetricMatrixView (VectorView _data) : base_type (_data) { assert (_data.size() == DATA_SIZE); } explicit SymmetricMatrixView (double _data[DATA_SIZE]) : base_type (VectorView (_data, DATA_SIZE)) { } SymmetricMatrixView (const SymmetricMatrixView & _smatrix) : base_type (_smatrix.m_data) { } SymmetricMatrixView (SymmetricMatrix & _smatrix) : base_type (VectorView (_smatrix.m_adata, DATA_SIZE)) { } SymmetricMatrixView& operator= (const SymmetricMatrixView & _smatrix) { m_data = _smatrix.m_data; return (*this); } SymmetricMatrixView& operator= (const base_base_type & _smatrix) { m_data = static_cast &>(_smatrix).m_data; return (*this); } friend void swap_view(SymmetricMatrixView & m1, SymmetricMatrixView & m2); }; //end SymmetricMatrix /* * class ConstBaseSymmetricMatrix methods */ template inline std::string ConstBaseSymmetricMatrix::str() const { std::ostringstream oss; oss << (*this); return oss.str(); } template inline ConstSymmetricMatrixView ConstBaseSymmetricMatrix::main_minor_const_view() const { ConstVectorView data(m_data.get_gsl_vector()->data, DATA_SIZE - DIM); ConstSymmetricMatrixView mm(data); return mm; } template inline SymmetricMatrix ConstBaseSymmetricMatrix::operator- () const { SymmetricMatrix result; for (size_t i = 0; i < DATA_SIZE; ++i) { result.m_data[i] = -m_data[i]; } return result; } /* * class ConstBaseSymmetricMatrix friend free functions */ template inline bool operator== (ConstBaseSymmetricMatrix const& _smatrix1, ConstBaseSymmetricMatrix const& _smatrix2) { return (_smatrix1.m_data == _smatrix2.m_data); } /* * class ConstBaseSymmetricMatrix related free functions */ template< size_t N, class charT > inline std::basic_ostream & operator<< (std::basic_ostream & os, const ConstBaseSymmetricMatrix & _matrix) { os << "[[" << _matrix(0,0); for (size_t j = 1; j < N; ++j) { os << ", " << _matrix(0,j); } os << "]"; for (size_t i = 1; i < N; ++i) { os << "\n [" << _matrix(i,0); for (size_t j = 1; j < N; ++j) { os << ", " << _matrix(i,j); } os << "]"; } os << "]"; return os; } /* * class ConstBaseSymmetricMatrix specialized methods */ template<> inline size_t ConstBaseSymmetricMatrix<2>::get_index (size_t i, size_t j) { return (i+j); } template<> inline size_t ConstBaseSymmetricMatrix<3>::get_index (size_t i, size_t j) { size_t k = i + j; if (i == 2 || j == 2) ++k; return k; } /* * class BaseSymmetricMatrix methods */ template inline SymmetricMatrixView BaseSymmetricMatrix::main_minor_view() { VectorView data(m_data.get_gsl_vector()->data, DATA_SIZE - DIM); SymmetricMatrixView mm(data); return mm; } /* * class SymmetricMatrixView friend free functions */ template inline void swap_view(SymmetricMatrixView & m1, SymmetricMatrixView & m2) { swap_view(m1.m_data, m2.m_data); } } /* end namespace NL*/ } /* end namespace Geom*/ #endif // _NL_SYMMETRIC_MATRIX_FS_H_ /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :