// Copyright 2019 Peter Dimov.
//
// 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

#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>

using boost::mp11::mp_int;

template<class N> using mod_2 = mp_int<N::value % 2>;
template<class N> using mod_3 = mp_int<N::value % 3>;
template<class N> using mod_6 = mp_int<N::value % 6>;

using boost::mp11::mp_not;
using boost::mp11::mp_plus;

template<class T> using P1 = mp_not<mod_6<T>>;
template<class T1, class... T> using P2 = mp_not<mp_plus<T...>>;

using boost::mp11::mp_bool;

template<std::size_t N> struct second_is
{
    template<class T1, class T2> using fn = mp_bool< T2::value == N >;
};

using boost::mp11::mp_first;
using boost::mp11::mp_filter_q;
using boost::mp11::mp_iota;
using boost::mp11::mp_size;

template<class L, std::size_t N> using at_c = mp_first< mp_filter_q< second_is<N>, L, mp_iota<mp_size<L>> > >;

int main()
{
    using boost::mp11::mp_iota_c;
    using boost::mp11::mp_filter;
    using boost::mp11::mp_list;
    using boost::mp11::mp_size_t;
    using boost::mp11::mp_transform;

    {
        int const N = 12;
        using L1 = mp_iota_c<N>;

        using R1 = mp_filter<P1, L1>;
        BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_list<mp_size_t<0>, mp_size_t<6>>>));

        using L2 = mp_transform<mod_2, L1>;
        using L3 = mp_transform<mod_3, L1>;
        using L6 = mp_transform<mod_6, L1>;

        using R2 = mp_filter<P2, L1, L6>;
        BOOST_TEST_TRAIT_TRUE((std::is_same<R2, mp_list<mp_size_t<0>, mp_size_t<6>>>));

        using R3 = mp_filter<P2, L1, L2, L3>;
        BOOST_TEST_TRAIT_TRUE((std::is_same<R3, mp_list<mp_size_t<0>, mp_size_t<6>>>));
    }

    {
        int const N = 64;
        int const M = 17;

        using L1 = mp_iota_c<N>;
        using R1 = at_c<L1, M>;

        BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_size_t<M>>));
    }

    return boost::report_errors();
}


//==================================================================================================
/*!

  Copyright 2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/constant/oneosqrteps.hpp>
#include <boost/simd/constant/sqrteps.hpp>
#include <boost/simd/as.hpp>
#include <simd_test.hpp>

STF_CASE_TPL( "Check oneosqrteps behavior for integral types"
            , (std::uint8_t)(std::uint16_t)(std::uint32_t)(std::uint64_t)
              (std::int8_t)(std::int16_t)(std::int32_t)(std::int64_t)
            )
{
  using boost::simd::as;
  using boost::simd::detail::oneosqrteps;
  using boost::simd::Oneosqrteps;

  STF_TYPE_IS(decltype(Oneosqrteps<T>()), T);
  STF_EQUAL(Oneosqrteps<T>(), T(1));
  STF_EQUAL(oneosqrteps( as(T{}) ),T(1));
}

STF_CASE_TPL( "Check oneosqrteps behavior for floating types"
            , (double)(float)
            )
{
  using boost::simd::as;
  using boost::simd::detail::oneosqrteps;
  using boost::simd::Oneosqrteps;
  using boost::simd::Sqrteps;

  STF_TYPE_IS(decltype(Oneosqrteps<T>()), T);
  STF_IEEE_EQUAL(Oneosqrteps<T>(), T(1/Sqrteps<T>()));
  STF_IEEE_EQUAL(oneosqrteps( as(T{}) ), T(1/Sqrteps<T>()));
}


#ifndef NET_UTIL_HH_
#define NET_UTIL_HH_

#include <algorithm>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <eigen3/Eigen/Dense>
#include <eigen3/Eigen/Sparse>
#include <vector>

#include "utils/util.hh"

struct network_component_t {
    using Scalar = float;
    using sp_mat_t = Eigen::SparseMatrix<Scalar>;
    using Index = sp_mat_t::Index;

    std::vector<std::string> index2vertex;
    sp_mat_t A;                                 // vertex x vertex
    sp_mat_t Mleft;                             // left vertex x edge
    sp_mat_t Mright;                            // right vertex x edge
    std::vector<std::pair<Index, Index>> Edges; // edges (i,j)
    std::vector<Index> colors;                  // edge colors
};

std::vector<std::shared_ptr<network_component_t>>
read_network_data(const std::string data_file,
                  const std::string color_file,
                  const bool,
                  const double);

template <typename Derived, typename Pair>
int construct_edge_incidence(const Eigen::SparseMatrixBase<Derived> &A,
                             Eigen::SparseMatrixBase<Derived> &Mleft,
                             Eigen::SparseMatrixBase<Derived> &Mright,
                             std::vector<Pair> &edges);

template <typename Data, typename Str2Int, typename Derived>
void read_sparse_pairs(const Data &data,
                       const Str2Int &vertex2index,
                       Eigen::SparseMatrixBase<Derived> &Amat);

template <typename Data, typename Str2Int, typename Graph>
void build_boost_graph(const Data &data, const Str2Int &vertex2index, Graph &G);

template <typename Graph, typename Scalar>
void prune_uninformative_edges(const Graph &gIn, Graph &gOut, const Scalar);

template <typename Data, typename Str2Int, typename Int2Str>
void build_vertex2index(const Data &data,
                        Str2Int &vertex2index,
                        Int2Str &index2vertex);

template <typename Derived, typename OtherDerived, typename Pair>
int construct_incidence_matrices(const Eigen::SparseMatrixBase<Derived> &A,
                                 Eigen::SparseMatrixBase<OtherDerived> &mleft,
                                 Eigen::SparseMatrixBase<OtherDerived> &mright,
                                 std::vector<Pair> &edges);

#include "utils/net_util_impl.hh"

#endif


// Copyright (c) Jeremy Siek 2001, Marc Wintermantel 2002
//
// 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_GRAPH_BANDWIDTH_HPP
#define BOOST_GRAPH_BANDWIDTH_HPP

#include <algorithm> // for std::min and std::max
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/numeric_traits.hpp>

namespace boost
{

template < typename Graph, typename VertexIndexMap >
typename graph_traits< Graph >::vertices_size_type ith_bandwidth(
    typename graph_traits< Graph >::vertex_descriptor i, const Graph& g,
    VertexIndexMap index)
{
    BOOST_USING_STD_MAX();
    using std::abs;
    typedef
        typename graph_traits< Graph >::vertices_size_type vertices_size_type;
    vertices_size_type b = 0;
    typename graph_traits< Graph >::out_edge_iterator e, end;
    for (boost::tie(e, end) = out_edges(i, g); e != end; ++e)
    {
        int f_i = get(index, i);
        int f_j = get(index, target(*e, g));
        b = max BOOST_PREVENT_MACRO_SUBSTITUTION(
            b, vertices_size_type(abs(f_i - f_j)));
    }
    return b;
}

template < typename Graph >
typename graph_traits< Graph >::vertices_size_type ith_bandwidth(
    typename graph_traits< Graph >::vertex_descriptor i, const Graph& g)
{
    return ith_bandwidth(i, g, get(vertex_index, g));
}

template < typename Graph, typename VertexIndexMap >
typename graph_traits< Graph >::vertices_size_type bandwidth(
    const Graph& g, VertexIndexMap index)
{
    BOOST_USING_STD_MAX();
    using std::abs;
    typedef
        typename graph_traits< Graph >::vertices_size_type vertices_size_type;
    vertices_size_type b = 0;
    typename graph_traits< Graph >::edge_iterator i, end;
    for (boost::tie(i, end) = edges(g); i != end; ++i)
    {
        int f_i = get(index, source(*i, g));
        int f_j = get(index, target(*i, g));
        b = max BOOST_PREVENT_MACRO_SUBSTITUTION(
            b, vertices_size_type(abs(f_i - f_j)));
    }
    return b;
}

template < typename Graph >
typename graph_traits< Graph >::vertices_size_type bandwidth(const Graph& g)
{
    return bandwidth(g, get(vertex_index, g));
}

template < typename Graph, typename VertexIndexMap >
typename graph_traits< Graph >::vertices_size_type edgesum(
    const Graph& g, VertexIndexMap index_map)
{
    typedef typename graph_traits< Graph >::vertices_size_type size_type;
    typedef
        typename detail::numeric_traits< size_type >::difference_type diff_t;
    size_type sum = 0;
    typename graph_traits< Graph >::edge_iterator i, end;
    for (boost::tie(i, end) = edges(g); i != end; ++i)
    {
        diff_t f_u = get(index_map, source(*i, g));
        diff_t f_v = get(index_map, target(*i, g));
        using namespace std; // to call abs() unqualified
        sum += abs(f_u - f_v);
    }
    return sum;
}

} // namespace boost

#endif // BOOST_GRAPH_BANDWIDTH_HPP