//=======================================================================
// Copyright 2001 University of Notre Dame.
// Copyright 2006 Trustees of Indiana University
// Authors: Jeremy G. Siek and Douglas Gregor <dgregor@cs.indiana.edu>
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef BOOST_ADJACENCY_MATRIX_HPP
#define BOOST_ADJACENCY_MATRIX_HPP

#include <boost/config.hpp>
#include <vector>
#include <memory>
#include <cassert>
#include <boost/limits.hpp>
#include <boost/iterator.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_mutability_traits.hpp>
#include <boost/graph/graph_selectors.hpp>
#include <boost/mpl/if.hpp>
#include <boost/graph/adjacency_iterator.hpp>
#include <boost/graph/detail/edge.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/pending/integer_range.hpp>
#include <boost/graph/properties.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/ice.hpp>

namespace boost {

  namespace detail {

    template <class Directed, class Vertex>
    class matrix_edge_desc_impl : public edge_desc_impl<Directed,Vertex>
    {
      typedef edge_desc_impl<Directed,Vertex> Base;
    public:
      matrix_edge_desc_impl() { }
      matrix_edge_desc_impl(bool exists, Vertex s, Vertex d,
                            const void* ep = 0)
        : Base(s, d, ep), m_exists(exists) { }
      bool exists() const { return m_exists; }
    private:
      bool m_exists;
    };

    struct does_edge_exist {
      template <class Edge>
      bool operator()(const Edge& e) const { return e.exists(); }
    };

    // Note to self... The int for get_edge_exists and set_edge exist helps
    // make these calls unambiguous.
    template <typename EdgeProperty>
    bool get_edge_exists(const std::pair<bool, EdgeProperty>& stored_edge, int) {
      return stored_edge.first;
    }
    template <typename EdgeProperty>
    void set_edge_exists(
        std::pair<bool, EdgeProperty>& stored_edge,
        bool flag,
        int
        ) {
      stored_edge.first = flag;
    }

    template <typename EdgeProxy>
    bool get_edge_exists(const EdgeProxy& edge_proxy, ...) {
      return edge_proxy;
    }
    template <typename EdgeProxy>
    EdgeProxy& set_edge_exists(EdgeProxy& edge_proxy, bool flag, ...) {
      edge_proxy = flag;
      return edge_proxy; // just to avoid never used warning
    }

    template <typename EdgeProperty>
    const EdgeProperty&
    get_property(const std::pair<bool, EdgeProperty>& stored_edge) {
      return stored_edge.second;
    }
    template <typename EdgeProperty>
    EdgeProperty&
    get_property(std::pair<bool, EdgeProperty>& stored_edge) {
      return stored_edge.second;
    }

    template <typename StoredEdgeProperty, typename EdgeProperty>
    inline void
    set_property(std::pair<bool, StoredEdgeProperty>& stored_edge,
                 const EdgeProperty& ep, int) {
      stored_edge.second = ep;
    }

    inline const no_property& get_property(const char&) {
      static no_property s_prop;
      return s_prop;
    }
    inline no_property& get_property(char&) {
      static no_property s_prop;
      return s_prop;
    }
    template <typename EdgeProxy, typename EdgeProperty>
    inline void
    set_property(EdgeProxy, const EdgeProperty&, ...) {}

    //=======================================================================
    // Directed Out Edge Iterator

    template <
        typename VertexDescriptor, typename MatrixIter
      , typename VerticesSizeType, typename EdgeDescriptor
    >
    struct dir_adj_matrix_out_edge_iter
      : iterator_adaptor<
            dir_adj_matrix_out_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        >
    {
        typedef iterator_adaptor<
            dir_adj_matrix_out_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        > super_t;

        dir_adj_matrix_out_edge_iter() { }

        dir_adj_matrix_out_edge_iter(
            const MatrixIter& i
          , const VertexDescriptor& src
          , const VerticesSizeType& n
           )
            : super_t(i), m_src(src), m_targ(0), m_n(n)
        { }

        void increment() {
            ++this->base_reference();
            ++m_targ;
        }

        inline EdgeDescriptor
        dereference() const
        {
            return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ,
                                  &get_property(*this->base()));
        }
        VertexDescriptor m_src, m_targ;
        VerticesSizeType m_n;
    };

    //=======================================================================
    // Directed In Edge Iterator

    template <
        typename VertexDescriptor, typename MatrixIter
      , typename VerticesSizeType, typename EdgeDescriptor
    >
    struct dir_adj_matrix_in_edge_iter
      : iterator_adaptor<
            dir_adj_matrix_in_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        >
    {
        typedef iterator_adaptor<
            dir_adj_matrix_in_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        > super_t;

        dir_adj_matrix_in_edge_iter() { }

        dir_adj_matrix_in_edge_iter(
            const MatrixIter& i
          , const MatrixIter& last
          , const VertexDescriptor& tgt
          , const VerticesSizeType& n
           )
          : super_t(i), m_last(last), m_src(0), m_targ(tgt), m_n(n)
        { }

        void increment() {
          if (VerticesSizeType(m_last - this->base_reference()) >= m_n) {
            this->base_reference() += m_n;
            ++m_src;
          } else {
            this->base_reference() = m_last;
          }
        }

        inline EdgeDescriptor
        dereference() const
        {
            return EdgeDescriptor(get_edge_exists(*this->base(), 0), m_src, m_targ,
                                  &get_property(*this->base()));
        }
        MatrixIter m_last;
        VertexDescriptor m_src, m_targ;
        VerticesSizeType m_n;
    };

    //=======================================================================
    // Undirected Out Edge Iterator

    template <
        typename VertexDescriptor, typename MatrixIter
      , typename VerticesSizeType, typename EdgeDescriptor
    >
    struct undir_adj_matrix_out_edge_iter
      : iterator_adaptor<
            undir_adj_matrix_out_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        >
    {
        typedef iterator_adaptor<
            undir_adj_matrix_out_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        > super_t;

        undir_adj_matrix_out_edge_iter() { }

        undir_adj_matrix_out_edge_iter(
            const MatrixIter& i
          , const VertexDescriptor& src
          , const VerticesSizeType& n
        )
          : super_t(i), m_src(src), m_inc(src), m_targ(0), m_n(n)
        {}

        void increment()
        {
            if (m_targ < m_src)     // first half
            {
                ++this->base_reference();
            }
            else if (m_targ < m_n - 1)
            {                  // second half
                ++m_inc;
                this->base_reference() += m_inc;
            }
            else
            {                  // past-the-end
                this->base_reference() += m_n - m_src;
            }
            ++m_targ;
        }

        inline EdgeDescriptor
        dereference() const
        {
            return EdgeDescriptor(
                get_edge_exists(*this->base(), 0), m_src, m_targ
              , &get_property(*this->base())
            );
        }

        VertexDescriptor m_src, m_inc, m_targ;
        VerticesSizeType m_n;
    };

    //=======================================================================
    // Undirected In Edge Iterator

    template <
        typename VertexDescriptor, typename MatrixIter
      , typename VerticesSizeType, typename EdgeDescriptor
    >
    struct undir_adj_matrix_in_edge_iter
      : iterator_adaptor<
            undir_adj_matrix_in_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        >
    {
        typedef iterator_adaptor<
            undir_adj_matrix_in_edge_iter<VertexDescriptor, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        > super_t;

        undir_adj_matrix_in_edge_iter() { }

        undir_adj_matrix_in_edge_iter(
            const MatrixIter& i
          , const VertexDescriptor& src
          , const VerticesSizeType& n
        )
          : super_t(i), m_src(src), m_inc(src), m_targ(0), m_n(n)
        {}

        void increment()
        {
            if (m_targ < m_src)     // first half
            {
                ++this->base_reference();
            }
            else if (m_targ < m_n - 1)
            {                  // second half
                ++m_inc;
                this->base_reference() += m_inc;
            }
            else
            {                  // past-the-end
                this->base_reference() += m_n - m_src;
            }
            ++m_targ;
        }

        inline EdgeDescriptor
        dereference() const
        {
            return EdgeDescriptor(
                     get_edge_exists(*this->base(), 0), m_targ, m_src
              , &get_property(*this->base())
            );
        }

        VertexDescriptor m_src, m_inc, m_targ;
        VerticesSizeType m_n;
    };

    //=======================================================================
    // Edge Iterator

    template <typename Directed, typename MatrixIter,
              typename VerticesSizeType, typename EdgeDescriptor>
    struct adj_matrix_edge_iter
      : iterator_adaptor<
            adj_matrix_edge_iter<Directed, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        >
    {
        typedef iterator_adaptor<
            adj_matrix_edge_iter<Directed, MatrixIter,  VerticesSizeType, EdgeDescriptor>
          , MatrixIter
          , EdgeDescriptor
          , use_default
          , EdgeDescriptor
          , std::ptrdiff_t
        > super_t;

        adj_matrix_edge_iter() { }

        adj_matrix_edge_iter(const MatrixIter& i, const MatrixIter& start, const VerticesSizeType& n)
            : super_t(i), m_start(start), m_src(0), m_targ(0), m_n(n) { }

        void increment()
        {
            increment_dispatch(this->base_reference(), Directed());
        }

        void increment_dispatch(MatrixIter& i, directedS)
        {
            ++i;
            if (m_targ == m_n - 1)
            {
                m_targ = 0;
                ++m_src;
            }
            else
            {
                ++m_targ;
            }
        }

        void increment_dispatch(MatrixIter& i, undirectedS)
        {
            ++i;
            if (m_targ == m_src)
            {
                m_targ = 0;
                ++m_src;
            }
            else
            {
                ++m_targ;
            }
        }

        inline EdgeDescriptor
        dereference() const
        {
            return EdgeDescriptor(
                get_edge_exists(
                    *this->base(), 0), m_src, m_targ, &get_property(*this->base())
            );
        }

        MatrixIter m_start;
        VerticesSizeType m_src, m_targ, m_n;
    };

  } // namespace detail

  //=========================================================================
  // Adjacency Matrix Traits
  template <typename Directed = directedS>
  class adjacency_matrix_traits {
    typedef typename Directed::is_directed_t is_directed;
  public:
    // The bidirectionalS tag is not allowed with the adjacency_matrix
    // graph type. Instead, use directedS, which also provides the
    // functionality required for a Bidirectional Graph (in_edges,
    // in_degree, etc.).
#if !defined(_MSC_VER) || _MSC_VER > 1300
    BOOST_STATIC_ASSERT(type_traits::ice_not<(is_same<Directed, bidirectionalS>::value)>::value);
#endif

    typedef typename mpl::if_<is_directed,
                                    bidirectional_tag, undirected_tag>::type
      directed_category;

    typedef disallow_parallel_edge_tag edge_parallel_category;

    typedef std::size_t vertex_descriptor;

    typedef detail::matrix_edge_desc_impl<directed_category,
      vertex_descriptor> edge_descriptor;
  };

  struct adjacency_matrix_class_tag { };

  struct adj_matrix_traversal_tag :
    public virtual adjacency_matrix_tag,
    public virtual vertex_list_graph_tag,
    public virtual incidence_graph_tag,
    public virtual adjacency_graph_tag,
    public virtual edge_list_graph_tag { };

  //=========================================================================
  // Adjacency Matrix Class
  template <typename Directed = directedS,
            typename VertexProperty = no_property,
            typename EdgeProperty = no_property,
            typename GraphProperty = no_property,
            typename Allocator = std::allocator<bool> >
  class adjacency_matrix {
    typedef adjacency_matrix self;
    typedef adjacency_matrix_traits<Directed> Traits;

  public:
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
    // The bidirectionalS tag is not allowed with the adjacency_matrix
    // graph type. Instead, use directedS, which also provides the
    // functionality required for a Bidirectional Graph (in_edges,
    // in_degree, etc.).
    BOOST_STATIC_ASSERT(!(is_same<Directed, bidirectionalS>::value));
#endif

#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
    typedef typename detail::retag_property_list<vertex_bundle_t, VertexProperty>::type
      vertex_property_type;
    typedef typename detail::retag_property_list<edge_bundle_t, EdgeProperty>::type
      edge_property_type;

  private:
    typedef typename detail::retag_property_list<vertex_bundle_t, VertexProperty>::retagged
      maybe_vertex_bundled;

    typedef typename detail::retag_property_list<edge_bundle_t, EdgeProperty>::retagged
      maybe_edge_bundled;

  public:
    // The types that are actually bundled
    typedef typename mpl::if_c<(is_same<maybe_vertex_bundled, no_property>::value),
                           no_vertex_bundle,
                           maybe_vertex_bundled>::type vertex_bundled;
    typedef typename mpl::if_c<(is_same<maybe_edge_bundled, no_property>::value),
                           no_edge_bundle,
                           maybe_edge_bundled>::type edge_bundled;
#else
    typedef EdgeProperty     edge_property_type;
    typedef VertexProperty   vertex_property_type;
    typedef no_vertex_bundle vertex_bundled;
    typedef no_edge_bundle   edge_bundled;
#endif
    typedef GraphProperty    graph_property_type;

  public: // should be private
    typedef typename mpl::if_<typename has_property<edge_property_type>::type,
      std::pair<bool, edge_property_type>, char>::type StoredEdge;
#if (defined(BOOST_MSVC) && BOOST_MSVC <= 1300) || defined(BOOST_NO_STD_ALLOCATOR)
    typedef std::vector<StoredEdge> Matrix;
#else
    // This causes internal compiler error for MSVC
    typedef typename Allocator::template rebind<StoredEdge>::other Alloc;
    typedef std::vector<StoredEdge, Alloc> Matrix;
#endif
    typedef typename Matrix::iterator MatrixIter;
    typedef typename Matrix::size_type size_type;
  public:
    // Graph concept required types
    typedef typename Traits::vertex_descriptor vertex_descriptor;
    typedef typename Traits::edge_descriptor edge_descriptor;
    typedef typename Traits::directed_category directed_category;
    typedef typename Traits::edge_parallel_category edge_parallel_category;
    typedef adj_matrix_traversal_tag traversal_category;

    static vertex_descriptor null_vertex()
    {
      return (std::numeric_limits<vertex_descriptor>::max)();
    }

    //private: if friends worked, these would be private

    typedef detail::dir_adj_matrix_out_edge_iter<
        vertex_descriptor, MatrixIter, size_type, edge_descriptor
    > DirOutEdgeIter;

    typedef detail::undir_adj_matrix_out_edge_iter<
        vertex_descriptor, MatrixIter, size_type, edge_descriptor
    > UnDirOutEdgeIter;

    typedef typename mpl::if_<
        typename Directed::is_directed_t, DirOutEdgeIter, UnDirOutEdgeIter
    >::type unfiltered_out_edge_iter;

    typedef detail::dir_adj_matrix_in_edge_iter<
        vertex_descriptor, MatrixIter, size_type, edge_descriptor
    > DirInEdgeIter;

    typedef detail::undir_adj_matrix_in_edge_iter<
        vertex_descriptor, MatrixIter, size_type, edge_descriptor
    > UnDirInEdgeIter;

    typedef typename mpl::if_<
        typename Directed::is_directed_t, DirInEdgeIter, UnDirInEdgeIter
    >::type unfiltered_in_edge_iter;

    typedef detail::adj_matrix_edge_iter<
        Directed, MatrixIter, size_type, edge_descriptor
    > unfiltered_edge_iter;

  public:

    // IncidenceGraph concept required types
    typedef filter_iterator<detail::does_edge_exist, unfiltered_out_edge_iter>
      out_edge_iterator;

    typedef size_type degree_size_type;

    // BidirectionalGraph required types
    typedef filter_iterator<detail::does_edge_exist, unfiltered_in_edge_iter>
      in_edge_iterator;

    // AdjacencyGraph required types
     typedef typename adjacency_iterator_generator<self,
       vertex_descriptor, out_edge_iterator>::type adjacency_iterator;

    // VertexListGraph required types
    typedef size_type vertices_size_type;
    typedef integer_range<vertex_descriptor> VertexList;
    typedef typename VertexList::iterator vertex_iterator;

    // EdgeListGraph required types
    typedef size_type edges_size_type;
    typedef filter_iterator<
        detail::does_edge_exist, unfiltered_edge_iter
    > edge_iterator;

    // PropertyGraph required types
    typedef adjacency_matrix_class_tag graph_tag;

    // Constructor required by MutableGraph
    adjacency_matrix(vertices_size_type n_vertices,
                     const GraphProperty& p = GraphProperty())
      : m_matrix(Directed::is_directed ?
                 (n_vertices * n_vertices)
                 : (n_vertices * (n_vertices + 1) / 2)),
      m_vertex_set(0, n_vertices),
      m_vertex_properties(n_vertices),
      m_num_edges(0),
      m_property(p) { }

    template <typename EdgeIterator>
    adjacency_matrix(EdgeIterator first,
                     EdgeIterator last,
                     vertices_size_type n_vertices,
                     const GraphProperty& p = GraphProperty())
      : m_matrix(Directed::is_directed ?
                 (n_vertices * n_vertices)
                 : (n_vertices * (n_vertices + 1) / 2)),
      m_vertex_set(0, n_vertices),
      m_vertex_properties(n_vertices),
      m_num_edges(0),
      m_property(p)
    {
      for (; first != last; ++first) {
        add_edge(first->first, first->second, *this);
      }
    }

    template <typename EdgeIterator, typename EdgePropertyIterator>
    adjacency_matrix(EdgeIterator first,
                     EdgeIterator last,
                     EdgePropertyIterator ep_iter,
                     vertices_size_type n_vertices,
                     const GraphProperty& p = GraphProperty())
      : m_matrix(Directed::is_directed ?
                 (n_vertices * n_vertices)
                 : (n_vertices * (n_vertices + 1) / 2)),
      m_vertex_set(0, n_vertices),
      m_vertex_properties(n_vertices),
      m_num_edges(0),
      m_property(p)
    {
      for (; first != last; ++first, ++ep_iter) {
        add_edge(first->first, first->second, *ep_iter, *this);
      }
    }

#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
    // Directly access a vertex or edge bundle
    vertex_bundled& operator[](vertex_descriptor v)
    { return get(vertex_bundle, *this)[v]; }

    const vertex_bundled& operator[](vertex_descriptor v) const
    { return get(vertex_bundle, *this)[v]; }

    edge_bundled& operator[](edge_descriptor e)
    { return get(edge_bundle, *this)[e]; }

    const edge_bundled& operator[](edge_descriptor e) const
    { return get(edge_bundle, *this)[e]; }
#endif

    //private: if friends worked, these would be private

    typename Matrix::const_reference
    get_edge(vertex_descriptor u, vertex_descriptor v) const {
      if (Directed::is_directed)
        return m_matrix[u * m_vertex_set.size() + v];
      else {
        if (v > u)
          std::swap(u, v);
        return m_matrix[u * (u + 1)/2 + v];
      }
    }
    typename Matrix::reference
    get_edge(vertex_descriptor u, vertex_descriptor v) {
      if (Directed::is_directed)
        return m_matrix[u * m_vertex_set.size() + v];
      else {
        if (v > u)
          std::swap(u, v);
        return m_matrix[u * (u + 1)/2 + v];
      }
    }

    Matrix m_matrix;
    VertexList m_vertex_set;
    std::vector<vertex_property_type> m_vertex_properties;
    size_type m_num_edges;
    GraphProperty m_property;
  };

  //=========================================================================
  // Functions required by the AdjacencyMatrix concept

  template <typename D, typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor,
            bool>
  edge(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
       typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor v,
       const adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    bool exists = detail::get_edge_exists(g.get_edge(u,v), 0);
    typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor
      e(exists, u, v, &detail::get_property(g.get_edge(u,v)));
    return std::make_pair(e, exists);
  }

  //=========================================================================
  // Functions required by the IncidenceGraph concept

  // O(1)
  template <typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<directedS,VP,EP,GP,A>::out_edge_iterator,
            typename adjacency_matrix<directedS,VP,EP,GP,A>::out_edge_iterator>
  out_edges
    (typename adjacency_matrix<directedS,VP,EP,GP,A>::vertex_descriptor u,
     const adjacency_matrix<directedS,VP,EP,GP,A>& g_)
  {
    typedef adjacency_matrix<directedS,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);
    typename Graph::vertices_size_type offset = u * g.m_vertex_set.size();
    typename Graph::MatrixIter f = g.m_matrix.begin() + offset;
    typename Graph::MatrixIter l = f + g.m_vertex_set.size();
    typename Graph::unfiltered_out_edge_iter
          first(f, u, g.m_vertex_set.size())
        , last(l, u, g.m_vertex_set.size());
    detail::does_edge_exist pred;
    typedef typename Graph::out_edge_iterator out_edge_iterator;
    return std::make_pair(out_edge_iterator(pred, first, last),
                          out_edge_iterator(pred, last, last));
  }

  // O(1)
  template <typename VP, typename EP, typename GP, typename A>
  std::pair<
    typename adjacency_matrix<undirectedS,VP,EP,GP,A>::out_edge_iterator,
    typename adjacency_matrix<undirectedS,VP,EP,GP,A>::out_edge_iterator>
  out_edges
    (typename adjacency_matrix<undirectedS,VP,EP,GP,A>::vertex_descriptor u,
     const adjacency_matrix<undirectedS,VP,EP,GP,A>& g_)
  {
    typedef adjacency_matrix<undirectedS,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);
    typename Graph::vertices_size_type offset = u * (u + 1) / 2;
    typename Graph::MatrixIter f = g.m_matrix.begin() + offset;
    typename Graph::MatrixIter l = g.m_matrix.end();

    typename Graph::unfiltered_out_edge_iter
        first(f, u, g.m_vertex_set.size())
      , last(l, u, g.m_vertex_set.size());

    detail::does_edge_exist pred;
    typedef typename Graph::out_edge_iterator out_edge_iterator;
    return std::make_pair(out_edge_iterator(pred, first, last),
                          out_edge_iterator(pred, last, last));
  }

  // O(N)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  typename adjacency_matrix<D,VP,EP,GP,A>::degree_size_type
  out_degree(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
             const adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    typename adjacency_matrix<D,VP,EP,GP,A>::degree_size_type n = 0;
    typename adjacency_matrix<D,VP,EP,GP,A>::out_edge_iterator f, l;
    for (tie(f, l) = out_edges(u, g); f != l; ++f)
      ++n;
    return n;
  }

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A,
    typename Dir, typename Vertex>
  typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor
  source(const detail::matrix_edge_desc_impl<Dir,Vertex>& e,
         const adjacency_matrix<D,VP,EP,GP,A>&)
  {
    return e.m_source;
  }

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A,
    typename Dir, typename Vertex>
  typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor
  target(const detail::matrix_edge_desc_impl<Dir,Vertex>& e,
         const adjacency_matrix<D,VP,EP,GP,A>&)
  {
    return e.m_target;
  }

  //=========================================================================
  // Functions required by the BidirectionalGraph concept

  // O(1)
  template <typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<directedS,VP,EP,GP,A>::in_edge_iterator,
            typename adjacency_matrix<directedS,VP,EP,GP,A>::in_edge_iterator>
  in_edges
    (typename adjacency_matrix<directedS,VP,EP,GP,A>::vertex_descriptor u,
     const adjacency_matrix<directedS,VP,EP,GP,A>& g_)
  {
    typedef adjacency_matrix<directedS,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);
    typename Graph::MatrixIter f = g.m_matrix.begin() + u;
    typename Graph::MatrixIter l = g.m_matrix.end();
    typename Graph::unfiltered_in_edge_iter
        first(f, l, u, g.m_vertex_set.size())
      , last(l, l, u, g.m_vertex_set.size());
    detail::does_edge_exist pred;
    typedef typename Graph::in_edge_iterator in_edge_iterator;
    return std::make_pair(in_edge_iterator(pred, first, last),
                          in_edge_iterator(pred, last, last));
  }

  // O(1)
  template <typename VP, typename EP, typename GP, typename A>
  std::pair<
    typename adjacency_matrix<undirectedS,VP,EP,GP,A>::in_edge_iterator,
    typename adjacency_matrix<undirectedS,VP,EP,GP,A>::in_edge_iterator>
  in_edges
    (typename adjacency_matrix<undirectedS,VP,EP,GP,A>::vertex_descriptor u,
     const adjacency_matrix<undirectedS,VP,EP,GP,A>& g_)
  {
    typedef adjacency_matrix<undirectedS,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);
    typename Graph::vertices_size_type offset = u * (u + 1) / 2;
    typename Graph::MatrixIter f = g.m_matrix.begin() + offset;
    typename Graph::MatrixIter l = g.m_matrix.end();

    typename Graph::unfiltered_in_edge_iter
        first(f, u, g.m_vertex_set.size())
      , last(l, u, g.m_vertex_set.size());

    detail::does_edge_exist pred;
    typedef typename Graph::in_edge_iterator in_edge_iterator;
    return std::make_pair(in_edge_iterator(pred, first, last),
                          in_edge_iterator(pred, last, last));
  }

  // O(N)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  typename adjacency_matrix<D,VP,EP,GP,A>::degree_size_type
  in_degree(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
             const adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    typename adjacency_matrix<D,VP,EP,GP,A>::degree_size_type n = 0;
    typename adjacency_matrix<D,VP,EP,GP,A>::in_edge_iterator f, l;
    for (tie(f, l) = in_edges(u, g); f != l; ++f)
      ++n;
    return n;
  }

  //=========================================================================
  // Functions required by the AdjacencyGraph concept

  template <typename D, typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::adjacency_iterator,
            typename adjacency_matrix<D,VP,EP,GP,A>::adjacency_iterator>
  adjacent_vertices
    (typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
     const adjacency_matrix<D,VP,EP,GP,A>& g_)
  {
      typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
      const Graph& cg = static_cast<const Graph&>(g_);
      Graph& g = const_cast<Graph&>(cg);
      typedef typename Graph::adjacency_iterator adjacency_iterator;
      typename Graph::out_edge_iterator first, last;
      boost::tie(first, last) = out_edges(u, g);
      return std::make_pair(adjacency_iterator(first, &g),
                            adjacency_iterator(last, &g));
  }

  //=========================================================================
  // Functions required by the VertexListGraph concept

  template <typename D, typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::vertex_iterator,
            typename adjacency_matrix<D,VP,EP,GP,A>::vertex_iterator>
  vertices(const adjacency_matrix<D,VP,EP,GP,A>& g_) {
    typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);
    return std::make_pair(g.m_vertex_set.begin(), g.m_vertex_set.end());
  }

  template <typename D, typename VP, typename EP, typename GP, typename A>
  typename adjacency_matrix<D,VP,EP,GP,A>::vertices_size_type
  num_vertices(const adjacency_matrix<D,VP,EP,GP,A>& g) {
    return g.m_vertex_set.size();
  }

  //=========================================================================
  // Functions required by the EdgeListGraph concept

  template <typename D, typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::edge_iterator,
            typename adjacency_matrix<D,VP,EP,GP,A>::edge_iterator>
  edges(const adjacency_matrix<D,VP,EP,GP,A>& g_)
  {
    typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
    Graph& g = const_cast<Graph&>(g_);

    typename Graph::unfiltered_edge_iter
      first(g.m_matrix.begin(), g.m_matrix.begin(),
                                    g.m_vertex_set.size()),
      last(g.m_matrix.end(), g.m_matrix.begin(),
                                    g.m_vertex_set.size());
    detail::does_edge_exist pred;
    typedef typename Graph::edge_iterator edge_iterator;
    return std::make_pair(edge_iterator(pred, first, last),
                          edge_iterator(pred, last, last));
  }

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  typename adjacency_matrix<D,VP,EP,GP,A>::edges_size_type
  num_edges(const adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    return g.m_num_edges;
  }

  //=========================================================================
  // Functions required by the MutableGraph concept

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A,
            typename EP2>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor, bool>
  add_edge(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
           typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor v,
           const EP2& ep,
           adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    typedef typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor
      edge_descriptor;
    if (detail::get_edge_exists(g.get_edge(u,v), 0) == false) {
      ++(g.m_num_edges);
      detail::set_property(g.get_edge(u,v), EP(ep), 0);
      detail::set_edge_exists(g.get_edge(u,v), true, 0);
      return std::make_pair
        (edge_descriptor(true, u, v, &detail::get_property(g.get_edge(u,v))),
         true);
    } else
      return std::make_pair
        (edge_descriptor(true, u, v, &detail::get_property(g.get_edge(u,v))),
         false);
  }
  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  std::pair<typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor, bool>
  add_edge(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
           typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor v,
           adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    EP ep;
    return add_edge(u, v, ep, g);
  }

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  void
  remove_edge(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor u,
              typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor v,
              adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    // Don'remove the edge unless it already exists.
    if(detail::get_edge_exists(g.get_edge(u,v), 0)) {
      --(g.m_num_edges);
      detail::set_edge_exists(g.get_edge(u,v), false, 0);
    }
  }

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A>
  void
  remove_edge(typename adjacency_matrix<D,VP,EP,GP,A>::edge_descriptor e,
              adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    remove_edge(source(e, g), target(e, g), g);
  }

  template <typename D, typename VP, typename EP, typename GP, typename A>
  inline typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor
  add_vertex(adjacency_matrix<D,VP,EP,GP,A>& g) {
    // UNDER CONSTRUCTION
    assert(false);
    return *vertices(g).first;
  }

  template <typename D, typename VP, typename EP, typename GP, typename A,
            typename VP2>
  inline typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor
  add_vertex(const VP2& /*vp*/, adjacency_matrix<D,VP,EP,GP,A>& g) {
    // UNDER CONSTRUCTION
    assert(false);
    return *vertices(g).first;
  }

  template <typename D, typename VP, typename EP, typename GP, typename A>
  inline void
  remove_vertex(typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor /*u*/,
                adjacency_matrix<D,VP,EP,GP,A>& /*g*/)
  {
    // UNDER CONSTRUCTION
    assert(false);
  }

  // O(V)
  template <typename VP, typename EP, typename GP, typename A>
  void
  clear_vertex
    (typename adjacency_matrix<directedS,VP,EP,GP,A>::vertex_descriptor u,
     adjacency_matrix<directedS,VP,EP,GP,A>& g)
  {
    typename adjacency_matrix<directedS,VP,EP,GP,A>::vertex_iterator
      vi, vi_end;
    for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
      remove_edge(u, *vi, g);
    for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
      remove_edge(*vi, u, g);
  }

  // O(V)
  template <typename VP, typename EP, typename GP, typename A>
  void
  clear_vertex
    (typename adjacency_matrix<undirectedS,VP,EP,GP,A>::vertex_descriptor u,
     adjacency_matrix<undirectedS,VP,EP,GP,A>& g)
  {
    typename adjacency_matrix<undirectedS,VP,EP,GP,A>::vertex_iterator
      vi, vi_end;
    for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
      remove_edge(u, *vi, g);
  }

  //=========================================================================
  // Functions required by the PropertyGraph concept

  // O(1)
  template <typename D, typename VP, typename EP, typename GP, typename A,
            typename Tag, typename Value>
  inline void
  set_property(adjacency_matrix<D,VP,EP,GP,A>& g, Tag, const Value& value)
  {
      get_property_value(g.m_property, Tag()) = value;
  }

  template <typename D, typename VP, typename EP, typename GP, typename A,
            typename Tag>
  inline
  typename graph_property<adjacency_matrix<D,VP,EP,GP,A>, Tag>::type&
  get_property(adjacency_matrix<D,VP,EP,GP,A>& g, Tag)
  {
      return get_property_value(g.m_property, Tag());
  }

  template <typename D, typename VP, typename EP, typename GP, typename A,
            typename Tag>
  inline
  const
  typename graph_property<adjacency_matrix<D,VP,EP,GP,A>, Tag>::type&
  get_property(const adjacency_matrix<D,VP,EP,GP,A>& g, Tag)
  {
      return get_property_value(g.m_property, Tag());
  }

  //=========================================================================
  // Vertex Property Map

  template <typename GraphPtr, typename Vertex, typename T, typename R,
    typename Tag>
  class adj_matrix_vertex_property_map
    : public put_get_helper<R,
         adj_matrix_vertex_property_map<GraphPtr, Vertex, T, R, Tag> >
  {
  public:
    typedef T value_type;
    typedef R reference;
    typedef Vertex key_type;
    typedef boost::lvalue_property_map_tag category;
    adj_matrix_vertex_property_map() { }
    adj_matrix_vertex_property_map(GraphPtr g) : m_g(g) { }
    inline reference operator[](key_type v) const {
      return get_property_value(m_g->m_vertex_properties[v], Tag());
    }
    GraphPtr m_g;
  };

  template <class Property, class Vertex>
  struct adj_matrix_vertex_id_map
    : public boost::put_get_helper<Vertex,
        adj_matrix_vertex_id_map<Property, Vertex> >
  {
    typedef Vertex value_type;
    typedef Vertex reference;
    typedef Vertex key_type;
    typedef boost::readable_property_map_tag category;
     adj_matrix_vertex_id_map() { }
    template <class Graph>
    inline adj_matrix_vertex_id_map(const Graph&) { }
    inline value_type operator[](key_type v) const { return v; }
  };

  namespace detail {

    struct adj_matrix_any_vertex_pa {
      template <class Tag, class Graph, class Property>
      struct bind_ {
        typedef typename property_value<Property,Tag>::type Value;
        typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;

        typedef adj_matrix_vertex_property_map<Graph*, Vertex, Value, Value&,
          Tag> type;
        typedef adj_matrix_vertex_property_map<const Graph*, Vertex, Value,
          const Value&, Tag> const_type;
      };
    };
    struct adj_matrix_id_vertex_pa {
      template <class Tag, class Graph, class Property>
      struct bind_ {
        typedef typename Graph::vertex_descriptor Vertex;
        typedef adj_matrix_vertex_id_map<Property, Vertex> type;
        typedef adj_matrix_vertex_id_map<Property, Vertex> const_type;
      };
    };

    template <class Tag>
    struct adj_matrix_choose_vertex_pa_helper {
      typedef adj_matrix_any_vertex_pa type;
    };
    template <>
    struct adj_matrix_choose_vertex_pa_helper<vertex_index_t> {
      typedef adj_matrix_id_vertex_pa type;
    };

    template <class Tag, class Graph, class Property>
    struct adj_matrix_choose_vertex_pa {
      typedef typename adj_matrix_choose_vertex_pa_helper<Tag>::type Helper;
      typedef typename Helper::template bind_<Tag,Graph,Property> Bind;
      typedef typename Bind::type type;
      typedef typename Bind::const_type const_type;
    };

    struct adj_matrix_vertex_property_selector {
      template <class Graph, class Property, class Tag>
      struct bind_ {
        typedef adj_matrix_choose_vertex_pa<Tag,Graph,Property> Choice;
        typedef typename Choice::type type;
        typedef typename Choice::const_type const_type;
      };
    };

  } // namespace detail

  template <>
  struct vertex_property_selector<adjacency_matrix_class_tag> {
    typedef detail::adj_matrix_vertex_property_selector type;
  };

  //=========================================================================
  // Edge Property Map

  template <typename Directed, typename Property, typename Vertex,
    typename T, typename R, typename Tag>
  class adj_matrix_edge_property_map
    : public put_get_helper<R,
         adj_matrix_edge_property_map<Directed, Property, Vertex, T, R, Tag> >
  {
  public:
    typedef T value_type;
    typedef R reference;
    typedef detail::matrix_edge_desc_impl<Directed, Vertex> key_type;
    typedef boost::lvalue_property_map_tag category;
    inline reference operator[](key_type e) const {
      Property& p = *(Property*)e.get_property();
      return get_property_value(p, Tag());
    }
  };
  struct adj_matrix_edge_property_selector {
    template <class Graph, class Property, class Tag>
    struct bind_ {
      typedef typename property_value<Property,Tag>::type T;
      typedef typename Graph::vertex_descriptor Vertex;
      typedef adj_matrix_edge_property_map<typename Graph::directed_category,
        Property, Vertex, T, T&, Tag> type;
      typedef adj_matrix_edge_property_map<typename Graph::directed_category,
        Property, Vertex, T, const T&, Tag> const_type;
    };
  };
  template <>
  struct edge_property_selector<adjacency_matrix_class_tag> {
    typedef adj_matrix_edge_property_selector type;
  };

  //=========================================================================
  // Functions required by PropertyGraph

  namespace detail {

    template <typename Property, typename D, typename VP, typename EP,
              typename GP, typename A>
    typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
      Property>::type
    get_dispatch(adjacency_matrix<D,VP,EP,GP,A>& g, Property,
                 vertex_property_tag)
    {
      typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
      typedef typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
        Property>::type PA;
      return PA(&g);
    }
    template <typename Property, typename D, typename VP, typename EP,
              typename GP, typename A>
    typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
      Property>::type
    get_dispatch(adjacency_matrix<D,VP,EP,GP,A>&, Property,
                 edge_property_tag)
    {
      typedef typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
        Property>::type PA;
      return PA();
    }
    template <typename Property, typename D, typename VP, typename EP,
              typename GP, typename A>
    typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
      Property>::const_type
    get_dispatch(const adjacency_matrix<D,VP,EP,GP,A>& g, Property,
                 vertex_property_tag)
    {
      typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
      typedef typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
        Property>::const_type PA;
      return PA(&g);
    }
    template <typename Property, typename D, typename VP, typename EP,
              typename GP, typename A>
    typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
      Property>::const_type
    get_dispatch(const adjacency_matrix<D,VP,EP,GP,A>&, Property,
                 edge_property_tag)
    {
      typedef typename boost::property_map<adjacency_matrix<D,VP,EP,GP,A>,
        Property>::const_type PA;
      return PA();
    }

  } // namespace detail

  template <typename Property, typename D, typename VP, typename EP,
            typename GP, typename A>
  inline
  typename property_map<adjacency_matrix<D,VP,EP,GP,A>, Property>::type
  get(Property p, adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    typedef typename property_kind<Property>::type Kind;
    return detail::get_dispatch(g, p, Kind());
  }

  template <typename Property, typename D, typename VP, typename EP,
            typename GP, typename A>
  inline
  typename property_map<adjacency_matrix<D,VP,EP,GP,A>, Property>::const_type
  get(Property p, const adjacency_matrix<D,VP,EP,GP,A>& g)
  {
    typedef typename property_kind<Property>::type Kind;
    return detail::get_dispatch(g, p, Kind());
  }

  template <typename Property, typename D, typename VP, typename EP,
            typename GP, typename A, typename Key>
  inline
  typename property_traits<
    typename property_map<adjacency_matrix<D,VP,EP,GP,A>, Property>::const_type
  >::value_type
  get(Property p, const adjacency_matrix<D,VP,EP,GP,A>& g,
      const Key& key)
  {
    return get(get(p, g), key);
  }

  template <typename Property, typename D, typename VP, typename EP,
            typename GP, typename A, typename Key, typename Value>
  inline void
  put(Property p, adjacency_matrix<D,VP,EP,GP,A>& g,
      const Key& key, const Value& value)
  {
    typedef adjacency_matrix<D,VP,EP,GP,A> Graph;
    typedef typename boost::property_map<Graph, Property>::type Map;
    Map pmap = get(p, g);
    put(pmap, key, value);
  }

  //=========================================================================
  // Other Functions

  template <typename D, typename VP, typename EP, typename GP, typename A>
  typename adjacency_matrix<D,VP,EP,GP,A>::vertex_descriptor
  vertex(typename adjacency_matrix<D,VP,EP,GP,A>::vertices_size_type n,
         const adjacency_matrix<D,VP,EP,GP,A>&)
  {
    return n;
  }

  // Support for bundled properties
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
  template <typename Directed, typename VertexProperty, typename EdgeProperty, typename GraphProperty,
            typename Allocator, typename T, typename Bundle>
  inline
  typename property_map<adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>,
                        T Bundle::*>::type
  get(T Bundle::* p, adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>& g)
  {
    typedef typename property_map<adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>,
                                  T Bundle::*>::type
      result_type;
    return result_type(&g, p);
  }

  template <typename Directed, typename VertexProperty, typename EdgeProperty, typename GraphProperty,
            typename Allocator, typename T, typename Bundle>
  inline
  typename property_map<adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>,
                        T Bundle::*>::const_type
  get(T Bundle::* p, adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator> const & g)
  {
    typedef typename property_map<adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>,
                                  T Bundle::*>::const_type
      result_type;
    return result_type(&g, p);
  }

  template <typename Directed, typename VertexProperty, typename EdgeProperty, typename GraphProperty,
            typename Allocator, typename T, typename Bundle, typename Key>
  inline T
  get(T Bundle::* p, adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator> const & g,
      const Key& key)
  {
    return get(get(p, g), key);
  }

  template <typename Directed, typename VertexProperty, typename EdgeProperty, typename GraphProperty,
            typename Allocator, typename T, typename Bundle, typename Key>
  inline void
  put(T Bundle::* p, adjacency_matrix<Directed, VertexProperty, EdgeProperty, GraphProperty, Allocator>& g,
      const Key& key, const T& value)
  {
    put(get(p, g), key, value);
  }

#endif

#define ADJMAT_PARAMS \
    typename D, typename VP, typename EP, typename GP, typename A
#define ADJMAT adjacency_matrix<D,VP,EP,GP,A>
template <ADJMAT_PARAMS>
struct graph_mutability_traits<ADJMAT> {
    typedef mutable_edge_property_graph_tag category;
};
#undef ADJMAT_PARAMS
#undef ADJMAT

} // namespace boost

#endif // BOOST_ADJACENCY_MATRIX_HPP


/// \file   quantity.hpp
///
/// \brief  A class used to enforce conversion without numerical error when
///         counting property, goods and other items.
///
/// \authors    Maarten P. Scholl
/// \date       2018-02-05
/// \copyright  Copyright 2017-2019 The Institute for New Economic Thinking,
///             Oxford Martin School, University of Oxford
///
///             Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
///
///             Unless required by applicable law or agreed to in writing,
///             software distributed under the License is distributed on an "AS
///             IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
///             express or implied. See the License for the specific language
///             governing permissions and limitations under the License.
///
///             You may obtain instructions to fulfill the attribution
///             requirements in CITATION.cff
///
#ifndef ESL_AMOUNT_HPP
#define ESL_AMOUNT_HPP

#include <array>
#include <cstdint>
#include <vector>

#include <iostream>

#include <boost/serialization/nvp.hpp>

#ifndef EXCEPTION_ON_BASIS_CHANGE
#define EXCEPTION_ON_BASIS_CHANGE true
#endif

namespace esl {
    ///
    /// \brief  The quantity class is used to losslessly deal with quantities of
    ///         economic goods in large quantities. A quantity is associated
    ///         with a basis (the number of parts that make up a unit amount of
    ///         the object).
    ///
    /// \details    The quantity is not a fraction: a property that dividies
    ///             into single parts, is not the same as a property that
    ///             divides into 100 parts. Hence, quantity(1,1) is not the same
    ///             as quantity(100,100). Implicit conversion or combination of
    ///             `quantity` with different `basis` is not encouraged, and the
    ///             preprocessor option EXCEPTION_ON_BASIS_CHANGE can be used to
    ///             disallow this.
    ///
    struct quantity
    {
    private:
    public:
        ///
        /// \note   We explicitly delete the division into quantity operator as
        /// this
        ///         loses the remainder. Instead, use
        ///         quantity::divide()
        template<typename divisor_type_>
        quantity &operator/=(divisor_type_) const = delete;

        ///
        ///`\brief  The number of parts
        ///
        std::uint64_t amount;

        ///
        /// \brief  The number of sub-units to make one part
        ///
        std::uint64_t basis;

        ///
        /// \param amount   The number of parts of something, e.g. 23 cents.
        ///                 Default: 0
        /// \param basis    The number of parts to make one unit, e.g.
        ///                 100 cents to 1 dollar. Default: 1
        explicit constexpr quantity(std::uint64_t amount = 0,
                                    std::uint64_t basis  = 1)
        : amount(amount), basis(basis)
        {
            if(basis < 1) {
                throw std::logic_error("quantity with 0 basis");
            }
        }

        ///
        /// \param q
        constexpr quantity(const quantity &q)
        : quantity(q.amount, q.basis)
        {

        }

        ///
        /// \param operand
        /// \return
        constexpr void assert_equal_basis(const quantity &operand) const
        {
            if(basis != operand.basis) {
                throw std::logic_error("assert_equal_basis");
            }
        }

        ///
        /// \tparam divisor_
        /// \return
        template<uint64_t divisor_>
        constexpr std::array<quantity, divisor_> divide() const
        {
            static_assert(divisor_ != 0, "division by zero");

            std::uint64_t quotient_  = amount / divisor_;
            std::uint64_t remainder_ = amount % divisor_;

            std::array<quantity, divisor_> result_;

            auto iterator_ = result_.begin();
            for(; iterator_ != result_.begin() + remainder_; ++iterator_) {
                iterator_->amount = quotient_ + 1;
                iterator_->basis  = basis;
            }

            for(; iterator_ != result_.end(); ++iterator_) {
                iterator_->amount = quotient_;
                iterator_->basis  = basis;
            }

            return result_;
        }

        [[nodiscard]] constexpr quantity
        operator*(const std::uint64_t &operand) const
        {
            return quantity(amount * operand, basis);
        }

        [[nodiscard]]
#if !EXCEPTION_ON_BASIS_CHANGE
        constexpr
#endif
        quantity
        operator*(const quantity &operand) const
        {
            auto numerator_ = amount * operand.amount;
            auto remainder_ = numerator_ % operand.basis;

            if(!remainder_) {
                return quantity(numerator_ / operand.basis, basis);
            }

            if(EXCEPTION_ON_BASIS_CHANGE) {
                throw std::logic_error("EXCEPTION_ON_BASIS_CHANGE");
            }

            auto coremainder_ = numerator_ % basis;

            if(!coremainder_) {
                return quantity(numerator_ / basis, operand.basis);
            }

            return quantity(numerator_, basis * operand.basis);
        }

        ///
        /// \param operand
        /// \return
        quantity &operator*=(const std::uint64_t &operand)
        {
            (*this) = (*this) * operand;
            return *this;
        }

        ///
        /// \brief  Add together two quantities.
        ///
        /// \param operand
        /// \return
        [[nodiscard]]
#if !EXCEPTION_ON_BASIS_CHANGE
        constexpr
#endif
        quantity operator+(const quantity &operand) const
        {
            auto numerator_ = amount * operand.basis + operand.amount * basis;
            auto remainder_ = numerator_ % operand.basis;

            if(!remainder_) {
                return quantity(numerator_ / operand.basis, basis);
            }

            if(EXCEPTION_ON_BASIS_CHANGE) {
                throw std::logic_error("EXCEPTION_ON_BASIS_CHANGE");
            }

            auto coremainder_ = numerator_ % basis;

            if(!coremainder_) {
                return quantity(numerator_ / basis, operand.basis);
            }

            return quantity(numerator_, basis * operand.basis);
        }

        ///
        /// \param operand
        /// \return
        quantity &operator+=(const quantity &operand)
        {
            (*this) = (*this) + operand;
            return *this;
        }

        ///
        /// \brief  subtract two quantities.
        ///
        /// \param operand
        /// \return
        [[nodiscard]]
#if !EXCEPTION_ON_BASIS_CHANGE
        constexpr
#endif
        quantity operator-(const quantity &operand) const
        {
            auto left_  = amount * operand.basis;
            auto right_ = operand.amount * basis;
            if(right_ > left_) {
                throw std::logic_error(
                    "subtraction results in negative quantity");
            }
            auto numerator_ = left_ - right_;
            auto remainder_ = numerator_ % operand.basis;

            if(!remainder_) {
                return quantity(numerator_ / operand.basis, basis);
            }

            if(EXCEPTION_ON_BASIS_CHANGE) {
                throw std::logic_error("EXCEPTION_ON_BASIS_CHANGE");
            }

            auto coremainder_ = numerator_ % basis;

            if(!coremainder_) {
                return quantity(numerator_ / basis, operand.basis);
            }

            return quantity(numerator_, basis * operand.basis);
        }

        quantity &operator=(const quantity &operand)
        {
            amount = operand.amount;
            basis  = operand.basis;
            return *this;
        }

        ///
        /// \param operand
        /// \return
        quantity &operator-=(const quantity &operand)
        {
            (*this) = (*this) - operand;
            return *this;
        }

        ///
        /// \brief  true if equal to the truncated double equivalent of this
        ///         quantity
        ///
        /// \param operand
        /// \return
        [[nodiscard]] constexpr bool operator==(double operand) const
        {
            return (amount == std::uint64_t(operand * basis));
        }

        ///
        /// \param operand
        /// \return
        [[nodiscard]] constexpr bool operator==(const quantity &operand) const
        {
            return (amount == operand.amount && basis == operand.basis);
        }

        [[nodiscard]] constexpr bool operator!=(double operand) const
        {
            return !((*this) == operand);
        }

        [[nodiscard]] constexpr bool operator<(double operand) const
        {
            return (amount < operand * basis);
        }

        [[nodiscard]] constexpr bool operator<(const quantity &operand) const
        {
            return (amount * basis < operand.amount * operand.basis);
        }

        [[nodiscard]] constexpr bool operator>(double operand) const
        {
            return (amount > operand * basis);
        }

        [[nodiscard]] constexpr bool operator>(const quantity &operand) const
        {
            return (amount * basis > operand.amount * operand.basis);
        }

        [[nodiscard]] constexpr bool operator<=(double operand) const
        {
            return (*this) < operand || (*this) == operand;
        }

        [[nodiscard]] constexpr bool operator<=(const quantity &operand) const
        {
            return (*this) < operand || (*this) == operand;
        }

        [[nodiscard]] constexpr bool operator>=(double operand) const
        {
            return (*this) > operand || (*this) == operand;
        }

        [[nodiscard]] constexpr bool operator>=(const quantity & operand) const
        {
            return (*this) > operand || (*this) == operand;
        }

        ///
        /// \brief  Division into `divisor` parts, allocating the remainder
        /// starting at the first quotient.
        ///
        /// \param divisor
        /// \return
        [[nodiscard]] std::vector<quantity>
        operator/(std::uint64_t divisor) const
        {
            std::uint64_t quotient_  = amount / divisor;
            std::uint64_t remainder_ = amount % divisor;

            if(divisor >= (2 * remainder_)) {
                std::vector<quantity> result_(divisor,
                                              quantity(quotient_, basis));
                for(auto iterator_ = result_.begin();
                    iterator_ != result_.begin() + remainder_;
                    ++iterator_) {
                    iterator_->amount = quotient_ + 1;
                }
                return result_;
            }

            std::vector<quantity> result_(divisor,
                                          quantity(quotient_ + 1, basis));
            for(auto iterator_ = result_.begin() + remainder_;
                iterator_ != result_.end();
                ++iterator_) {
                iterator_->amount = quotient_;
            }
            return result_;
        }

        ///
        /// \return amount/basis as a double precision floating point number.
        ///
        [[nodiscard]] explicit operator double() const
        {
            return double(amount) / basis;
        }

        friend std::ostream &operator<<(std::ostream &stream, const quantity &q)
        {
            stream << q.amount;
            if(q.basis != 1) {
                stream << '/';
                stream << q.basis;
            }
            return stream;
        }

        template<class archive_t>
        void serialize(archive_t &archive, const unsigned int version)
        {
            (void)version;
            archive &BOOST_SERIALIZATION_NVP(amount);
            archive &BOOST_SERIALIZATION_NVP(basis);
        }
    };

}  // namespace esl

#endif  // ESL_AMOUNT_HPP


// Project: libv.algo, File: src/libv/algo/wildcard.cpp, Author: Császár Mátyás [Vader]

// hpp
#include <libv/algo/wildcard.hpp>
// ext
#include <boost/container/small_vector.hpp>

namespace libv {

// -------------------------------------------------------------------------------------------------

bool match_wildcard(const std::string_view str, const std::string_view pattern) noexcept {
	static constexpr auto WILDCARD_SINGLE = '?';
	static constexpr auto WILDCARD_ANY = '*';
//	static constexpr auto WILDCARD_ESCAPE = '\\';
//	static constexpr auto WILDCARD_ESCAPE_ESCAPE = "\\\\";

	boost::container::small_vector<bool, 1024> table;
	table.resize((str.size() + 1) * (pattern.size() + 1), false);
	const auto index = [&](size_t i, size_t j) -> bool& {
		return table[(pattern.size() + 1) * i + j];
	};

	// clear
	for (size_t i = 0; i <= str.size(); ++i)
		for (size_t j = 0; j <= pattern.size(); ++j)
			index(i, j) = false;

	// accept any leading WILDCARD_ANY as str start
	for (size_t j = 1; j <= pattern.size() && pattern[j - 1] == WILDCARD_ANY; ++j)
		index(0, j) = true;

	// base case
	index(0, 0) = true;

	// solve
	for (size_t i = 1; i <= str.size(); i++) {
		for (size_t j = 1; j <= pattern.size(); j++) {
			if (str[i - 1] == pattern[j - 1] || pattern[j - 1] == WILDCARD_SINGLE)
				index(i, j) = index(i - 1, j - 1);

			else if (pattern[j - 1] == WILDCARD_ANY)
				index(i, j) = index(i, j - 1) || index(i - 1, j);
		}
	}

	return index(str.size(), pattern.size());
}

// -------------------------------------------------------------------------------------------------

struct ImplWildcardGlobMatcher {
	static constexpr std::string_view WILDCARD_ESCAPE = "\\";

	static constexpr std::string_view WILDCARD_LAYER_ANY = "**";
	static constexpr std::string_view WILDCARD_LAYER = "*";
	static constexpr std::string_view WILDCARD_SINGLE = "?";
	//	static constexpr std::string_view WILDCARD_RANGE = "[abc]";
	//	static constexpr std::string_view WILDCARD_RANGE = "[a-z]";
	//	static constexpr std::string_view WILDCARD_NEGATED_RANGE = "[!abc]";
	//	static constexpr std::string_view WILDCARD_NEGATED_RANGE = "[!a-z]";
	//	static constexpr std::string_view WILDCARD_ALTERNATE = "(a.txt|b.jpg)";

	/// Separator is not allowed in WILDCARD_SINGLE or WILDCARD_LAYER (but it is allowed in WILDCARD_LAYER_ANY)
	static constexpr std::string_view WILDCARD_SEPARATOR = "/";

	enum class TokenType {
		literal,   // abc
		single,    // ?
		layer,     // *
		layer_any, // **
	};

	struct Token {
		TokenType type;
		size_t begin = 0;
		size_t size = 0;
	};

public:
	boost::container::small_vector<Token, 10> pattern;
	boost::container::small_vector<std::string_view::value_type, 256> pattern_literals;

public:
	mutable boost::container::small_vector<bool, 1024> table;

public:
	void preprocess(const std::string_view pattern_str) {
		pattern.clear();
		pattern_literals.clear();

		// Preprocess pattern
		for (size_t i = 0; i < pattern_str.size();) {
			if (pattern_str.substr(i).starts_with(WILDCARD_ESCAPE) && pattern_str.size() - i != WILDCARD_ESCAPE.size()) {
				i += WILDCARD_ESCAPE.size();

				if (!pattern.empty() && pattern.back().type == TokenType::literal)
					pattern.back().size++;
				else
					pattern.push_back(Token{TokenType::literal, pattern_literals.size(), 1});

				pattern_literals.push_back(pattern_str[i]);
				i++;

			} else if (pattern_str.substr(i).starts_with(WILDCARD_LAYER_ANY)) {
				i += WILDCARD_LAYER_ANY.size();
				if (!pattern.empty() && pattern.back().type == TokenType::layer)
					pattern.back().type = TokenType::layer_any;

				else if (pattern.empty() || pattern.back().type != TokenType::layer_any)
					pattern.push_back(Token{TokenType::layer_any});

			} else if (pattern_str.substr(i).starts_with(WILDCARD_LAYER)) {
				i += WILDCARD_LAYER.size();
				if (pattern.empty() || (pattern.back().type != TokenType::layer && pattern.back().type != TokenType::layer_any))
					pattern.push_back(Token{TokenType::layer});

			} else if (pattern_str.substr(i).starts_with(WILDCARD_SINGLE)) {
				i += WILDCARD_SINGLE.size();
				if (!pattern.empty() && pattern.back().type == TokenType::single)
					pattern.back().size++;
				else
					pattern.push_back(Token{TokenType::single, 0, 1});

			} else {
				if (!pattern.empty() && pattern.back().type == TokenType::literal)
					pattern.back().size++;
				else
					pattern.push_back(Token{TokenType::literal, pattern_literals.size(), 1});

				pattern_literals.push_back(pattern_str[i]);
				i++;
			}
		}
	}

	inline bool& index(size_t i, size_t j) const noexcept {
		return table[(pattern.size() + 1) * i + j];
	}

	bool match(const std::string_view str) const {
		table.resize((str.size() + 1) * (pattern.size() + 1), false);

		// accept any leading WILDCARD_ANY and at most one WILDCARD_LAYER as str start
		{
			bool layer_accept = false;
			for (size_t j = 1; j <= pattern.size(); ++j) {
				if (pattern[j - 1].type == TokenType::layer && !layer_accept) {
					layer_accept = true;
					index(0, j) = true;
					continue;
				}
				if (pattern[j - 1].type == TokenType::layer_any) {
					index(0, j) = true;
					continue;
				}
				break;
			}
		}

		// base case
		index(0, 0) = true;

		// solve
		for (size_t i = 1; i <= str.size(); i++) {
			for (size_t j = 1; j <= pattern.size(); j++) {
				if (index(i, j)) // Optimization: Already calculated
					continue;

				const auto& token = pattern[j - 1];
				const auto str_literal = str.substr(i - 1);

				const bool up = index(i - 1, j);
				const bool left = index(i, j - 1);
				const bool up_left = index(i - 1, j - 1);

				if (token.type == TokenType::literal) {
					const bool accept = str_literal.starts_with(std::string_view(pattern_literals.data() + token.begin, token.size));
					if (accept && up_left)
						// Optimization: Prefill the every matched character
						for (size_t s = 0; s < token.size && i + s <= str.size() && index(i + s, j) == false; ++s)
							index(i + s, j) = true;

				} else if (token.type == TokenType::single) {
					const bool accept = str_literal.size() >= token.size && str_literal.substr(0, token.size).find_first_of(WILDCARD_SEPARATOR) == str_literal.npos;
					if (accept && up_left)
						// Optimization: Prefill the every matched character
						for (size_t s = 0; s < token.size && i + s <= str.size() && index(i + s, j) == false; ++s)
							index(i + s, j) = true;

				} else if (token.type == TokenType::layer_any) {
					index(i, j) |= left || up;

				} else if (token.type == TokenType::layer) {
					index(i, j) |= left || (up && !str_literal.starts_with(WILDCARD_SEPARATOR));
				}
			}
		}

		return index(str.size(), pattern.size());
	}
};

// -------------------------------------------------------------------------------------------------

WildcardGlobMatcher::WildcardGlobMatcher(const std::string_view pattern_str) :
	self(std::make_unique<ImplWildcardGlobMatcher>()) {
	self->preprocess(pattern_str);
}

void WildcardGlobMatcher::pattern(const std::string_view pattern_str) {
	self->preprocess(pattern_str);
}

bool WildcardGlobMatcher::match(const std::string_view str) const {
	return self->match(str);
}

WildcardGlobMatcher::~WildcardGlobMatcher() {
	// For the sake of forward declared unique_ptr
}

// -------------------------------------------------------------------------------------------------

bool match_wildcard_glob(const std::string_view str, const std::string_view pattern_str) noexcept {
	ImplWildcardGlobMatcher matcher;
	matcher.preprocess(pattern_str);
	return matcher.match(str);
}

// -------------------------------------------------------------------------------------------------

} // namespace libv


/*

Copyright (c) 2005-2017, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the University of Oxford nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef NAGAIHONDADIFFERENTIALADHESIONFORCE_HPP_
#define NAGAIHONDADIFFERENTIALADHESIONFORCE_HPP_

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

#include "NagaiHondaForce.hpp"

#include <iostream>

/**
 * A force class for use in vertex-based simulations, based on a model
 * model proposed by T. Nagai and H. Honda ("A dynamic cell model for
 * the formation of epithelial tissues", Philosophical Magazine Part B
 * 81:699-719) to include differential adhesion between normal and
 * labelled cells. To include differential adhesion we override the
 * GetAdhesionParameter() method.
 *
 * Each of the model parameter member variables are rescaled such that
 * mDampingConstantNormal takes the default value 1, whereas Nagai and
 * Honda (who denote the parameter by nu) take the value 0.01.
 */
template<unsigned DIM>
class NagaiHondaDifferentialAdhesionForce  : public NagaiHondaForce<DIM>
{
private:

    /**
     * Cell-cell adhesion energy parameter for two labelled cells.
     * Has units of kg (cell size at equilibrium rest length)^2 s^-2.
     * Takes the default value 1.0.
     */
    double mNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter;

    /**
     * Cell-cell adhesion energy parameter for labelled and non-labelled cells.
     * Has has units of kg (cell size at equilibrium rest length)^2 s^-2.
     * Takes the default value 1.0.
     */
    double mNagaiHondaLabelledCellCellAdhesionEnergyParameter;

    /**
     * Cell-boundary adhesion energy parameter for labelled cells.
     * Has units of kg (cell size at equilibrium rest length)^2 s^-2.
     * Takes the default value 1.0.
     */
    double mNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter;

    friend class boost::serialization::access;
    /**
     * Boost Serialization method for archiving/checkpointing.
     * Archives the object and its member variables.
     *
     * @param archive  The boost archive.
     * @param version  The current version of this class.
     */
    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & boost::serialization::base_object<NagaiHondaForce<DIM> >(*this);
        archive & mNagaiHondaLabelledCellCellAdhesionEnergyParameter;
        archive & mNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter;
        archive & mNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter;
    }

public:

    /**
     * Constructor.
     */
    NagaiHondaDifferentialAdhesionForce();

    /**
     * Destructor.
     */
    virtual ~NagaiHondaDifferentialAdhesionForce();

    /**
     * Overridden GetAdhesionParameter() method.
     *
     * Get the adhesion parameter for the edge between two given nodes. Depends
     * on the type of cells attached to the elements.
     *
     * @param pNodeA one node
     * @param pNodeB the other node
     * @param rVertexCellPopulation reference to the cell population
     *
     * @return the adhesion parameter for this edge.
     */
    virtual double GetAdhesionParameter(Node<DIM>* pNodeA, Node<DIM>* pNodeB, VertexBasedCellPopulation<DIM>& rVertexCellPopulation);

    /**
     * @return mNagaiHondaLabelledCellCellAdhesionEnergyParameter
     */
    double GetNagaiHondaLabelledCellCellAdhesionEnergyParameter();

    /**
     * @return mNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter
     */
    double GetNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter();

    /**
     * @return mNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter
     */
    double GetNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter();

    /**
     * Set mNagaiHondaLabelledCellCellAdhesionEnergyParameter.
     *
     * @param labelledCellCellAdhesionEnergyParameter the new value of mNagaiHondaLabelledCellCellAdhesionEnergyParameter
     */
    void SetNagaiHondaLabelledCellCellAdhesionEnergyParameter(double labelledCellCellAdhesionEnergyParameter);

    /**
     * Set mNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter.
     *
     * @param labelledCellLabelledCellAdhesionEnergyParameter the new value of mNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter
     */
    void SetNagaiHondaLabelledCellLabelledCellAdhesionEnergyParameter(double labelledCellLabelledCellAdhesionEnergyParameter);

    /**
     * Set mNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter.
     *
     * @param labelledCellBoundaryAdhesionEnergyParameter the new value of mNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter
     */
    void SetNagaiHondaLabelledCellBoundaryAdhesionEnergyParameter(double labelledCellBoundaryAdhesionEnergyParameter);

    /**
     * Overridden OutputForceParameters() method.
     *
     * @param rParamsFile the file stream to which the parameters are output
     */
    void OutputForceParameters(out_stream& rParamsFile);
};

#include "SerializationExportWrapper.hpp"
EXPORT_TEMPLATE_CLASS_SAME_DIMS(NagaiHondaDifferentialAdhesionForce)

#endif /*NAGAIHONDADIFFERENTIALADHESIONFORCE_HPP_*/


//   Copyright 2019 <Huawei Technologies Co., Ltd>
//
//   Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include <chrono>
#include <cstdint>
#include <iostream>

#include "simulator-mpi/funcs.hpp"

namespace po = boost::program_options;

uint64_t calcSwaps(uint64_t aL, uint64_t aM, std::vector<uint64_t> anInvPerm,
                   std::vector<uint64_t> aPairs)
{
     uint64_t res = 0;

     for (uint64_t rank = 0; rank < (1ul << (aL - aM)); ++rank) {
          auto start = std::chrono::high_resolution_clock::now();

          for (uint64_t index = 0; index < (1ul << aM); ++index) {
               uint64_t new_rank = rank;
               uint64_t new_index = index;
               for (size_t pi = 0; pi < aPairs.size(); pi += 2) {
                    uint64_t remote_qubit = aPairs[pi];
                    uint64_t local_qubit = aPairs[pi + 1];

                    uint64_t remote_bit
                        = (1ul << (anInvPerm[remote_qubit] - aM));
                    uint64_t local_bit = (1ul << anInvPerm[local_qubit]);
                    bool rb = rank & remote_bit;
                    bool ib = index & local_bit;
                    new_index ^= (-rb ^ new_index) & local_bit;
                    new_rank ^= (-ib ^ new_rank) & remote_bit;
               }

               if (new_rank != rank) {
                    res += new_index;
                    //				std::cout << format("(%d: %d)->(%d: %d)") %
                    // rank % index % new_rank % new_index << std::endl;
               }
          }

          auto end = std::chrono::high_resolution_clock::now();
          std::chrono::duration<double, std::milli> elapsed_us = end - start;
          std::cout << boost::format("rank: %d, ") % rank
                    << boost::format("elapsed time: %.3f ms")
                           % elapsed_us.count()
                    << std::endl;
     }

     return res;
}

template <size_t NumPairs>
uint64_t calcSwaps1(uint64_t aL, uint64_t aM, std::vector<uint64_t> aSwapBits)
{
     uint64_t res = 0;

     for (uint64_t rank = 0; rank < (1ul << (aL - aM)); ++rank) {
          auto start = std::chrono::high_resolution_clock::now();

          for (uint64_t index = 0; index < (1ul << aM); ++index) {
               uint64_t new_rank = rank;
               uint64_t new_index = index;

               uint64_t dst_idx = 0;

               for (size_t pi = 0; pi < 2 * NumPairs; pi += 2) {
                    uint64_t remote_bit = aSwapBits[pi];
                    uint64_t local_bit = aSwapBits[pi + 1];

                    bool rb = rank & remote_bit;
                    bool ib = index & local_bit;
                    new_index ^= (-rb ^ new_index) & local_bit;
                    new_rank ^= (-ib ^ new_rank) & remote_bit;

                    dst_idx ^= (-ib ^ dst_idx) & (1ul << (pi / 2));
               }

               res += new_index;

               if (new_rank != rank) {
                    std::cout
                        << boost::format("(%d: %d)->(%d: %d),  dst_idx: %d")
                               % rank % index % new_rank % new_index % dst_idx
                        << std::endl;
               }
          }

          auto end = std::chrono::high_resolution_clock::now();
          std::chrono::duration<double, std::milli> elapsed_us = end - start;
          std::cout << boost::format("rank: %d, ") % rank
                    << boost::format("elapsed time: %.3f ms")
                           % elapsed_us.count()
                    << std::endl;
     }

     return res;
}

template <>
uint64_t calcSwaps1<0>(uint64_t, uint64_t, std::vector<uint64_t>)
{
     return 0;
}

template <size_t NumPairs, class T = uint64_t>
struct CalcSwaps
{
     static T doCalc(uint64_t L, uint64_t M, const std::vector<T>& swap_bits)
     {
          if (NumPairs * 2 == swap_bits.size()) {
               return calcSwaps1<NumPairs>(L, M, swap_bits);
          }
          else {
               return CalcSwaps<NumPairs - 1, T>::doCalc(L, M, swap_bits);
          }
     }
};

template <class T>
struct CalcSwaps<0, T>
{
     static T doCalc(uint64_t L, uint64_t M, const std::vector<T>& swap_bits)
     {
          return calcSwaps1<0>(L, M, swap_bits);
     }
};

int main(int argc, const char** argv)
{
     uint64_t L = 0;
     uint64_t M = 0;
     std::vector<uint64_t> swap_pairs;
     std::vector<uint64_t> perm_pairs;

     po::options_description desc("Options");
     desc.add_options()("help", "produce help message")(
         "L", po::value<uint64_t>(&L), "total number of qubits")(
         "M", po::value<uint64_t>(&M), "number of local qubits")(
         "swap", po::value<std::vector<uint64_t>>(&swap_pairs)->multitoken(),
         "pair to swap")(
         "perm", po::value<std::vector<uint64_t>>(&perm_pairs)->multitoken(),
         "initial permutation by pairs");

     po::variables_map vm;
     po::store(po::parse_command_line(argc, argv, desc), vm);
     po::notify(vm);

     if (vm.count("help")) {
          std::cout << desc << "\n";
          return 0;
     }

     std::cout << boost::format("L: %d, M: %d") % L % M << std::endl;

     printPairs(std::cout, "Current permutation:", perm_pairs);
     printPairs(std::cout, "Do swaps:", swap_pairs);

     auto perm = permuteQubits(naturalOrdering(L), perm_pairs);

     //	auto res = calcSwaps(L, M, inversePermutation(perm), swap_pairs);

     std::vector<uint64_t> swapBits
         = q2bits<uint64_t>(M, swap_pairs, inversePermutation(perm));
     auto res = CalcSwaps<5>::doCalc(L, M, swapBits);

     return res;
}