/* Copyright (c) 1997-2006
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/

#ifndef _POLYMAKE_INCIDENCE_AND_SPARSE_MATRIX_H
#define _POLYMAKE_INCIDENCE_AND_SPARSE_MATRIX_H "$Project: polymake $$Id: Incidence_and_SparseMatrix.h,v 1.11 2006/02/01 17:39:15 gawrilow Exp $"

namespace pm {

template <typename IncMatrixRef, typename ElemRef>
class SameElementSparseMatrix
   : public GenericMatrix< SameElementSparseMatrix<IncMatrixRef, ElemRef>,
			   typename object_traits<typename deref<ElemRef>::type>::persistent_type > {
protected:
   alias<IncMatrixRef> matrix;
   alias<ElemRef> apparent_elem;

public:
   typedef typename alias<IncMatrixRef>::arg_type first_arg_type;
   typedef typename alias<ElemRef>::arg_type second_arg_type;

   typedef typename deref<ElemRef>::type value_type;
   typedef const value_type& const_reference;
   typedef const_reference reference;

   SameElementSparseMatrix(first_arg_type matrix_arg, second_arg_type data_arg)
      : matrix(matrix_arg), apparent_elem(data_arg) { }

   typename alias<IncMatrixRef>::const_reference get_matrix() const { return matrix; }
   typename alias<ElemRef>::const_reference get_apparent_element() const { return apparent_elem; }
};

template <typename IncMatrixRef, typename ElemRef>
struct spec_object_traits< SameElementSparseMatrix<IncMatrixRef, ElemRef> >
   : spec_object_traits<is_container> {
   static const bool is_temporary=true, is_always_const=true;
};

template <typename IncMatrixRef, typename ElemRef>
class matrix_random_access_methods< SameElementSparseMatrix<IncMatrixRef, ElemRef> > {
   typedef SameElementSparseMatrix<IncMatrixRef, ElemRef> master;
public:
   const typename deref<ElemRef>::type& operator() (int i, int j) const
   {
      const master& me=static_cast<const master&>(*this);
      if (me.get_matrix()(i,j)) return me.get_apparent_element();
      operations::clear<typename deref<ElemRef>::type> zero;
      return zero();
   }
};

template <typename IncMatrixRef, typename ElemRef>
class Rows< SameElementSparseMatrix<IncMatrixRef, ElemRef> >
   : public modified_container_pair_impl< Rows< SameElementSparseMatrix<IncMatrixRef,ElemRef> >,
               cons< Container1< masquerade<Rows, IncMatrixRef> >,
	       cons< Container2< unlimited_constant_container<typename attrib<ElemRef>::plus_const_ref> >,
               cons< Accessor< operations::construct_binary<SameElementSparseVector> >,
		     Hidden< SameElementSparseMatrix<IncMatrixRef, ElemRef> > > > >
            > {
   typedef modified_container_pair_impl<Rows> _super;
public:
   const typename _super::container1& get_container1() const
   {
      return rows(this->hidden().get_matrix());
   }
   const typename _super::container2& get_container2() const
   {
      return constant(this->hidden().get_apparent_element());
   }
};

template <typename IncMatrixRef, typename ElemRef>
class Cols< SameElementSparseMatrix<IncMatrixRef, ElemRef> >
   : public modified_container_pair_impl< Cols< SameElementSparseMatrix<IncMatrixRef,ElemRef> >,
               cons< Container1< masquerade<Cols, IncMatrixRef> >,
	       cons< Container2< unlimited_constant_container<typename attrib<ElemRef>::plus_const_ref> >,
               cons< Accessor< operations::construct_binary<SameElementSparseVector> >,
                     Hidden< SameElementSparseMatrix<IncMatrixRef, ElemRef> > > > >
            > {
   typedef modified_container_pair_impl<Cols> _super;
public:
   const typename _super::container1& get_container1() const
   {
      return cols(this->hidden().get_matrix());
   }
   const typename _super::container2& get_container2() const
   {
      return constant(this->hidden().get_apparent_element());
   }
};

template <typename E, typename Matrix> inline
const SameElementSparseMatrix<const Matrix&, E>
same_element_sparse_matrix(const GenericIncidenceMatrix<Matrix>& m)
{
   return SameElementSparseMatrix<const Matrix&, E>(m.top(), E(1));
}

template <typename E, typename Matrix> inline
const SameElementSparseMatrix<const Matrix&, const E&>
same_element_sparse_matrix(const GenericIncidenceMatrix<Matrix>& m, const E& x)
{
   return SameElementSparseMatrix<const Matrix&, const E&>(m.top(), x);
}

} // end namespace pm

namespace polymake {
   using pm::same_element_sparse_matrix;
}

#endif // _POLYMAKE_INCIDENCE_AND_SPARSE_MATRIX_H

// Local Variables:
// mode:C++
// End:
