/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include "toplevelfixture.hpp"
#include <boost/test/unit_test.hpp>
#include <qle/termstructures/flatcorrelation.hpp>
#include <qle/termstructures/interpolatedcorrelationcurve.hpp>

#include <ql/quotes/simplequote.hpp>
#include <ql/time/calendars/nullcalendar.hpp>

#include <boost/make_shared.hpp>

using namespace QuantExt;
using namespace QuantLib;
using namespace boost::unit_test_framework;

BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)

BOOST_AUTO_TEST_SUITE(CorrelationTermstructureTest)

BOOST_AUTO_TEST_CASE(testFlatCorrelation) {

    boost::shared_ptr<SimpleQuote> q = boost::make_shared<SimpleQuote>(0.02);
    Handle<Quote> hq(q);
    Handle<FlatCorrelation> flatCorr(boost::make_shared<FlatCorrelation>(0, NullCalendar(), hq, Actual365Fixed()));

    // check we get the expected quote value
    BOOST_CHECK_MESSAGE(flatCorr->correlation(1) == 0.02, "unexpected correlation value: " << flatCorr->correlation(1));

    // move market data
    q->setValue(0.03);

    BOOST_CHECK_MESSAGE(flatCorr->correlation(1) == 0.03, "unexpected correlation value: " << flatCorr->correlation(1));

    // check failures

    q->setValue(-1.1);
    BOOST_CHECK_THROW(flatCorr->correlation(1), QuantLib::Error);

    q->setValue(1.1);
    BOOST_CHECK_THROW(flatCorr->correlation(1), QuantLib::Error);
}

BOOST_AUTO_TEST_CASE(testInterpolatedCorrelationCurve) {

    // build interpolated correlation curve
    std::vector<Time> times;
    std::vector<boost::shared_ptr<SimpleQuote> > simpleQuotes;
    std::vector<Handle<Quote> > quotes;

    Size numYears = 10;
    for (Size i = 1; i < numYears; i++) {

        Real corr = 0.1;

        simpleQuotes.push_back(boost::make_shared<SimpleQuote>(corr));
        quotes.push_back(Handle<Quote>(simpleQuotes.back()));

        times.push_back(static_cast<Time>(i));
    }

    Handle<PiecewiseLinearCorrelationCurve> interpCorr(
        boost::make_shared<PiecewiseLinearCorrelationCurve>(times, quotes, Actual365Fixed(), NullCalendar()));

    Time t = 1;
    while (t < numYears) {
        BOOST_CHECK_MESSAGE(interpCorr->correlation(t) == 0.1,
                            "unexpected correlation value: " << interpCorr->correlation(t));
        t += 0.5;
    }

    // Now check quotes update
    for (Size i = 0; i < simpleQuotes.size(); ++i) {
        simpleQuotes[i]->setValue(1);
    }

    t = 1;
    while (t < numYears) {
        BOOST_CHECK_MESSAGE(interpCorr->correlation(t) == 1,
                            "unexpected correlation value: " << interpCorr->correlation(t));
        t += 0.5;
    }

    // Now check interpolation
    for (Size i = 0; i < simpleQuotes.size(); ++i) {
        simpleQuotes[i]->setValue(0.1 + 0.01 * i);
    }

    Real tol = 1.0E-8;
    BOOST_CHECK_CLOSE(interpCorr->correlation(1.5), 0.105, tol);
    BOOST_CHECK_CLOSE(interpCorr->correlation(2.5), 0.115, tol);
    BOOST_CHECK_CLOSE(interpCorr->correlation(3.5), 0.125, tol);
    BOOST_CHECK_CLOSE(interpCorr->correlation(11), 0.18, tol);
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


//==============================================================================
//         Copyright 2003 - 2013   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2013   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <nt2/include/functions/oneminus.hpp>

#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <complex>
#include <nt2/sdk/complex/complex.hpp>
#include <nt2/sdk/complex/dry.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/sdk/config.hpp>

#include <nt2/include/constants/mone.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/two.hpp>
#include <nt2/include/constants/zero.hpp>
#include <nt2/include/constants/inf.hpp>
#include <nt2/include/constants/minf.hpp>
#include <nt2/include/constants/nan.hpp>

NT2_TEST_CASE_TPL ( oneminus_real,  BOOST_SIMD_REAL_TYPES)
{
  using nt2::oneminus;
  using nt2::tag::oneminus_;
  typedef typename std::complex<T> cT;

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(oneminus(cT(nt2::Inf<T>(), nt2::Inf<T>())) , cT(-nt2::Inf<T>(),nt2::Minf<T>()));
  NT2_TEST_EQUAL(oneminus(cT(nt2::Minf<T>(),nt2::Minf<T>())), cT(-nt2::Minf<T>(),nt2::Inf<T>()));
  NT2_TEST_EQUAL(oneminus(cT(nt2::Nan<T>(), nt2::Nan<T>())), cT(nt2::Nan<T>(),nt2::Nan<T>()));
  NT2_TEST_EQUAL(oneminus(nt2::Inf<cT>()),  -nt2::Inf<cT>());
  NT2_TEST_EQUAL(oneminus(nt2::Minf<cT>()), -nt2::Minf<cT>());
  NT2_TEST_EQUAL(oneminus(nt2::Nan<cT>()),  nt2::Nan<cT>());
#endif
  NT2_TEST_EQUAL(oneminus(cT(nt2::Mone<T>(),nt2::Mone<T>())), cT(nt2::Two<T>(),nt2::One<T>()));
  NT2_TEST_EQUAL(oneminus(cT(nt2::One<T>(), nt2::One<T>())), cT(nt2::Zero<T>(),nt2::Mone<T>()));
  NT2_TEST_EQUAL(oneminus(cT(nt2::Zero<T>(),nt2::Zero<T>())),  cT(nt2::One<T>(),nt2::Zero<T>()));
  NT2_TEST_EQUAL(oneminus(nt2::Mone<cT>()), nt2::Two<cT>());
  NT2_TEST_EQUAL(oneminus(nt2::One<cT>()),  nt2::Zero<cT>());
  NT2_TEST_EQUAL(oneminus(nt2::Zero<cT>()), nt2::One<cT>());
}


#include "2020/day18/cpp/include/parser.hpp"

#include <boost/algorithm/string/replace.hpp>
#include <iostream>

Parser::Parser(std::unordered_map<int, std::vector<char>> m, int max_op,
               std::string num_, std::string op_)
    : max_op_m(max_op),    // Default number of preceding rules
      re_number_m(num_),   // Default regex for finding numbers
      re_operator_m(op_),  // Default regex for finding operator
      re_operands_m() {
  // Regex to access operands for an operator: "123+456" -> "123","+", "456"
  // Here, we set the operator precedence
  for (int o = 0; o < max_op_m + 1; o++) {
    std::string rg;
    for (auto &op : m[o]) {
      rg += "\\" + std::string(1, op) + "|";
    }
    rg = rg.substr(0, rg.length() - 1);
    re_operands_m[o] = boost::regex("(-?\\d+)([" + rg + "])(-?\\d+)");
  }
}

// Apply operation
int64_t Parser::operate(const int64_t &a, const int64_t &b, const char &op) {
  if (op == '+') {
    return a + b;
  } else if (op == '*') {
    return a * b;
  } else {
    std::cout << "Fail\n";
    return -1;
  }
}
// Extract, e.g., "a+(b*(c+d)+f)+f"->"(b*(c+d)+f)""
std::string Parser::extract_parenthesis(std::string &line) {
  // Stop when we find a closing parenthesis
  std::vector<int> open_id, close_id;
  auto found_parenthesis(false);
  for (size_t i = 0; i < line.length(); i++) {
    if (line[i] == '(') {
      open_id.push_back(i);
    }
    if (line[i] == ')') {
      close_id.push_back(i);
      if (close_id.size() == open_id.size()) {
        found_parenthesis = true;
        break;
      }
    }
  }
  if (found_parenthesis) {
    return line.substr(open_id[0], close_id.back() + 1 - open_id[0]);
  }
  return std::string();
}

int64_t Parser::compute_expression(std::string line) {
  // Padding to handle minus sign
  boost::replace_all(line, "-", "+-");

  // Go through the operators in priority order
  for (int i = 0; i < max_op_m + 1; i++) {
    // Keep going until all operations are completed
    while (true) {
      boost::smatch sm;
      std::vector<std::string> m;
      if (boost::regex_search(line, sm, re_operands_m[i])) {
        for (auto s : sm) {
          m.push_back(s);
        }
        auto cm = operate(std::stoll(m[1]), std::stoll(m[3]), m[2][0]);
        boost::replace_all(line, m[0], std::to_string(cm));
      } else {
        break;
      }
    }
  }
  // After all operations are done, we should have a number
  if (boost::regex_match(line, boost::regex("^\\d+$"))) {
    return std::stoll(line);
  }
  // Otherwise, something went wrong
  return -1;
}

int64_t Parser::evaluate(std::string line) {
  // Make sure that any spaces are removed
  boost::replace_all(line, " ", "");

  // Find parenthes and evaulate them
  while (true) {
    // Get a closed parenthesis
    auto parenthesis = extract_parenthesis(line);
    if (parenthesis.length() == 0) {
      break;
    }
    // Compute its contents
    auto parse_parenthesis =
        evaluate(parenthesis.substr(1, parenthesis.length() - 2));
    // Replace the expression
    boost::replace_all(line, parenthesis, std::to_string(parse_parenthesis));
  }
  return compute_expression(line);
}


// Boost.Geometry (aka GGL, Generic Geometry Library)
// QuickBook Example

// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//[segment_view
//` Shows usage of the Boost.Range compatible view on a box

#include <iostream>

#include <boost/geometry.hpp>

int main()
{
    typedef boost::geometry::model::segment
        <
            boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>
        > segment_type;

    typedef boost::geometry::segment_view<segment_type> segment_view;

    segment_type segment;
    boost::geometry::assign_values(segment, 0, 0, 1, 1);

    segment_view view(segment);

    // Iterating over the points of this segment
    for (boost::range_iterator<segment_view const>::type it = boost::begin(view);
        it != boost::end(view); ++it)
    {
        std::cout << " " << boost::geometry::dsv(*it);
    }
    std::cout << std::endl;

    // Note that a segment_view is tagged as a linestring, so supports length etc.
    std::cout << "Length: " << boost::geometry::length(view) << std::endl;

    return 0;
}

//]

//[segment_view_output
/*`
Output:
[pre
 (0, 0) (0, 4) (4, 4) (4, 0) (0, 0)
Area: 16
]
*/
//]


#pragma once

#include "ArithmeticProgression.hpp"
#include "Misc.hpp"
#include "Reversed.hpp"
#include "Sequences.hpp"
#include "VectorHelpers.hpp"
#include "detail/PartitionsDetail.hpp"
#include <boost/iterator/iterator_facade.hpp>

namespace discreture
{

////////////////////////////////////////////////////////////
/// \brief class of partitions of the number n.
/// \param IntType should be an integral type with enough space to store n and
/// k. It can be signed or unsigned. # Example:
///
///	 partitions X(6);
///		for (auto&& x : X)
///			cout << x << ' ';
///
/// Prints out:
///
/// 	[ 1 1 1 1 1 1 ] [ 2 1 1 1 1 ] [ 3 1 1 1 ] [ 2 2 1 1 ] [ 4 1 1 ] [ 3 2 1
/// ] [ 2 2 2 ] [ 5 1 ] [ 4 2 ] [ 3 3 ] [ 6 ]
////////////////////////////////////////////////////////////
template <class IntType = int, class RAContainerInt = std::vector<IntType>>
class Partitions
{
public:
    static_assert(std::is_integral<IntType>::value,
                  "Template parameter IntType must be integral");
    static_assert(std::is_signed<IntType>::value,
                  "Template parameter IntType must be signed");
    using value_type = RAContainerInt;
    using partition = value_type;
    using difference_type = std::ptrdiff_t;
    using size_type = difference_type;
    class iterator;
    using const_iterator = iterator;
    class reverse_iterator;
    using const_reverse_iterator = reverse_iterator;

    ////////////////////////////////////////////////////////////
    /// \brief Constructor
    ///
    /// \param n is an integer >= 0
    ///
    ////////////////////////////////////////////////////////////
    explicit Partitions(IntType n)
        : n_(n), min_num_parts_(1), max_num_parts_(n), size_(calc_size(n))
    {}

    ////////////////////////////////////////////////////////////
    /// \brief Constructor
    ///
    /// \param n is an integer >= 0
    /// \param numparts is an integer >= 1 and <= n
    ///
    ////////////////////////////////////////////////////////////
    Partitions(IntType n, IntType numparts)
        : n_(n)
        , min_num_parts_(numparts)
        , max_num_parts_(numparts)
        , size_(calc_size(n, numparts))
    {}

    ////////////////////////////////////////////////////////////
    /// \brief Constructor
    ///
    /// \param n is an integer >= 0
    /// \param minnumparts is an integer >= 1 and <= n
    /// \param maxnumparts is an integer >= minnumparts and <= n
    ///
    ////////////////////////////////////////////////////////////
    Partitions(IntType n, IntType minnumparts, IntType maxnumparts)
        : n_(n)
        , min_num_parts_(minnumparts)
        , max_num_parts_(maxnumparts)
        , size_(calc_size(n, minnumparts, maxnumparts))
    {}

    ////////////////////////////////////////////////////////////
    /// \brief The total number of partitions
    ///
    /// \return p_n
    ///
    ////////////////////////////////////////////////////////////
    size_type size() const { return size_; }

    IntType get_n() const { return n_; }

    iterator begin() const { return iterator(n_, max_num_parts_); }

    const iterator end() const
    {
        return iterator::make_invalid_with_id(size());
    }

    reverse_iterator rbegin() const
    {
        return reverse_iterator(n_, min_num_parts_);
    }

    const reverse_iterator rend() const
    {
        return reverse_iterator::make_invalid_with_id(size());
    }

    template <class Func>
    void for_each(Func f) const
    {
        for (auto k : reversed(II(min_num_parts_, max_num_parts_ + 1)))
        {
            for_each(f, k);
        }
    }

    ////////////////////////////////////////////////////////////
    /// \brief Bidirectional iterator class.
    ////////////////////////////////////////////////////////////
    class iterator
        : public boost::iterator_facade<iterator, const partition&, boost::bidirectional_traversal_tag>
    {
    public:
        iterator() : n_(0), data_() {}

        explicit iterator(IntType n, IntType numparts)
            : n_(n), data_(numparts, 1)
        {
            if (numparts > 0)
                data_[0] = n - numparts + 1;
        }

        inline size_type ID() const { return ID_; }

        // boost::iterator_facade provides all the public interface you need,
        // like ++, etc.

        static const iterator make_invalid_with_id(size_type id)
        {
            iterator it;
            it.ID_ = id;
            return it;
        }

    private:
        void increment()
        {
            ++ID_;

            next_partition(data_, n_);
        }

        void decrement()
        {
            --ID_;

            prev_partition(data_, n_);
        }

        const partition& dereference() const { return data_; }

        bool equal(const iterator& it) const { return it.ID() == ID(); }

        difference_type distance_to(const iterator& lhs) const
        {
            return static_cast<difference_type>(lhs.ID()) - ID();
        }

    private:
        size_type ID_{0};
        IntType n_;
        partition data_;

        friend class boost::iterator_core_access;
    }; // end class iterator

    ////////////////////////////////////////////////////////////
    /// \brief Bidirectional iterator class.
    ////////////////////////////////////////////////////////////
    class reverse_iterator
        : public boost::iterator_facade<reverse_iterator,
                                        const partition&,
                                        boost::bidirectional_traversal_tag>
    {
    public:
        reverse_iterator() : n_(0), data_() {}

        explicit reverse_iterator(IntType n, IntType numparts) : n_(n), data_()
        {
            last_with_given_number_of_parts(data_, n, numparts);
        }

        inline size_type ID() const { return ID_; }

        // boost::iterator_facade provides all the public interface you need,
        // like ++, etc.

        static const reverse_iterator make_invalid_with_id(size_type id)
        {
            reverse_iterator it;
            it.ID_ = id;
            return it;
        }

    private:
        void increment()
        {
            ++ID_;

            prev_partition(data_, n_);
        }

        void decrement()
        {
            --ID_;

            next_partition(data_, n_);
        }

        const partition& dereference() const { return data_; }

        bool equal(const reverse_iterator& it) const { return it.ID() == ID(); }

        difference_type distance_to(const reverse_iterator& lhs) const
        {
            return static_cast<difference_type>(lhs.ID()) - ID();
        }

    private:
        size_type ID_{0};
        IntType n_;
        partition data_;

        friend class boost::iterator_core_access;
    }; // end class reverse_iterator

    // **************** Begin static functions
    static void next_partition(partition& data, IntType n)
    {
        size_t t = data.size();

        if (t < 2)
        {
            return;
        }

        if (data.front() - data.back() < 2) // We must change size!
        {
            first_with_given_number_of_parts(data, n, t - 1);
            return;
        }

        // If no size change is necessary

        // Starting from the end, we look at the first whose difference is at
        // least 2 in order to transfer one unit from that one and then divide
        // unevenly among the other ones.
        IntType smallest = data.back();
        difference_type suffixSum = smallest;

        for (difference_type i = t - 2; i >= 0; --i)
        {
            if (data[i] - smallest > 1)
            {
                --data[i];
                distribute_unevenly(data.begin() + i + 1,
                                    data.end(),
                                    suffixSum + 1,
                                    data[i]);
                return;
            }
            suffixSum += data[i];
        }
    }

    static void prev_partition(partition& data, IntType n)
    {
        size_type t = data.size();
        if (t == 0)
            return;
        if (t == 1 || data[1] == 1)
        {
            last_with_given_number_of_parts(data, n, t + 1);
            return;
        }

        difference_type suffixSum = data.back();

        for (IntType i = t - 2; i >= 0; --i)
        {

            if (can_increase(data, i))
            {
                ++data[i];
                distribute_evenly(data.begin() + i + 1, data.end(), suffixSum - 1);
                return;
            }
            suffixSum += data[i];
        }
    }

    static void first_with_given_number_of_parts(partition& data,
                                                 IntType n,
                                                 IntType k)
    {
        if (n == 0)
        {
            data.clear();
            return;
        }

        data.resize(k);

        std::fill(data.begin(), data.end(), 1);

        data[0] = n - k + 1;
    }

    static void last_with_given_number_of_parts(partition& data,
                                                IntType n,
                                                IntType k)
    {
        if (n == 0)
        {
            data.clear();
            return;
        }
        data.resize(k);

        distribute_evenly(data.begin(), data.end(), n);
    }

    static partition conjugate(const partition& P)
    {
        assert(!P.empty());
        partition result(P[0], 1);
        auto n = P.size();

        result[0] = n;

        for (size_t i = 1; i < n; ++i)
        {
            auto t =
              std::lower_bound(P.begin(), P.end(), i, std::greater<IntType>());

            int r = t - P.begin();

            if (r > 0)
                result[i] = r;
        }

        return result;
    }

    // **************** End static functions

private:
    IntType n_;
    IntType min_num_parts_;
    IntType max_num_parts_;
    size_type size_;

    static size_type calc_size(IntType n) { return partition_number(n); }

    static size_type calc_size(IntType n, IntType numparts)
    {
        return partition_number(n, numparts);
    }

    static size_type calc_size(IntType n, IntType minnumparts, IntType maxnumparts)
    {
        size_type toReturn = 0;
        for (size_type k = minnumparts; k <= maxnumparts; ++k)
            toReturn += partition_number(n, k);
        return toReturn;
    }

    static bool can_increase(const partition& data, size_type i)
    {
        if (i == 0)
            return true;

        if (data[i] == 1 || data[i + 1] == 1)
            return false;

        if (data[i - 1] == data[i])
            return false;

        return true;
    }

    template <class Iter>
    static void distribute_evenly(const Iter& first, const Iter& last, IntType n)
    {
        if (first == last)
            return;
        IntType k = last - first;

        auto quot_rem = std::div(n, k);

        //         IntType lower = n/k;
        //         IntType residue = n - lower*k;

        auto mid = first + quot_rem.rem;
        std::fill(first, mid, quot_rem.quot + 1);
        std::fill(mid, last, quot_rem.quot);
    }

    template <class Iter>
    static void distribute_unevenly(Iter first,
                                    const Iter& last,
                                    IntType n,
                                    IntType maximum)
    {
        auto k = last - first;
        IntType excess = n - k;
        for (; first != last; ++first)
        {
            *first = std::min<IntType>(maximum, excess + 1);
            excess += (1 - *first);
        }
    }

    template <class Func>
    void for_each(Func f, IntType k) const
    {
        // I'm really sorry about this. I don't know how to improve it. If you
        // do, by all means, tell me about it.
        switch (k)
        {
            // clang-format off
        using part = partition;
        case 0: detail::for_each_partition<part, 0>::apply(n_, f); break;
        case 1: detail::for_each_partition<part, 1>::apply(n_, f); break;
        case 2: detail::for_each_partition<part, 2>::apply(n_, f); break;
        case 3: detail::for_each_partition<part, 3>::apply(n_, f); break;
        case 4: detail::for_each_partition<part, 4>::apply(n_, f); break;
        case 5: detail::for_each_partition<part, 5>::apply(n_, f); break;
        case 6: detail::for_each_partition<part, 6>::apply(n_, f); break;
        case 7: detail::for_each_partition<part, 7>::apply(n_, f); break;
        case 8: detail::for_each_partition<part, 8>::apply(n_, f); break;
        case 9: detail::for_each_partition<part, 9>::apply(n_, f); break;
        case 10: detail::for_each_partition<part, 10>::apply(n_, f); break;
        case 11: detail::for_each_partition<part, 11>::apply(n_, f); break;
        case 12: detail::for_each_partition<part, 12>::apply(n_, f); break;
        case 13: detail::for_each_partition<part, 13>::apply(n_, f); break;
        case 14: detail::for_each_partition<part, 14>::apply(n_, f); break;
        case 15: detail::for_each_partition<part, 15>::apply(n_, f); break;
        case 16: detail::for_each_partition<part, 16>::apply(n_, f); break;

            // clang-format on

        default:
        {
            for (auto&& x : Partitions<IntType, RAContainerInt>(n_, k))
            {
                f(x);
            }

            break;
        }
        } // end switch(k)
    }

}; // end class Partitions

using boost::container::static_vector;

using partitions = Partitions<int>;
using partitions_stack = Partitions<int, static_vector<int, 128>>;

} // namespace discreture


#ifndef __CORE_CORE_H__
#define __CORE_CORE_H__

#define EIGEN_NO_DEBUG

#include <string>
#include <vector>
#include <array>
#include <iostream>
using namespace std::literals;

#include <Eigen/Dense>

#include <fmt/format.h>
#include <fmt/ostream.h>
using namespace fmt::literals;

// assert
#ifdef ITP_NDEBUG
#define ITP_ASSERT(expression, comments) ((void)0)
#else
#define ITP_ASSERT(expression, comments) (void)(              \
			(!!(expression)) ||                                   \
			((std::cerr << __FILE__ << "(" << __LINE__ << ")\n" << comments << std::endl, exit(-2), 0))   \
	)
