/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: SparseVector.h 9991 2010-12-12 23:36:28Z gawrilow $
*/

#ifndef POLYMAKE_SPARSE_VECTOR_H
#define POLYMAKE_SPARSE_VECTOR_H

#include "polymake/GenericVector.h"
#include "polymake/internal/tree_containers.h"
#include "polymake/internal/sparse.h"
#include "polymake/internal/shared_object.h"
#include "polymake/internal/AVL.h"

namespace pm {

template <typename NodeRef>
class sparse_vector_accessor : public AVL::node_accessor<NodeRef> {
   typedef AVL::node_accessor<NodeRef> _super;
public:
   typedef typename inherit_ref<typename deref<NodeRef>::type::mapped_type, typename _super::argument_type>::type result_type;
   result_type operator() (typename _super::argument_type n) const { return n.key_and_data.second; }
};

template <typename NodeRef>
struct sparse_vector_index_accessor {
   typedef NodeRef argument_type;
   typedef const int result_type;
   result_type operator() (NodeRef n) const { return n.key_and_data.first; }
};

/** \ref vector_sec "Vector type" class which is an associative container with
    element indices (coordinates) as keys; elements equal to the default value
    (@c ElementType(), which is 0 for most numerical types) are not stored,
    but implicitly encoded by the gaps in the key set.  It is based on an AVL
    tree.
*/

template <typename E, typename Predicate>
class SparseVector
   : public modified_tree< SparseVector<E,Predicate>,
                           list( Container< AVL::tree< AVL::traits<int, E, operations::cmp> > >,
                                 Operation< pair< BuildUnary<sparse_vector_accessor>,
                                                  BuildUnary<sparse_vector_index_accessor> > > ) >,
     public GenericVector<SparseVector<E,Predicate>, E> {
   typedef modified_tree<SparseVector> _super;
protected:
   typedef AVL::tree< AVL::traits<int, E, operations::cmp> > tree_type;
   struct impl {
      tree_type tree;
      int d;
      Predicate non_zero;
 
      impl() : d(0) {}
      void clear() { d=0; tree.clear(); }
   };
   shared_object<impl, AliasHandler<shared_alias_handler> > data;

   friend SparseVector& make_mutable_alias(SparseVector& alias, SparseVector& owner)
   {
      alias.data.make_mutable_alias(owner.data);
      return alias;
   }

   typedef sparse_proxy_base<SparseVector> proxy_base;

   template <typename Iterator>
   void init(Iterator src, int dim_arg)
   {
      data.get()->d=dim_arg;
      data.get()->tree.assign(src);
   }

public:
   typedef random_access_iterator_tag container_category;
   typedef sparse_elem_proxy<proxy_base> reference;

   tree_type& get_container() { return data->tree; }
   const tree_type& get_container() const { return data->tree; }

   int dim() const { return data->d; }

   SparseVector() {}

   explicit SparseVector(int dim_arg) { data.get()->d=dim_arg; }

   template <typename Iterator>
   SparseVector(int dim_arg, Iterator src, typename enable_if_iterator<Iterator,end_sensitive>::type=0)
   {
      init(construct_sparse_iterator<Iterator,E>::_do(src, dim_arg), dim_arg);
   }

   /// Copy of a disguised SparseVector object.
   SparseVector(const GenericVector<SparseVector>& v)
      : data(v.top().data) {}

   template <typename Vector2>
   SparseVector(const GenericVector<Vector2,E>& v)
   {
      init(ensure(v.top(), (pure_sparse*)0).begin(), v.dim());
   }

   template <typename Vector2, typename E2>
   explicit SparseVector(const GenericVector<Vector2,E2>& v)
   {
      init(ensure(attach_converter<E>(v.top()), (pure_sparse*)0).begin(), v.dim());
   }

   template <size_t n>
   explicit SparseVector(const E (&a)[n])
   {
      init(ensure(array2container(a), (pure_sparse*)0).begin(), n);
   }

   template <typename E2, size_t n>
   explicit SparseVector(const E2 (&a)[n])
   {
      init(ensure(attach_converter<E>(array2container(a)), (pure_sparse*)0).begin(), n);
   }

   /// truncate to zero size
   void clear() { data.apply(shared_clear()); }

   /// change the size, initialize appended elements with default constructor
   void resize(int n)
   {
      if (n<data->d) {
         typename _super::reverse_iterator i=this->rbegin();
         while (!i.at_end() && i.index()>=n) this->erase(i++);
      }
      data->d=n;
   }

   /// assignment
   SparseVector& operator= (const SparseVector& v) { assign(v); return *this; }

   using SparseVector::generic_type::operator=;

   void swap(SparseVector& v) { data.swap(v.data); }

   friend void relocate(SparseVector* from, SparseVector* to)
   {
      relocate(&from->data, &to->data);
   }

   /// random access, may cost O(log(n)) time; \ref vector_performance
   reference operator[] (int i)
   {
      if (POLYMAKE_DEBUG) {
         if (i<0 || i>=dim())
            throw std::runtime_error("SparseVector::operator[] - index out of range");
      }
      return proxy_base(*this,i);
   }

   /// constant random access, may cost O(log(n)) time; \ref vector_performance
   const E& operator[] (int i) const
   {
      if (POLYMAKE_DEBUG) {
         if (i<0 || i>=dim())
            throw std::runtime_error("SparseVector::operator[] - index out of range");
      }
      operations::clear<E> zero;
      return zero.deref_sparse(this->find(i));
   }

   /// appending a GenericVector
   template <typename Vector2>
   SparseVector& operator|= (const GenericVector<Vector2,E>& v)
   {
      const int d=data->d;
      tree_type& t=data->tree;
      for (typename ensure_features<Vector2,pure_sparse>::const_iterator src=ensure(v.top(), (pure_sparse*)0).begin();  !src.at_end();  ++src)
         t.push_back(src.index()+d, *src);
      data->d += v.dim();
      return *this;
   }

   /// appending an element
   SparseVector& operator|= (const E& r)
   {
      if (data->non_zero(r)) data->tree.push_back(data->d, r);
      data->d++;
      return *this;
   }

#if POLYMAKE_DEBUG
   void check() const { data->tree.check(""); }
   void tree_dump() const { data->tree.dump(); }
#endif

protected:
   template <typename, typename> friend class GenericVector;

   void assign(const SparseVector& v) { data=v.data; }

   template <typename Vector2>
   void assign(const Vector2& v)
   {
      if (data.is_shared()) {
         *this=SparseVector(v);
      } else {
         data.get()->tree.assign(ensure(v, (pure_sparse*)0).begin());
         data.get()->d=v.dim();
      }
   }

   template <typename Operation>
   void assign_op(const Operation& op)
   {
      if (data.is_shared())
         *this=SparseVector(LazyVector1<const SparseVector&, Operation>(*this,op));
      else
         SparseVector::generic_type::assign_op(op);
   }

   template <typename Vector2, typename Operation>
   void assign_op(const Vector2& v, const Operation& op)
   {
      if (data.is_shared())
         *this=SparseVector(LazyVector2<const SparseVector&, const Vector2&, Operation>(*this,v,op));
      else
         SparseVector::generic_type::assign_op(v,op);
   }

   template <typename E2>
   void _fill(const E2& x, pure_sparse)
   {
      data->tree.clear();
      if (data.get()->non_zero(x)) {
         tree_type& t=data.get()->tree;
         const int d=data.get()->d;
         for (int i=0; i<d; ++i) t.push_back(i,x);
      }
   }
};

template <typename E, typename Predicate>
struct check_container_feature<SparseVector<E, Predicate>, pure_sparse> : True {};

template <typename Vector, typename E, typename Permutation> inline
typename enable_if<SparseVector<E>, Vector::is_sparse>::type
permuted(const GenericVector<Vector,E>& v, const Permutation& perm)
{
   if (POLYMAKE_DEBUG || !Unwary<Vector>::value) {
      if (v.dim() != perm.size())
         throw std::runtime_error("permuted - dimension mismatch");
   }
   SparseVector<E> result(v.dim());
   for (typename ensure_features<Permutation, cons<end_sensitive,indexed> >::const_iterator p=ensure(perm, (cons<end_sensitive,indexed>*)0);
        !p.at_end();  ++p) {
      typename Vector::const_iterator e=v.top().find(*p);
      if (!e.at_end()) result.push_back(p.index(), *e);
   }
   return result;
}

template <typename Vector, typename E, typename Permutation> inline
typename enable_if<SparseVector<E>, Vector::is_sparse>::type
permuted_inv(const GenericVector<Vector,E>& v, const Permutation& perm)
{
   if (POLYMAKE_DEBUG || !Unwary<Vector>::value) {
      if (v.dim() != perm.size())
         throw std::runtime_error("permuted_inv - dimension mismatch");
   }
   SparseVector<E> result(v.dim());
   int pos=0;
   typename Permutation::const_iterator p=perm.begin();
   for (typename Entire<Vector>::const_iterator e=entire(v.top());  !e.at_end();  ++e) {
      std::advance(p, e.index()-pos);
      pos=e.index();
      result.insert(*p,*e);
   }
   return result;
}

} // end namespace pm

namespace polymake {
   using pm::SparseVector;
}

namespace std {
   template <typename E, typename Predicate> inline
   void swap(pm::SparseVector<E, Predicate>& v1, pm::SparseVector<E,Predicate>& v2) { v1.swap(v2); }
}

#endif // POLYMAKE_SPARSE_VECTOR_H

// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End:
