#include <iostream>
#include <vector>
#include <utility>
#include <iterator>
#include <cstdlib>
#include <limits>
#include <cerrno>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/concept_check.hpp>
#include <boost/operators.hpp>
#include <boost/iterator.hpp>
#include <boost/multi_array.hpp>
#include <boost/random.hpp>

#include <sys/time.h>
#include "../src/edmonds_optimum_branching.hpp"

using namespace std;
using namespace boost;

const char *PNAME =  "test";

// global random number generator
boost::mt19937 g_generator;

// definitions of a complete graph that implements the EdgeListGraph
// concept of Boost's graph library.
namespace boost {
    struct complete_graph {
        complete_graph(int n_vertices) : n_vertices(n_vertices) {}
        int n_vertices;

        struct edge_iterator : public input_iterator_helper<edge_iterator, int, std::ptrdiff_t, int const *, int>
        {
            int edge_idx, n_vertices;

            edge_iterator() : edge_idx(0), n_vertices(-1) {}
            edge_iterator(int n_vertices, int edge_idx) : edge_idx(edge_idx), n_vertices(n_vertices) {}
            edge_iterator &operator++()
            {
                if (edge_idx >= n_vertices * n_vertices)
                    return *this;
                ++edge_idx;
                if (edge_idx / n_vertices == edge_idx % n_vertices)
                    ++edge_idx;
                return *this;
            }
            int operator*() const {return edge_idx;}
            bool operator==(const edge_iterator &iter) const
            {
                return edge_idx == iter.edge_idx;
            }
        };
    };

    template<>
    struct graph_traits<complete_graph> {
        typedef int                             vertex_descriptor;
        typedef int                             edge_descriptor;
        typedef directed_tag                    directed_category;
        typedef disallow_parallel_edge_tag      edge_parallel_category;
        typedef edge_list_graph_tag             traversal_category;
        typedef complete_graph::edge_iterator   edge_iterator;
        typedef unsigned                        edges_size_type;

        static vertex_descriptor null_vertex() {return -1;}
    };

    pair<complete_graph::edge_iterator, complete_graph::edge_iterator>
    edges(const complete_graph &g)
    {
        return make_pair(complete_graph::edge_iterator(g.n_vertices, 1),
                         complete_graph::edge_iterator(g.n_vertices, g.n_vertices*g.n_vertices));
    }

    unsigned
    num_edges(const complete_graph &g)
    {
        return (g.n_vertices - 1) * (g.n_vertices - 1);
    }

    int
    source(int edge, const complete_graph &g)
    {
        return edge / g.n_vertices;
    }

    int
    target(int edge, const complete_graph &g)
    {
        return edge % g.n_vertices;
    }
}

typedef graph_traits<complete_graph>::edge_descriptor Edge;
typedef graph_traits<complete_graph>::vertex_descriptor Vertex;

// is_cyclic()
//
// returns true if the choice of parents for the vertices creates a
// cycle, i.e. if 'parent' does not represent a branching
bool
is_cyclic(const vector<Vertex> &parent)
{
    unsigned size = parent.size();
    vector<bool> visited(size, false);

    for (unsigned i = 0; i < size; ++i)
    {
        if (visited[i])
            continue;

        vector<bool> visited_this_iteration(size, false);
        visited[i] = true;
        visited_this_iteration[i] = true;
        Vertex v = i;
        while (parent[v] != v)
        {
            v = parent[v];
            if (visited_this_iteration[v])
                return true;
            visited_this_iteration[v] = true;
            if (visited[v])
                break;
        }
    }
    return false;
}

// next_parent()
//
// Creates the next lexicographical parent vector. Returns true if the
// the parent returned is not the lexicographically first parent vector.
bool
next_parent(vector<Vertex> &parent)
{
    unsigned size = parent.size();

    bool carry = true;
    unsigned i = 0;
    while (carry && i < size)
    {
        parent[i] += 1;
        if (parent[i] < size)
        {
            carry = false;
        }
        else
        {
            parent[i] = 0;
        }
        ++i;
    }

    return !carry;
}

int
main(int argc, char *argv[])
{
    // Parse and read the command line arguments.
    if (argc != 5)
    {
        cerr << "Usage: " << PNAME
             << " <min-weight> <max-weight> <#vertices> <#tests>\n";
        exit(1);
    }

    long int min_weight = strtol(argv[1], 0, 0);
    long int max_weight = strtol(argv[2], 0, 0);
    long int n_vertices = strtol(argv[3], 0, 0);
    long int n_tests = strtol(argv[4], 0, 0);

    if (errno)
    {
        cerr << "Bad arguments\n";
        exit(1);
    }

    // Check consistency of command line arguments.
    if (n_tests < 0)
    {
        cerr << "the number of tests must be a positive integer\n";
        exit(1);
    }

    if (n_vertices > numeric_limits<unsigned>::digits)
    {
        cerr << "Too many vertices\n"
             << "Maximum n.o. vertices is "
             << numeric_limits<unsigned>::digits << "\n";
        exit(1);
    }

    if (n_vertices < 2)
    {
        cerr << "Too few vertices\n"
             << "must be at least two\n";
        exit(1);
    }

    if (min_weight > max_weight)
    {
        cerr << "min weight must be greater than max weight\n";
        exit(1);
    }

    if (abs(max_weight) >= numeric_limits<int>::max() / n_vertices ||
        abs(min_weight) >= numeric_limits<int>::max() / n_vertices)
    {
        cerr << "weights too large\n";
        exit(1);
    }

    // Initialize the random number generator.
    timeval tv;
    gettimeofday(&tv, 0);
    g_generator.seed(tv.tv_sec * 1000000 + tv.tv_usec);
    boost::uniform_int<int> uniform_int_dist(min_weight, max_weight);
    boost::variate_generator<mt19937, uniform_int<int> > rng_i(g_generator, uniform_int_dist);

    // Perform the tests.
    enum {MAX_SPAN_0, MAX_SPAN_1, MAX_SPAN_2,
          MAX_NOSPAN_0, MAX_NOSPAN_1, MAX_NOSPAN_2,
          MIN_SPAN_0, MIN_SPAN_1, MIN_SPAN_2,
          MIN_NOSPAN_0, MIN_NOSPAN_1, MIN_NOSPAN_2,
          N_CASES};
    string case_names[] = {
        "MAX_SPAN_0", "MAX_SPAN_1", "MAX_SPAN_2",
        "MAX_NOSPAN_0", "MAX_NOSPAN_1", "MAX_NOSPAN_2",
        "MIN_SPAN_0", "MIN_SPAN_1", "MIN_SPAN_2",
        "MIN_NOSPAN_0", "MIN_NOSPAN_1", "MIN_NOSPAN_2"
    };

    complete_graph      g(n_vertices);
    multi_array<int, 2> weights(extents[n_vertices][n_vertices]);
    vector<Vertex>      parent(n_vertices);
    Vertex              roots[] = {0, 1};

    vector<Edge>        branching;
    vector< vector< Edge > > all_branchings(N_CASES);
    vector<int>         ans(N_CASES);

    while (n_tests--)
    {
        // Clear all the branchings from previous iteration.
        BOOST_FOREACH (vector<Edge> &vec, all_branchings)
        {
            vec.clear();
        }

        // create new weights
        int *end = weights.origin() + n_vertices * n_vertices;
        for (int *ip = weights.origin(); ip != end; ++ip)
        {
            *ip = rng_i();
        }

        // run edmonds algorithm for a few cases. The cases will be
        // the cross product of the following properties:
        // optimum-is-maximum x attempt-to-span x num-specified-roots
        // where num-specified roots is either 0, 1, or 2. Also the
        // specified roots are either none, the vertex 0, or the
        // vertices 0 and 1.
        edmonds_optimum_branching<true, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 0, back_inserter(all_branchings[MAX_SPAN_0]));
        edmonds_optimum_branching<true, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 1, back_inserter(all_branchings[MAX_SPAN_1]));
        edmonds_optimum_branching<true, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 2, back_inserter(all_branchings[MAX_SPAN_2]));
        edmonds_optimum_branching<true, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 0, back_inserter(all_branchings[MAX_NOSPAN_0]));
        edmonds_optimum_branching<true, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 1, back_inserter(all_branchings[MAX_NOSPAN_1]));
        edmonds_optimum_branching<true, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 2, back_inserter(all_branchings[MAX_NOSPAN_2]));
        edmonds_optimum_branching<false, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 0, back_inserter(all_branchings[MIN_SPAN_0]));
        edmonds_optimum_branching<false, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 1, back_inserter(all_branchings[MIN_SPAN_1]));
        edmonds_optimum_branching<false, true, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 2, back_inserter(all_branchings[MIN_SPAN_2]));
        edmonds_optimum_branching<false, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 0, back_inserter(all_branchings[MIN_NOSPAN_0]));
        edmonds_optimum_branching<false, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 1, back_inserter(all_branchings[MIN_NOSPAN_1]));
        edmonds_optimum_branching<false, false, true>
            (g, identity_property_map(), weights.origin(),
             roots, roots + 2, back_inserter(all_branchings[MIN_NOSPAN_2]));

        for (int i = 0; i < N_CASES; ++i)
        {
            ans[i] = 0;
            BOOST_FOREACH (Edge e, all_branchings[i])
            {
                ans[i] += weights[source(e, g)][target(e, g)];
            }
        }

        // Exhaustively test all branchings and check if the answers
        // from edmonds's algorithm is optimal.
        int bad_case = -1;
        fill(parent.begin(), parent.end(), 0);
        do
        {
            if (is_cyclic(parent))
                continue;

            int weight = 0;
            for (int i = 0; i < n_vertices; ++i)
            {
                if (parent[i] == i)
                    continue;

                weight += weights[parent[i]][i];
            }

            int num_roots = 0;
            for (int i = 0; i < n_vertices; ++i)
            {
                num_roots += parent[i] == i ? 1 : 0;
            }

            bad_case = MAX_NOSPAN_0;
            if (weight > ans[bad_case])
                break;

            bad_case = MIN_NOSPAN_0;
            if (weight < ans[bad_case])
                break;

            bad_case = MAX_NOSPAN_1;
            if (parent[0] == 0 && weight > ans[bad_case])
                break;

            bad_case = MIN_NOSPAN_1;
            if (parent[0] == 0 && weight < ans[bad_case])
                break;

            bad_case = MAX_NOSPAN_2;
            if (parent[0] == 0 && parent[1] == 1 && weight > ans[bad_case])
                break;

            bad_case = MIN_NOSPAN_2;
            if (parent[0] == 0 && parent[1] == 1 && weight < ans[bad_case])
                break;

            bad_case = MAX_SPAN_0;
            if (num_roots == 1 && weight > ans[bad_case])
                break;

            bad_case = MIN_SPAN_0;
            if (num_roots == 1 && weight < ans[bad_case])
                break;

            bad_case = MAX_SPAN_1;
            if (num_roots == 1 && parent[0] == 0 && weight > ans[bad_case])
                break;

            bad_case = MIN_SPAN_1;
            if (num_roots == 1 && parent[0] == 0 && weight < ans[bad_case])
                break;

            bad_case = MAX_SPAN_2;
            if (num_roots == 1 && parent[0] == 0 && parent[1] == 1 &&
                weight > ans[bad_case])
                break;

            bad_case = MIN_SPAN_2;
            if (num_roots == 1 && parent[0] == 0 && parent[1] == 1 &&
                weight < ans[bad_case])
                break;

            bad_case = -1;
        } while (next_parent(parent));

        // If we broke out of the loop prematurely, then something was
        // wrong.
        if (bad_case > 0)
        {
            cout << "\ntest failed.\n";

            cout << "weights:\n";
            for (int i = 0; i < n_vertices; ++i)
            {
                for (int j = 0; j < n_vertices; ++j)
                {
                    cout << weights[i][j] << " ";
                }
                cout << "\n";
            }
            cout << "\n";

            int weight = 0;
            for (int i = 0; i < n_vertices; ++i)
            {
                if (parent[i] == i)
                    continue;

                weight += weights[parent[i]][i];
            }

            cout << "counter example (weight = " << weight << "):\n";
            for (int i = 0; i < n_vertices; ++i)
            {
                if (parent[i] == i)
                    continue;
                cout << "(" << parent[i] << ", " << i << ")\t";
            }
            cout << "\n";

            weight = 0;
            cout << "case: " << case_names[bad_case] << ":\n";
            BOOST_FOREACH (Edge e, all_branchings[bad_case])
            {
                cout << "(" << source(e, g) << ", " << target(e, g) << ")\t";
                weight += weights[source(e, g)][target(e, g)];
            }
            cout << "\n";
            cout << "weight:\t" << weight << "\n";

            exit(1);
        }
        cerr << ".";
    }
    cerr << "\n";

    return EXIT_SUCCESS;
}


/*
  Copyright (c) 2015 DataStax

  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.
*/

#define BOOST_TEST_DYN_LINK
#ifdef STAND_ALONE
#   define BOOST_TEST_MODULE cassandra
#endif

#include "address.hpp"
#include "md5.hpp"
#include "murmur3.hpp"
#include "token_map.hpp"

#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/random/mersenne_twister.hpp>

#include <limits>

cass::SharedRefPtr<cass::Host> create_host(const std::string& ip) {
  return cass::SharedRefPtr<cass::Host>(new cass::Host(cass::Address(ip, 4092), false));
}

template <class HashType>
struct TestTokenMap {
  typedef HashType(HashFunc)(const std::string& s);
  typedef std::map<HashType, cass::SharedRefPtr<cass::Host> > TokenHostMap;

  TokenHostMap tokens;
  cass::TokenMap token_map;
  cass::SharedRefPtr<cass::ReplicationStrategy> strategy;

  void build(const std::string& partitioner,
             const std::string& ks_name) {
    token_map.set_partitioner(partitioner);

    if (!strategy) {
      strategy =  cass::SharedRefPtr<cass::ReplicationStrategy>(
                    new cass::NonReplicatedStrategy(""));
    }

    token_map.set_replication_strategy(ks_name, strategy);

    for (typename TokenHostMap::iterator i = tokens.begin(); i != tokens.end(); ++i) {
      cass::TokenStringList tokens;
      tokens.push_back(boost::lexical_cast<std::string>(i->first));
      token_map.update_host(i->second, tokens);
    }

    token_map.build();
  }

  void verify(HashFunc hash_func, const std::string& ks_name) {
    for (int i = 0; i < 24; ++i) {
      std::string value(1, 'a' + i);
      const cass::CopyOnWriteHostVec& replicas
          = token_map.get_replicas(ks_name, value);

      HashType hash = hash_func(value);
      typename TokenHostMap::iterator token = tokens.upper_bound(hash);

      if (token != tokens.end()) {
        BOOST_CHECK(replicas->front() == token->second);
      } else {
        BOOST_CHECK(replicas->front() == tokens.begin()->second);
      }
    }
  }
};

BOOST_AUTO_TEST_SUITE(token_map)

int64_t murmur3_hash(const std::string& s) {
  return cass::MurmurHash3_x64_128(s.data(), s.size(), 0);
}

BOOST_AUTO_TEST_CASE(murmur3)
{
  TestTokenMap<int64_t> test_murmur3;

  test_murmur3.tokens[std::numeric_limits<int64_t>::min() / 2] = create_host("1.0.0.1");
  test_murmur3.tokens[0] = create_host("1.0.0.2");
  test_murmur3.tokens[std::numeric_limits<int64_t>::max() / 2] = create_host("1.0.0.3");
  // Anything greater than the last host should be wrapped around to host1

  test_murmur3.build(cass::Murmur3Partitioner::PARTITIONER_CLASS, "test");
  test_murmur3.verify(murmur3_hash, "test");
}

BOOST_AUTO_TEST_CASE(murmur3_multiple_tokens_per_host)
{
  TestTokenMap<int64_t> test_murmur3;

  const size_t tokens_per_host = 256;

  cass::HostVec hosts;
  hosts.push_back(create_host("1.0.0.1"));
  hosts.push_back(create_host("1.0.0.2"));
  hosts.push_back(create_host("1.0.0.3"));
  hosts.push_back(create_host("1.0.0.4"));

  boost::mt19937_64 ng;

  for (cass::HostVec::iterator i = hosts.begin(); i != hosts.end(); ++i) {
    for (size_t j = 0; j < tokens_per_host; ++j) {
      int64_t t = static_cast<int64_t>(ng());
      test_murmur3.tokens[t] = *i;
    }
  }

  test_murmur3.build(cass::Murmur3Partitioner::PARTITIONER_CLASS, "test");
  test_murmur3.verify(murmur3_hash, "test");
}

boost::multiprecision::int128_t random_hash(const std::string& s) {
  cass::Md5 m;
  m.update(reinterpret_cast<const uint8_t*>(s.data()), s.size());
  uint8_t h[16];
  m.final(h);
  std::string hex("0x");
  for (int i = 0; i < 16; ++i) {
    char buf[4];
    sprintf(buf, "%02X", h[i]);
    hex.append(buf);
  }
  return boost::multiprecision::int128_t(hex);
}

BOOST_AUTO_TEST_CASE(random)
{
  TestTokenMap<boost::multiprecision::int128_t> test_random;

  test_random.tokens[boost::multiprecision::int128_t("42535295865117307932921825928971026432")] = create_host("1.0.0.1");  // 2^127 / 4
  test_random.tokens[boost::multiprecision::int128_t("85070591730234615865843651857942052864")] = create_host("1.0.0.2");  // 2^127 / 2
  test_random.tokens[boost::multiprecision::int128_t("1605887595351923798765477786913079296")] = create_host("1.0.0.3"); // 2^127 * 3 / 4
  // Anything greater than the last host should be wrapped around to host1

  test_random.build(cass::RandomPartitioner::PARTITIONER_CLASS, "test");
  test_random.verify(random_hash, "test");
}

std::string byte_ordered_hash(const std::string& s) {
  return s;
}

BOOST_AUTO_TEST_CASE(byte_ordered)
{
  TestTokenMap<std::string> test_byte_ordered;

  test_byte_ordered.tokens["g"] = create_host("1.0.0.1");
  test_byte_ordered.tokens["m"] = create_host("1.0.0.2");
  test_byte_ordered.tokens["s"] = create_host("1.0.0.3");
  // Anything greater than the last host should be wrapped around to host1

  test_byte_ordered.build(cass::ByteOrderedPartitioner::PARTITIONER_CLASS, "test");
  test_byte_ordered.verify(byte_ordered_hash, "test");
}

BOOST_AUTO_TEST_CASE(remove_host)
{
  TestTokenMap<int64_t> test_remove_host;

  test_remove_host.strategy =
      cass::SharedRefPtr<cass::ReplicationStrategy>(new cass::SimpleStrategy("", 2));

  test_remove_host.tokens[std::numeric_limits<int64_t>::min() / 2] = create_host("1.0.0.1");
  test_remove_host.tokens[0] = create_host("1.0.0.2");
  test_remove_host.tokens[std::numeric_limits<int64_t>::max() / 2] = create_host("1.0.0.3");

  test_remove_host.build(cass::Murmur3Partitioner::PARTITIONER_CLASS, "test");

  cass::TokenMap& token_map = test_remove_host.token_map;

  {
    const cass::CopyOnWriteHostVec& replicas
        = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 2);
    BOOST_CHECK((*replicas)[0]->address() == cass::Address("1.0.0.1", 9042));
    BOOST_CHECK((*replicas)[1]->address() == cass::Address("1.0.0.2", 9042));
  }

  TestTokenMap<int64_t>::TokenHostMap::iterator host_to_remove_it = test_remove_host.tokens.begin();

  token_map.remove_host(host_to_remove_it->second);

  {
    const cass::CopyOnWriteHostVec& replicas
        = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 2);
    BOOST_CHECK((*replicas)[0]->address() == cass::Address("1.0.0.2", 9042));
    BOOST_CHECK((*replicas)[1]->address() == cass::Address("1.0.0.3", 9042));
  }

  ++host_to_remove_it;
  token_map.remove_host(host_to_remove_it->second);

  {
    const cass::CopyOnWriteHostVec& replicas
        = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 1);
    BOOST_CHECK((*replicas)[0]->address() == cass::Address("1.0.0.3", 9042));
  }

  ++host_to_remove_it;
  token_map.remove_host(host_to_remove_it->second);

  {
    const cass::CopyOnWriteHostVec& replicas = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 0);
  }
}

BOOST_AUTO_TEST_CASE(drop_keyspace)
{
  TestTokenMap<int64_t> test_drop_keyspace;

  test_drop_keyspace.strategy =
      cass::SharedRefPtr<cass::ReplicationStrategy>(new cass::SimpleStrategy("", 2));

  test_drop_keyspace.tokens[std::numeric_limits<int64_t>::min() / 2] = create_host("1.0.0.1");
  test_drop_keyspace.tokens[0] = create_host("1.0.0.2");
  test_drop_keyspace.tokens[std::numeric_limits<int64_t>::max() / 2] = create_host("1.0.0.3");

  test_drop_keyspace.build(cass::Murmur3Partitioner::PARTITIONER_CLASS, "test");

  cass::TokenMap& token_map = test_drop_keyspace.token_map;

  {
    const cass::CopyOnWriteHostVec& replicas
        = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 2);
    BOOST_CHECK((*replicas)[0]->address() == cass::Address("1.0.0.1", 9042));
    BOOST_CHECK((*replicas)[1]->address() == cass::Address("1.0.0.2", 9042));
  }

  token_map.drop_keyspace("test");

  {
    const cass::CopyOnWriteHostVec& replicas
        = token_map.get_replicas("test", "abc");

    BOOST_REQUIRE(replicas->size() == 0);
  }
}

BOOST_AUTO_TEST_SUITE_END()


/***********************************************************************
Copyright 2018 Gregory Bryant

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 "neview.h"
#include "neconsolewindow.h"
#include <iostream>
#include <sstream>
#include <string>
#include <boost/multiprecision/gmp.hpp>
using boost::multiprecision::mpz_int;
using boost::multiprecision::mpf_float;
using boost::multiprecision::abs;

#define QN(X) QString::number(X)

NEView::NEView(QWidget *parent) : QWidget(parent)
{
    image = new QImage(width(),height(),QImage::Format_RGB32);
    image->fill(Qt::black);
    setFocusPolicy(Qt::StrongFocus);
    xFactorialOffset = 0;
    yFactorialOffset = 0;
    factorialXScrolling=false;
    factorialYScrolling=false;
    yOffset = 0;
    xOffset = 0;
    xScrollAmt=0;
    yScrollAmt=0;
    originalXScrollAmt=0;
    originalYScrollAmt=0;
    scale=1;
    resolution=1;
    showCrossHairs=true;
    showClickPoints=true;
}

void NEView::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawImage(0,0,*image);
}

void NEView::getScreenBounds(mpz_int *top, mpz_int *bottom, mpz_int *left, mpz_int *right)//bounds in terms of points, not pixels
{
    //the plus and minus 1s are to over report the points to draw by one in each dimension
    //this ensures edge points aren't left off due to rounding down when zoomed in

    if(resolution!=1)
    {
        *top = (yOffset+height()-1)/resolution/scale;
        *top += 1;
        *bottom = yOffset/resolution/scale;
        *bottom -= 1;
        *left = xOffset/resolution/scale;
        *left -= 1;
        *right = (xOffset+width()-1)/resolution/scale;
        *right += 1;
        return;
    }
    *top = (yOffset+height()-1)/scale;
    *top += 1;
    *bottom = yOffset/scale;
    *bottom -= 1;
    *left = xOffset/scale;
    *left -= 1;
    *right = (xOffset+width()-1)/scale;
    *right += 1;

}

void NEView::setScale(int scale)
{
    if(scale<=0){scale=1;}
    if(scale>300){scale=300;}
    if(scale>this->scale)
    {
        this->scale=scale;
        mpf_float w = width();
        mpf_float s = scale;
        mpf_float sW = w/(s-1)/2;
        mpf_float h = height();
        mpf_float sH = h/(s-1)/2;
        mpf_float xo = xOffset;
        mpf_float sX = xo/(s-1)*s;
        mpf_float yo = yOffset;
        mpf_float sY = yo/(s-1)*s;

        mpf_float a = sX+sW;
        mpf_float b = sY+sH;

        xOffset = (mpz_int)a;
        yOffset = (mpz_int)b;

        xScrollAmt = xOffset;
        yScrollAmt = yOffset;
    }
    else if(scale<this->scale)
    {
        this->scale=scale;
        mpf_float w = width();
        mpf_float s = scale;
        mpf_float sW = w/(s+1)/2;
        mpf_float h = height();
        mpf_float sH = h/(s+1)/2;
        mpf_float xo = xOffset;
        mpf_float sX = xo/(s+1)*s;
        mpf_float yo = yOffset;
        mpf_float sY = yo/(s+1)*s;

        mpf_float a = sX-sW;
        mpf_float b = sY-sH;

        xOffset = (mpz_int)a;
        yOffset = (mpz_int)b;

        xScrollAmt = xOffset;
        yScrollAmt = yOffset;
    }
}

void NEView::setXPos(mpz_int x)
{
    xScrollAmt=x*scale-width()/2;
    xOffset=xScrollAmt;
}

void NEView::setYPos(mpz_int y)
{
    yScrollAmt=y*scale-height()/2;
    yOffset=yScrollAmt;
}

void NEView::setPoint(mpz_int x, mpz_int y)
{
    yVal = height()-1-(y*scale)+yOffset;
    xVal = (x*scale)-xOffset;

    //we can speed this up by minimizing the use of the mpz types, precompute when possible
    //        and convert to int early if possible!
    //when scale is large everything runs too slow! though faster in debug mode

    if(scale==1)
    {
        if(static_cast<int>(yVal)>0 && static_cast<int>(yVal)<height() && static_cast<int>(xVal)>0 && static_cast<int>(xVal)<width())
        {
            QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)));
            scanLine[static_cast<int>(xVal)]=qRgb(255,255,255);
        }
    }
    else
    {
        for(int j=0;j<scale;j++)
        {
            for(int i=0;i<scale;i++)
            {
                if(static_cast<int>(yVal)+j>0 && static_cast<int>(yVal)+j<height() && static_cast<int>(xVal)+i>0 && static_cast<int>(xVal)+i<width())
                {
                    QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)+j));
                    scanLine[static_cast<int>(xVal)+i]=qRgb(255,255,255);
                }
            }
        }
    }

}

void NEView::setPoint(mpz_int x, mpz_int y, int r, int g, int b)
{
    yVal = height()-1-(y*scale)+yOffset;
    xVal = (x*scale)-xOffset;

    //we can speed this up by minimizing the use of the mpz types, precompute when possible
    //        and convert to int early if possible!
    //when scale is large everything runs too slow! though faster in debug mode

    if(scale==1)
    {
        if(static_cast<int>(yVal)>0 && static_cast<int>(yVal)<height() && static_cast<int>(xVal)>0 && static_cast<int>(xVal)<width())
        {
            QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)));
            scanLine[static_cast<int>(xVal)]=qRgb(r,g,b);
        }
    }
    else
    {
        for(int j=0;j<scale;j++)
        {
            for(int i=0;i<scale;i++)
            {
                if(static_cast<int>(yVal)+j>0 && static_cast<int>(yVal)+j<height() && static_cast<int>(xVal)+i>0 && static_cast<int>(xVal)+i<width())
                {
                    QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)+j));
                    scanLine[static_cast<int>(xVal)+i]=qRgb(r,g,b);
                }
            }
        }
    }

}

void NEView::setPoint(mpf_float x, mpf_float y)
{

    yVal = height()-1-(static_cast<int>(y)*scale*resolution)+yOffset;
    xVal = (static_cast<int>(x)*scale*resolution)-xOffset;

    //we can speed this up by minimizing the use of the mpz types, precompute when possible
    //        and convert to int early if possible!
    //when scale is large everything runs too slow! though faster in debug mode

    if(scale==1)
    {
        if(static_cast<int>(yVal)>0 && static_cast<int>(yVal)<height() && static_cast<int>(xVal)>0 && static_cast<int>(xVal)<width())
        {
            QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)));
            scanLine[static_cast<int>(xVal)]=qRgb(255,255,255);
        }
    }
    else
    {
        for(int j=0;j<scale;j++)
        {
            for(int i=0;i<scale;i++)
            {
                if(static_cast<int>(yVal)+j>0 && static_cast<int>(yVal)+j<height() && static_cast<int>(xVal)+i>0 && static_cast<int>(xVal)+i<width())
                {
                    QRgb *scanLine = reinterpret_cast<QRgb*>(image->scanLine(static_cast<int>(yVal)+j));
                    scanLine[static_cast<int>(xVal)+i]=qRgb(255,255,255);
                }
            }
        }
    }

}

void NEView::render()
{
    image->fill(Qt::black);
    for( int i=0; i<displayObjects.count(); i++ )
    {
        displayObjects[i]->render(this);
    }
    if(showCrossHairs)
    {
        QPainter painter(image);
        painter.setPen(Qt::green);
        painter.setBrush(Qt::green);
        painter.drawLine(0,height()/2,width()-1,height()/2);
        painter.drawLine(width()/2,0,width()/2,height()-1);
    }
}

void NEView::resizeEvent(QResizeEvent *event)
{
    delete image;
    image = new QImage(width(),height(),QImage::Format_RGB32);
    render();
}

void NEView::printScreenPoint(int x, int y)
{
    mpz_int pX = x+xOffset;
    mpf_float fX = pX;
    mpf_float fScale = scale;
    pX.assign(boost::multiprecision::floor(fX/scale));
    std::stringstream pXStream;
    pXStream<<pX;

    mpz_int pY = height()-y+yOffset;
    mpf_float fY = pY;
    pY.assign(boost::multiprecision::ceil(fY/fScale));
    std::stringstream pYStream;
    pYStream<<pY;

    mpz_int pP=pX+(pY/pX);
    std::stringstream pPStream;
    pPStream<<pP;
    //p=x+(y/x)

    consoleWindow->appendText(QString::fromStdString(pXStream.str())+","+QString::fromStdString(pYStream.str())+":"+QString::fromStdString(pPStream.str())+"\n");
}

void NEView::mouseMoveEvent(QMouseEvent *event)
{
    xOffset = originalXOffset+(clickPoint.x()-event->pos().x());
    yOffset = originalYOffset+(event->pos().y()-clickPoint.y());

    xScrollAmt = originalXScrollAmt+(clickPoint.x()-event->pos().x());
    yScrollAmt = originalYScrollAmt+(event->pos().y()-clickPoint.y());

    render();
    update();
}

void NEView::mousePressEvent(QMouseEvent *event)
{
    clickPoint = event->pos();
    originalXOffset = xOffset;
    originalYOffset = yOffset;
    originalXScrollAmt = xScrollAmt;
    originalYScrollAmt = yScrollAmt;
    if(showClickPoints)
    {
        printScreenPoint(clickPoint.x(),clickPoint.y());
    }

}

void NEView::keyPressEvent(QKeyEvent *event)
{
    //float sW,sH,sX,sY;
    //factorial+=1;
    //mpz_fac_ui(yOffset.backend().data(),factorial);
    boost::multiprecision::mpz_int amount;
    switch(event->key())
    {
        case Qt::Key_Space:
        {
            printScreenPoint(width()/2,height()/2);
        }
        break;
        case Qt::Key_Equal:
        {
            if(event->modifiers()&Qt::ControlModifier)
            {
                setScale(scale+1);
                render();
                update();
            }
            else if(event->modifiers()&Qt::AltModifier)
            {
                resolution+=1;
                render();
                update();
            }
        }
        break;
        case Qt::Key_Minus:
        {
            if(event->modifiers()&Qt::ControlModifier)
            {
                setScale(scale-1);
                render();
                update();
            }
            else if(event->modifiers()&Qt::AltModifier)
            {
                resolution-=1;
                if(resolution<1)
                {resolution=1;}
                render();
                update();
            }
        }
        break;
        case Qt::Key_Up:
        {
            amount=10;
            if(event->modifiers()&Qt::ShiftModifier){amount=1;}
            if(event->modifiers()&Qt::ControlModifier){amount=100;}
            if(event->modifiers()&Qt::ControlModifier&&event->modifiers()&Qt::ShiftModifier){amount=500;}
            if(event->modifiers()==Qt::AltModifier)
            {
                yFactorialOffset+=1;
                amount=0;
            }

            if(yFactorialOffset!=0)
            {
                mpz_fac_ui(yOffset.backend().data(),abs(yFactorialOffset));
                if(yFactorialOffset<0){yOffset*=-1;}
            }
            else
            {
                yOffset=0;
            }
            yScrollAmt+=amount;
            yOffset+=yScrollAmt;

            render();
            update();
        }
        break;

    case Qt::Key_Down:
    {
        amount=10;
        if(event->modifiers()&Qt::ShiftModifier){amount=1;}
        if(event->modifiers()&Qt::ControlModifier){amount=100;}
        if(event->modifiers()&Qt::ControlModifier&&event->modifiers()&Qt::ShiftModifier){amount=500;}
        if(event->modifiers()==Qt::AltModifier)
        {
            yFactorialOffset-=1;
            amount=0;
        }

        if(yFactorialOffset!=0)
        {
            mpz_fac_ui(yOffset.backend().data(),abs(yFactorialOffset));
            if(yFactorialOffset<0){yOffset*=-1;}

        }
        else
        {
            yOffset=0;
        }
        yScrollAmt-=amount;
        yOffset+=yScrollAmt;

        render();
        update();
    }
    break;

    case Qt::Key_Left:
    {
        amount=10;
        if(event->modifiers()&Qt::ShiftModifier){amount=1;}
        if(event->modifiers()&Qt::ControlModifier){amount=100;}
        if(event->modifiers()&Qt::ControlModifier&&event->modifiers()&Qt::ShiftModifier){amount=500;}
        if(event->modifiers()==Qt::AltModifier)
        {
            xFactorialOffset-=1;
            amount=0;
        }

        if(xFactorialOffset!=0)
        {
            mpz_fac_ui(xOffset.backend().data(),abs(xFactorialOffset));
            if(xFactorialOffset<0){xOffset*=-1;}
        }
        else
        {
            xOffset=0;
        }
        xScrollAmt-=amount;
        xOffset+=xScrollAmt;

        render();
        update();
    }
    break;

    case Qt::Key_Right:
    {
        amount=10;
        if(event->modifiers()&Qt::ShiftModifier){amount=1;}
        if(event->modifiers()&Qt::ControlModifier){amount=100;}
        if(event->modifiers()&Qt::ControlModifier&&event->modifiers()&Qt::ShiftModifier){amount=500;}
        if(event->modifiers()==Qt::AltModifier)
        {
            xFactorialOffset+=1;
            amount=0;
        }

        if(xFactorialOffset!=0)
        {
            mpz_fac_ui(xOffset.backend().data(),abs(xFactorialOffset));
            if(xFactorialOffset<0){xOffset*=-1;}
        }
        else
        {
            xOffset=0;
        }
        xScrollAmt+=amount;
        xOffset+=xScrollAmt;

        render();
        update();
    }
    break;

    case Qt::Key_Escape:
    {
       scale=1;
       resolution=1;
       xOffset=0;
       yOffset=0;
       xScrollAmt=0;
       yScrollAmt=0;
       xFactorialOffset=0;
       yFactorialOffset=0;
       render();
       update();
    }
    break;
    }
}


/**
 * @file calc-jump.cpp
 *
 * @brief calc jump function.
 *
 * This program calculates jump polynomial from the specified jump steps
 * and a characteristic polynomial calculated by mtgp32-calc-poly or
 * mtgp64-calc-poly.
 *
 * This program need NTL to compile.
 *
 * usage:

 * mtgp-calc-jump [-a] jump-step poly-file

 *   -a       : output array format

 *              without -a output will be in string format

 *   jump-step: a number between zero and 2^{MTGP_MEXP}-1.

 *              large decimal number is allowed.

 *   poly-file: output of mtgp32-calc-poly or mtgp64-calc-poly

 *
 * @author Mutsuo Saito (Hiroshima University)
 * @author Makoto Matsumoto (The University of Tokyo)
 *
 * Copyright (C) 2012 Mutsuo Saito, Makoto Matsumoto,
 * Hiroshima University and The University of Tokyo.
 * All rights reserved.
 *
 * The 3-clause BSD License is applied to this software, see
 * LICENSE.txt
 */
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include <string.h>
#include <inttypes.h>
#include <stdint.h>
#include <time.h>
#include <NTL/GF2X.h>
#include <NTL/vec_GF2.h>
#include <NTL/ZZ.h>
#include "mtgp-calc-jump.hpp"

using namespace NTL;
using namespace std;

static void read_file(GF2X& lcmpoly, long line_no, const string& file);

/**
 * show usage
 * @param name program name
 */
static void usage(char * name) {
    cout << name << " [-a] jump-step poly-file" << endl;
    cout << "    -a       : output array format" << endl;
    cout << "    jump-step: a number between zero and 2^{MTGP_MEXP}-1.\n"
	 << "               large decimal number is allowed." << endl;
    cout << "    poly-file: output of calc-poly"
	 << "file" << endl;
}

/**
 * main function
 * @param argc number of arguments
 * @param argv an array of arguments
 * @return -1 if error, 0 if normal
 */
int main(int argc, char * argv[]) {
    if (argc <= 2) {
	usage(argv[0]);
	return -1;
    }
    int offset = 0;
    if (strcmp(argv[1],"-a") == 0) {
	if (argc <= 3) {
	    usage(argv[0]);
	    return -1;
	}
	offset = 1;
    }
    string step_string = argv[offset + 1];
    string filename = argv[offset + 2];
    long no = 0;
    GF2X lcmpoly;
    read_file(lcmpoly, no, filename);
    long degree = deg(lcmpoly);
    ZZ step;
    stringstream ss(step_string);
    ss >> step;
    if (offset == 0) {
	string jump_str;
	calc_jump(jump_str, step, lcmpoly);
#if defined(DEBUG)
	cout << "deg lcmpoly:" << dec << deg(lcmpoly) << endl;
#endif
	cout << "jump polynomial:" << endl;
	cout << jump_str << endl;
    } else {
	int size = degree / 32 + 1;
	uint32_t array[size];
	calc_jump(array, size, step, lcmpoly);
	cout << "/* jump step:" << step_string << " */" << endl;
	cout << "uint32_t jump_array[] = {";
	for (int i = 0; i < size; i++) {
	    if (i % 5 == 0) {
		cout << endl;
	    }
	    cout << "0x" << setfill('0') << setw(8) << hex << array[i]
		 << ",";
	}
	cout << endl;
	cout << "};" << endl;
    }
    return 0;
}

/**
 * read characteristic polynomial from file.
 * @param[out] characteristic characteristic polynomial
 * @param[in] line_no number of line in file if the file contains
 * multiple polynomials.
 * @param[in] file file name of characteristic polynomial
 */
static void read_file(GF2X& characteristic, long line_no, const string& file)
{
    ifstream ifs(file.c_str());
    string line;
    for (int i = 0; i < line_no; i++) {
	getline(ifs,line);
	getline(ifs,line);
    }
    if (ifs) {
	getline(ifs,line);
	line = "";
	getline(ifs,line);
    }
    stringtopoly(characteristic, line);
}


#include <boost/math/constants/constants.hpp>
#include <Eigen/Dense>

#include <TMath.h>

#include "IbdInteraction.hh"
#include "IbdFirstOrder.hh"
#include "PDGVariables.hh"
#include "TypesFunctions.hh"

#include "ParametricLazy.hpp"

const double pi = boost::math::constants::pi<double>();

using namespace Eigen;

IbdFirstOrder::IbdFirstOrder()
{
  transformation_("Enu")
    .input("Ee")
    .input("ctheta")
    .types(TypesFunctions::toMatrix<0,1,0>)
    .output("Enu")
    .func(&IbdFirstOrder::calc_Enu);
  transformation_("xsec")
    .input("Enu")
    .input("ctheta")
    .types(TypesFunctions::pass<0>,TypesFunctions::ifNd<0,2>)
    .output("xsec")
    .func(&IbdFirstOrder::calc_Xsec);
  transformation_("jacobian")
    .input("Enu")
    .input("Ee")
    .input("ctheta")
    .types(TypesFunctions::pass<0>)
    .output("jacobian")
    .func(&IbdFirstOrder::calc_dEnu_wrt_Ee);
  PDGVariables *p = m_pdg;
  {
    using namespace ParametricLazyOps;

    ElectronMass2 = mkdep(Pow(p->ElectronMass, 2));
    NeutronMass2 = mkdep(Pow(p->NeutronMass, 2));
    ProtonMass2 = mkdep(Pow(p->ProtonMass, 2));

    y2 = mkdep((Pow(m_DeltaNP, 2)-ElectronMass2)*0.5);
  }
}

void IbdFirstOrder::calc_Enu(FunctionArgs fargs) {
  const auto &Ee = fargs.args[0].x;
  const auto &ctheta = fargs.args[1].x;

  ArrayXd r = Ee / m_pdg->ProtonMass;
  ArrayXd Ve = (1.0 - ElectronMass2 / Ee.square()).sqrt();
  std::transform(Ve.data(), Ve.data() + Ve.size(), Ve.data(),
                [](double E){return (!std::isnan(E) ? E : 0.);});
  ArrayXd Ee0 = Ee + (NeutronMass2-ProtonMass2-ElectronMass2)/m_pdg->ProtonMass*0.5;
  ArrayXXd corr = (1.0-(1.0-(Ve.matrix()*ctheta.matrix().transpose()).array()).colwise()*r).inverse();
  fargs.rets[0].arr2d = corr.colwise()*Ee0;
}

double IbdFirstOrder::Xsec(double Eneu, double ctheta) {
  double Ee0 = Eneu - m_DeltaNP;
  if ( Ee0<=m_pdg->ElectronMass ) return 0.0;
  double pe0 = std::sqrt(Ee0*Ee0 - ElectronMass2);
  double ve0 = pe0 / Ee0;
  double ElectronMass5 = ElectronMass2 * ElectronMass2 * m_pdg->ElectronMass;
  double sigma0 = 2.* pi * pi /
    (PhaseFactor*(fsq+3.*gsq)*ElectronMass5*m_pdg->NeutronLifeTime/(1.E-6*TMath::Hbar()/TMath::Qe()));

  double Ee1 = Ee0 * ( 1.0 - Eneu/m_NucleonMass * ( 1.0 - ve0*ctheta ) ) - y2/m_NucleonMass;
  if (Ee1 <= m_pdg->ElectronMass) return 0.0;
  double pe1 = std::sqrt( Ee1*Ee1 - ElectronMass2 );
  double ve1 = pe1/Ee1;

  double sigma1a = sigma0*0.5 * ( ( fsq + 3.*gsq ) + ( fsq - gsq ) * ve1 * ctheta ) * Ee1 * pe1;

  double gamma_1 = 2.0 * g * ( f + f2 ) * ( ( 2.0 * Ee0 + m_DeltaNP ) * ( 1.0 - ve0 * ctheta ) - ElectronMass2/Ee0 );
  double gamma_2 = ( fsq + gsq ) * ( m_DeltaNP * ( 1.0 + ve0*ctheta ) + ElectronMass2/Ee0 );
  double A = ( ( Ee0 + m_DeltaNP ) * ( 1.0 - ctheta/ve0 ) - m_DeltaNP );
  double gamma_3 = ( fsq + 3.0*gsq )*A;
  double gamma_4 = ( fsq -     gsq )*A*ve0*ctheta;

  double sigma1b = -0.5 * sigma0 * Ee0 * pe0 * ( gamma_1 + gamma_2 + gamma_3 + gamma_4 ) / m_NucleonMass;

  return sigma1a + sigma1b;
}

void IbdFirstOrder::calc_Xsec(FunctionArgs fargs) {
  const auto &Eneu = fargs.args[0].arr2d;
  const auto &ctheta = fargs.args[1].x;
  auto &xsec = fargs.rets[0].arr2d;

  const double MeV2J = 1.E6 * TMath::Qe();
  const double J2MeV = 1./MeV2J;

  const double MeV2cm = pow(TMath::Hbar()*TMath::C()*J2MeV, 2) * 1.E4;

  for (int i = 0; i < Eneu.rows(); ++i) {
    for (int j = 0; j < Eneu.cols(); ++j) {
      xsec(i, j) = MeV2cm * Xsec(Eneu(i, j), ctheta(j));
    }
  }
}

void IbdFirstOrder::calc_dEnu_wrt_Ee(FunctionArgs fargs) {
  auto& args=fargs.args;
  const auto &Enu = args[0].arr2d;
  const auto &Ee = args[1].x;
  const auto &ctheta = args[2].x;
  auto& jacobian = fargs.rets[0].arr2d;

  ArrayXd Ve = (1.0 - ElectronMass2 / (Ee*Ee)).sqrt();
  ArrayXXd Vectheta = (Ve.matrix()*ctheta.matrix().transpose()).array();
  ArrayXXd ctheta_per_Ve = (Ve.inverse().matrix()*ctheta.matrix().transpose()).array();
  jacobian = (m_pdg->ProtonMass + (1.0-ctheta_per_Ve)*Enu )/( m_pdg->ProtonMass - (1-Vectheta).colwise()*Ee );
  std::transform(jacobian.data(), jacobian.data() + jacobian.size(), jacobian.data(),
                [](double E){return (std::isfinite(E) ? E : 0.);}); // FIXME: should be done by using proper Views
}


/*
 * Copyright (c) 2009 Carnegie Mellon University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://www.graphlab.ml.cmu.edu
 *
 */

#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <boost/unordered_map.hpp>
#include <time.h>

#include <graphlab.hpp>
#include <graphlab/graph/distributed_graph.hpp>

struct vdata {
  uint64_t labelid;
  vdata() :
      labelid(0) {
  }

  void save(graphlab::oarchive& oarc) const {
    oarc << labelid;
  }
  void load(graphlab::iarchive& iarc) {
    iarc >> labelid;
  }
};

typedef graphlab::distributed_graph<vdata, graphlab::empty> graph_type;

//set label id at vertex id
void initialize_vertex(graph_type::vertex_type& v) {
  v.data().labelid = v.id();
}

//message where summation means minimum
struct min_message {
  uint64_t value;
  explicit min_message(uint64_t v) :
      value(v) {
  }
  min_message() :
      value(std::numeric_limits<uint64_t>::max()) {
  }
  min_message& operator+=(const min_message& other) {
    value = std::min<uint64_t>(value, other.value);
    return *this;
  }

  void save(graphlab::oarchive& oarc) const {
    oarc << value;
  }
  void load(graphlab::iarchive& iarc) {
    iarc >> value;
  }
};

class label_propagation: public graphlab::ivertex_program<graph_type, size_t,
    min_message>, public graphlab::IS_POD_TYPE {
private:
  size_t recieved_labelid;
  bool perform_scatter;
public:
  label_propagation() {
    recieved_labelid = std::numeric_limits<size_t>::max();
    perform_scatter = false;
  }

  //receive messages
  void init(icontext_type& context, const vertex_type& vertex,
      const message_type& msg) {
    recieved_labelid = msg.value;
  }

  //do not gather
  edge_dir_type gather_edges(icontext_type& context,
      const vertex_type& vertex) const {
    return graphlab::NO_EDGES;
  }
  size_t gather(icontext_type& context, const vertex_type& vertex,
      edge_type& edge) const {
    return 0;
  }

  //update label id. If updated, scatter messages
  void apply(icontext_type& context, vertex_type& vertex,
      const gather_type& total) {
    if (recieved_labelid == std::numeric_limits<size_t>::max()) {
      perform_scatter = true;
    } else if (vertex.data().labelid > recieved_labelid) {
      perform_scatter = true;
      vertex.data().labelid = recieved_labelid;
    }
  }

  edge_dir_type scatter_edges(icontext_type& context,
      const vertex_type& vertex) const {
    if (perform_scatter)
      return graphlab::ALL_EDGES;
    else
      return graphlab::NO_EDGES;
  }

  //If a neighbor vertex has a bigger label id, send a massage
  void scatter(icontext_type& context, const vertex_type& vertex,
      edge_type& edge) const {
    if (edge.source().id() != vertex.id()
        && edge.source().data().labelid > vertex.data().labelid) {
      context.signal(edge.source(), min_message(vertex.data().labelid));
    }
    if (edge.target().id() != vertex.id()
        && edge.target().data().labelid > vertex.data().labelid) {
      context.signal(edge.target(), min_message(vertex.data().labelid));
    }
  }
};

class graph_writer {
public:
  std::string save_vertex(graph_type::vertex_type v) {
    std::stringstream strm;
    strm << v.id() << "," << v.data().labelid << "\n";
    return strm.str();
  }
  std::string save_edge(graph_type::edge_type e) {
    return "";
  }
};

int main(int argc, char** argv) {
  std::cout << "Connected Component\n\n";

  graphlab::mpi_tools::init(argc, argv);
  graphlab::distributed_control dc;
  global_logger().set_log_level(LOG_INFO);
  //parse options
  graphlab::command_line_options clopts("Connected Component.");
  std::string graph_dir;
  std::string saveprefix;
  std::string format = "adj";
  std::string exec_type = "synchronous";
  clopts.attach_option("graph", graph_dir,
                       "The graph file. This is not optional");
  clopts.add_positional("graph");
  clopts.attach_option("format", format,
                       "The graph file format");
  clopts.attach_option("engine", exec_type,
                       "The engine type synchronous or asynchronous");
  clopts.attach_option("saveprefix", saveprefix,
                       "If set, will save the pairs of a vertex id and "
                       "a component id to a sequence of files with prefix "
                       "saveprefix");
  if (!clopts.parse(argc, argv)) {
    dc.cout() << "Error in parsing command line arguments." << std::endl;
    return EXIT_FAILURE;
  }
  if (graph_dir == "") {
    std::cout << "--graph is not optional\n";
    return EXIT_FAILURE;
  }

  //load graph
  dc.cout() << "Loading graph in format: "<< format << std::endl;
  graphlab::timer timer;
  graph_type graph(dc, clopts);
  graph.load_format(graph_dir, format);
  const double loading = timer.current_time();
  dc.cout() << "Loading graph. Finished in "
            << loading << std::endl;

  dc.cout() << "Finalizing graph." << std::endl;
  timer.start();
  graph.finalize();
  const double finalizing = timer.current_time();
  dc.cout() << "Finalizing graph. Finished in "
            << finalizing << std::endl;

  // NOTE: ingress time = loading time + finalizing time
  const double ingress = loading + finalizing;
  dc.cout() << "Final Ingress (second): " << ingress << std::endl;

  dc.cout() << "#vertices: " << graph.num_vertices()
            << " #edges:" << graph.num_edges() << std::endl;

  // init
  graph.transform_vertices(initialize_vertex);

  //running the engine
  graphlab::omni_engine<label_propagation> engine(dc, graph, exec_type, clopts);
  engine.signal_all();
  timer.start();
  engine.start();

  const double runtime = timer.current_time();
  dc.cout() << "----------------------------------------------------------"
            << std::endl
            << "Final Runtime (seconds):   " << runtime
            << std::endl
            << "Updates executed: " << engine.num_updates() << std::endl
            << "Update Rate (updates/second): "
            << engine.num_updates() / runtime << std::endl;

  //write results
  if (saveprefix.size() > 0) {
    graph.save(saveprefix, graph_writer(),
        false, //set to true if each output file is to be gzipped
        true, //whether vertices are saved
        false); //whether edges are saved
  }

  graphlab::mpi_tools::finalize();

  return EXIT_SUCCESS;
}


/*
// Copyright 2018 University of Liege
//
// 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.
//
// Authors:
// - Adrien Crovato
*/

//// Pre-processing
// Load settings and geometry from external files *.cfg and *.pts (located in /IO/)
// Store information into relevant structures
//
// Inputs:
// - arvg: command line argument provided to main (contains path to config and grid files)
// - numC: list of numerical parameters (structure)
// - symY: defines symmetry about Y axis
// - sRef: reference surface of the full wing
// - Minf: freestream Mach number
// - alpha: freestream angle of attack
// - vInf: freestream velocity vector
// - bPan: (network of) body panels (structure)
// - wPan: (network of) wake panels (structure)
// - fPan: field panels (structure)
// Outputs:
// - 0, if function succeeded
// - 1, if function failed

#include <iostream>
#include <array>
#include <Eigen/Dense>

#include "pre.h"
#include "read_config.h"
#include "read_sgrid.h"
#include "create_panel.h"
#include "create_wake.h"
#include "create_field.h"
#include "map_field.h"
#include "map_derivatives.h"

#define ANSI_COLOR_BLUE    "\x1b[1;34m"
#define ANSI_COLOR_RESET   "\x1b[0m"

using namespace std;
using namespace Eigen;

int pre(char *argv[], Numerical_CST &numC, bool &symY, double &sRef, double &machInf, double &AoA, Vector3d &vInf,
        Network &bPan, Network &wPan, Field &fPan, Subpanel &sp) {

    //// Initialization
    // Temporary arrays to store grid information
    array<array<double, 3>, 8> box{}; // Corner points defining domain
    MatrixX3d sGrid ; // Surface grid corner points

    // Path definition
    string configParamPath = argv[1];
    string surfGridPath = argv[2];

    //// Begin preprocessing
    cout << ANSI_COLOR_BLUE;
    cout << "*****************************" << endl;
    cout << "*Beginning pre-processing...*" << endl;
    cout << "*****************************";
    cout << ANSI_COLOR_RESET << endl;

    // Read config and grid from files
    read_config(configParamPath, numC, symY, sRef, machInf, AoA, box, fPan, sp);
    read_sgrid(surfGridPath, sGrid, bPan);

    // Set freestream velocity and speed of sound
    vInf(0) = cos(AoA);
    vInf(1) = 0;
    vInf(2) = sin(AoA);

    // Create surface grid
    create_panel(sGrid, bPan);
    create_wake(sGrid, bPan, wPan);

    // Create volume grid, map cells and derivatives
    create_field(box, fPan);
    map_field(sGrid, numC, bPan, fPan);
    map_derivatives(sGrid, numC, bPan, wPan, fPan);

    //// End preprocessing
    cout << ANSI_COLOR_BLUE;
    cout << "****************************" << endl;
    cout << "*Pre-processing successful!*" << endl;
    cout << "****************************";
    cout << ANSI_COLOR_RESET << endl;
    return 0;
}


/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#define BOOST_TEST_MODULE MaterialPropertyValues

#include "main.cc"

#include <cap/geometry.h>
#include <cap/mp_values.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/base/quadrature_lib.h>

BOOST_AUTO_TEST_CASE(fe_values)
{
  // MPValues::get_values has recently changed and takes fe_values instead of
  // cell.  Here we check that if the cell material_id changes, we do not need
  // to call fe_values.reinit(cell) again.  This is more intended to make sure
  // we understand how dealii::FEValues behaves than to actually test anything.
  int constexpr dim = 3;
  dealii::Triangulation<dim> triangulation;
  dealii::GridGenerator::hyper_cube(triangulation);
  dealii::FE_Q<dim> fe(1);
  dealii::DoFHandler<dim> dof_handler(triangulation);
  dof_handler.distribute_dofs(fe);
  dealii::DoFHandler<dim>::active_cell_iterator cell =
      dof_handler.begin_active();
  dealii::FEValues<dim> fe_values(fe, dealii::QGauss<dim>(1),
                                  dealii::update_default);
  fe_values.reinit(cell);
  BOOST_TEST(cell->material_id() != 99);
  BOOST_TEST(fe_values.get_cell()->material_id() != 99);
  cell->set_material_id(99);
  BOOST_TEST(cell->material_id() == 99);
  BOOST_TEST(fe_values.get_cell()->material_id() == 99);
}

// space varying material property built on top of dealii::Function<dim>
BOOST_AUTO_TEST_CASE(function_space, *boost::unit_test::tolerance(1e-15))
{
  int constexpr dim = 2;
  std::shared_ptr<cap::MPValues<dim>> mp_values;

  // make a dummy triangulation to get an active cell iterator
  dealii::Triangulation<dim> triangulation;
  dealii::GridGenerator::hyper_cube(triangulation);
  dealii::FE_Q<dim> fe(1);
  dealii::DoFHandler<dim> dof_handler(triangulation);
  dof_handler.distribute_dofs(fe);
  dealii::DoFHandler<dim>::active_cell_iterator cell =
      dof_handler.begin_active();

  std::vector<dealii::Point<dim>> points = {{0, 0}, {0, 1}, {0.5, 0.5}, {1, 1}};
  // NOTE: I tried with dealii::update_default but I got a memory access
  // violation instead of some deal.II exception as I expected...
  // I was using deal.II in release mode.
  dealii::FEValues<dim> fe_values(fe, dealii::Quadrature<dim>(points),
                                  dealii::update_quadrature_points);
  fe_values.reinit(cell);

  boost::property_tree::ptree ptree;
  BOOST_CHECK_THROW(std::make_shared<cap::FunctionSpaceMPValues<dim>>(ptree),
                    boost::property_tree::ptree_bad_path);
  ptree.put("expression", "2*x");
  mp_values = std::make_shared<cap::FunctionSpaceMPValues<2>>(ptree);
  // in the same way as UniformConstantMPValues, the key is ignored when calling
  // get_values()
  auto const key = "key does not matter";
  std::vector<double> values;
  values.resize(points.size());
  mp_values->get_values(key, fe_values, values);
  for (std::size_t p = 0; p < points.size(); ++p)
    BOOST_TEST(values[p] == 2 * points[p][0]);
  //  BOOST_CHECK_THROW(mp_values->get_values(key, fe_values, values),
  //                    dealii::ExceptionBase);

  ptree.clear();
  ptree.put("variables", "x0,x1");
  ptree.put("expression", "cos(pi*x1)");
  ptree.put("constants", "pi=3.1415926535897932384");
  mp_values = std::make_shared<cap::FunctionSpaceMPValues<2>>(ptree);
  mp_values->get_values(key, fe_values, values);
  for (std::size_t p = 0; p < points.size(); ++p)
    BOOST_TEST(values[p] == boost::math::cos_pi(points[p][1]));
}

// demonstrate how unifom constant and composite properties are used
BOOST_AUTO_TEST_CASE(mp_values)
{
  int constexpr dim = 2;
  std::shared_ptr<cap::MPValues<dim>> mp_values;

  // make a dummy triangulation to get an active cell iterator
  dealii::Triangulation<dim> triangulation;
  dealii::GridGenerator::hyper_cube(triangulation);
  dealii::FE_Q<dim> fe(1);
  dealii::DoFHandler<dim> dof_handler(triangulation);
  dof_handler.distribute_dofs(fe);
  dealii::DoFHandler<dim>::active_cell_iterator cell =
      dof_handler.begin_active();
  dealii::FEValues<dim> fe_values(fe, dealii::QGauss<dim>(1),
                                  dealii::update_default);
  fe_values.reinit(cell);

  // create a vector
  std::vector<double> values;
  // note that `MPValues::get_values(...)` does not allocate memory.
  // the user is responsible for passing `values` with the right size.
  values.resize(fe_values.get_quadrature().size());

  // build a constant uniform property
  double const value = 3.14;
  mp_values = std::make_shared<cap::UniformConstantMPValues<dim>>(value);

  // key property name is ignored for constant uniform property
  mp_values->get_values("doesnotmatter", fe_values, values);
  // all constant uniform property do is a `std::fill(...)`
  for (auto const &v : values)
    BOOST_TEST(v == value);

  // define a custom composite property
  class MyCompositeProMPValues : public cap::CompositePro<2>
  {
  public:
    MyCompositeProMPValues()
    {
      for (auto const &x : _map)
        (this->_properties)
            .emplace(x.first, std::make_shared<cap::UniformConstantMPValues<2>>(
                                  x.second));
    }
    std::map<std::string, double> _map = {{"foo", 1.0}, {"bar", 2.0}};
  };

  // build it
  mp_values = std::make_shared<MyCompositeProMPValues>();

  // if the property is not registered in the `this->_properties` map an
  // exception will be thrown
  BOOST_CHECK_THROW(mp_values->get_values("notregistered", fe_values, values),
                    std::runtime_error);

  // the composite property just redirects the call
  for (auto const &x :
       std::dynamic_pointer_cast<MyCompositeProMPValues>(mp_values)->_map)
  {
    mp_values->get_values(x.first, fe_values, values);
    for (auto const &v : values)
      BOOST_TEST(v == x.second);
  }

  // define another custom composite property
  // this time the map is based on `material_id`s
  class MyCompositeMatMPValues : public cap::CompositeMat<2>
  {
  public:
    MyCompositeMatMPValues()
    {
      for (auto const &x : _map)
        (this->_materials)
            .emplace(x.first, std::make_shared<cap::UniformConstantMPValues<2>>(
                                  x.second));
    }
    std::map<dealii::types::material_id, double> _map = {
        {3, 3.0}, {4, 4.0}, {5, 5.0}};
  };

  // build it
  mp_values = std::make_shared<MyCompositeMatMPValues>();

  // if the material is not registered in the `this->_materials` map an
  // exception will be thrown
  cell->set_material_id(1);
  BOOST_CHECK_THROW(mp_values->get_values("willbeignored", fe_values, values),
                    std::runtime_error);

  // the composite property just redirects the call
  for (auto const &x :
       std::dynamic_pointer_cast<MyCompositeMatMPValues>(mp_values)->_map)
  {
    cell->set_material_id(x.first);
    mp_values->get_values("", fe_values, values);
    for (auto const &v : values)
      BOOST_TEST(v == x.second);
  }
}

BOOST_AUTO_TEST_CASE(test_mp_values_throw)
{
  // ensure missing database will not segfault
  BOOST_CHECK_THROW(cap::SuperCapacitorMPValuesFactory<2>::build(
                        cap::MPValuesParameters<2>(nullptr)),
                    std::runtime_error);

  // same if geometry is missing
  auto empty_database = std::make_shared<boost::property_tree::ptree>();
  BOOST_CHECK_THROW(cap::SuperCapacitorMPValuesFactory<2>::build(
                        cap::MPValuesParameters<2>(empty_database)),
                    std::runtime_error);
}

BOOST_AUTO_TEST_CASE(test_inhomogenous_mp_values)
{
  boost::mpi::communicator world;

  // Use the standard input to build a SuperCapacitor
  boost::property_tree::ptree ptree;
  boost::property_tree::read_info("super_capacitor.info", ptree);

  // Extract the section for the material properties
  auto database = std::make_shared<boost::property_tree::ptree>(
      ptree.get_child("material_properties"));

  // Create an standard homogeneous SuperCapacitorMPValues using the build(...)
  // method which is static.
  cap::MPValuesParameters<2> params(database);
  params.geometry = std::make_shared<cap::Geometry<2>>(
      std::make_shared<boost::property_tree::ptree>(
          ptree.get_child("geometry")),
      world);
  std::shared_ptr<cap::MPValues<2>> mp_values =
      cap::SuperCapacitorMPValuesFactory<2>::build(params);
  BOOST_TEST(
      std::dynamic_pointer_cast<cap::SuperCapacitorMPValues<2>>(mp_values));

  // Now modify the material properties database to create the inhomogeneous
  // version of the MPValues.
  database->put("inhomogeneous", true);
  // NOTE: if parameters == 0, SuperCapacitorMPValues::build(...) still
  // instancies the map cell_id -> MPValues but the computation should be
  // identical to the homogeneous case that has a map material_id -> MPValues
  database->put("parameters", 2);
  database->put("parameter_0.path", "separator_material.void_volume_fraction");
  database->put("parameter_0.distribution_type", "uniform");
  database->put("parameter_0.range", "0.55, 0.65");
  database->put("parameter_1.path", "electrode_material.void_volume_fraction");
  database->put("parameter_1.distribution_type", "normal");
  database->put("parameter_1.mean", "0.67");
  database->put("parameter_1.standard_deviation", "0.04");
  database->put("parameter_2.path",
                "electrode_material.pores_characteristic_dimension");
  database->put("parameter_2.distribution_type", "lognormal");
  database->put("parameter_2.mean", "1.5e-7");
  database->put("parameter_2.standard_deviation", "4.5e-7");
  mp_values = cap::SuperCapacitorMPValuesFactory<2>::build(params);
  BOOST_TEST(
      std::dynamic_pointer_cast<cap::InhomogeneousSuperCapacitorMPValues<2>>(
          mp_values));

  // Check that an exception is thrown if the same path is registered for
  // multiple parameters.
  database->put("parameter_1.path", "separator_material.void_volume_fraction");
  BOOST_CHECK_THROW(cap::SuperCapacitorMPValuesFactory<2>::build(params),
                    std::runtime_error);
  // Undo it.
  database->put("parameter_1.path", "electrode_material.void_volume_fraction");
  BOOST_CHECK_NO_THROW(cap::SuperCapacitorMPValuesFactory<2>::build(params));

  // Check that an exception is thrown the parameter path does not already exist
  // in the database. It most likely means that it is typo and we want to catch
  // that.
  database->put("parameter_0.path", "electrode_material.does_not_exist");
  BOOST_CHECK_THROW(cap::SuperCapacitorMPValuesFactory<2>::build(params),
                    std::runtime_error);
}

BOOST_AUTO_TEST_CASE(custom_liquid_electrical_conductivity)
{
  boost::mpi::communicator world;

  // Use the standard input to build a SuperCapacitor
  boost::property_tree::ptree ptree;
  boost::property_tree::read_info("super_capacitor.info", ptree);

  // Extract the section for the material properties
  auto database = std::make_shared<boost::property_tree::ptree>(
      ptree.get_child("material_properties"));

  // Use expression for the liquid electrical conductivity
  std::string prefix =
      "separator_material.custom_liquid_electrical_conductivity.";
  database->put(prefix + "constants", "pi=3.14");
  database->put(prefix + "expression", "-pi");
  prefix = "electrode_material.custom_liquid_electrical_conductivity.";
  database->put(prefix + "expression", "1.41");

  // Create an standard homogeneous SuperCapacitorMPValues using the build(...)
  // method which is static.
  int constexpr dim = 2;
  cap::MPValuesParameters<dim> params(database);
  params.geometry = std::make_shared<cap::Geometry<dim>>(
      std::make_shared<boost::property_tree::ptree>(
          ptree.get_child("geometry")),
      world);
  std::shared_ptr<cap::MPValues<dim>> mp_values =
      cap::SuperCapacitorMPValuesFactory<dim>::build(params);

  dealii::FE_Q<dim> fe(1);
  dealii::FEValues<dim> fe_values(fe, dealii::QGauss<dim>(1),
                                  dealii::update_quadrature_points);

  dealii::DoFHandler<dim> dof_handler(*params.geometry->get_triangulation());
  dof_handler.distribute_dofs(fe);
  dealii::DoFHandler<dim>::active_cell_iterator cell =
      dof_handler.begin_active();
  fe_values.reinit(cell);

  std::vector<double> values(1);

  // NOTE:  The following matches material ids in
  // Geometry<dim>::fill_material_and_boundary_maps()
  // set anode material id
  cell->set_material_id(0);
  mp_values->get_values("liquid_electrical_conductivity", fe_values, values);
  BOOST_TEST(values[0] == 1.41);
  cell->set_material_id(1);
  mp_values->get_values("liquid_electrical_conductivity", fe_values, values);
  BOOST_TEST(values[0] == -3.14);
}

BOOST_AUTO_TEST_CASE(test_mp_values)
{
  // Fill in the geometry database
  std::shared_ptr<boost::property_tree::ptree> geometry_database(
      new boost::property_tree::ptree());

  boost::property_tree::ptree material_0_database;
  material_0_database.put("name", "anode");
  material_0_database.put("material_id", 1);

  boost::property_tree::ptree material_1_database;
  material_1_database.put("name", "separator");
  material_1_database.put("material_id", 2);

  boost::property_tree::ptree material_2_database;
  material_2_database.put("name", "cathode");
  material_2_database.put("material_id", 3);

  boost::property_tree::ptree material_3_database;
  material_3_database.put("name", "collector");
  material_3_database.put("material_id", "4,5");

  boost::property_tree::ptree boundary_0_database;
  boundary_0_database.put("name", "anode");
  boundary_0_database.put("boundary_id", 1);

  boost::property_tree::ptree boundary_1_database;
  boundary_1_database.put("name", "cathode");
  boundary_1_database.put("boundary_id", 2);

  geometry_database->put("type", "file");
  geometry_database->put("mesh_file", "mesh_2d.ucd");
  geometry_database->put("anode_collector_thickness", 5.0e-4);
  geometry_database->put("anode_electrode_thickness", 50.0e-4);
  geometry_database->put("separator_thickness", 25.0e-4);
  geometry_database->put("cathode_electrode_thickness", 50.0e-4);
  geometry_database->put("cathode_collector_thickness", 5.0e-4);
  geometry_database->put("geometric_area", 25.0e-2);
  geometry_database->put("tab_height", 5.0e-4);
  geometry_database->put("materials", 4);
  geometry_database->put_child("material_0", material_0_database);
  geometry_database->put_child("material_1", material_1_database);
  geometry_database->put_child("material_2", material_2_database);
  geometry_database->put_child("material_3", material_3_database);
  geometry_database->put("boundaries", 2);
  geometry_database->put_child("boundary_0", boundary_0_database);
  geometry_database->put_child("boundary_1", boundary_1_database);

  std::shared_ptr<cap::Geometry<2>> geometry =
      std::make_shared<cap::Geometry<2>>(geometry_database,
                                         boost::mpi::communicator());

  // Fill in the material properties database
  std::shared_ptr<boost::property_tree::ptree> material_properties_database(
      new boost::property_tree::ptree());

  boost::property_tree::ptree anode_database;
  anode_database.put("type", "porous_electrode");
  anode_database.put("matrix_phase", "electrode_material");
  anode_database.put("solution_phase", "electrolyte");

  boost::property_tree::ptree cathode_database;
  cathode_database.put("type", "porous_electrode");
  cathode_database.put("matrix_phase", "electrode_material");
  cathode_database.put("solution_phase", "electrolyte");

  boost::property_tree::ptree separator_database;
  separator_database.put("type", "permeable_membrane");
  separator_database.put("matrix_phase", "separator_material");
  separator_database.put("solution_phase", "electrolyte");

  boost::property_tree::ptree collector_database;
  collector_database.put("type", "current_collector");
  collector_database.put("metal_foil", "collector_material");

  boost::property_tree::ptree separator_material_database;
  separator_material_database.put("void_volume_fraction", 0.6);
  separator_material_database.put("tortuosity_factor", 1.29);
  separator_material_database.put("pores_characteristic_dimension", 1.5e-7);
  separator_material_database.put("pores_geometry_factor", 2.0);
  separator_material_database.put("mass_density", 3.2);
  separator_material_database.put("heat_capacity", 1.2528e3);
  separator_material_database.put("thermal_conductivity", 0.0019e2);

  boost::property_tree::ptree electrode_material_database;
  electrode_material_database.put("differential_capacitance", 3.134);
  electrode_material_database.put("exchange_current_density", 7.463e-10);
  electrode_material_database.put("void_volume_fraction", 0.67);
  electrode_material_database.put("tortuosity_factor", 2.3);
  electrode_material_database.put("pores_characteristic_dimension", 1.5e-7);
  electrode_material_database.put("pores_geometry_factor", 2.0);
  electrode_material_database.put("mass_density", 2.3);
  electrode_material_database.put("electrical_resistivity", 1.92);
  electrode_material_database.put("heat_capacity", 0.93e3);
  electrode_material_database.put("thermal_conductivity", 0.0011e2);

  boost::property_tree::ptree collector_material_database;
  collector_material_database.put("mass_density", 2.7);
  collector_material_database.put("electrical_resistivity", 28.2e-7);
  collector_material_database.put("heat_capacity", 2.7e3);
  collector_material_database.put("thermal_conductivity", 237.0);

  boost::property_tree::ptree electrolyte_database;
  electrolyte_database.put("mass_density", 1.2);
  electrolyte_database.put("electrical_resistivity", 1.49e3);
  electrolyte_database.put("heat_capacity", 0.0);
  electrolyte_database.put("thermal_conductivity", 0.0);

  material_properties_database->put_child("anode", anode_database);
  material_properties_database->put_child("cathode", cathode_database);
  material_properties_database->put_child("separator", separator_database);
  material_properties_database->put_child("collector", collector_database);
  material_properties_database->put_child("separator_material",
                                          separator_material_database);
  material_properties_database->put_child("electrode_material",
                                          electrode_material_database);
  material_properties_database->put_child("collector_material",
                                          collector_material_database);
  material_properties_database->put_child("electrolyte", electrolyte_database);

  cap::MPValuesParameters<2> params(material_properties_database);
  params.geometry = geometry;
  std::shared_ptr<cap::MPValues<2>> mp_values =
      std::make_shared<cap::SuperCapacitorMPValues<2>>(params);

  dealii::FE_Q<2> fe(1);
  dealii::DoFHandler<2> dof_handler(*(geometry->get_triangulation()));
  dof_handler.distribute_dofs(fe);
  dealii::DoFHandler<2>::active_cell_iterator cell = dof_handler.begin_active();
  dealii::FEValues<2> fe_values(fe, dealii::QGauss<2>(1),
                                dealii::update_default);
  fe_values.reinit(cell);

  std::vector<double> values(1);
  double const tolerance = 1e-2;
  mp_values->get_values("density", fe_values, values);
  BOOST_TEST(values[0] == 1563.);
  mp_values->get_values("solid_electrical_conductivity", fe_values, values);
  BOOST_TEST(std::abs(values[0] - 17.1785) < tolerance);

  // Move to another material
  for (unsigned int i = 0; i < 300; ++i)
    ++cell;
  fe_values.reinit(cell);

  mp_values->get_values("density", fe_values, values);
  BOOST_TEST(values[0] == 2000.);
  mp_values->get_values("solid_electrical_conductivity", fe_values, values);
  BOOST_TEST(std::abs(values[0]) == 0.);
}


/************************************************************************/
/*                                                                      */
/*               Copyright 2007-2019 by Hans Meine                      */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#include "vigra/dsl.hxx"

#include <boost/python.hpp>
#include <boost/python/detail/api_placeholder.hpp>
#include <boost/python/make_constructor.hpp>
#include <vector>

using namespace boost::python;
using namespace vigra;

template<class DSL>
struct DSLPickleSuite : pickle_suite
{
    static tuple getinitargs(DSL const& dsl)
    {
        return make_tuple(dsl.a(), dsl.b(), dsl.pos());
    }
};

tuple pyTangentDSL(list pyFreemanCodes, int index, bool closed)
{
    std::vector<unsigned char> freemanCodes(len(pyFreemanCodes));
    for(unsigned int i = 0; i < freemanCodes.size(); ++i)
        freemanCodes[i] = extract<unsigned char>(pyFreemanCodes[i])();

    DigitalStraightLine<int, true> result(0, 1, 0);
    int offset = tangentDSL(freemanCodes.begin(), freemanCodes.end(),
                            index, closed, result);
    return make_tuple(result, offset ? object(offset) : object());
}

void defDSL()
{
    enum_<DSL::LeaningType>("LeaningType")
        .value("CenterLine", DSL::CenterLine)
        .value("LowerLeaningLine", DSL::LowerLeaningLine)
        .value("UpperLeaningLine", DSL::UpperLeaningLine)
    ;

    typedef DigitalStraightLine<int, true> DigitalStraightLine8;

    class_<DigitalStraightLine8>("DigitalStraightLine8", init<int, int, int>())
        .def("eightConnected", &DigitalStraightLine8::eightConnected)
        .add_property("a", &DigitalStraightLine8::a, &DigitalStraightLine8::setA)
        .add_property("b", &DigitalStraightLine8::b, &DigitalStraightLine8::setB)
        .add_property("pos", &DigitalStraightLine8::pos, &DigitalStraightLine8::setPos)
        .def("__call__", &DigitalStraightLine8::operator())
        .def("width", &DigitalStraightLine8::width)
        .def("contains", &DigitalStraightLine8::contains)
        .def("slope", &DigitalStraightLine8::slope)
        .def("axisIntercept", &DigitalStraightLine8::axisIntercept,
             arg("leaningType") = DSL::CenterLine)
        .def("mirrorX", &DigitalStraightLine8::mirrorX)
        .def("mirrorXY", &DigitalStraightLine8::mirrorXY)
        .def("mirrorY", &DigitalStraightLine8::mirrorY)
        .def("addPoint", &DigitalStraightLine8::addPoint)
        .def("convertToFourConnected", &DigitalStraightLine8::convertToFourConnected)
        .def_pickle(DSLPickleSuite<DigitalStraightLine8>())
    ;

    typedef DigitalStraightLine<int, false> DigitalStraightLine4;

    class_<DigitalStraightLine4>("DigitalStraightLine4", init<int, int, int>())
        .def("eightConnected", &DigitalStraightLine4::eightConnected)
        .add_property("a", &DigitalStraightLine4::a, &DigitalStraightLine4::setA)
        .add_property("b", &DigitalStraightLine4::b, &DigitalStraightLine4::setB)
        .add_property("pos", &DigitalStraightLine4::pos, &DigitalStraightLine4::setPos)
        .def("__call__", &DigitalStraightLine4::operator())
        .def("width", &DigitalStraightLine4::width)
        .def("contains", &DigitalStraightLine4::contains)
        .def("slope", &DigitalStraightLine4::slope)
        .def("axisIntercept", &DigitalStraightLine4::axisIntercept,
             arg("leaningType") = DSL::CenterLine)
        .def("mirrorX", &DigitalStraightLine4::mirrorX)
        .def("mirrorXY", &DigitalStraightLine4::mirrorXY)
        .def("mirrorY", &DigitalStraightLine4::mirrorY)
        .def_pickle(DSLPickleSuite<DigitalStraightLine4>())
    ;

    def("tangentDSL", &pyTangentDSL);
}


#include <iostream>
#include <iomanip>
#include <fstream>
#include <list>
#include <string>
#include <vector>
#include <cmath>
#include <cassert>
#include <cfloat>
#include <algorithm>
#include <numeric>
#include <complex>
#include <ctime>
#include <map>
#include <set>
#include <deque>
#include <climits>
#include <array>
#include <utility>
#include <sys/stat.h>
#include <boost/random.hpp>
#include "fftw3-mpi.h"
#include "_hypre_utilities.h"
#include "HYPRE_krylov.h"
#include "HYPRE_struct_ls.h"


// $Id$
//
// Copyright (c) 2003-2006 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//

#include <RDGeneral/test.h>
#include "QueryObjects.h"
#include <iostream>
#include <math.h>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace Queries;

void test1() {
  cout << "Float" << endl;
  EqualityQuery<double> q(1.0);

  CHECK_INVARIANT(!q.Match(0.0), "");
  CHECK_INVARIANT(q.Match(1.0), "");
  CHECK_INVARIANT(!q.Match(1.001), "");
  CHECK_INVARIANT(!q.Match(1.1), "");
  CHECK_INVARIANT(!q.Match(-2), "");

  cout << "With Tolerance" << endl;
  q.setTol(0.002);
  CHECK_INVARIANT(!q.Match(0.0), "");
  CHECK_INVARIANT(q.Match(1.0), "");
  CHECK_INVARIANT(q.Match(1.001), "");
  CHECK_INVARIANT(!q.Match(1.1), "");
  CHECK_INVARIANT(!q.Match(-2), "");

  Query<double> *newQ;
  newQ = q.copy();
  CHECK_INVARIANT(!newQ->Match(0.0), "");
  CHECK_INVARIANT(newQ->Match(1.0), "");
  CHECK_INVARIANT(newQ->Match(1.001), "");
  CHECK_INVARIANT(!newQ->Match(1.1), "");
  CHECK_INVARIANT(!newQ->Match(-2), "");
  delete newQ;
}

void test2() {
  cout << "Set" << endl;
  SetQuery<int> q;
  q.insert(1);
  q.insert(3);
  q.insert(5);

  CHECK_INVARIANT(!q.Match(0), "");
  CHECK_INVARIANT(q.Match(1), "");
  CHECK_INVARIANT(q.Match(3), "");
  CHECK_INVARIANT(!q.Match(-3), "");

  Query<int> *newQ;
  newQ = q.copy();
  CHECK_INVARIANT(!newQ->Match(0), "");
  CHECK_INVARIANT(newQ->Match(1), "");
  CHECK_INVARIANT(newQ->Match(3), "");
  CHECK_INVARIANT(!newQ->Match(-3), "");
  delete newQ;
}

void test3() {
  cout << "And" << endl;
  auto *q = new AndQuery<int>;
  auto *l = new LessQuery<int>;
  l->setVal(0);
  auto *g = new GreaterEqualQuery<int>;
  g->setVal(3);

  q->addChild(Query<int>::CHILD_TYPE(l));
  q->addChild(Query<int>::CHILD_TYPE(g));

  CHECK_INVARIANT(!q->Match(0), "");
  CHECK_INVARIANT(q->Match(1), "");
  CHECK_INVARIANT(q->Match(3), "");
  CHECK_INVARIANT(!q->Match(-3), "");

  Query<int> *newQ;
  newQ = q->copy();
  CHECK_INVARIANT(!newQ->Match(0), "");
  CHECK_INVARIANT(newQ->Match(1), "");
  CHECK_INVARIANT(newQ->Match(3), "");
  CHECK_INVARIANT(!newQ->Match(-3), "");

  delete newQ;
  delete q;
}

void test4() {
  cout << "Or" << endl;
  auto *q = new OrQuery<int>;
  auto *l = new LessQuery<int>;
  l->setVal(0);
  auto *g = new GreaterEqualQuery<int>;
  g->setVal(3);

  q->addChild(Query<int>::CHILD_TYPE(l));
  q->addChild(Query<int>::CHILD_TYPE(g));

  CHECK_INVARIANT(q->Match(0), "");
  CHECK_INVARIANT(q->Match(1), "");
  CHECK_INVARIANT(q->Match(3), "");
  CHECK_INVARIANT(q->Match(-3), "");

  Query<int> *newQ;
  newQ = q->copy();
  CHECK_INVARIANT(newQ->Match(0), "");
  CHECK_INVARIANT(newQ->Match(1), "");
  CHECK_INVARIANT(newQ->Match(3), "");
  CHECK_INVARIANT(newQ->Match(-3), "");

  delete newQ;
  delete q;
}

void test5() {
  cout << "XOr" << endl;
  auto *q = new XOrQuery<int>;
  auto *l = new LessQuery<int>;
  l->setVal(0);
  auto *g = new GreaterEqualQuery<int>;
  g->setVal(3);

  q->addChild(Query<int>::CHILD_TYPE(l));
  q->addChild(Query<int>::CHILD_TYPE(g));

  CHECK_INVARIANT(q->Match(-1), "");
  CHECK_INVARIANT(q->Match(0), "");
  CHECK_INVARIANT(!q->Match(1), "");
  CHECK_INVARIANT(!q->Match(3), "");
  CHECK_INVARIANT(q->Match(-3), "");

  Query<int> *newQ;
  newQ = q->copy();
  CHECK_INVARIANT(newQ->Match(-1), "");
  CHECK_INVARIANT(newQ->Match(0), "");
  CHECK_INVARIANT(!newQ->Match(1), "");
  CHECK_INVARIANT(!newQ->Match(3), "");
  CHECK_INVARIANT(newQ->Match(-3), "");

  delete newQ;
  delete q;
}

int foofun(double bar) { return int(floor(bar)); };

void test6() {
  cout << "pointer and copy foo" << endl;
  EqualityQuery<int, double, true> q;
  q.setDataFunc(foofun);
  q.setVal(6);
  CHECK_INVARIANT(q.Match(6.0), "");
  CHECK_INVARIANT(q.Match(6.1), "");
  CHECK_INVARIANT(!q.Match(5.0), "");

  Query<int, double, true> *newQ;
  newQ = q.copy();
  CHECK_INVARIANT(newQ->Match(6.0), "");
  CHECK_INVARIANT(newQ->Match(6.1), "");
  CHECK_INVARIANT(!newQ->Match(5.0), "");

  Query<int, double, true> *newQ2 = &q;
  CHECK_INVARIANT(newQ2->Match(6.0), "");
  CHECK_INVARIANT(newQ2->Match(6.1), "");
  CHECK_INVARIANT(!newQ2->Match(5.0), "");

  Query<int, double, true> *newQ3;
  newQ3 = newQ2->copy();
  CHECK_INVARIANT(newQ3->Match(6.0), "");
  CHECK_INVARIANT(newQ3->Match(6.1), "");
  CHECK_INVARIANT(!newQ3->Match(5.0), "");

  delete newQ;
  delete newQ3;
}

bool matchF(int v) { return v == 3; }

int dataF(float v) { return int(floor(v)) * 3; }

bool cmp(int v) { return v < 3; }

void basics1() {
  cout << "Query" << endl;
  Query<int, float, true> q;
  q.setMatchFunc(matchF);
  q.setDataFunc(dataF);

  CHECK_INVARIANT(!q.Match(0.0), "");
  CHECK_INVARIANT(q.Match(1.0), "");
  CHECK_INVARIANT(q.Match(1.1), "");
  CHECK_INVARIANT(!q.Match(-2.0), "");

  TEST_ASSERT(!q.getMatchFunc()(0));
  TEST_ASSERT(q.getMatchFunc()(3));
  TEST_ASSERT(q.getDataFunc()(1.0) == dataF(1.0));

  cout << "Query2" << endl;
  Query<bool, int, true> q2;
  q2.setDataFunc(cmp);
  CHECK_INVARIANT(q2.Match(0), "");
  CHECK_INVARIANT(q2.Match(1), "");
  CHECK_INVARIANT(!q2.Match(3), "");
  CHECK_INVARIANT(!q2.Match(4), "");
  CHECK_INVARIANT(!q2.Match(4.0), "");
}

void basics2() {
  cout << "Equality" << endl;
  EqualityQuery<int> q2;
  q2.setVal(3);
  CHECK_INVARIANT(!q2.Match(0), "");
  CHECK_INVARIANT(!q2.Match(1), "");
  CHECK_INVARIANT(q2.Match(3), "");
  CHECK_INVARIANT(!q2.Match(-3), "");

  cout << "Greater" << endl;
  GreaterQuery<int> q3;
  q3.setVal(3);
  CHECK_INVARIANT(q3.Match(0), "");
  CHECK_INVARIANT(q3.Match(1), "");
  CHECK_INVARIANT(!q3.Match(3), "");
  CHECK_INVARIANT(!q3.Match(5), "");

  cout << "GreaterEqual" << endl;
  GreaterEqualQuery<int> q4(3);
  CHECK_INVARIANT(q4.Match(0), "");
  CHECK_INVARIANT(q4.Match(1), "");
  CHECK_INVARIANT(q4.Match(3), "");
  CHECK_INVARIANT(!q4.Match(5), "");

  cout << "Less" << endl;
  LessQuery<int> q5;
  q5.setVal(3);
  CHECK_INVARIANT(!q5.Match(0), "");
  CHECK_INVARIANT(!q5.Match(1), "");
  CHECK_INVARIANT(!q5.Match(3), "");
  CHECK_INVARIANT(q5.Match(5), "");

  cout << "LessEqual" << endl;
  LessEqualQuery<int> q6(3);

  CHECK_INVARIANT(!q6.Match(0), "");
  CHECK_INVARIANT(!q6.Match(1), "");
  CHECK_INVARIANT(q6.Match(3), "");
  CHECK_INVARIANT(q6.Match(5), "");

  cout << "Open Range" << endl;
  RangeQuery<int> q7(0, 3);
  CHECK_INVARIANT(!q7.Match(0), "");
  CHECK_INVARIANT(q7.Match(1), "");
  CHECK_INVARIANT(!q7.Match(3), "");
  CHECK_INVARIANT(!q7.Match(5), "");

  cout << "Closed Range" << endl;
  q7.setEndsOpen(false, false);
  CHECK_INVARIANT(q7.Match(0), "");
  CHECK_INVARIANT(q7.Match(1), "");
  CHECK_INVARIANT(q7.Match(3), "");
  CHECK_INVARIANT(!q7.Match(5), "");
}

int convFunc(const char *arg) { return boost::lexical_cast<int>(arg); };

void test7() {
  cout << "Set2" << endl;
  SetQuery<int, const char *, true> q;
  q.setDataFunc(convFunc);
  q.insert(1);
  q.insert(3);
  q.insert(5);

  CHECK_INVARIANT(!q.Match("0"), "");
  CHECK_INVARIANT(q.Match("1"), "");
  CHECK_INVARIANT(q.Match("3"), "");
  CHECK_INVARIANT(!q.Match("-3"), "");

  Query<int, const char *, true> *newQ;
  newQ = q.copy();
  CHECK_INVARIANT(!newQ->Match("0"), "");
  CHECK_INVARIANT(newQ->Match("1"), "");
  CHECK_INVARIANT(newQ->Match("3"), "");
  CHECK_INVARIANT(!newQ->Match("-3"), "");

  delete newQ;
}

int main() {
  basics1();
  basics2();

  test1();
  test2();
  test3();
  test4();
  test5();
  test6();
  test7();
  return 0;
}


/*
 * GridMapVisualizationHelpers.hpp
 *
 *  Created on: Jun 24, 2014
 *      Author: Péter Fankhauser
 *   Institute: ETH Zurich, Autonomous Systems Lab
 */

#pragma once

// ROS
#include <ros/ros.h>
#include <visualization_msgs/MarkerArray.h>
#include <std_msgs/ColorRGBA.h>

// Eigen
#include <Eigen/Core>

namespace grid_map_visualization {

/*!
 * Create a color message from a color vector.
 * @param[out] colorMessage the color message.
 * @param[in] colorVector the color vector
 * @param[in] resetTransparency if transparency should be reset (to fully visible) or left at current value.
 */
void getColorMessageFromColorVector(std_msgs::ColorRGBA& colorMessage, const Eigen::Vector3f& colorVector, bool resetTransparency = true);

/*!
 * Create a color vector from a color message.
 * @param[out] colorVector the color vector.
 * @param[in] colorMessage the color message.
 */
void getColorVectorFromColorMessage(Eigen::Vector3f& colorVector, const std_msgs::ColorRGBA& colorMessage);

/*!
 * Sets a color message from a color value.
 * @param[out] color the color message.
 * @param[in] colorValue the color value.
 * @param[in] resetTransparency if transparency should be reset (to fully visible) or left at current value.
 */
void setColorFromColorValue(std_msgs::ColorRGBA& color, const unsigned long& colorValue, bool resetTransparency = true);

/*!
 * Set the color channel from a scalar value.
 * @param[out] colorChannel the color channel to be set.
 * @param[in] value the scalar value.
 * @param[in] lowerValueBound the lower boundary of the value.
 * @param[in] upperValueBound the upper boundary of the value.
 * @param[in] invert if interpolation should be inverted.
 * @param[in] colorChannelLowerValue the lower value for the color channel.
 * @param[in] colorChannelUpperValue the upper value for the color channel.
 */
void setColorChannelFromValue(float& colorChannel, const double value, const double lowerValueBound,
                              const double upperValueBound, const bool invert = false, const double colorChannelLowerValue = 0.0,
                              const double colorChannelUpperValue = 1.0);

/*!
 * Sets the color to the interpolation between two colors based on a scalar value.
 * @param[out] color the color the be set.
 * @param[in] colorForLowerValue the color for the lower value boundary.
 * @param[in] colorForUpperValue the color for the upper value boundary.
 * @param[in] value the scalar value.
 * @param[in] lowerValueBound the lower boundary of the value.
 * @param[in] upperValueBound the upper boundary of the value.
 */
void interpolateBetweenColors(std_msgs::ColorRGBA& color, const std_msgs::ColorRGBA& colorForLowerValue,
                              const std_msgs::ColorRGBA& colorForUpperValue, const double value,
                              const double lowerValueBound, const double upperValueBound);

/*!
 * Sets the saturation of the color from a scalar value.
 * @param[out] color the color the be set.
 * @param[in] value the scalar value.
 * @param[in] lowerValueBound the lower boundary of the value.
 * @param[in] upperValueBound the upper boundary of the value.
 * @param[in] maxSaturation the maximum saturation.
 * @param[in] minSaturation the minimum saturation.
 */
void setSaturationFromValue(std_msgs::ColorRGBA& color, const double value, const double lowerValueBound,
                            const double upperValueBound, const double maxSaturation, const double minSaturation);

/*!
 * Set the color from the rainbow color spectrum based on scalar value.
 * @param[out] color the color the be set.
 * @param[in] value the scalar value.
 * @param[in] lowerValueBound the lower boundary of the value.
 * @param[in] upperValueBound the upper boundary of the value.
 */
void setColorFromValue(std_msgs::ColorRGBA& color, const double value, const double lowerValueBound,
                       const double upperValueBound);

/*!
 * Computes a linear mapping for a query from the source and to the map.
 * @param sourceValue the query from the source.
 * @param sourceLowerValue the lower source boundary.
 * @param sourceUpperValue the upper source boundary.
 * @param mapLowerValue the lower map boundary.
 * @param mapUpperValue the upper map boundary.
 * @return the query mapped to the map.
 */
double computeLinearMapping(
    const double& sourceValue, const double& sourceLowerValue, const double& sourceUpperValue,
    const double& mapLowerValue, const double& mapUpperValue);

} /* namespace */


#include <boost/multiprecision/cpp_int.hpp>

using T = boost::multiprecision::cpp_int;

const int k = 4;
const int dimension = 1<<k;

#include "gadget.h"
#include "rational.h"
#include "optimizer.h"
#include "orbit.h"
#include <vector>
#include <iostream>

int main() {

    std::cout << "Analyzing orbits of the symmetry group..." << std::endl;

    OrbitInfo orbitInfo;
    Optimizer optimizer;
    Evaluator evaluator(orbitInfo);

    std::cout << "Optimizing gadget..." << std::endl;

    auto gadget = optimizer.gadgetSearch(orbitInfo);

    std::cout << "Finished optimizing gadget" << std::endl;

    auto randomCost = evaluator.relaxedRandomCost(gadget);
    auto dictCost = Rational<T>(gadget.getTotalWeight(), dimension);

    auto inapproximabilityFactor = randomCost / dictCost;

    std::cout << "The found gadget has inapproximability factor " << inapproximabilityFactor.a << "/" << inapproximabilityFactor.b << std::endl;
}


// Coulombo Ⓒ 2018
// [Computer Physics Communications] Różański & Zieliński:
// Efficient computation of Coulomb and exchange integrals for multi-million atom nanostructures
#ifndef COULOMBO_BASE_HPP
#define COULOMBO_BASE_HPP

#include <cassert>
#include <complex>

#ifdef NDEBUG
#define ARMA_NO_DEBUG
#endif
#define ARMA_64BIT_WORD
#include <armadillo>
using arma::uword;

using real = double;
using complex = std::complex<real>;

template<typename T>
struct Vector3D {
	T x, y, z;
};

/**
 * e²/4πε₀ [eV·Å]
 */
const double E2_4PE0 = 14.39963737103201;

/**
 * integral of 1/|r₁-r₂| over box [0;1]³×[0;1]³
 */
const double BOX_INTEGRAL_0 = 1.88231264439;

#endif


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#ifndef MTL_OPERATORS_INCLUDE
#define MTL_OPERATORS_INCLUDE

#include <boost/utility/enable_if.hpp>
#include <boost/mpl/and.hpp>

#include <boost/numeric/mtl/utility/ashape.hpp>
#include <boost/numeric/mtl/matrix/operators.hpp>
//#include <boost/numeric/mtl/vector/operators.hpp>
#include <boost/numeric/mtl/operation/mult_result.hpp>
#include <boost/numeric/mtl/operation/div_result.hpp>
#include <boost/numeric/mtl/operation/dot.hpp>
#include <boost/numeric/mtl/operation/mat_cvec_times_expr.hpp>
#include <boost/numeric/mtl/matrix/all_mat_expr.hpp>
#include <boost/numeric/mtl/utility/enable_if.hpp>
#include <boost/numeric/mtl/utility/category.hpp>
#include <boost/numeric/mtl/utility/true_copy.hpp>
#include <boost/numeric/mtl/vector/rvec_mat_times_expr.hpp>

namespace mtl {

namespace matrix {

    /// Multiplication for all supported types of operations
    /** Enable-if-like technique make sure that only called when properly defined **/
    template <typename Op1, typename Op2>
    typename mtl::traits::mult_result<typename mtl::traits::true_copy<Op1>::type, Op2>::type
    inline operator*(const Op1& op1, const Op2& op2)
    {

        return typename mtl::traits::mult_result<typename mtl::traits::true_copy<Op1>::type, Op2>::type(op1, op2);
    }

    /// Division of matrices and vectors by salars
    /** Enable-if-like technique make sure that only called when properly defined **/
    // added by Hui Li
    // enable_if_matrix shouldn't be needed but was nessecary in cuppen.hpp
    template < typename Op1, typename Op2 >
    typename mtl::traits::enable_if_matrix<Op1, typename mtl::traits::div_result<Op1,Op2>::type>::type
    inline operator/(const Op1& op1, const Op2& op2)
    {
        return typename mtl::traits::div_result<Op1,Op2>::type(op1,op2);
    }

} // namespace matrix

namespace vector {

    /// Multiplication for all supported types of operations
    /** Enable-if-like technique make sure that only called when properly defined **/
    template <typename Op1, typename Op2>
    typename mtl::traits::vec_mult_result<typename mtl::traits::true_copy<Op1>::type, Op2>::type
    inline operator*(const Op1& op1, const Op2& op2)
    {
        return typename mtl::traits::vec_mult_result<typename mtl::traits::true_copy<Op1>::type, Op2>::type(op1, op2);
    }

    /// Multiply row vector with column vector; result is scalar
    template <typename Op1, typename Op2>
    typename traits::lazy_enable_if_rvec_cvec_mult<Op1, Op2, detail::dot_result<Op1, Op2> >::type
    inline operator*(const Op1& op1, const Op2& op2)
    {
	return dot_real(op1, op2);
    }

    /// Division of matrices and vectors by salars
    /** Enable-if-like technique make sure that only called when properly defined **/
    // added by Hui Li
    template < typename Op1, typename Op2 >
    typename traits::div_result<Op1,Op2>::type
    inline operator/(const Op1& op1, const Op2& op2)
    {
        return typename traits::div_result<Op1,Op2>::type(op1,op2);
    }

    /// Compare two vectors for equality
    /** Enable-if makes sure that only called when properly defined **/
    template < typename Op1, typename Op2 >
    typename boost::enable_if<boost::mpl::and_<mtl::traits::is_vector<Op1>,
					       mtl::traits::is_vector<Op2> >,
			      bool>::type
    inline operator==(const Op1& op1, const Op2& op2)
    {
	unsigned s1= num_rows(op1) * num_cols(op1), s2= num_rows(op2) * num_cols(op2); // ugly hack to fight with ADL
	if (s1 != s2)
	    return false;
	for (unsigned i= 0; i < s1; i++)
	    if (op1[i] != op2[i])
		return false;
	return true;
    }

    /// Compare two vectors for unequality
    /** Enable-if makes sure that only called when properly defined **/
    template < typename Op1, typename Op2 >
    typename boost::enable_if<boost::mpl::and_<mtl::traits::is_vector<Op1>,
					       mtl::traits::is_vector<Op2> >,
			      bool>::type
    inline operator!=(const Op1& op1, const Op2& op2)
    {
	return !(op1 == op2);
    }

} // namespace vector

} // namespace mtl

#endif // MTL_OPERATORS_INCLUDE