#endif

// math
namespace itp
{
	constexpr long double pi = 3.14159265358979323846264338327950288L;
	constexpr long double exp1 = 2.71828182845904523536028747135266250L;
}

// type define
namespace itp
{
	using Eigen::Dynamic;

	template <typename T>
	using Mat = Eigen::Array<T, Dynamic, Dynamic>;

	template <typename T>
	using Vec = Eigen::Array<T, Dynamic, 1>;

	using boxd = Mat<Eigen::Array3d>;

	using matd = Eigen::ArrayXXd;
	using mati = Eigen::ArrayXXi;

	using vecd = Eigen::ArrayXd;
	using veci = Eigen::ArrayXi;
}

#endif // !__CORE_CORE_H__

/* vim: set filetype=cpp et sw=2 ts=2 ai: */


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_TRIGONOMETRIC_FUNCTIONS_GENERIC_COTPI_HPP_INCLUDED
#define NT2_TRIGONOMETRIC_FUNCTIONS_GENERIC_COTPI_HPP_INCLUDED
#include <nt2/trigonometric/functions/cotpi.hpp>
#include <nt2/trigonometric/functions/scalar/impl/trigo.hpp>
#include <nt2/trigonometric/functions/simd/common/impl/trigo.hpp>
#include <boost/simd/sdk/simd/meta/is_native.hpp>
#include <nt2/include/functions/tofloat.hpp>
#include <nt2/include/functions/scalar/is_flint.hpp>
#include <nt2/include/constants/nan.hpp>
#include <nt2/include/constants/inf.hpp>
#include <nt2/include/functions/is_eqz.hpp>

namespace nt2 { namespace ext
{
  NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::cotpi_, tag::cpu_
                            , (A0)
                            , (generic_< arithmetic_<A0> >)
                            )
  {
    typedef typename boost::dispatch::meta::as_floating<A0>::type result_type;
    inline result_type operator()(A0 const& a0)const
    {
      return nt2::if_else(nt2::is_eqz(a0),
                          nt2::Inf<result_type>(),
                          nt2::Nan<result_type>());
    }
  };

  NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::cotpi_, tag::cpu_
                            , (A0)
                            , (generic_< floating_<A0> >)
                            )
  {
    typedef A0 result_type;
    typedef typename boost::simd::meta::is_native<A0>::type is_native_t;
    NT2_FUNCTOR_CALL(1)
    {
      return impl::trig_base<A0,pi_tag,is_native_t>::cota(a0);
    }
  };
} }

#endif


/*
 * Copyright 2013 Matthew Harvey
 *
 * 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 "frequency.hpp"
#include "interval_type.hpp"
#include "dcm_exceptions.hpp"
#include "string_conv.hpp"
#include <boost/lexical_cast.hpp>
#include <jewel/decimal.hpp>
#include <jewel/decimal_exceptions.hpp>
#include <jewel/exception.hpp>
#include <wx/string.h>
#include <string>

using boost::lexical_cast;
using jewel::Decimal;
using jewel::DecimalMultiplicationException;
using std::string;

namespace dcm
{

namespace
{
    Decimal const& days_per_year()
    {
        static Decimal const ret("365.25");
        return ret;
    }
    Decimal const& days_per_week()
    {
        static Decimal const ret("7");
        return ret;
    }
    Decimal const& months_per_year()
    {
        static Decimal const ret("12");
        return ret;
    }
    Decimal const& days_per_canonical_interval()
    {
        // A number with that's wholly divisible
        // by various commonly used Frequencies expressed
        // in numbers of days.
        static Decimal const ret(654528, 0);
        return ret;
    }
    Decimal const& weeks_per_canonical_interval()
    {
        static Decimal const ret =
            days_per_canonical_interval() / days_per_week();
        JEWEL_ASSERT (round(ret, 0) == ret);
        return ret;
    }
    Decimal const& years_per_canonical_interval()
    {
        static Decimal const ret =
            days_per_canonical_interval() / days_per_year();
        JEWEL_ASSERT (round(ret, 0) == ret);
        return ret;
    }
    Decimal const& months_per_canonical_interval()
    {
        static Decimal const ret =
            years_per_canonical_interval() * months_per_year();
        JEWEL_ASSERT (round(ret, 0) == ret);
        return ret;
    }

}  // end anonymous namespace

Frequency::Frequency
(   int p_num_steps,
    IntervalType p_step_type
):
    m_num_steps(p_num_steps),
    m_step_type(p_step_type)
{
    if (p_num_steps < 1)
    {
        JEWEL_THROW
        (   InvalidFrequencyException,
            "In Frequency constructor, p_num_steps passed a value less than 1."
        );
    }
    JEWEL_ASSERT (p_num_steps > 0);
}

int
Frequency::num_steps() const
{
    return m_num_steps;
}

IntervalType
Frequency::step_type() const
{
    return m_step_type;
}

string
frequency_description(Frequency const& frequency, string const& first_word)
{
    string ret = first_word + " ";
    int const num_steps = frequency.num_steps();
    if (num_steps > 1)
    {
        ret += lexical_cast<string>(num_steps);
        ret += " ";
        ret += wx_to_std8(phrase(frequency.step_type(), true));
    }
    else
    {
        ret += wx_to_std8(phrase(frequency.step_type(), false));
    }
    return ret;
}

Frequency const&
canonical_frequency()
{
    JEWEL_ASSERT
    (   round(days_per_canonical_interval(), 0) ==
        days_per_canonical_interval()
    );
    static Frequency const ret
    (   round(days_per_canonical_interval(), 0).intval(),
        IntervalType::days
    );
    return ret;
}

Decimal
convert_to_canonical(Frequency const& p_frequency, Decimal const& p_amount)
{
    auto const num_steps = p_frequency.num_steps();
    static_assert
    (   sizeof(Decimal::int_type) >= sizeof(num_steps),
        "Potentially unsafe integral conversion."
    );
    Decimal const steps(num_steps, 0);  // will not throw

    // The next part could throw DecimalMultiplicationException or
    // DecimalDivisionException.
    switch (p_frequency.step_type())
    {
    case IntervalType::days:
        return p_amount * days_per_canonical_interval() / steps;
    case IntervalType::weeks:
        return p_amount * weeks_per_canonical_interval() / steps;
    case IntervalType::months:  // fall through
    case IntervalType::month_ends:
        return p_amount * months_per_canonical_interval() / steps;
    default:
        JEWEL_HARD_ASSERT (false);
    }
}

Decimal
convert_from_canonical(Frequency const& p_frequency, Decimal const& p_amount)
{
    auto const num_steps = p_frequency.num_steps();
    static_assert
    (   sizeof(Decimal::int_type) >= sizeof(num_steps),
        "Potentially unsafe integral conversion."
    );
    Decimal const steps(num_steps, 0);  // will not throw

    // Might throw DecimalMultiplicationException.
    Decimal const intermediate = p_amount * steps;

    // The next part will throw jewel::DecimalDivisionException if and only if
    // the number of significant digits in intermediate is
    // equal to jewel::Decimal::maximum_precision().
    switch (p_frequency.step_type())
    {
    case IntervalType::days:
        return intermediate / days_per_canonical_interval();
    case IntervalType::weeks:
        return intermediate / weeks_per_canonical_interval();
    case IntervalType::months:  // fall through
    case IntervalType::month_ends:
        return intermediate / months_per_canonical_interval();
    default:
        JEWEL_HARD_ASSERT (false);
    }
}

bool
operator==(Frequency const& lhs, Frequency const& rhs)
{
    return
        (lhs.num_steps() == rhs.num_steps()) &&
        (lhs.step_type() == rhs.step_type());
}

bool
operator!=(Frequency const& lhs, Frequency const& rhs)
{
    return !(lhs == rhs);
}

}  // namespace dcm


#include <boost/hana.hpp>
#include <string>

using namespace boost::hana;

int main()
{
	auto t = make_tuple(type_c<std::string>, type_c<int>, type_c<bool>);

	auto r1 = index_if(t, equal.to(type_c<bool>));
	static_assert(r1.value().value == 2);

	auto r2 = index_if(t, equal.to(type_c<double>));
	static_assert(r2.value_or(-1) == -1);
}


///////////////////////////////////////////////////////////////////////////////
// frequency.hpp                                                             //
//                                                                           //
//  Copyright 2010 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_DETAIL_ACCUMULATOR_STATISTICS_FREQUENCY_HPP_ER_2010
#define BOOST_STATISTICS_DETAIL_ACCUMULATOR_STATISTICS_FREQUENCY_HPP_ER_2010
/*

#include <iostream> // tmp

#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/if.hpp>

#include <boost/parameter/binding.hpp>

#include <boost/accumulators/framework/extractor.hpp>
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/depends_on.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/count.hpp>

#include <boost/statistics/detail/non_parametric/empirical_distribution/count.hpp>

namespace boost {
namespace statistics{
namespace detail{
namespace empirical_distribution{

    // Usage:
    //     namespace ns = empirical_distribution;
    //     accumulator_set<T,stats<ns::tag::count<is_cum> > > acc;
    //     acc = boost:for_each(samples,acc);
    //     ns::extract::count<is_cum>(acc,x);
    // The result of the last statement is the % of observation matching (less
    // than) x in the samples if is_cum = false (true).

namespace impl{

    // Frequency as percentage of the sample size
    //
    // Warning : See empirical_distribution::impl::count.
	template<typename T,bool is_cum,typename T1>
	class frequency : public boost::accumulators::accumulator_base{

		typedef std::size_t size_;
        typedef boost::accumulators::dont_care dont_care_;

        public:

        frequency(dont_care_){}

        typedef size_ size_type;
        typedef T sample_type;  // See accumulator_set
        typedef T1 result_type;

        void operator()(dont_care_)const{}

        template<typename Args>
        result_type result(const Args& args) const
        {
        }
    };

}

namespace tag
{
    template<bool is_cum,typename T1 = double>
    struct frequency
      : boost::accumulators::depends_on<
      	statistics::detail::empirical_distribution::tag::count<is_cum>,
        boost::accumulators::tag::count
    >
    {
        struct impl{
            template<typename T,typename W>
            struct apply{
        		typedef statistics::detail::empirical_distribution
                	::impl::frequency<T,is_cum,T1> type;
            };
        };
    };
}

namespace result_of{

    template<bool is_cum,typename T1,typename AccSet>
    struct frequency{

        typedef boost::statistics::detail
        	::empirical_distribution::tag::frequency<is_cum,T1> tag_;
        typedef typename boost::accumulators
        	::detail::template extractor_result<AccSet,tag_>::type type;

    };
}

namespace extract
{

    // Usage : frequency<is_cum,T1>(acc,x)
    template<bool is_cum,typename T1,typename AccSet,typename T>
    typename boost::statistics::detail::empirical_distribution
    	::result_of::template frequency<is_cum,T1,AccSet>::type
    frequency(AccSet const& acc,const T& x)
    {
		    typedef std::size_t size_;
        	typedef boost::accumulators::tag::count tag_n_;

            namespace ns = boost::statistics::detail::empirical_distribution;

            size_ i =  ns::extract::count<is_cum>( acc, x );
            size_ n = boost::accumulators::extract_result<tag_n_>( acc );
            return static_cast<T1>(i)/static_cast<T1>(n);
    }

}

using extract::frequency;

}// empirical_distribution
}// detail
}// statistics
}// boost

*/

#endif


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "reference/workloads/DetectionPostProcess.cpp"

#include <armnn/Descriptors.hpp>
#include <armnn/Types.hpp>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(RefDetectionPostProcess)

BOOST_AUTO_TEST_CASE(TopKSortTest)
{
    unsigned int k = 3;
    unsigned int indices[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
    float values[8] = { 0, 7, 6, 5, 4, 3, 2, 500 };
    TopKSort(k, indices, values, 8);
    BOOST_TEST(indices[0] == 7);
    BOOST_TEST(indices[1] == 1);
    BOOST_TEST(indices[2] == 2);
}

BOOST_AUTO_TEST_CASE(FullTopKSortTest)
{
    unsigned int k = 8;
    unsigned int indices[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
    float values[8] = { 0, 7, 6, 5, 4, 3, 2, 500 };
    TopKSort(k, indices, values, 8);
    BOOST_TEST(indices[0] == 7);
    BOOST_TEST(indices[1] == 1);
    BOOST_TEST(indices[2] == 2);
    BOOST_TEST(indices[3] == 3);
    BOOST_TEST(indices[4] == 4);
    BOOST_TEST(indices[5] == 5);
    BOOST_TEST(indices[6] == 6);
    BOOST_TEST(indices[7] == 0);
}

BOOST_AUTO_TEST_CASE(IouTest)
{
    float boxI[4] = { 0.0f, 0.0f, 10.0f, 10.0f };
    float boxJ[4] = { 1.0f, 1.0f, 11.0f, 11.0f };
    float iou = IntersectionOverUnion(boxI, boxJ);
    BOOST_TEST(iou == 0.68, boost::test_tools::tolerance(0.001));
}

BOOST_AUTO_TEST_CASE(NmsFunction)
{
    std::vector<float> boxCorners({
        0.0f, 0.0f, 1.0f, 1.0f,
        0.0f, 0.1f, 1.0f, 1.1f,
        0.0f, -0.1f, 1.0f, 0.9f,
        0.0f, 10.0f, 1.0f, 11.0f,
        0.0f, 10.1f, 1.0f, 11.1f,
        0.0f, 100.0f, 1.0f, 101.0f
    });

    std::vector<float> scores({ 0.9f, 0.75f, 0.6f, 0.93f, 0.5f, 0.3f });

    std::vector<unsigned int> result = NonMaxSuppression(6, boxCorners, scores, 0.0, 3, 0.5);
    BOOST_TEST(result.size() == 3);
    BOOST_TEST(result[0] == 3);
    BOOST_TEST(result[1] == 0);
    BOOST_TEST(result[2] == 5);
}

void DetectionPostProcessTestImpl(bool useRegularNms, const std::vector<float>& expectedDetectionBoxes,
                                  const std::vector<float>& expectedDetectionClasses,
                                  const std::vector<float>& expectedDetectionScores,
                                  const std::vector<float>& expectedNumDetections)
{
    armnn::TensorInfo boxEncodingsInfo({ 1, 6, 4 }, armnn::DataType::Float32);
    armnn::TensorInfo scoresInfo({ 1, 6, 3 }, armnn::DataType::Float32);
    armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);

    armnn::TensorInfo detectionBoxesInfo({ 1, 3, 4 }, armnn::DataType::Float32);
    armnn::TensorInfo detectionScoresInfo({ 1, 3 }, armnn::DataType::Float32);
    armnn::TensorInfo detectionClassesInfo({ 1, 3 }, armnn::DataType::Float32);
    armnn::TensorInfo numDetectionInfo({ 1 }, armnn::DataType::Float32);

    armnn::DetectionPostProcessDescriptor desc;
    desc.m_UseRegularNms = useRegularNms;
    desc.m_MaxDetections = 3;
    desc.m_MaxClassesPerDetection = 1;
    desc.m_DetectionsPerClass =1;
    desc.m_NmsScoreThreshold = 0.0;
    desc.m_NmsIouThreshold = 0.5;
    desc.m_NumClasses = 2;
    desc.m_ScaleY = 10.0;
    desc.m_ScaleX = 10.0;
    desc.m_ScaleH = 5.0;
    desc.m_ScaleW = 5.0;

    std::vector<float> boxEncodings({
        0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, -1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f
    });
    std::vector<float> scores({
        0.0f, 0.9f, 0.8f,
        0.0f, 0.75f, 0.72f,
        0.0f, 0.6f, 0.5f,
        0.0f, 0.93f, 0.95f,
        0.0f, 0.5f, 0.4f,
        0.0f, 0.3f, 0.2f
    });
    std::vector<float> anchors({
        0.5f, 0.5f, 1.0f, 1.0f,
        0.5f, 0.5f, 1.0f, 1.0f,
        0.5f, 0.5f, 1.0f, 1.0f,
        0.5f, 10.5f, 1.0f, 1.0f,
        0.5f, 10.5f, 1.0f, 1.0f,
        0.5f, 100.5f, 1.0f, 1.0f
    });

    std::vector<float> detectionBoxes(detectionBoxesInfo.GetNumElements());
    std::vector<float> detectionScores(detectionScoresInfo.GetNumElements());
    std::vector<float> detectionClasses(detectionClassesInfo.GetNumElements());
    std::vector<float> numDetections(1);

    armnn::DetectionPostProcess(boxEncodingsInfo, scoresInfo, anchorsInfo,
                                detectionBoxesInfo, detectionClassesInfo,
                                detectionScoresInfo, numDetectionInfo, desc,
                                boxEncodings.data(), scores.data(), anchors.data(),
                                detectionBoxes.data(), detectionClasses.data(),
                                detectionScores.data(), numDetections.data());

    BOOST_TEST(detectionBoxes == expectedDetectionBoxes);
    BOOST_TEST(detectionScores == expectedDetectionScores);
    BOOST_TEST(detectionClasses == expectedDetectionClasses);
    BOOST_TEST(numDetections == expectedNumDetections);
}

BOOST_AUTO_TEST_CASE(RegularNmsDetectionPostProcess)
{
    std::vector<float> expectedDetectionBoxes({
        0.0f, 10.0f, 1.0f, 11.0f,
        0.0f, 10.0f, 1.0f, 11.0f,
        0.0f, 0.0f, 0.0f, 0.0f
    });

    std::vector<float> expectedDetectionScores({ 0.95f, 0.93f, 0.0f });
    std::vector<float> expectedDetectionClasses({ 1.0f, 0.0f, 0.0f });
    std::vector<float> expectedNumDetections({ 2.0f });

    DetectionPostProcessTestImpl(true, expectedDetectionBoxes, expectedDetectionClasses,
                                 expectedDetectionScores, expectedNumDetections);
}

BOOST_AUTO_TEST_CASE(FastNmsDetectionPostProcess)
{
    std::vector<float> expectedDetectionBoxes({
        0.0f, 10.0f, 1.0f, 11.0f,
        0.0f, 0.0f, 1.0f, 1.0f,
        0.0f, 100.0f, 1.0f, 101.0f
    });
    std::vector<float> expectedDetectionScores({ 0.95f, 0.9f, 0.3f });
    std::vector<float> expectedDetectionClasses({ 1.0f, 0.0f, 0.0f });
    std::vector<float> expectedNumDetections({ 3.0f });

    DetectionPostProcessTestImpl(false, expectedDetectionBoxes, expectedDetectionClasses,
                                 expectedDetectionScores, expectedNumDetections);
}

BOOST_AUTO_TEST_SUITE_END()


#include "marginal_algorithm.h"

#include <Eigen/Dense>
#include <cassert>
#include <stan/math/prim/fun.hpp>

#include "algorithm_state.pb.h"
#include "base_algorithm.h"
#include "src/collectors/base_collector.h"

void MarginalAlgorithm::remove_singleton(const unsigned int idx) {
  // Relabel allocations
  for (auto &c : allocations) {
    if (c > idx) {
      c -= 1;
    }
  }
  // Remove cluster
  unique_values.erase(unique_values.begin() + idx);
}

Eigen::VectorXd MarginalAlgorithm::lpdf_from_state(
    const Eigen::MatrixXd &grid, const Eigen::RowVectorXd &hier_covariate,
    const Eigen::RowVectorXd &mix_covariate) {
  // Read mixing state
  unsigned int n_data = curr_state.cluster_allocs_size();
  unsigned int n_clust = curr_state.cluster_states_size();
  mixing->set_state_from_proto(curr_state.mixing_state());
  // Initialize estimate containers
  Eigen::MatrixXd lpdf_local(grid.rows(), n_clust + 1);
  Eigen::VectorXd lpdf_final(grid.rows());
  auto temp_hier = unique_values[0]->clone();

  for (size_t j = 0; j < n_clust; j++) {
    // Get hierarchy and mass values
    temp_hier->set_state_from_proto(curr_state.cluster_states(j));
    double mass_ex = mixing->mass_existing_cluster(n_data, true, false,
                                                   temp_hier, mix_covariate);
    // Get local, single-point estimate
    lpdf_local.col(j) =
        temp_hier->like_lpdf_grid(grid, hier_covariate).array() + mass_ex;
  }
  double mass_new =
      mixing->mass_new_cluster(n_data, true, false, n_clust, mix_covariate);
  lpdf_local.col(n_clust) =
      lpdf_marginal_component(temp_hier, grid, hier_covariate).array() +
      mass_new;
  // Loop over grid points
  for (size_t i = 0; i < grid.rows(); i++) {
    // Final estimate for i-th grid point
    lpdf_final(i) = stan::math::log_sum_exp(lpdf_local.row(i));
    assert(!isnan(lpdf_final(i)));
  }
  return lpdf_final;
}


#pragma once

// deal.II includes --------------------
#include <deal.II/base/function.h>

// my own includes
#include "var_form/polar_var_form.hpp"

namespace boltzmann {

/**
 * @brief spatial integrals for weighted least squares formulation
 *
 *
 * \f$ \operatorname{L} := v \cdot \nabla_x + \sigma(x)\f$
 *
 */
template <int dimX, typename APP>
class LeastSquaresVarForm : public PolarXVarForm<dimX>
{
 public:
  /**
   * @param fe : fe space
   */
  template <typename FE>
  LeastSquaresVarForm(const FE& fe)
      : PolarXVarForm<dimX>(fe)
  { /* empty */
  }

 public:
  /**
   * @brief transport matrix \f$ \left ( \operatorname{R} b_i , \epsilon(x) \operatorname{L} b_j
   * \right)_{L^2} \f$
   * where \f$ \operatorname{R} = \operatorname{L} \f$
   * @param cell
   *
   *
   * Query results with members: PolarXVarForm::S0(), PolarXVarForm::S1(), PolarXVarForm::T1(),
   * PolarXVarForm::T2()
   *
   * Note that for thea bsorption free case, i.e. \f$\sigma(x) = 0\f$, only T2() has nonzero
   * contribution.
   *
   */
  template <typename cell_iterator>
  void calc_transport_cell(const cell_iterator& cell);

  /**
   * @brief Stabilized identity \f$ \left ( \operatorname{R} b_i,
   *        \epsilon(x) b_j \right )_{L^2} \f$
   *        where \f$ \operatorname{R} = v \cdot \nabla_x + \sigma(x)\f$
   *
   *
   * @param cell
   *
   *
   * Query results with members: PolarXVarForm::S0(), PolarXVarForm::S1()
   *
   *
   */
  template <typename cell_iterator>
  void calc_identity(const cell_iterator& cell);

  /**
   * @brief Stabilized identity
   *        \f$
   *        \left ( \operatorname{R} b_i, b_j \right )_{L_2(\Omega)} +
   *        \left ( b_i, \operatorname{R} b_j \right )_{L_2(\Omega)}
   *        \f$
   *        where \f$ \operatorname{R} = v \cdot \nabla_x \f$
   * DEPRECATED
   *
   * @param cell
   *
   *
   */
  template <typename cell_iterator>
  void calc_identity_sym(const cell_iterator& cell) __attribute__((deprecated));

  /**
   * @brief just overlap (without stabilization term)
   *        hint: this uses the weighted l2 scalar product
   *        \f$ \left(b_i, b_j\right )_L^2 \f$
   *
   * Query results with members: PolarXVarForm::S0()
   *
   */
  template <typename cell_iterator>
  void calc_raw_identity(const cell_iterator& cell);

  template <typename cell_iterator>
  void calc_boundary(const cell_iterator& cell);

  static const std::string info;
};

template <int dimX, typename APP>
const std::string LeastSquaresVarForm<dimX, APP>::info = "Weighted least squares";

// --------------------------------------------------------------------------------
template <int dimX, typename APP>
template <typename cell_iterator>
inline void
LeastSquaresVarForm<dimX, APP>::calc_transport_cell(const cell_iterator& cell)
{
  // update fevalues
  this->init_cell(cell);
  // clear S0_mat, S1_mat, T1_mat, T2_mat
  PolarXVarForm<dimX>::clear_storage();

  const int n_qpoints = this->quad.size();
  // make sure the arrays have the right size
  const int dofs_per_cell = this->fe_values.dofs_per_cell;

  for (int ix1 = 0; ix1 < dofs_per_cell; ++ix1) {
    for (int ix2 = 0; ix2 < dofs_per_cell; ++ix2) {
      for (int q = 0; q < n_qpoints; ++q) {
        auto shape_ix1 = this->fe_values.shape_value(ix1, q);
        auto shape_ix2 = this->fe_values.shape_value(ix2, q);
        auto grad_ix1 = this->fe_values.shape_grad(ix1, q);
        auto grad_ix2 = this->fe_values.shape_grad(ix2, q);
        double weight = this->fe_values.JxW(q);

#if DEAL_II_VERSION_MAJOR >= 8 && DEAL_II_VERSION_MINOR <= 3
        typename PolarXVarForm<dimX>::T2_t T2tmp;
        outer_product(T2tmp, grad_ix1, grad_ix2 * weight);
        this->T2_mat[ix1][ix2] += T2tmp;
#else
        this->T2_mat[ix1][ix2] += outer_product(grad_ix1, grad_ix2 * weight);
#endif  // DEAL_II_VERSION_MAJOR >= 8 && DEAL_II_VERSION_MINOR <= 3
        // mass contributions
      }
    }
  }
}

// --------------------------------------------------------------------------------
template <int dimX, typename APP>
template <typename cell_iterator>
inline void
LeastSquaresVarForm<dimX, APP>::calc_identity(const cell_iterator& cell)
{
  // update fevalues
  this->init_cell(cell);
  // clear S0_mat, S1_mat, T1_mat, T2_mat
  PolarXVarForm<dimX>::clear_storage();

  const int n_qpoints = this->quad.size();

  const int dofs_per_cell = this->fe_values.dofs_per_cell;
  for (int ix1 = 0; ix1 < dofs_per_cell; ++ix1) {
    // test
    for (int ix2 = 0; ix2 < dofs_per_cell; ++ix2) {
      // trial
      for (int q = 0; q < n_qpoints; ++q) {
        auto shape_ix1 = this->fe_values.shape_value(ix1, q);
        auto shape_ix2 = this->fe_values.shape_value(ix2, q);
        auto grad_ix1 = this->fe_values.shape_grad(ix1, q);
        double weight = this->fe_values.JxW(q);
        // mass contributions
        this->S1_mat[ix1][ix2] += grad_ix1 * (shape_ix2 * weight);
      }
    }
  }
}

// --------------------------------------------------------------------------------
template <int dimX, typename APP>
template <typename cell_iterator>
inline void
LeastSquaresVarForm<dimX, APP>::calc_identity_sym(const cell_iterator& cell)
{
  // update fevalues
  this->init_cell(cell);
  // clear S0_mat, S1_mat, T1_mat, T2_mat
  PolarXVarForm<dimX>::clear_storage();

  const int n_qpoints = this->quad.size();
  const int dofs_per_cell = this->fe_values.dofs_per_cell;

  for (int ix1 = 0; ix1 < dofs_per_cell; ++ix1) {
    // test
    for (int ix2 = 0; ix2 < dofs_per_cell; ++ix2) {
      // trial
      for (int q = 0; q < n_qpoints; ++q) {
        auto shape_ix1 = this->fe_values.shape_value(ix1, q);
        auto shape_ix2 = this->fe_values.shape_value(ix2, q);
        auto& grad_ix1 = this->fe_values.shape_grad(ix1, q);
        auto& grad_ix2 = this->fe_values.shape_grad(ix2, q);
        // auto grad_ix2 = this->fe_values.shape_grad(ix2,q);
        double weight = this->fe_values.JxW(q);
        // mass contributions
        this->S1_mat[ix1][ix2] += grad_ix1 * (shape_ix2 * weight) + grad_ix2 * (shape_ix1 * weight);
      }
    }
  }
}

// --------------------------------------------------------------------------------
template <int dimX, typename APP>
template <typename cell_iterator>
inline void
LeastSquaresVarForm<dimX, APP>::calc_raw_identity(const cell_iterator& cell)
{
  // update fevalues
  this->init_cell(cell);
  // clear S0_mat, S1_mat, T1_mat, T2_mat
  PolarXVarForm<dimX>::clear_storage();

  const int n_qpoints = this->quad.size();
  // make sure the arrays have the right size

  const int dofs_per_cell = this->fe_values.dofs_per_cell;
  for (int ix1 = 0; ix1 < dofs_per_cell; ++ix1) {
    // test
    for (int ix2 = 0; ix2 < dofs_per_cell; ++ix2) {
      // trial
      for (int q = 0; q < n_qpoints; ++q) {
        auto shape_ix1 = this->fe_values.shape_value(ix1, q);
        auto shape_ix2 = this->fe_values.shape_value(ix2, q);
        double weight = this->fe_values.JxW(q);
        // mass contributions
        this->S0_mat[ix1][ix2] += shape_ix1 * shape_ix2 * weight;
      }
    }
  }
}

// -------------------------------------------------------------------------------
template <int dimX, typename APP>
template <typename cell_iterator>
inline void
LeastSquaresVarForm<dimX, APP>::calc_boundary(const cell_iterator& cell)
{
  // update fevalues
  // clear S0_mat, S1_mat, T1_mat, T2_mat
  PolarXVarForm<dimX>::clear_storage();

  if (cell->at_boundary()) return;

  const int faces_per_cell = dealii::GeometryInfo<dimX>::faces_per_cell;
  const int n_qpoints = this->face_quad.size();
  const int dofs_per_cell = this->fe_values.dofs_per_cell;

  for (int face_idx = 0; face_idx < faces_per_cell; ++face_idx) {
    this->init_face(cell, face_idx);
    for (int ix1 = 0; ix1 < dofs_per_cell; ++ix1) {
      // test
      for (int ix2 = 0; ix2 < dofs_per_cell; ++ix2) {
        // trial
        for (int q = 0; q < n_qpoints; ++q) {
          auto shape_ix1 = this->fe_face_values.shape_value(ix1, q);
          auto shape_ix2 = this->fe_face_values.shape_value(ix2, q);
          double weight = this->fe_values.JxW(q);
          // mass contributions
          this->S1_mat[ix1][ix2] +=
              (this->fe_face_values.normal_vector(q) * shape_ix1 * shape_ix2 * weight);
        }
      }
    }
  }
}

}  // end namespace boltzmann


#include <iostream>
#include <fstream>
//#include <cstdlib>
#include <stdlib.h>
#include <time.h>
#include <iterator>
#include <vector>
#include <cmath>

#include <boost/program_options.hpp>

#define STRINGIFY(a) #a

namespace po = boost::program_options;

using namespace std;

// Build and parameters for populating the grid
int l;// = 49;
int h;// = 49;
vector< vector<int> > grid;//(l, vector<int>(h));

string grid_load_filename;

float grid_density;// = 0.50;
float init_coop_level;// = 0.50;
int cooperators,defectors,empty;

// Set up neighborhood
int numNeighbors;// = 4;
vector<int> nghb_h;//(numNeighbors);
vector<int> nghb_l;//(numNeighbors);

// Players
int focal_player_l,focal_player_h;
int player2_l,player2_h;

// Prisoner's Dilemma Constants and Variables
float T;// = 1.3;
float R;// = 1.0;
float P;// = 0.1;
float S;// = 0.0;

int strategy_focal_player;
float payoff_focal_player;

// Strategy update parameters
string update_style = "Dirk"; // warning : I've commented out the Fermi update function

float noise;// = 0.000;
float imitation_likelihood;
//float imitation_r;// = 1- imitation_likelihood;
float reset_strategy_likelihood;// = noise;

float fermi_temperature;// = 0.1;

// Migration parameters
int migration_range;// = 5;
float random_migration;// = 0;
float expell_likelihood;// = 0.01;

int n_migration_sites;// = (2*migration_range + 1)*(2*migration_range + 1) - 1;
vector<int> migration_array_l;//(n_migration_sites);
vector<int> migration_array_h;//(n_migration_sites);

// Simulation Parameters;

int verbose;// = 1;
int iterations;
int save_grids;

int MCS;// = l*h*iterations;//static_cast<const int>(l)*static_cast<const int>(h)*static_cast<const int>(iterations);

vector<int> rand_steps_l;//(MCS);
vector<int> rand_steps_h;//(MCS);
int current_step;
int count_changes = 1;

int chosen_migration_site;

ofstream output_all_mv;
ofstream output_summary;
ofstream output_grid_states;
string summary;

bool fileExists(string fileName)
{
    ifstream infile(fileName);
    return infile.good();
}

void prepare_parameters() {
    MCS = l*h*iterations;
    grid.resize(l, vector<int>(h));
    rand_steps_l.resize(MCS);
    rand_steps_h.resize(MCS);
    nghb_h.resize(numNeighbors);
    nghb_l.resize(numNeighbors);
    n_migration_sites = (2*migration_range + 1)*(2*migration_range + 1) - 1;
    migration_array_l.resize(n_migration_sites);
    migration_array_h.resize(n_migration_sites);
    }

// Output;

void open_output_files(){
    char Buffer[500];
    string str;
    int length = 0;
    length += sprintf(Buffer+length, "iter_%d",iterations);
    length += sprintf(Buffer+length, "_l_%d",l);
    length += sprintf(Buffer+length, "_h_%d",h);
    length += sprintf(Buffer+length, "_d_%0.3f", grid_density);
    length += sprintf(Buffer+length, "_cl_%0.3f",init_coop_level);
    length += sprintf(Buffer+length, "_ns_%d",numNeighbors);
    length += sprintf(Buffer+length, "_il_%0.3f",imitation_likelihood);
    length += sprintf(Buffer+length, "_q_%0.3f",reset_strategy_likelihood);
    length += sprintf(Buffer+length, "_M_%d",migration_range);
    length += sprintf(Buffer+length, "_m_%0.3f",random_migration);
    length += sprintf(Buffer+length, "_s_%0.4f",expell_likelihood);

    str.assign(Buffer, Buffer + length);

    int k = 0;
    string filename_output_all_mv = "results/allmoves/" + str + "_" + to_string(k) + ".csv";
    string filename_output_summary = "results/summary/" + str + "_" + to_string(k) + ".csv";
    string filename_configurations = "results/grids/" + str + "_" + to_string(k) + ".csv";

    while (fileExists(filename_output_summary)){
        k++;
        filename_output_all_mv = "results/allmoves/" + str + "_" + to_string(k) + ".csv";
        filename_output_summary = "results/summary/" + str + "_" + to_string(k) + ".csv";
        filename_configurations = "results/grids/" + str + "_" + to_string(k) + ".csv";
        }

    output_all_mv.open(filename_output_all_mv, ios::trunc); // open all moves output file;
    output_summary.open(filename_output_summary, ios::trunc); // open summary output file;
    output_summary << "simul_step,completion,coop_level,cooperators,defectors,empty\n";
    output_grid_states.open(filename_configurations, ios::trunc); // open configuration output file;
    }

string format_summary(){

    char Buffer[500];
    string str;
    int length = 0;

    length += sprintf(Buffer+length, "%d,",current_step);
    length += sprintf(Buffer+length, "%0.3f,",current_step/static_cast<float>(MCS));
    length += sprintf(Buffer+length, "%0.3f,",static_cast<float>(cooperators)/(cooperators + defectors));
    length += sprintf(Buffer+length, "%d,",cooperators);
    length += sprintf(Buffer+length, "%d,",defectors);
    length += sprintf(Buffer+length, "%d\n",empty);

    str.assign(Buffer, Buffer + length);

    return str;
    }

float rand01() {
	return (float)arc4random_uniform(100000)/100000;
	}

void makeGrid() {
	/* Makes a grid of size l with equal number
	 of cooperators (value 1) and defectors (value 0). If grid_density is
	 less than 100%, then the some sites are emptied randmonly (value -1)
	 */

	for (int i = 0; i < l; i++) {
		for (int j = 0; j < h; j++) {
            if (rand01() < init_coop_level) grid[i][j] = 1;
            else grid[i][j] = 0;

			if (rand01() > grid_density) { // remove player from grid as a function of grid_density
				grid[i][j] = -1;
            }
        }
    }
}

void countCDE(){
	/* Performs a count of cooperators, defectors and empty sites.
	 If update = 1, cooperators, defectors, and empty variables are updated
	 If update = 0, assuming that if there is no update, then the then the only reason
	 for invoking this function is to print out the current state of cooperation and defection.
	 Regardless of the value of update, if verbose >=2, then the current state of cooperation and defection is printed out.
	 */

	//int c,d,e = 0; // initialize count variables;

	cooperators = 0;
	defectors = 0;
	empty = 0;

	for (int i = 0; i < l; i++){
		for (int j = 0; j < h; j++){
			if (grid[i][j] == 1) {
				cooperators++;
            }

			else if (grid[i][j] == 0) {
				defectors++;
            }

			else {
				empty++;
            }
        }
    }

	if (verbose >= 2){
		cout << "cooperators:" << cooperators << ", defectors:" << defectors << ", empty sites:" << empty << endl;
    }

}

void load_grid(){

    std::ifstream testFile(grid_load_filename, std::ios::binary);

    string cell;
    int cellInt;

    grid.resize(l, vector<int>(h));

    int i=0;

    while(getline(testFile,cell,',')){
        stringstream str(cell);
        str >> cellInt;
        //cout << i/h << " " << i%h << " " << cellInt << endl;
        //grid[i/h][i%h] = cellInt;
        grid[i%h][i/h] = cellInt;
        i++;
    }
    countCDE(); // update values for cooperators, defectors, and empty
}

void showGrid(int subset = 20) {
	/* Displays the grid on the command line
	 Note that the grid is large, the display won't be nice.
	 */

    int height;
    int length;

    if (subset == 0){
        height = h;
        length = l;
        }
    else {
        height = length = subset;
        }

    string character;

	for (int j = 0; j < height; j++){
		for (int i=0; i < length; i++) {
            if (grid[i][j] == -1) character = " ";
            else character = to_string(grid[i][j]);

            if (i+1==length){

				if (grid[0][j+1] < 0){
					cout << character << "\n";
					//cout << grid[i][j] << "\n";
				}
				else {
					cout << character << "\n ";
				}
            }
			else {
				if (grid[i+1][j] < 0){
					cout << character << "\t";
                }
				else {
					cout << character << "\t ";
                }
            }
        }
    }
	cout << endl;
}

void save_grid_state(){

    output_grid_states << current_step << ":[";

    for (int j = 0; j < h; j++){
		for (int i=0; i < l; i++) {
            //output_grid_states << "(" << i << "," << j << "," << grid[i][j] << "),";
            output_grid_states << grid[i][j] << ",";
            }
        }
    output_grid_states << "]\n";
    }

void findNeighbors(int player_l, int player_h) {
	/*Find neighbors of a focal site:
	 If numNeighbors = 4, the 4 sites in direct contact are selected.
	 If numNeighbors = 8, the 8 sites around the focal site are selected.
	 This function is useful to compare payoffs between the focal player and her neighbors.
	 */

	//cout << "focal site: " << player_l << " " << player_h << " " << grid[player_l][player_h] << endl;
	//cout << player_l  << "," << player_h  << "\n" << endl;

	if ((numNeighbors != 4) && (numNeighbors != 8)){
		cout << "wrong neighborhood number" << endl;
    }

	if (numNeighbors==4){
		nghb_l[0] = player_l;
		nghb_h[0] = (player_h - 1 + h)%h;

		nghb_l[1] = (player_l - 1 + l)%l;
		nghb_h[1] = player_h;

		nghb_l[2] = (player_l + 1 + l)%l;
		nghb_h[2] = player_h;

		nghb_l[3] = player_l;
		nghb_h[3] = (player_h + 1 + h)%h;

    }

	/*
     cout << (player_h - 1 + h)%h  << "," << player_l << endl;
     cout << player_h << "," << (player_l - 1 + l)%l << endl;
     cout << player_h << "," << (player_l + 1 + l)%l << endl;
     cout << (player_h + 1 + h)%h << "," << player_l << endl;
     */

    /*
     cout << nghb_h[0]  << "," << nghb_l[0] << endl;
     cout << nghb_h[1] << "," << nghb_l[1] << endl;
     cout << nghb_h[2]<< "," << nghb_l[2] << endl;
     cout << nghb_h[3] << "," << nghb_l[3] << endl;
     */

	else if (numNeighbors==8){

		nghb_l[0] = (player_l - 1 + l)%l;
		nghb_h[0] = (player_h - 1 + h)%h;

		nghb_l[1] = player_l;
		nghb_h[1] = (player_h - 1 + h)%h;

		nghb_l[2] = (player_l + 1 + l)%l;
		nghb_h[2] = (player_h - 1 + h)%h;

		nghb_l[3] = (player_l - 1 + l)%l;
		nghb_h[3] = player_h;

		nghb_l[4] = (player_l + 1 + l)%l;
		nghb_h[4] = player_h;

		nghb_l[5] = (player_l - 1 + l)%l;
		nghb_h[5] = (player_h + 1 + h)%h;

		nghb_l[6] = player_l;
		nghb_h[6] = (player_h + 1 + h)%h;

		nghb_l[7] = (player_l + 1 + l)%l;
		nghb_h[7] = (player_h + 1 + h)%h;

    }

	if (verbose >= 2){
		for (int i=0; i < numNeighbors; i++) {
			cout << nghb_l[i]  << "," << nghb_h[i] << endl;
        }
    }

}

void explore_m_range(int player_l, int player_h){
	/* Explore migration range to find best sites. */

	int l_index;
	int h_index;

	int k = 0;
	for (int j= player_h - migration_range ; j < player_h + migration_range +1 ; j++) {
		for (int i = player_l - migration_range ; i < player_l + migration_range +1 ; i++){

			l_index = (i + l)%l;
			h_index = (j + h)%h;

			if ((l_index == player_l)&&(h_index == player_h)){
				continue;
            }

			migration_array_l[k] = l_index;
			migration_array_h[k] = h_index;
			k++;
		}
	}

	if (verbose >= 2){

		cout << "focal player: "
		<< player_l
		<< ","
		<< player_h
		<< " strategy: "
		<< grid[player_l][player_h]
		<< endl;

		k=0;
		for (int i = 0; i < n_migration_sites ; i++) {
			//cout << i << " (" << migration_array_l[i] << "," << migration_array_h[i] << ")" << endl;

			if ( (i-1) == (n_migration_sites-1)/2){
				cout << "X" << "," << "X" << "  ";
				k=1;
			}

			if ( (i + 1 + k)  % (2*migration_range +1) == 0){
				cout << migration_array_l[i] << "," << migration_array_h[i] << "(" << grid[ migration_array_l[i]][ migration_array_h[i]] << ")\n";
			}

			else {
				cout << migration_array_l[i] << "," << migration_array_h[i]  << "(" << grid[ migration_array_l[i]][ migration_array_h[i]] << ") ";
            }

        }
		cout << endl;
    }

}

float compute_migration_distance(float site_l, float site_h, float migration_site_l, float migration_site_h){
    // computes a simple distance between 2 sites

    return sqrt(pow(min(abs(site_l-migration_site_l), l-1-abs(site_l-migration_site_l)),2)+  pow(min(abs(site_h - migration_site_h), h-1-abs(site_h-migration_site_h)),2));
    }

float pDilemma(int strategy, int stragegy_nghb) {
	/* Implements the prisoners dilemma game between */

	float pd_payoff = 0;

	if ((strategy == 1) && (stragegy_nghb == 1)) {
		pd_payoff = R;
    }

	else if ((strategy == 0) && (stragegy_nghb == 1)) {
		pd_payoff = T;
    }

	else if ((strategy == 1) && (stragegy_nghb == 0)) {
		pd_payoff = S;
    }

	else if ((strategy == 0) && (stragegy_nghb == 0)) {
		pd_payoff = P;
    }

	else {
		cout << "error with input strategies" << endl;
		return -1;
    }

	return pd_payoff;
}

float payoff(int player_l, int player_h, int strategy){
	// Compute payoff from playing with neighbors

	//int strategy = grid[player_l][player_h];
	float sum_payoff = 0;

	findNeighbors(player_l,player_h); // Search for neighbors

	int strategy_nghb;

	for (int i=0; i < numNeighbors; i++) {

		strategy_nghb = grid[nghb_l[i]][nghb_h[i]];

		if (strategy_nghb != -1){

			sum_payoff += pDilemma(strategy, strategy_nghb);

			/*
             cout << nghb_l[i]
             << ","
             << nghb_h[i]
             << "  strategy :"
             << strategy_nghb
             << " payoff: "
             << payoff
             << endl;
             */
        }
    }

	//cout << "sum payoff: " << sum_payoff << endl;
	return sum_payoff;
}

int strategy_update_Fermi(float o_pay_off, float best_pay_off) {
	/*update strategy of focal player by trying to reproduce
	 the strategy of the best performing neighbor, using
	 Fermi Temperature*/

	if ((o_pay_off - best_pay_off) >= 0){
		/* If initial strategy has better payoff or
		 both strategies have same payoff, do nothing */
		//cout << " higher original payoff or same payoff: " << o_pay_off;
		return 0;

    }

	else {
		float f_temperature = 1./(1 + exp(o_pay_off - best_pay_off)/fermi_temperature);

		if (rand01() < f_temperature) {
			//cout << "update strategy" << endl;
			return 1;
        }
		else {
			//cout << "no update " << endl;
			return 0;
		}

    }

}

int strategy_update_Dirk(float o_pay_off, float best_pay_off){

	if ((o_pay_off < best_pay_off) and (rand01() <  imitation_likelihood)){
        //cout << o_pay_off << " " << best_pay_off << " " << rand01() << endl;
        return 2; // copy strategy
    }
	else if ((rand01() > imitation_likelihood) and (rand01() < reset_strategy_likelihood)){
		return 1; // cooperate
    }
    else if ((rand01() > imitation_likelihood ) and (rand01() > reset_strategy_likelihood) and (reset_strategy_likelihood > 0)){
		return 0; // defect
    }
    else {
        return -1; // do nothing
    }
}

void compare_payoff_with_nghbs(int player_l, int player_h, int update_strategies = 1){

    strategy_focal_player = grid[player_l][player_h];
	payoff_focal_player = payoff(player_l,player_h, strategy_focal_player);

	findNeighbors(player_l,player_h);

	//copy(begin(nghb_l), end(nghb_l), begin(nghbl));
	//int nghbh = nghb_h;

	float payoff_nghb;
	float strategy_nghb;
	float highest_payoff = payoff_focal_player;
	int win_strategy = strategy_focal_player;
	int win_nghb_l = player_l;
	int win_nghb_h = player_h;

	//vector<int> nghbl(numNeighbors];
	//vector<int> nghbh(numNeighbors];

    vector<int> nghbl(nghb_l);
	vector<int> nghbh(nghb_h);

    //copy(nghb_l, nghb_l + numNeighbors, nghbl);
	//copy(nghb_h, nghb_h + numNeighbors, nghbh);

	for (int i=0; i < numNeighbors; i++) {
		/* Parkour all neighbors to find the strategy with highest payoff */

		//cout << nghb_l[i] << "," << nghb_h[i] << " " << nghbl[i] << "," << nghbh[i] << endl;
		strategy_nghb = grid[nghbl[i]][nghbh[i]];

		if (strategy_nghb == -1) {
			//cout << "empty site" << endl;
			payoff_nghb = -1000; // assign an arbitrary small payoff
		}
		else {
			payoff_nghb = payoff(nghbl[i],nghbh[i],strategy_nghb);
		}

		if (payoff_nghb > highest_payoff){
			highest_payoff = payoff_nghb;
			win_nghb_l = nghbl[i];
			win_nghb_h = nghbh[i];
			win_strategy = strategy_nghb;
			//cout << highest_payoff << " " << win_strategy << " (" << win_nghb_l << "," << win_nghb_h << ") " << grid[win_nghb_l][win_nghb_h] << endl;
		}
	}

	if (update_strategies == 1){
		/* Attempt strategy update:
		 provides a binary value to determine if an update actually ocurred
		 (1 => update, 0 => no update) */
		int update_s;

		/* Choose update method */
		//if (update_style == "Fermi"){
		//	update_s = strategy_update_Fermi(payoff_focal_player, highest_payoff);
        //}
		//else if (update_style == "Dirk"){
        update_s = strategy_update_Dirk(payoff_focal_player, highest_payoff);
			//cout << "Dirk update " << update_s << endl;
        //}

		if ((update_s == 2) and (win_strategy != strategy_focal_player)){ //
			grid[player_l][player_h] = grid[win_nghb_l][win_nghb_h]; // update strategy

			//cout << grid[player_l][player_h] << endl;

            countCDE(); //recount current number of cooperators, defectors and empty sites.

			// write update to output_all_mv file
			output_all_mv  << current_step <<","
            << cooperators << ","
            << defectors << ","
            << empty << ","
            << "U" << ","
            << player_l << ","
            << player_h << ","
            << strategy_focal_player << ","
            << grid[win_nghb_l][win_nghb_h] << ","
            << payoff_focal_player << ","
            << highest_payoff
            << "\n";

            count_changes +=1;

			if (verbose >= 2){
				cout << "strategy updated for ("
				<< player_l
				<< ","
				<< player_h
				<< ")"
				<< " from "
				<< strategy_focal_player
				<< " to "
				<< win_strategy
				<< endl;
            }
        }

		else if ((update_s == 0) or (update_s == 1)){
			int old_strategy = grid[player_l][player_h];
			grid[player_l][player_h] = update_s;

            countCDE();

            output_all_mv  << current_step <<","
            << cooperators << ","
            << defectors << ","
            << empty << ","
            << "R" << ","
            << player_l << ","
            << player_h << ","
            << old_strategy << ","
            << grid[player_l][player_h]
            << "\n";

            count_changes +=1;
        }

        else {
            return;
        }
    }

}

void compare_payoff_m_range(int player_l, int player_h, float random_migration_likelihood, float expell, int force_migrate){

    strategy_focal_player = grid[player_l][player_h];
    int sfp = grid[player_l][player_h];
    payoff_focal_player = payoff(player_l,player_h, strategy_focal_player);
	explore_m_range(player_l,player_h);

    float pf;
	float best_pay_off;

    float migration_payoff[n_migration_sites];
    float migration_distance[n_migration_sites];
    float distance; //migration distance
	float shortest_distance = 1000; // shortest migration distance

	int index;

    int mv_destination_l;
    int mv_destination_h;

    string migration_type;

    vector<int> sites_empty;
	vector<int>::iterator it_e;

	vector<int> sites_occupied;
	vector<int>::iterator it_o;

	vector<int> best_sites_empty;
	vector<int>::iterator it_bse;

	vector<int> better_sites_empty;
	vector<int>::iterator it_rse;

    vector<int> better_sites_empty_payoff;
	vector<int>::iterator it_rsep;

	vector<int> best_sites_occupied;
	vector<int>::iterator it_bso;

    vector<int> worse_sites_empty;
	vector<int>::iterator it_wse;

    vector<int> worse_sites_empty_payoff;
	vector<int>::iterator it_wsep;

	if (verbose >=2) cout << "(" << player_l << "," << player_h << ") " << "orig. strategy : " << strategy_focal_player << "  orig. payoff : " << payoff_focal_player << endl;

	if (force_migrate == 1) best_pay_off = -10;// assign an arbitrary small value to force migration to make sure a "better" spot can be found
	else best_pay_off = payoff_focal_player + 0.0001; // added a small value to ensure that only sites with higher payoff are selected

	for (int q=0; q < n_migration_sites; q++){
        /* compute payoff on all possible migration sites */

        grid[player_l][player_h] = -1; //nasty hack to compute payoff assuming that the player has already left the site

		migration_payoff[q] = payoff(migration_array_l[q], migration_array_h[q],strategy_focal_player);
        migration_distance[q] = compute_migration_distance(player_l, player_h,migration_array_l[q] ,migration_array_h[q]);

        grid[player_l][player_h] = strategy_focal_player; // follow up nasty hack: restore original strategy because at this point is unclear whether the player will move

        if (migration_payoff[q] > best_pay_off) {
            // find the highest possible payoff among all sites
            best_pay_off = migration_payoff[q];
            }
    }

	//cout << "\n";

	for (int j=0; j < n_migration_sites; j++) {

        //cout << "("<< migration_array_l[j] << "," << migration_array_h[j] << ")" << strategy_focal_player << " " << payoff(migration_array_l[j], migration_array_h[j],strategy_focal_player) << endl;

        if (grid[migration_array_l[j]][migration_array_h[j]] == -1){
            //find all EMPTY sites
            it_e = sites_empty.end();
            sites_empty.insert(it_e,j); // add site index to sites_empty vector

            }

        if (grid[migration_array_l[j]][migration_array_h[j]] > -1){
            //find all OCCUPIED sites
            it_o = sites_occupied.end();
            sites_occupied.insert(it_o,j); // add site index to sites_occupied vector

        }

		if (migration_payoff[j] == best_pay_off) {
            //find all EMPTY sites with HIGHEST payoff (there might be multiple ones)
			if (grid[migration_array_l[j]][migration_array_h[j]] == -1){
				it_bse = best_sites_empty.end();
				best_sites_empty.insert(it_bse,j); // add site index to best_sites_empty vector
            }
			else {
                // find all OCCUPIED sites with highest payoff (there might be multiple ones)
				it_bso = best_sites_occupied.end();
				best_sites_occupied.insert(it_bso,j); // add site index to best_sites_occupied vector
            }
        }
		else if ((grid[migration_array_l[j]][migration_array_h[j]] == -1) and (migration_payoff[j] < best_pay_off) and (migration_payoff[j] > payoff_focal_player)){
            // find all EMPTY sites with HIGHER payoff
			it_rse = better_sites_empty.end();
			better_sites_empty.insert (it_rse,j); // add site index to better_sites_empty vector

            it_rsep = better_sites_empty_payoff.end();
			better_sites_empty_payoff.insert(it_rsep,j); // add site index to better_sites_empty vector
        }

        else if ((grid[migration_array_l[j]][migration_array_h[j]] == -1) and (migration_payoff[j] <= payoff_focal_player) and (force_migrate == 1)){
            // find all EMPTY sites with LOWER payoff
			it_wse = worse_sites_empty.end();
			worse_sites_empty.insert(it_wse,j); // add site index to better_sites_empty vector

            it_wsep = worse_sites_empty_payoff.end();
			worse_sites_empty_payoff.insert(it_wsep,j); // add site index to better_sites_empty vecto
        }

		if (verbose >= 2){
			cout << j
			<< " ("
			<< migration_array_l[j]
			<< ","
			<< migration_array_h[j]
			<< ") "
			<< grid[migration_array_l[j]][migration_array_h[j]]
			<< "  payoff: " << pf << endl;
		}

	}

    float rand_migration = rand01(); // draw a uniform random variable for random migration likelihood
    float rand_expell = rand01();

    if (rand_migration < random_migration_likelihood) {  // random relocation

        if ((sites_occupied.size() > 0) and (rand_expell < expell)) {  // with property violation
            //int size = sites_occupied.size();
            //int r_site = arc4random_uniform(static_cast<int>(sites_occupied.size()));
            index = sites_occupied[arc4random_uniform(static_cast<int>(sites_occupied.size()))];

            migration_type = "RE";

            mv_destination_l = migration_array_l[index];
            mv_destination_h = migration_array_h[index];

            shortest_distance = compute_migration_distance(player_l, player_h,mv_destination_l,mv_destination_h);

            //cout << "RE "<< index << " ("<< mv_destination_l<< "," << mv_destination_h << ") "<< endl;

            //cout << "E "<< size << " " << r_site << " "<< index << " ("<< mv_destination_l<< "," << mv_destination_h << ") "<< endl;

            grid[player_l][player_h] = -1; // clear old site first to allow relocation of the expelled player to this site
            //cout << "expell: cleared site: (" << player_l << "," << player_h << ") " << grid[player_l][player_h] << "\n";
            compare_payoff_m_range(mv_destination_l,mv_destination_h,0,0,1); // force migration (recursive function)
            grid[mv_destination_l][mv_destination_h] = sfp; // move agent (i.e., copy strategy from old to new site)
            countCDE(); // count cooperators, defectors and empty sites

        }
        else if ((sites_empty.size() > 0) and (rand_expell > expell)){ // without property violation
            //int size = sites_empty.size();
            //int r_site = arc4random_uniform(static_cast<int>(sites_empty.size()));
            index = sites_empty[arc4random_uniform(static_cast<int>(sites_empty.size()))];

            migration_type = "RM";

            mv_destination_l = migration_array_l[index];
            mv_destination_h = migration_array_h[index];

            shortest_distance = compute_migration_distance(player_l, player_h,mv_destination_l,mv_destination_h);

            //cout << "M "<< size << " " << r_site << " "<< index << " ("<< mv_destination_l<< "," << mv_destination_h << ") "<< endl;

            if (verbose >= 2) cout << "best empty site: "<< "(" << mv_destination_l << "," << mv_destination_h << ") " << shortest_distance << "\n"<< endl;

            grid[mv_destination_l][mv_destination_h] = strategy_focal_player;
            grid[player_l][player_h] = -1;
            countCDE(); // count cooperators, defectors and empty sites

        }

        else return;
    }

    else if ((best_sites_empty.size() > 0) and (rand_migration < (1 - random_migration_likelihood))){
            /* find closest EMPTY site with highest payoff AND shortest dist*/
        //shortest_distance = 1000;
        for (int i=0; i < best_sites_empty.size(); i++) {
            distance = compute_migration_distance(player_l, player_h,migration_array_l[best_sites_empty[i]], migration_array_h[best_sites_empty[i]]);

            if (distance < shortest_distance){
                shortest_distance = distance;
                chosen_migration_site = i;
                }
        }

        index = best_sites_empty[chosen_migration_site];

        if (force_migrate == 1) migration_type = "FM";
        else migration_type = "M";

        mv_destination_l = migration_array_l[index];
        mv_destination_h = migration_array_h[index];

        if (verbose >= 2) cout << "best empty site: "<< "(" << mv_destination_l << "," << mv_destination_h << ") " << shortest_distance << "\n"<< endl;

        grid[mv_destination_l][mv_destination_h] = strategy_focal_player;
        grid[player_l][player_h] = -1;
        countCDE(); // count cooperators, defectors and empty sites
    }

    else if ((best_sites_empty.size() == 0) and (best_sites_occupied.size() > 0) and (rand_expell < expell)){
        /* find closest OCCUPIED site with highest payoff (if no empty site with similar payoff is available */
        //shortest_distance = 1000;
        for (int i=0; i < best_sites_occupied.size(); i++) {
            distance = compute_migration_distance(
                player_l, player_h,
                migration_array_l[best_sites_occupied[i]], migration_array_h[best_sites_occupied[i]]
                );

            if (distance < shortest_distance){
                shortest_distance = distance;
                chosen_migration_site = i;
            }
        }

        index = best_sites_occupied[chosen_migration_site];
        migration_type = "E";

        mv_destination_l = migration_array_l[index];
        mv_destination_h = migration_array_h[index];

        grid[player_l][player_h] = -1; // clear old site first to allow relocation of the expelled player to this site
        //cout << "expell: cleared site: (" << player_l << "," << player_h << ") " << grid[player_l][player_h] << "\n";
        compare_payoff_m_range(mv_destination_l,mv_destination_h,0,0,1); // force migration (recursive function)
        grid[mv_destination_l][mv_destination_h] = sfp; // move agent (i.e., copy strategy from old to new site)
        countCDE(); // count cooperators, defectors and empty sites
    }

    else if ((better_sites_empty.size() > 0) and (rand_migration < (1 - random_migration_likelihood))) {
        /* Find the best available site with higher payoff, if all sites with highest payoff are occupied and the property violation step has not occurred (resp. if the player is forced to move)*/
        best_pay_off = payoff_focal_player;

        for (int i=0; i < better_sites_empty.size(); i++) {
            distance = compute_migration_distance(player_l, player_h,migration_array_l[better_sites_empty[i]], migration_array_h[better_sites_empty[i]]);

            if (distance < shortest_distance){
                shortest_distance = distance;
                chosen_migration_site = i;
            }
        }

        index = better_sites_empty[chosen_migration_site];

        if (force_migrate == 1) migration_type = "FM";
        else migration_type = "M";

        mv_destination_l = migration_array_l[index];
        mv_destination_h = migration_array_h[index];

        shortest_distance = compute_migration_distance(player_l, player_h,mv_destination_l, mv_destination_h);

        if (verbose >= 2 and force_migrate==1) cout << "better empty site: "<< "(" << mv_destination_l << "," << mv_destination_h << ") " << shortest_distance << "\n"<< endl;

        grid[mv_destination_l][mv_destination_h] = strategy_focal_player;
        grid[player_l][player_h] = -1;
        countCDE(); // count cooperators, defectors and empty sites
    }

    else if ((worse_sites_empty.size() > 0) and (rand_migration < (1 - random_migration_likelihood))) {

        for (int i=0; i < worse_sites_empty.size(); i++) {
            distance = compute_migration_distance(player_l, player_h,migration_array_l[worse_sites_empty[i]], migration_array_h[worse_sites_empty[i]]);

            if (distance < shortest_distance){
                shortest_distance = distance;
                chosen_migration_site = i;
            }
        }

        index = worse_sites_empty[chosen_migration_site];

        if (force_migrate == 1) migration_type = "FM";
        else migration_type = "M";

        mv_destination_l = migration_array_l[index];
        mv_destination_h = migration_array_h[index];

        shortest_distance = compute_migration_distance(player_l, player_h,mv_destination_l, mv_destination_h);

        if (verbose >= 2 and force_migrate==1) cout << "worse empty site: "<< "(" << mv_destination_l << "," << mv_destination_h << ") " << shortest_distance << "\n"<< endl;

        grid[mv_destination_l][mv_destination_h] = strategy_focal_player;
        grid[player_l][player_h] = -1;
        countCDE(); // count cooperators, defectors and empty sites
    }

    else {
        /*
        if (force_migrate==1) {
            cout << current_step << "  blah" << endl;
            cout << worse_sites_empty.size() << " " << rand_migration <<endl;
            verbose = 2;
            explore_m_range(player_l, player_h);
            verbose = 1;

        }
        */
        return;
    }

    // write update to output_all_mv file
    output_all_mv  << current_step <<","
    << cooperators << ","
    << defectors << ","
    << empty << ","
    << migration_type << ","
    << player_l << ","
    << player_h << ","
    << mv_destination_l << ","
    << mv_destination_h << ","
    << grid[mv_destination_l][mv_destination_h] << ","
    << payoff(mv_destination_l, mv_destination_h,grid[mv_destination_l][mv_destination_h]) - payoff(player_l, player_h, grid[mv_destination_l][mv_destination_h]) << ","
    << shortest_distance
    << "\n";

    count_changes +=1;

    focal_player_l = mv_destination_l;
    focal_player_h = mv_destination_h;

    }

void oneStep(){
	/*Performs one step of the simulation:
	 a: compare payoffs with those of neighbors
	 b: update strategy (not implemented yet)
	 c: explore migration range M
     */

	focal_player_l = rand_steps_l[current_step];
	focal_player_h = rand_steps_h[current_step];
	strategy_focal_player = grid[focal_player_l][focal_player_h];

	if ((strategy_focal_player != -1) and migration_range > 0){
        compare_payoff_m_range(focal_player_l, focal_player_h,random_migration,expell_likelihood,0);
        compare_payoff_with_nghbs(focal_player_l,focal_player_h,1);
    }
    else if ((strategy_focal_player != -1) and migration_range == 0){
        compare_payoff_with_nghbs(focal_player_l,focal_player_h,1);
    }

	if (verbose >= 2){
		cout << "( " << focal_player_l << "," << focal_player_h << ") " << strategy_focal_player << endl;
    }
}

void randomSteps(){
	// Generate random grids (randSteps_l and randSteps_h) of size MCS
	//srand ( time(NULL) ); //initialize the random seed
	for(int i=0; i < MCS; i++){
		rand_steps_l[i] = arc4random_uniform(l);
		rand_steps_h[i] = arc4random_uniform(h);
	}
}

void simulate(){

	randomSteps();
	countCDE();
    summary = format_summary();
    output_summary << summary;
    save_grid_state();
    //showGrid();

    int coop_count;

    if (verbose > 0) cout << "(start) " << 0/static_cast<float>(MCS)*100 << "% " << static_cast<float>(cooperators)/(cooperators + defectors)*100 << "%\tcooperators: " << cooperators << ", defectors:" << defectors << ", empty sites:" << empty << endl;
	if (verbose >= 2) showGrid();

	for (int i=0; i<MCS; i++) {

		if ((count_changes)%100 == 0) {
			countCDE();
            coop_count = cooperators;

            summary = format_summary();
            output_summary << summary;
            if (save_grids > 0) {
                save_grid_state();
                }

			if (verbose > 0) cout << summary;
			else if (verbose >= 2) showGrid();

            count_changes += 1; // just to make sure the same grid does not show up again if no change occurs

        }
		if ((cooperators == 0) or (defectors == 0)){
            countCDE();

            summary = format_summary();
            output_summary << summary;
            save_grid_state();

            if (verbose > 0) cout << summary;

			if (verbose >= 2) showGrid();
            break;
        }

		if (i+1 == MCS){
            countCDE();
             summary = format_summary();
            output_summary << summary;
            save_grid_state();
			if (verbose > 0) cout << summary;
            if (verbose >= 2) showGrid();
			break;
        }

		current_step = i;
		oneStep();
    }
	output_all_mv.close(); // close output_all_mv file;
    output_summary.close(); // close output summary file;
    output_grid_states.close(); // close grid state file;
};

void testing(){
    /*
	cout << "1. Test Make Grid\n" << endl;
	makeGrid();
	showGrid();
	countCDE();
	cout << "cooperators:	" << cooperators << ", defectors:" << defectors << ", empty sites:" << empty << endl;

     cout << "\n2. Test Find Neighbors" << endl;
     int player_l = 4;
     int player_h = 9;
     cout << "focal player: " << player_l << "," << player_h << endl;
     findNeighbors(player_l,player_h);

     cout << "\n3. Test Prisoners' Dilemma" << endl;

     pDilemma(0,0);
     cout << payoff_focal_player << endl;

     cout << "\n4. Test One Step Simmulation" << endl;
     randomSteps();
     current_step = 10;
     oneStep();

     cout << "\n5. Test explore Migration Range" << endl;
     current_step = 10;
     randomSteps();
     focal_player_l = rand_steps_l[current_step];
     focal_player_h = rand_steps_h[current_step];

     explore_m_range(focal_player_l,focal_player_h);
     cout << endl;

     cout << "\n6. Test compare payoffs migration range" << endl;
     compare_payoff_m_range(focal_player_l,focal_player_h);
     */

    /*
     cout << "\n7. Test Fermi Update" << endl;
     strategy_update_Fermi(4, 6.);
     */

    /*
    cout << "\n8. Test Migration distance" << endl;
    cout << compute_migration_distance(12, 17, 47, 3) << endl;
    */

    cout << "\n5. Test Whole Simulation" << endl;
    simulate();
    cout << MCS << " done" << endl;

    /*

     char str[10];

     //Creates an instance of ofstream, and opens example.txt
     ofstream a_file ( "example.txt" , ios::trunc);
     // Outputs to example.txt through a_file

     for (int i=0; i < 100000; i++) {
     a_file << "This text will now be inside of example.txt\n";
     }
     // Close the file stream explicitly

     a_file.close();
     //Opens for reading the file

     string line;
     ifstream b_file ( "example.txt" );
     while (std::getline(b_file, line)){
     cout << line;
     }
     //Reads one string from the file
     b_file >> str;
     //Should output 'this'
     cout<< str <<"\n";
     //cin.get();    // wait for a keypress
     // b_file is closed implicitly here
     */
    }

int main(int ac, char* av[])
    {
        try {
            string config_file;

            // Declare a group of options that will be
            // allowed only on command line
            po::options_description generic("Generic options");
            generic.add_options()
            ("version,v", "print version string")
            ("help", "produce help message")
            ("config,c", po::value<string>(&config_file)->default_value("pgame.cfg"),
             "name of a file with configuration.")
            ;

            // Declare a group of options that will be
            // allowed both on command line and in
            // config file
            po::options_description config("Configuration");
            config.add_options()
            ("verbose", po::value<int>(&verbose)->default_value(0),"verbose 0 to 3 (default 0)")
            ("iterations,i", po::value<int>(&iterations)-> default_value(200),"number of iterations")
            ("grid_length,l",po::value<int>(&l)-> default_value(50),"grid length")
            ("grid_height,h",po::value<int>(&h)-> default_value(50),"grid heigth")
            ("grid_density,d",po::value<float>(&grid_density) -> default_value(0.5),"grid density (between 0 and 1)")
            ("load_grid,g", po::value<string>(&grid_load_filename),
             "name of a file with initial grid configuration.")
            ("save_grids", po::value<int>(&save_grids),
             "save intermediary grids.")
            ("init_coop_level",po::value<float>(&init_coop_level) -> default_value(0.5),"cooperation level at initialization (between 0 and 1)")
            ("neighbors,n",po::value<int>(&numNeighbors)-> default_value(4),"set 4 or 8 neighbors to play with")
            ("migration_range,M",po::value<int>(&migration_range) -> default_value(5),"migration range (M >= 1)")
            ("imitation_likelihood,r",po::value<float>(&imitation_likelihood)-> default_value(0),"probability r to imitate best neighbor (between 0 and 1)")
            ("reset_strategy_likelihood,q",po::value<float>(&reset_strategy_likelihood)-> default_value(0),"probability q to reset strategy (between 0 and 1). Cooperate with probability q and to defect with probability 1-q")
            ("random_migration,m",po::value<float>(&random_migration)-> default_value(1),"random migration (m between 0 and 1)")
            ("expell_likelihood,s",po::value<float>(&expell_likelihood)-> default_value(0),"expell_likelihood (between 0 and 1)")
            ("temptation,T",po::value<float>(&T)-> default_value(1.3),"temptation payoff (c.f., game theory to tune this parameter)")
            ("reward,R",po::value<float>(&R)->default_value(1.0),"cooperation reward payoff(c.f., game theory to tune this parameter)")
            ("punishment,P",po::value<float>(&P)->default_value(0.1),"reciprocator payoff (c.f., game theory to tune this parameter)")
            ("sucker,S",po::value<float>(&S)->default_value(0.0),"sucker payoff (c.f., game theory to tune this parameter)")
            ;

            // Hidden options, will be allowed both on command line and
            // in config file, but will not be shown to the user.

            po::options_description hidden("Hidden options");
            hidden.add_options()
            ;

            po::options_description cmdline_options;
            cmdline_options.add(generic).add(config).add(hidden);

            po::options_description config_file_options;
            config_file_options.add(config).add(hidden);

            po::options_description visible("Allowed options");
            visible.add(generic).add(config);

            po::positional_options_description p;
            //p.add("input-file", -1);

            po::variables_map vm;
            store(po::command_line_parser(ac, av).
                  options(cmdline_options).positional(p).run(), vm);
            notify(vm);

            ifstream ifs(config_file.c_str());
            if (!ifs)
            {
                cout << "can not open config file: " << config_file << "\n";
                return 0;
            }
            else
            {
                store(parse_config_file(ifs, config_file_options), vm);
                notify(vm);
            }

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

            if (vm.count("version")) {
                cout << "Property Game, version 1.0\n";
                return 0;
            }

        }
        catch(exception& e)
        {
            cout << e.what() << "\n";
            return 1;
        }

        prepare_parameters();

        if (fileExists(grid_load_filename)) {
            cout << "loading grid from " << grid_load_filename << endl;
            load_grid();
            //showGrid();
            //cout << format_summary()<< endl;
        }
        else {
            cout << "generating new grid" << endl;
            makeGrid();
        }

        open_output_files();
        //testing();

        simulate();
        return 0;
    }


///////////////////////////////////////////////////////////////////////////////
//  Copyright 2013 Nikhar Agrawal
//  Copyright 2013 Christopher Kormanyos
//  Copyright 2013 John Maddock
//  Copyright 2013 Paul Bristow
//  Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef _BOOST_POLYGAMMA_2013_07_30_HPP_
  #define _BOOST_POLYGAMMA_2013_07_30_HPP_

  #include <boost/array.hpp>
  #include <boost/cstdint.hpp>
  #include <boost/math/special_functions/factorials.hpp>
  #include "detail/polygamma.hpp"

  namespace boost { namespace math {

  template<class T>
  struct promoteftod
  {
	  typedef T type;
  };

  template<>
  struct promoteftod<float>
  {
	  typedef double type;
  };

  template<class T, class Policy>
  inline T polygamma(const int n, T x, const Policy &pol)
  {
	typedef typename promoteftod<T>::type result_type;
//	std::cout<<"~:"<<typeid(T).name()<<std::endl;
//	std::cout<<"~:"<<typeid(result_type).name()<<std::endl;
	result_type xx=result_type(x);
        result_type result= boost::math::detail::polygamma_imp(n,xx,pol);
	return T(result);
  }

  template<class T>
  inline T polygamma(const int n, T x)
  {
      return boost::math::polygamma(n,x,policies::policy<>());
  }

/*  template<class T, class Policy>
  inline T digamma(T x, const Policy &pol)
  {
      return boost::math::polygamma(0,x,pol);
  }

  template<class T>
  inline T digamma(T x)
  {
      return boost::math::digamma(x,policies::policy<>());
  }
*/
  template<class T, class Policy>
  inline T trigamma(T x, const Policy &pol)
  {
      return boost::math::polygamma(1,x,pol);
  }

  template<class T>
  inline T trigamma(T x)
  {
      return boost::math::trigamma(x,policies::policy<>());
  }

} } // namespace boost::math

#endif // _BOOST_BERNOULLI_2013_05_30_HPP_


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "ConvImpl.hpp"

#include <boost/assert.hpp>

#include <cmath>
#include <limits>

namespace armnn
{

QuantizedMultiplierSmallerThanOne::QuantizedMultiplierSmallerThanOne(float multiplier)
{
    BOOST_ASSERT(multiplier >= 0.0f && multiplier < 1.0f);
    if (multiplier == 0.0f)
    {
        m_Multiplier = 0;
        m_RightShift = 0;
    }
    else
    {
        const double q = std::frexp(multiplier, &m_RightShift);
        m_RightShift = -m_RightShift;
        int64_t qFixed = static_cast<int64_t>(std::round(q * (1ll << 31)));
        BOOST_ASSERT(qFixed <= (1ll << 31));
        if (qFixed == (1ll << 31))
        {
            qFixed /= 2;
            --m_RightShift;
        }
        BOOST_ASSERT(m_RightShift >= 0);
        BOOST_ASSERT(qFixed <= std::numeric_limits<int32_t>::max());
        m_Multiplier = static_cast<int32_t>(qFixed);
    }
}

int32_t QuantizedMultiplierSmallerThanOne::operator*(int32_t rhs) const
{
    int32_t x = SaturatingRoundingDoublingHighMul(rhs, m_Multiplier);
    return RoundingDivideByPOT(x, m_RightShift);
}

int32_t QuantizedMultiplierSmallerThanOne::SaturatingRoundingDoublingHighMul(int32_t a, int32_t b)
{
    // Check for overflow.
    if (a == b && a == std::numeric_limits<int32_t>::min())
    {
        return std::numeric_limits<int32_t>::max();
    }
    int64_t a_64(a);
    int64_t b_64(b);
    int64_t ab_64 = a_64 * b_64;
    int32_t nudge = ab_64 >= 0 ? (1 << 30) : (1 - (1 << 30));
    int32_t ab_x2_high32 = static_cast<std::int32_t>((ab_64 + nudge) / (1ll << 31));
    return ab_x2_high32;
}

int32_t QuantizedMultiplierSmallerThanOne::RoundingDivideByPOT(int32_t x, int exponent)
{
    BOOST_ASSERT(exponent >= 0 && exponent <= 31);
    int32_t mask = (1 << exponent) - 1;
    int32_t remainder = x & mask;
    int32_t threshold = (mask >> 1) + (x < 0 ? 1 : 0);
    return (x >> exponent) + (remainder > threshold ? 1 : 0);
}

} //namespace armnn