/*
 [auto_generated]
 boost/numeric/odeint/iterator/const_step_iterator.hpp

 [begin_description]
 Iterator for iterating through the solution of an ODE with constant step size.
 [end_description]

 Copyright 2012-2013 Karsten Ahnert
 Copyright 2013 Mario Mulansky

 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_NUMERIC_ODEINT_ITERATOR_CONST_STEP_ODE_ITERATOR_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_ITERATOR_CONST_STEP_ODE_ITERATOR_HPP_INCLUDED

#include <boost/numeric/odeint/util/stepper_traits.hpp>
#include <boost/numeric/odeint/stepper/stepper_categories.hpp>
#include <boost/numeric/odeint/iterator/detail/ode_iterator_base.hpp>
#include <boost/numeric/odeint/iterator/impl/const_step_iterator_impl.hpp>

namespace boost {
namespace numeric {
namespace odeint {

    /* use the const_step_iterator_impl with the right tags */
    template< class Stepper , class System , class State
#ifndef DOXYGEN_SKIP
    , class StepperTag = typename base_tag< typename traits::stepper_category< Stepper >::type >::type
#endif
    >
    class const_step_iterator : public const_step_iterator_impl<
            const_step_iterator< Stepper , System , State , StepperTag > ,
            Stepper , System , State , detail::ode_state_iterator_tag , StepperTag
        >
    {
        typedef typename traits::time_type< Stepper >::type time_type;
        typedef const_step_iterator< Stepper , System , State , StepperTag > iterator_type;

    public:
        const_step_iterator( Stepper stepper , System sys , State &s , time_type t_start , time_type t_end , time_type dt )
            : const_step_iterator_impl< iterator_type , Stepper , System , State , detail::ode_state_iterator_tag , StepperTag >( stepper , sys , s , t_start , t_end , dt )
        {}

        const_step_iterator( Stepper stepper , System sys , State &s )
            : const_step_iterator_impl< iterator_type , Stepper , System , State , detail::ode_state_iterator_tag , StepperTag >( stepper , sys , s )
        {}
    };

    /* make functions */

    template< class Stepper , class System , class State >
    const_step_iterator< Stepper , System, State > make_const_step_iterator_begin(
        Stepper stepper ,
        System system ,
        State &x ,
        typename traits::time_type< Stepper >::type t_start ,
        typename traits::time_type< Stepper >::type t_end ,
        typename traits::time_type< Stepper >::type dt )
    {
        return const_step_iterator< Stepper , System , State >( stepper , system , x , t_start , t_end , dt );
    }

    template< class Stepper , class System , class State >
    const_step_iterator< Stepper , System , State > make_const_step_iterator_end(
        Stepper stepper ,
        System system ,
        State &x )
    {
        return const_step_iterator< Stepper , System , State >( stepper , system , x );
    }

    template< class Stepper , class System , class State >
    std::pair< const_step_iterator< Stepper , System , State > , const_step_iterator< Stepper , System , State > >
    make_const_step_range(
        Stepper stepper ,
        System system ,
        State &x ,
        typename traits::time_type< Stepper >::type t_start ,
        typename traits::time_type< Stepper >::type t_end ,
        typename traits::time_type< Stepper >::type dt )
    {
        return std::make_pair(
            const_step_iterator< Stepper , System , State >( stepper , system , x , t_start , t_end , dt ) ,
            const_step_iterator< Stepper , System , State >( stepper , system , x )
            );
    }

    /**
     * \class const_step_iterator
     *
     * \brief ODE Iterator with constant step size. The value type of this iterator is the state type of the stepper.
     *
     * Implements an iterator representing the solution of an ODE from t_start
     * to t_end evaluated at steps with constant step size dt.
     * After each iteration the iterator dereferences to the state x at the next
     * time t+dt.
     * This iterator can be used with Steppers and
     * DenseOutputSteppers and it always makes use of the all the given steppers
     * capabilities. A for_each over such an iterator range behaves similar to
     * the integrate_const routine.
     *
     * const_step_iterator is a model of single-pass iterator.
     *
     * The value type of this iterator is the state type of the stepper. Hence one can only access the state and not the current time.
     *
     * \tparam Stepper The stepper type which should be used during the iteration.
     * \tparam System The type of the system function (ODE) which should be solved.
     * \tparam State The state type of the ODE.
     */

    /**
     * \fn make_const_step_iterator_begin(
        Stepper stepper ,
        System system ,
        State &x ,
        typename traits::time_type< Stepper >::type t_start ,
        typename traits::time_type< Stepper >::type t_end ,
        typename traits::time_type< Stepper >::type dt )
     *
     * \brief Factory function for const_step_iterator. Constructs a begin iterator.
     *
     * \param stepper The stepper to use during the iteration.
     * \param system The system function (ODE) to solve.
     * \param x The initial state. const_step_iterator stores a reference of s and changes its value during the iteration.
     * \param t_start The initial time.
     * \param t_end The end time, at which the iteration should stop.
     * \param dt The initial time step.
     * \returns The const step iterator.
     */

    /**
     * \fn make_const_step_iterator_end( Stepper stepper , System system , State &x )
     * \brief Factory function for const_step_iterator. Constructs a end iterator.
     *
     * \param stepper The stepper to use during the iteration.
     * \param system The system function (ODE) to solve.
     * \param x The initial state. const_step_iterator stores a reference of s and changes its value during the iteration.
     * \returns The const_step_iterator.
     */

    /**
     * \fn make_const_step_range( Stepper stepper , System system , State &x ,
        typename traits::time_type< Stepper >::type t_start ,
        typename traits::time_type< Stepper >::type t_end ,
        typename traits::time_type< Stepper >::type dt )
     *
     * \brief Factory function to construct a single pass range of const step iterators. A range is here a pair
     * of const_step_iterator.
     *
     * \param stepper The stepper to use during the iteration.
     * \param system The system function (ODE) to solve.
     * \param x The initial state. const_step_iterator store a reference of s and changes its value during the iteration.
     * \param t_start The initial time.
     * \param t_end The end time, at which the iteration should stop.
     * \param dt The initial time step.
     * \returns The const step range.
     */

} // namespace odeint
} // namespace numeric
} // namespace boost

//#include <boost/numeric/odeint/iterator/impl/const_step_iterator_dense_output_impl.hpp>

#endif // BOOST_NUMERIC_ODEINT_ITERATOR_CONST_STEP_ODE_ITERATOR_HPP_INCLUDED


// <SmartLexicalCast.hpp> -*- C++ -*-

/*!
 * \file SmartLexicalCast.hpp
 * \brief Smart lexical casting supporting prefixes, separator ignoring, and
 * suffixes.
 */

#ifndef __SMART_LEX_H__
#define __SMART_LEX_H__

#include <iostream>
#include <utility>
#include <memory>

#include <boost/lexical_cast.hpp>

#include "sparta/utils/LexicalCast.hpp"
#include "sparta/utils/SpartaException.hpp"
#include "sparta/utils/Utils.hpp"
#include "sparta/utils/ValidValue.hpp"

namespace sparta {
    namespace utils {

/*!
 * \brief Modifier instance - Associates some suffix strings (e.g. "b") with
 * a semantic (e.g. multiply by one billion)
 */
struct Modifier {
    /*!
     * \brief Suffix strings identifying this modifier (case sensitive)
     */
    std::vector<const char*> options;

    /*!
     * \brief Multiplier applied to the value when this modifier is found
     */
    uint64_t mult;
};

/*!
 * \brief Prefix instance - Associates some prefix strings (e.g. "0x") with
 * a radix and a set of allowed digit characters for parsing a string following
 * this radix.
 */
struct RadixPrefix {

    /*!
     * \brief Prefix strings identifying this prefix (case sensitive)
     */
    const std::vector<const char*> options;

    /*!
     * \brief Radix associated with this prefix
     */
    const uint32_t radix;

    /*!
     * \brief Valid digits in a number following this prefix
     */
    const char* const digits;
};

static const uint32_t DEFAULT_RADIX = 10;

/*!
 * \brief Radixes supported
 * \note The digits field will have precidence over any suffix after the number.
 * Specifically, hex digits b or B will be treated as a hex digit and NEVER as
 * a suffix (billion). If the billion suffix were desired, the g or G suffix
 * would need to be used
 */
static const std::vector<RadixPrefix> prefixes = {
    {{"0x", "0X"},         16, "0123456789abcdefABCDEF"},
    {{"0b", "0B"},         2,  "01"},
    {{"0"},                8,  "01234567"} // '0' Must be last to avoid false positives
};

/*!
 * \brief Suffixes supported.
 */
static const std::vector<Modifier> suffixes = {

    // ISO/IEC 8000 unit prefixes
    // http://en.wikipedia.org/wiki/Mebi#IEC_standard_prefixes

    {{"ki", "Ki",
      "kI", "KI"},             1_u64<<10}, // kibi
    {{"mi", "Mi",
      "mI", "MI"},             1_u64<<20}, // mebi
    {{"gi", "Gi", "bi", "Bi",
      "gI", "GI", "bI", "BI"}, 1_u64<<30}, // gibi
    {{"ti", "Ti",
      "tI", "TI"},             1_u64<<40}, // tebi
    {{"pi", "Pi",
      "pI", "PI"},             1_u64<<50}, // pebi

    // SI unit prefixes (e.g. 'K' in 'KB')

    {{"n", "N"},               1},                // normal
    {{"k", "K"},               1000},             // kilo
    {{"m", "M"},               1000000},          // mega
    {{"g", "G", "b", "B"},     1000000000},       // giga
    {{"t", "T"},               1000000000000},    // tera
    {{"p", "P"},               1000000000000000}  // peta
};

/*!
 * \brief All whitespace characters allowed
 */
static const char* WHITESPACE = " _,\t\n";

/*!
 * \brief All decimal (base 10) digits allowed and '.'
 */
static const char* DECIMAL_DIGITS = "0123456789.";

/*!
 * \brief Performs a lexical cast on a string while attempting to interpret
 * radix prefixes (\see prefixes) and multiplying suffixes (\see suffixes)
 * \param s String to parse. String must contain no extra non-witespace characters where
 * "whitespace" is defined as any character in the WHITESPACE string.
 * \param end_pos [out] Position of string after parsing. All characters after point will be
 * whitespace. If all characters of \a s are consumed, this will be std::string::npos
 * \param allow_recursion Allow recursion during parsing. This allows stringing together values
 * to add together in the way the large values are spoken such as 1b5k (for one billion, five
 * thousand). Note that a prefix on the initial value does not apply to any subsequent values
 * encountered. For example, 0xck22 is (hex 0xc) * (decimal 1000) + (decimal 22)
 * When recursing intenally, this method is always reentered with allow_prefix=false, meaning
 * values parsed after the first are NOT allowed to have prefixes.
 * \param allow_prefix Allow parsing of prefixes. If false, prefixes are not allowed in \a s.
 * this is typiclly useful when recursively parsing the end of the string because of ambiguity
 * between certain suffixes (e.g. 50b and 0b111 could not be joined together because of the '0b').
 *
 * Example:
 * \code
 * // With allow_recursion=true && allow_prefix=true
 * 5b1        => five billion
 * 5t10k2     => five trillion, 10 thousdand, and 2
 * 0xcccb1    => hex value 0xcccb1
 * 0xcccb1g50 => (hex value 0xcccb1 * one billion) + decimal 50
 *
 * // Always illegal
 * 5t0xc00    => ERROR: Prefixes are not allowed on trailing values
 *
 * // With allow_recursion=false && allow_prefix=true
 * 5b         => five billion
 * 0x500      => hex value 0x500
 * 5b100      => ERROR: Recursion disabled
 *
 * // With allow_recursion=true && allow_prefix=false
 * 5b100      => five billion, one hundred
 * 0x5b2k     => ERROR: prefixes disabled
 * \endcode
 *
 * // With period (and allow_recursion)
 * 0.5M       => 500,000
 * .5m        => 500,000
 * .5m2k      => 502,000
 * .5m.2k     => 500,200
 *
 * \todo To resolve prefix/suffix ambiguity and allow stringing together multiple value with
 * prefixes support could be added for '+' as a disamgiuator (e.g. 50+0b111)
 */
template <typename T>
inline T smartLexicalCast(const std::string& s,
                          size_t& end_pos,
                          bool allow_recursion=true,
                          bool allow_prefix=true) {
    (void) allow_recursion;
    (void) allow_prefix;
    T result = lexicalCast<T>(s, 0); // 0 => use auto-radix
    end_pos = std::string::npos;
    return result;
}

/*!
 * \brief Parse and return a numeric string from after a certain position in an input string
 * \param s Input string
 * \param pos Position in input string to begin parsing at
 * \param digits Allowed digits in numeric string (in addition to WHITESPACE)
 * \param after_numeric [out] Position of string \a s after numeric string is extracted
 * \return Parsed numeric string (if possible) Returns "" if not.
 */
inline std::string parseNumericString(const std::string& s, size_t pos, const char* digits, size_t& after_numeric) {
    std::string raw_value_chars = digits;
    raw_value_chars += WHITESPACE;
    after_numeric = s.find_first_not_of(raw_value_chars, pos);

    if(after_numeric == pos){
        return "";
    }

    std::string numeric;
    if(after_numeric == std::string::npos){
        numeric = s.substr(pos);
    }else{
        numeric = s.substr(pos, after_numeric - pos);
    }

    // Remove all "whitespace" from within the string
    for(const char* pc = WHITESPACE; *pc != '\0'; ++pc) {
        std::string to_replace;
        to_replace += *pc;
        replaceSubstring(numeric, to_replace, "");
    }

    return numeric;
}

template <>
inline uint64_t smartLexicalCast(const std::string& s,
                                 size_t& end_pos,
                                 bool allow_recursion,
                                 bool allow_prefix) {
    size_t pos = 0;

    // Skip leading space. If string is ONLY leading space, return 0
    pos = s.find_first_not_of(WHITESPACE);
    if(pos == std::string::npos){
        end_pos = pos; // Output ending position
        return 0;
    }

    std::string numeric; // Numeric (integer) portion of this string
    std::string fractional; // Decimal portion of the string (if any)
    size_t suffix_pos = pos;

    // Determine prefix (if allowed)

    uint32_t radix = DEFAULT_RADIX;
    const char* digits = DECIMAL_DIGITS;
    if(allow_prefix){
        // Look for a prefix (if any) at start of string (after whitespace) and extract radix
        bool found_prefix = false;
        for(auto & prefix : prefixes) {
            for(auto & str : prefix.options) {
                size_t prefix_pos = s.find(str, pos);
                if(prefix_pos == pos) {
                    //std::cout << "found prefix at " << prefix_pos << std::endl;

                    // Attempt to read ahead using this prefix. Parser must be able to get a
                    // non-null string for this prefix to be considered a match.
                    // Note that because the digits string for various prefixes does not contain
                    // '.', this will fail to parse a numeric string if it contains a '.'. This is
                    // the correct behavior
                    size_t spec_suffix_pos;
                    numeric = parseNumericString(s, prefix_pos + strlen(str), prefix.digits, spec_suffix_pos);
                    if(numeric.size() != 0){
                        radix = prefix.radix;
                        digits = prefix.digits;
                        pos = suffix_pos = spec_suffix_pos;
                        found_prefix = true;
                        break;
                    }
                }
            }
            if(found_prefix){
                break;
            }
        }
    }

    //std::cout << "radix = " << radix << std::endl;

    // Extract the (hopefully) numeric portion of the string
    if(numeric.size() == 0){
        sparta_assert(suffix_pos == pos);
        numeric = parseNumericString(s, pos, digits, suffix_pos);
        if(numeric.size() == 0){
            throw SpartaException("Unable to parse a numeric value from substring \"")
                  << s.substr(pos) << "\" within full string \"" << s
                  << "\" for smart lexical casting";
        }
    }

    pos = suffix_pos;

    // Convert a decimal number.
    // note, there are no whitespace or separators in numeric at this time
    size_t decimal_pos = numeric.find('.');
    if(decimal_pos != std::string::npos){
        if(decimal_pos == numeric.size() - 1){
            throw SpartaException("Encountered \".\" at the end of a numeric portion (\"") << numeric
                  << "\") of a string \"" << s << "\"";
        }
        fractional = numeric.substr(decimal_pos + 1);
        numeric = numeric.substr(0, decimal_pos);
    }

    uint64_t value = 0;
    // The C functions of yester-year might or might not error on
    // empty strings.  Different machines do different things. It's
    // silly to send a null string to be cast either way, so catch it
    // here and evaluate to 0.
    if(numeric.find_first_not_of(WHITESPACE) != std::string::npos) {
        // Determine raw integer value of the numeric portion of the string
        value = lexicalCast<uint64_t>(numeric, radix);
    }

    if(pos == std::string::npos){
        if(fractional.size() != 0){
            throw SpartaException("Encountered a fractional value: \"") << numeric << "\" . \""
                  << fractional << "\" but no suffix was found, so this cannot possibly represent "
                  " an integer. Found in \"" << s << "\"";
        }

        end_pos = pos; // Output ending position
    }else{
        // This is redundant with the value extraction above
        //// Ensure the numeric string ONLY contains valid numeric characters
        //size_t non_numeric_char_pos = numeric.find_first_not_of(digits);
        //if(non_numeric_char_pos != std::string::npos){
        //    throw SpartaException("Found non-numeric digit '") << numeric[non_numeric_char_pos]
        //          << "' in portion of string (\"" << numeric << "\") expected to be only the digits: \""
        //          << digits << "\". Encountered when parsing full string\"" << s << "\"";
        //}

        // Find the suffix (if any) and extract a modifier function (e.g. x*1000)
        size_t after_suffix_pos = pos;
        uint64_t suffix_multiplier = 0;
        for(auto & suffix : suffixes) {
            for(auto & str : suffix.options) {
                auto tmp = s.find(str, pos);
                // Check if this suffix comes before another that was found later in the string
                if(tmp == pos) {
                    //std::cout << "found suffix at " << suffix_pos << std::endl;
                    suffix_multiplier = suffix.mult;
                    after_suffix_pos = tmp + strlen(str);
                    break;
                }
            }
            if(suffix_multiplier != 0){
                break;
            }
        }

        if(suffix_multiplier == 0){
            suffix_multiplier = 1;
        }

        // Apply suffix modifier extracted when parsing the suffix (e.g. "k" = N*1000)
        value *= suffix_multiplier;

        // Apply suffix modifier to the fractional portion
        if(fractional.size() != 0){
            // Check each digit to ensure that it is an integer portion of the
            // This is done manually to guarantee NO floating point rounding errors can occur
            uint32_t ten_div = 10;
            for(auto ch : fractional){
                uint64_t frac = (ch - '0');
                sparta_assert(frac < 10);
                frac *= suffix_multiplier;
                if(frac < ten_div){
                    throw SpartaException("Encountered a fractional value: \"") << numeric << "\" . \""
                          << fractional << "\" but suffix multipler was only " << suffix_multiplier
                          << ", so this fraction does not represent and integer. Fraction should "
                          "not have a 1/" << ten_div << " place. Found in \"" << s << "\"";
                }
                frac /= ten_div;
                value += frac;
                ten_div *= 10;
            }
        }

        // Recursively reparse remainder of string and add result to current value
        if(allow_recursion){
            if(after_suffix_pos != std::string::npos){
                uint64_t addition = smartLexicalCast<uint64_t>(s.substr(after_suffix_pos),
                                                               after_suffix_pos, // Pos after parsing
                                                               true,             // Allow recursion
                                                               false);           // Disallow prefixes

                value += addition;
            }
        }

        end_pos = after_suffix_pos;

        // Reject any garbage remaining
        if(end_pos != std::string::npos){
            size_t garbage_pos = s.find_first_not_of(WHITESPACE, end_pos);
            if(garbage_pos != std::string::npos) {
                throw SpartaException("Found non-'whitespace' grabage character '") << s[garbage_pos]
                      << "' after suffix (at or after char " << end_pos << ") in string being "\
                      "smart-lexically-cast: \"" << s << "\"";
            }
        }
    }

    return value;
}

template <>
inline uint32_t smartLexicalCast(const std::string& s,
                                 size_t& end_pos,
                                 bool allow_recursion,
                                 bool allow_prefix) {
    uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_u64 << 32)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a uint32_t because it "
              "contained a value this type could not contain: " << val;
    }
    return (uint32_t)val;
}

template <>
inline uint16_t smartLexicalCast(const std::string& s,
                                 size_t& end_pos,
                                 bool allow_recursion,
                                 bool allow_prefix) {
    uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_u64 << 16)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a uint32_t because it "
              "contained a value this type could not contain: " << val;
    }
    return (uint16_t)val;
}

template <>
inline uint8_t smartLexicalCast(const std::string& s,
                                size_t& end_pos,
                                bool allow_recursion,
                                bool allow_prefix) {
    uint64_t val = smartLexicalCast<uint64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_u64 << 8)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a uint32_t because it "
              "contained a value this type could not contain: " << val;
    }
    return (uint8_t)val;
}

template <>
inline int64_t smartLexicalCast(const std::string& s,
                                size_t& end_pos,
                                bool allow_recursion,
                                bool allow_prefix) {
    // Get negative sign from front of string
    size_t after_neg_pos = 0;
    size_t neg_pos = s.find_first_not_of(WHITESPACE);
    bool negate = false;
    if(neg_pos != std::string::npos){
        if(s[neg_pos] == '-'){
            negate = true;
            after_neg_pos = neg_pos + 1;
        }
        // after_neg_pos remains 0
    }

    uint64_t val = smartLexicalCast<uint64_t>(s.substr(after_neg_pos), end_pos, allow_recursion, allow_prefix);
    if((negate == false && val >= (1_u64 << 63))
       || (negate == true && val > (1_u64 << 63))) {
        throw SpartaException("Could not lexically cast \"") << s << "\" to a int64_t because it "
              "contained a value  this type could not contain: " << val;
    }
    int64_t signed_val = val;
    if(negate){
        signed_val *= -1;
    }
    return signed_val;
}

template <>
inline int32_t smartLexicalCast(const std::string& s,
                                size_t& end_pos,
                                bool allow_recursion,
                                bool allow_prefix) {
    int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_64 << 31)
       || val < -(1_64 << 31)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a int32_t because it "
              "contained a value larger than this type could not contain: " << val;
    }
    return (int32_t)val;
}

template <>
inline int16_t smartLexicalCast(const std::string& s,
                                size_t& end_pos,
                                bool allow_recursion,
                                bool allow_prefix) {
    int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_64 << 16)
       || val < -(1_64 << 16)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a int16_t because it "
              "contained a value this type could not contain: " << val;
    }
    return (int16_t)val;
}

template <>
inline int8_t smartLexicalCast(const std::string& s,
                               size_t& end_pos,
                               bool allow_recursion,
                               bool allow_prefix) {
    int64_t val = smartLexicalCast<int64_t>(s, end_pos, allow_recursion, allow_prefix);
    if(val >= (1_64 << 8)
       || val < -(1_64 << 8)){
        throw SpartaException("Could not lexically cast \"") << s << "\" to a int8_t because it "
              "contained a value this type could not contain: " << val;
    }
    return (int8_t)val;
}

template <>
inline double smartLexicalCast(const std::string& s,
                               size_t& end_pos,
                               bool allow_recursion,
                               bool allow_prefix) {
    (void) allow_recursion;
    (void) allow_prefix;

    utils::ValidValue<double> dbl_value;
    end_pos = 0;

    try {
        dbl_value = boost::lexical_cast<double>(s);
    } catch (const boost::bad_lexical_cast &) {
        throw SpartaException("Could not lexically cast \"") << s << "\" to a double";
    }

    end_pos = std::string::npos;
    return dbl_value.getValue();
}

    }; // namespace utils
} // namespace sparta

// __SMART_LEX_H__
#endif


/******************************************************************************
 * Copyright 2019 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * 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 <gtest/gtest.h>

#include <rw/math/Q.hpp>
#include <rw/math/Rotation3D.hpp>
#include <rw/math/Transform3D.hpp>
#include <rw/math/Vector2D.hpp>
#include <rw/math/Vector3D.hpp>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <sstream>

using namespace rw::math;

namespace {
    class MyClass {
        public:
            Q myQ;
            Vector2D<double> myVec2D;
            Vector2D<float> myVec2Df;
            Vector3D<double> myVec3D;
            Vector3D<float> myVec3Df;
            Rotation3D<double> myR;
            Rotation3D<float> myRf;
            Transform3D<double> myT;
            Transform3D<float> myTf;

        private:
            friend class boost::serialization::access;

            template<class Archive>
            void serialize(Archive & ar, const unsigned int version)
            {
                ar & myQ;
                ar & myVec2D;
                ar & myVec2Df;
                ar & myVec3D;
                ar & myVec3Df;
                ar & myR;
                ar & myRf;
                ar & myT;
                ar & myTf;
            }
    };
}

TEST(BoostSerialization, Q) {
    static const Q q(3, 0.11, 0.12, 0.13);
    static const Vector2D<double> vec2(0.1, 0.2);
    static const Vector2D<float> vec2f(0.3f, 0.4f);
    static const Vector3D<double> vec3(0.5, 0.6, 0.7);
    static const Vector3D<float> vec3f(0.8f, 0.9f, 1.0f);
    static const Rotation3D<double> R(1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 3.3);
    static const Rotation3D<float> Rf(4.1f, 4.2f, 4.3f, 5.1f, 5.2f, 5.3f, 6.1f, 6.2f, 6.3f);
    static const Transform3D<double> T(vec3, R);
    static const Transform3D<float> Tf(vec3f, Rf);
    std::stringstream stream;

    //save
    {
        MyClass myClassObj;
        myClassObj.myQ = q;
        myClassObj.myVec2D = vec2;
        myClassObj.myVec2Df = vec2f;
        myClassObj.myVec3D = vec3;
        myClassObj.myVec3Df = vec3f;
        myClassObj.myR = R;
        myClassObj.myRf = Rf;
        myClassObj.myT = T;
        myClassObj.myTf = Tf;

        boost::archive::text_oarchive oa(stream);
        oa << myClassObj;
    }

    // load
    {
        MyClass myClassObj;
        boost::archive::text_iarchive ia(stream);
        ia >> myClassObj;
        EXPECT_EQ(q, myClassObj.myQ);
        EXPECT_EQ(vec2, myClassObj.myVec2D);
        EXPECT_EQ(vec2f, myClassObj.myVec2Df);
        EXPECT_EQ(vec3, myClassObj.myVec3D);
        EXPECT_EQ(vec3f, myClassObj.myVec3Df);
        EXPECT_EQ(R, myClassObj.myR);
        EXPECT_EQ(Rf, myClassObj.myRf);
        EXPECT_EQ(T, myClassObj.myT);
        EXPECT_EQ(Tf, myClassObj.myTf);
        EXPECT_TRUE(myClassObj.myQ == q);
        EXPECT_TRUE(myClassObj.myVec2D == vec2);
        EXPECT_TRUE(myClassObj.myVec2Df == vec2f);
        EXPECT_TRUE(myClassObj.myVec3D == vec3);
        EXPECT_TRUE(myClassObj.myVec3Df == vec3f);
        EXPECT_TRUE(myClassObj.myR == R);
        EXPECT_TRUE(myClassObj.myRf == Rf);
        EXPECT_TRUE(myClassObj.myT == T);
        EXPECT_TRUE(myClassObj.myTf == Tf);
    }
}


#include <string>
#include <stdexcept>

#include <cstdlib>

#include <armadillo>

#include "Conv2D/Mesh.hpp"
#include "Conv2D/EulerDefaultBase.hpp"

class Euler : public EulerDefaultBase
{
public:
    Euler() : EulerDefaultBase()
    {
    }

    ~Euler() = default;

    void computeBottomFlux(const arma::vec &UInt, const arma::rowvec &n,
                           arma::vec &U, arma::vec &F, double &s) const;

    void computeRightFlux(const arma::vec &UInt, const arma::rowvec &n,
                          arma::vec &U, arma::vec &F, double &s) const;

    void computeTopFlux(const arma::vec &UInt, const arma::rowvec &n,
                        arma::vec &U, arma::vec &F, double &s) const;

    void computeLeftFlux(const arma::vec &UInt, const arma::rowvec &n,
                         arma::vec &U, arma::vec &F, double &s) const;
};

void Euler::computeTopFlux(const arma::vec &UInt, const arma::rowvec &n,
                           arma::vec &U, arma::vec &F, double &s) const
{
    applyInvisidWallBC(UInt, n, U, F, s);
}

void Euler::computeBottomFlux(const arma::vec &UInt, const arma::rowvec &n,
                              arma::vec &U, arma::vec &F, double &s) const
{
    applyInvisidWallBC(UInt, n, U, F, s);
}

void Euler::computeLeftFlux(const arma::vec &UInt, const arma::rowvec &n,
                            arma::vec &U, arma::vec &F, double &s) const
{
    applyInflowBC(UInt, n, U, F, s);
}

void Euler::computeRightFlux(const arma::vec &UInt, const arma::rowvec &n,
                             arma::vec &U, arma::vec &F, double &s) const
{
    applyOutflowBC(UInt, n, U, F, s);
}

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        throw std::runtime_error("No choice of input mesh given");
    }

    int choice = std::atoi(argv[1]);

    if (choice < 0 || choice > 4)
    {
        throw std::runtime_error("Invalid choice of input mesh");
    }

    const std::string choiceString = std::to_string(choice);

    const std::string meshFile       = "bump" + choiceString + ".gri";
    const std::string residualFile   = "FirstOrderSolverResidual" + choiceString + ".dat";
    const std::string validationFile = "FirstOrderSolverValidation" + choiceString + ".dat";
    const std::string pressureFile   = "FirstOrderSolverPressureCoefficients" + choiceString + ".dat";
    const std::string machFile       = "FirstOrderSolverMachNumbers" + choiceString + ".vtk";
    const std::string solutionFile   = "FirstOrderSolverSolution" + choiceString + ".dat";

    Mesh mesh;
    mesh.readFromFile(meshFile);
    mesh.computeMatrices();

    Euler problem;
    problem.setMesh(mesh);
    problem.setGasConstant(1.0);
    problem.setSpecificHeatRatio(1.4);
    problem.setFreeFlowMachNumber(0.5);
    problem.setFreeFlowStaticPressure(1.0);
    problem.setCFLNumber(0.5);

    problem.setInitialState();

    const double tolerance = 1.0e-07;
    problem.runFirstOrderSolver(tolerance, residualFile);

    problem.writeValidationValuesTofile(validationFile);
    problem.writePressureCoefficientsToFile(pressureFile);
    problem.writeMachNumbersToFile(machFile);

    problem.writeStateToFile(solutionFile);

    return 0;
}


#include <ros/ros.h>
#include <ros/package.h>
#include "mtf_bridge/SharedImageReader.h"
#include "mtf_bridge/PatchTrackers.h"

// OpenCV
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// C++
#include <vector>
#include <math.h>
#include <assert.h>
#include <Eigen/Core>

// Modular Tracking Framework
#include "mtf/mtf.h"
#include "mtf/pipeline.h"
#include "mtf/Utilities/miscUtils.h"
#include "mtf/Utilities/objUtils.h"

using namespace mtf;
using namespace mtf::params;
using namespace mtf::utils;

typedef std::shared_ptr<mtf::TrackerBase> Tracker_;
// neded to avoid duplicate preprocessors
std::vector<PreProc_> pre_procs;

int const rate = 30;

using namespace mtf::params;

struct TrackerStruct{
	TrackerStruct(Tracker_ &_tracker, PreProc_ &_pre_proc, int _id) :
		tracker(_tracker), pre_proc(_pre_proc), id(_id){
	}
	bool update(const cv::Mat &frame, int frame_id = -1) {
		try{
			//! update pre-processor
			pre_proc->update(frame, frame_id);
			//! update tracker
			tracker->update();
		} catch(const mtf::utils::Exception &err){
			printf("Exception of type %s encountered while updating the tracker: %s\n",
				err.type(), err.what());
			return false;
		}
		return true;
	}
	void setRegion(const cv::Mat& corners){
		tracker->setRegion(corners);
	}
	const cv::Mat& getRegion() {
		return tracker->getRegion();
	}
	int getID() const{ return id; }
private:
	Tracker_ tracker;
	PreProc_ pre_proc;
	int id;
};

cv::Mat display_frame;
std::vector<cv::Point> new_tracker_points;
std::vector<TrackerStruct> trackers;
int tracker_id;
std::vector<cv::Scalar> colors;
int n_colors;

ros::Publisher tracker_pub;
SharedImageReader *image_reader;

cv::Point getPatchCenter(const cv::Point2d (&cv_corners)[4]) {
    Eigen::Vector3d tl(cv_corners[0].x, cv_corners[0].y, 1);
    Eigen::Vector3d tr(cv_corners[1].x, cv_corners[1].y, 1);
    Eigen::Vector3d br(cv_corners[2].x, cv_corners[2].y, 1);
    Eigen::Vector3d bl(cv_corners[3].x, cv_corners[3].y, 1);

    Eigen::Vector3d center_vec = center_vec = tl.cross(br).cross(tr.cross(bl));

    cv::Point center;
    center.x = center_vec(0) / center_vec(2);
    center.y = center_vec(1) / center_vec(2);
    return center;
}

mtf_bridge::Patch getTrackerPatch(TrackerStruct &tracker) {
	cv::Point2d cv_corners[4];
	mtf::utils::Corners(tracker.getRegion()).points(cv_corners);
    mtf_bridge::Point top_left;
    top_left.x = cv_corners[0].x;
    top_left.y = cv_corners[0].y;

    mtf_bridge::Point top_right;
    top_right.x = cv_corners[1].x;
    top_right.y = cv_corners[1].y;

    mtf_bridge::Point bot_right;
    bot_right.x = cv_corners[2].x;
    bot_right.y = cv_corners[2].y;

    mtf_bridge::Point bot_left;
    bot_left.x = cv_corners[3].x;
    bot_left.y = cv_corners[3].y;

    mtf_bridge::Patch patch;
    patch.corners[0] = top_left;
    patch.corners[1] = top_right;
    patch.corners[2] = bot_right;
    patch.corners[3] = bot_left;

	cv::Point center_point = getPatchCenter(cv_corners);

    mtf_bridge::Point center;
    center.x = center_point.x;
    center.y = center_point.y;
    patch.center = center;

    return patch;
}

void updateTrackers() {
    if (trackers.empty()) {
        return;
    }
	//! opdate trackers
    mtf_bridge::PatchTrackers tracker_msg;
    for(std::vector<TrackerStruct>::iterator tracker = trackers.begin();
		tracker != trackers.end(); ++tracker) {
		(*tracker).update(*(image_reader->getFrame()), image_reader->getFrameID());
        mtf_bridge::Patch tracker_patch = getTrackerPatch(*tracker);
        tracker_msg.trackers.push_back(tracker_patch);
    }
    tracker_pub.publish(tracker_msg);
}

void drawPatch(const cv::Point2d* corners, cv::Scalar color) {
    line(display_frame, corners[0], corners[1], color);
    line(display_frame, corners[1], corners[2], color);
    line(display_frame, corners[2], corners[3], color);
    line(display_frame, corners[3], corners[0], color);
}

void drawFrame(std::string cv_window_title) {
    cv::cvtColor(*(image_reader->getFrame()), display_frame, cv::COLOR_RGB2BGR);

    // Draw trackers
    if (!trackers.empty()) {
		for(std::vector<TrackerStruct>::iterator tracker = trackers.begin();
			tracker != trackers.end(); ++tracker) {
			cv::Point2d cv_corners[4];
			mtf::utils::Corners((*tracker).getRegion()).points(cv_corners);
			cv::Scalar obj_col = colors[(*tracker).getID() % n_colors];
			drawPatch(cv_corners, obj_col);
			cv::Point center = getPatchCenter(cv_corners);
			cv::circle(display_frame, center, 5, obj_col, -1);
            // Black outline
            cv::circle(display_frame, center, 5, cv::Scalar(0, 0, 0), 2);
        }
    }
    // Show construction of tracker
    for (std::vector<cv::Point>::const_iterator point = new_tracker_points.begin(); point != new_tracker_points.end(); ++point) {
        // White filled circle
        cv::circle(display_frame, *point, 5, cv::Scalar(255, 255, 255), -1);
        // Black outline
        cv::circle(display_frame, *point, 5, cv::Scalar(0, 0, 0), 2);
    }
    imshow(cv_window_title, display_frame);
    char key = cv::waitKey(10);

    if (key == 'd') {
        if (trackers.size() > 0) {
            trackers.erase(trackers.begin());
            pre_procs.erase(pre_procs.begin());
        }
    }
}

bool create(const cv::Mat init_frame, const cv::Mat init_corners, int frame_id) {
	Tracker_ tracker;
	PreProc_ pre_proc;
	try{
		tracker.reset(mtf::getTracker(mtf_sm, mtf_am, mtf_ssm, mtf_ilm));
		if(!tracker){
			printf("Tracker could not be created successfully\n");
			return false;
		}
	} catch(const mtf::utils::Exception &err){
		printf("Exception of type %s encountered while creating the tracker: %s\n",
			err.type(), err.what());
		return false;
	}
	try{
		pre_proc = mtf::getPreProc(pre_procs, tracker->inputType(), pre_proc_type);
	} catch(const mtf::utils::Exception &err){
		printf("Exception of type %s encountered while creating the pre processor: %s\n",
			err.type(), err.what());
		return false;
	}
	try{
		pre_proc->initialize(init_frame, frame_id);
	} catch(const mtf::utils::Exception &err){
		printf("Exception of type %s encountered while initializing the pre processor: %s\n",
			err.type(), err.what());
		return false;
	}
	try{
		for(PreProc_ curr_obj = pre_proc; curr_obj; curr_obj = curr_obj->next){
			tracker->setImage(curr_obj->getFrame());
		}
		tracker->initialize(init_corners);
	} catch(const mtf::utils::Exception &err){
		printf("Exception of type %s encountered while initializing the tracker: %s\n",
			err.type(), err.what());
		return false;
	}

	trackers.push_back(TrackerStruct(tracker, pre_proc, tracker_id));
	pre_procs.push_back(pre_proc);
	++tracker_id;
	return true;
}

// Assume points are ordered: 1 ---- 2
//                            |      |
//                            4 ---- 3
void initializeTracker() {
	if(!readParams(0, nullptr)){ return; }

    cv::Mat cv_corners(2, 4, CV_64FC1);
	for(unsigned int i = 0; i < 4; ++i) {
		cv_corners.at<double>(0, i) = new_tracker_points[i].x;
		cv_corners.at<double>(1, i) = new_tracker_points[i].y;
	}
	if(!create(*(image_reader->getFrame()), cv_corners, image_reader->getFrameID())) {
		ROS_INFO_STREAM("Tracker could not be created");
	}
    ROS_INFO_STREAM("Tracker initialized");
    drawFrame("TrackingNode");
}

void mouseHandler(int mouse_event, int x, int y, int flags, void* param) {
    // Right mouse click restarts setting of tracker points
    if (mouse_event == CV_EVENT_RBUTTONUP) {
        new_tracker_points.clear();
        return;
    }

    if (mouse_event == CV_EVENT_LBUTTONUP) {
        ROS_DEBUG_STREAM("Click at x: " << x << ", " << y);
        new_tracker_points.push_back(cv::Point(x,y));
        if (new_tracker_points.size() == 4) {
            initializeTracker();
            new_tracker_points.clear();
        }
        return;
    }
}

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "trackingNode");
    ros::NodeHandle nh_("~");

    // Initialize input_obj
	config_dir = ros::package::getPath("mtf_bridge") + "/cfg";
	if(!readParams(argc, argv)){ return EXIT_FAILURE; }

	ObjUtils(obj_cols).getCols(colors);
	n_colors = colors.size();

    image_reader = new SharedImageReader();
	tracker_id = 0;

    // Initialize OpenCV window and mouse callback
    std::string cv_window_title = "TrackingNode";
	cv::namedWindow(cv_window_title, cv::WINDOW_AUTOSIZE);
    cv::setMouseCallback(cv_window_title, mouseHandler);

    tracker_pub = nh_.advertise<mtf_bridge::PatchTrackers>("patch_tracker", 1);

	ros::Rate loop_rate(rate);

    while(!image_reader->isInitialized()) {
        ROS_INFO_STREAM("Waiting while system initializes");
        ros::spinOnce();
        ros::Duration(0.7).sleep();
    }

    ROS_INFO_STREAM("Left click to select tracker corners. Right click to reset corners, press 'd' to delete tracker");

	while(ros::ok()){
		ros::spinOnce();
        updateTrackers();
        drawFrame(cv_window_title);
		loop_rate.sleep();
    }
    return 0;
}


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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/ieee/include/functions/ldexp.hpp>
#include <vector>
#include <nt2/include/constants/valmin.hpp>
#include <nt2/include/constants/valmax.hpp>
#include <nt2/include/constants/maxexponent.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/mone.hpp>
#include <nt2/include/constants/zero.hpp>
#include <nt2/sdk/unit/tests/cover.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <boost/simd/sdk/simd/io.hpp>

NT2_TEST_CASE_TPL ( ldexp_all_types,  NT2_SIMD_REAL_TYPES)
{
  using nt2::ldexp;
  using nt2::tag::ldexp_;
  using boost::simd::native;
  typedef NT2_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef typename nt2::meta::as_integer<T>::type iT;
  typedef native<T,ext_t>                nT;
  typedef native<iT,ext_t>              inT;

  typedef typename nt2::meta::call<ldexp_(T, iT)>::type r_t;

  // random verifications
  nt2::uint32_t NR  = NT2_NB_RANDOM_TEST;
  std::vector<T> in1(NR);
  std::vector<iT> in2(NR);
  T Mi = nt2::Mone<T>();
  T Ma = nt2::One<T>();
  nt2::roll(in1, Mi, Ma);
  iT iMi = -nt2::Maxexponent<T>()/2;
  iT iMa =  nt2::Maxexponent<T>()/2;
  nt2::roll(in2,iMi, iMa);

  std::vector<r_t> ref(NR);
  for(nt2::uint32_t i=0; i < NR ; ++i) ref[i] = ldexp(in1[i], in2[i]);
  NT2_COVER_ULP_EQUAL(ldexp_, ((nT, in1))((inT, in2)), ref, 0);

}


//=======================================================================
// Copyright (c)
//
// 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)
//=======================================================================
/**
 * @file local_search_custom_components_test.cpp
 * @brief
 * @author Piotr Wygocki
 * @version 1.0
 * @date 2014-02-04
 */

#include "test_utils/simple_single_local_search_components.hpp"
#include "test_utils/logger.hpp"

#include "paal/local_search/custom_components.hpp"
#include "paal/data_structures/components/components_replace.hpp"
#include "paal/data_structures/tabu_list/tabu_list.hpp"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(local_search_custom_components)

namespace ls = paal::local_search;
using namespace paal;

BOOST_AUTO_TEST_CASE(conditional_gain_adaptor_test) {
    int solution(0);

    auto condGain = ls::make_conditional_gain_adaptor(
        search_comps().get<ls::Gain>(), [](int sol, int move) {
        return sol + move <= 3;
    });

    ls::first_improving(solution, paal::data_structures::replace<ls::Gain>(
                                      condGain, search_comps()));
    BOOST_CHECK_EQUAL(solution, 3);
    LOGLN("solution " << solution);
}

BOOST_AUTO_TEST_CASE(tabu_gain_adaptor_test) {
    int currentSolution(0);
    int best(0);

    auto condGain = ls::make_tabu_gain_adaptor(
        data_structures::tabu_list_remember_solution_and_move<int, int>(20),
        utils::always_true(), [](int s, int m) {
        return s + m <= 3. && s + m >= 0.;
    });

    auto recordSolutionCommit = ls::make_record_solution_commit_adapter(
        best, commit(), paal::utils::make_functor_to_comparator(f));

    ls::first_improving(currentSolution,
                        ls::make_search_components(get_moves(), condGain,
                                                   recordSolutionCommit));

    BOOST_CHECK_EQUAL(best, 3);
    LOGLN("solution " << best);
}

BOOST_AUTO_TEST_SUITE_END()


#include <boost/compute/functional/math.hpp>


/*
 * fusion_runge_kutta.hpp
 *
 * Copyright 2010-2011 Mario Mulansky
 * Copyright 2010-2012 Karsten Ahnert
 *
 * 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 FUSION_EXPLICIT_RK_HPP_
#define FUSION_EXPLICIT_RK_HPP_

#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/size_t.hpp>

#include <boost/fusion/container.hpp>
#include <boost/fusion/algorithm/iteration.hpp>

#include <boost/array.hpp>

#include "fusion_algebra.hpp"
//#include "fusion_foreach_performance.hpp"

namespace mpl = boost::mpl;
namespace fusion = boost::fusion;

using namespace std;

struct intermediate_stage {};
struct last_stage {};

template< class T , class Constant >
struct array_wrapper
{
    typedef const typename boost::array< T , Constant::value > type;
};

template< class T , size_t i , class StageCategory >
struct stage
{
    T c;
    boost::array< T , i > a;
    typedef StageCategory category;
};

template< class T , size_t i>
struct stage< T , i , last_stage >
{
    T c;
    boost::array< T , i > b;
    typedef last_stage category;
};

template< class T , class Constant , class StageCategory >
struct stage_wrapper
{
    typedef stage< T , Constant::value , StageCategory > type;
};

template< class StateType , size_t stage_count >
class explicit_rk
{

public:

    typedef StateType state_type;

    typedef mpl::range_c< size_t , 1 , stage_count > stage_indices;

    typedef typename fusion::result_of::as_vector
    <
        typename mpl::copy
        <
            stage_indices ,
            mpl::inserter
            <
                mpl::vector0< > ,
                mpl::push_back< mpl::_1 , array_wrapper< double , mpl::_2 > >
            >
        >::type
    >::type coef_a_type;

    typedef boost::array< double , stage_count > coef_b_type;
    typedef boost::array< double , stage_count > coef_c_type;

    typedef typename fusion::result_of::as_vector
    <
        typename mpl::push_back
        <
            typename mpl::copy
            <
                stage_indices,
                mpl::inserter
                <
                    mpl::vector0<> ,
                    mpl::push_back< mpl::_1 , stage_wrapper< double , mpl::_2 , intermediate_stage > >
                >
            >::type ,
            stage< double , stage_count , last_stage >
        >::type
    >::type stage_vector_base;

    struct stage_vector : public stage_vector_base
    {
        struct do_insertion
        {
            stage_vector_base &m_base;
            const coef_a_type &m_a;
            const coef_c_type &m_c;

            do_insertion( stage_vector_base &base , const coef_a_type &a , const coef_c_type &c )
            : m_base( base ) , m_a( a ) , m_c( c ) { }

            template< class Index >
            void operator()( Index ) const
            {
                //fusion::at< Index >( m_base ) = stage< double , Index::value+1 , intermediate_stage >( m_c[ Index::value ] , fusion::at< Index >( m_a ) );
                fusion::at< Index >( m_base ).c  = m_c[ Index::value ];
                fusion::at< Index >( m_base ).a = fusion::at< Index >( m_a );
            }
        };

        stage_vector( const coef_a_type &a , const coef_b_type &b , const coef_c_type &c )
        {
            typedef mpl::range_c< size_t , 0 , stage_count - 1 > indices;
            mpl::for_each< indices >( do_insertion( *this , a , c ) );
            //fusion::at_c< 0 >( fusion::at_c< stage_count - 1 >( *this ) ) = stage_count - 1 ;
            fusion::at_c< stage_count - 1 >( *this ).c = c[ stage_count - 1 ];
            fusion::at_c< stage_count - 1 >( *this ).b = b;
        }
    };

    template< class System >
    struct calculate_stage
    {
        System &system;
        state_type &x , &x_tmp;
        state_type *F;
        const double t;
        const double dt;

        calculate_stage( System &_system , state_type &_x , state_type &_x_tmp , state_type *_F ,
                            const double _t , const double _dt )
        : system( _system ) , x( _x ) , x_tmp( _x_tmp ) , F( _F ) , t( _t ) , dt( _dt )
        {}

        template< typename T , size_t stage_number >
        void inline operator()( stage< T , stage_number , intermediate_stage > const &stage ) const
        //typename stage_fusion_wrapper< T , mpl::size_t< stage_number > , intermediate_stage >::type const &stage ) const
        {
            if( stage_number == 1 )
                system( x , F[stage_number-1] , t + stage.c * dt );
            else
                system( x_tmp , F[stage_number-1] , t + stage.c * dt );

            fusion_algebra<stage_number>::foreach( x_tmp , x , stage.a , F , dt);
        }

        template< typename T , size_t stage_number >
        void inline operator()( stage< T , stage_number , last_stage > const &stage ) const
        //void operator()( typename stage_fusion_wrapper< T , mpl::size_t< stage_number > , last_stage >::type const &stage ) const
        {
            if( stage_number == 1 )
                system( x , F[stage_number-1] , t + stage.c * dt );
            else
                system( x_tmp , F[stage_number-1] , t + stage.c * dt );

            fusion_algebra<stage_number>::foreach( x , x , stage.b , F , dt);
        }

    };

public:

    explicit_rk( const coef_a_type &a ,
                  const coef_b_type &b ,
                  const coef_c_type &c )
    : m_stages( a , b , c )

    { }

    template< class System >
    void inline do_step( System system , state_type &x , const double t , const double dt )
    {
        fusion::for_each( m_stages , calculate_stage< System >( system , x , m_x_tmp , m_F , t , dt ) );
    }

private:

    stage_vector m_stages;
    state_type m_x_tmp;

protected:
    state_type m_F[stage_count];

};

#endif /* FUSION_EXPLICIT_RK_HPP_ */


//=======================================================================
// Copyright (c) 2013 Robert Rosolek
//
// 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)
//=======================================================================
/**
 * @file rotate.hpp
 * @brief
 * @author Robert Rosolek
 * @version 1.0
 * @date 2014-08-20
 */

#ifndef PAAL_ROTATE_HPP
#define PAAL_ROTATE_HPP
#include "paal/utils/type_functions.hpp"

#include <boost/range/iterator.hpp>
#include <boost/range/join.hpp>

#include <iterator>

namespace paal {
namespace utils {

   /**
    * @brief returns rotated view of the given range
    *
    * @tparam ForwardRange
    * @param rng
    * @param n
    *
    * @return
    */
template <class ForwardRange>
auto rotate(const ForwardRange& rng, range_to_diff_type_t<ForwardRange> n)
{
   // TODO for some reason std::next doesn't compile under clang
   // for boost::zip range
   //auto const mid = std::next(std::begin(rng), n);
   auto const mid = std::begin(rng) + n;
   return boost::join(
      boost::make_iterator_range(mid, std::end(rng)),
      boost::make_iterator_range(std::begin(rng), mid)
   );
}

} //!data_structures
} //!paal

#endif // PAAL_ROTATE_HPP


// Copyright (c) 2015 The Bitcoin Core developers
// Copyright (c) 2015-2017 The Bitcoin Unlimited developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chain.h"
#include "chainparams.h"
#include "pow.h"
#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

using namespace std;

BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup)

/* Test calculation of next difficulty target with no constraints applying */
BOOST_AUTO_TEST_CASE(get_next_work)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& params = Params().GetConsensus();

    int64_t nLastRetargetTime = 1261130161; // Block #30240
    CBlockIndex pindexLast;
    pindexLast.nHeight = 32255;
    pindexLast.nTime = 1262152739;  // Block #32255
    pindexLast.nBits = 0x1d00ffff;
    BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00d86a);
}

/* Test the constraint on the upper bound for next work */
BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& params = Params().GetConsensus();

    int64_t nLastRetargetTime = 1231006505; // Block #0
    CBlockIndex pindexLast;
    pindexLast.nHeight = 2015;
    pindexLast.nTime = 1233061996;  // Block #2015
    pindexLast.nBits = 0x1d00ffff;
    BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00ffff);
}

/* Test the constraint on the lower bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& params = Params().GetConsensus();

    int64_t nLastRetargetTime = 1279008237; // Block #66528
    CBlockIndex pindexLast;
    pindexLast.nHeight = 68543;
    pindexLast.nTime = 1279297671;  // Block #68543
    pindexLast.nBits = 0x1c05a3f4;
    BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c0168fd);
}

/* Test the constraint on the upper bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& params = Params().GetConsensus();

    int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time
    CBlockIndex pindexLast;
    pindexLast.nHeight = 46367;
    pindexLast.nTime = 1269211443;  // Block #46367
    pindexLast.nBits = 0x1c387f6f;
    BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd);
}

BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
{
    SelectParams(CBaseChainParams::MAIN);
    const Consensus::Params& params = Params().GetConsensus();

    std::vector<CBlockIndex> blocks(10000);
    for (int i = 0; i < 10000; i++) {
        blocks[i].pprev = i ? &blocks[i - 1] : NULL;
        blocks[i].nHeight = i;
        blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
        blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */
        blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
    }

    for (int j = 0; j < 1000; j++) {
        CBlockIndex *p1 = &blocks[GetRand(10000)];
        CBlockIndex *p2 = &blocks[GetRand(10000)];
        CBlockIndex *p3 = &blocks[GetRand(10000)];

        int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params);
        BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime());
    }
}

// MVF-BU begin
/* added unit test after we found that on regtest, difficulty calculation
   can lead to overflow of 256-bit integer. Here an excessive retarget time
   is set in order to trigger the overflow case, in which case the previous
   difficulty is re-used. */
BOOST_AUTO_TEST_CASE(MVFCheckOverflowCalculation_test)
{
    SelectParams(CBaseChainParams::REGTEST);
    const Consensus::Params& params = Params().GetConsensus();
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); // MVF-BU moved here

    // test scenario post fork
    FinalActivateForkHeight = 2016;

    int64_t nLastRetargetTime = 7;  // Force an excessive retarget time to trigger overflow
    CBlockIndex pindexLast;
    pindexLast.nHeight = 2024;
    pindexLast.nTime = 1279297671;  // Block #68543
    pindexLast.nBits = 0x207aaaaa;  // Almost overflowing already

    // an overflow causes the POW limit to be returned
    // need to set -force-retarget, otherwise cannot test overflow
    // because it would never reach the computation
    SoftSetBoolArg("-force-retarget", true);
    BOOST_CHECK_EQUAL(CalculateMVFNextWorkRequired(&pindexLast, nLastRetargetTime, params), bnPowLimit.GetCompact());
}

/* added unit test for fork reset. doesn't test easily in regtest
 * because takes some retargets before raising bits off the limit  */
BOOST_AUTO_TEST_CASE(MVFCheckCalculateMVFResetWorkRequired)
{
    SelectParams(CBaseChainParams::REGTEST);
    const Consensus::Params& params = Params().GetConsensus();
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); // MVF-BU moved here

    // define last block
    CBlockIndex pindexLast;
    pindexLast.nHeight = 68543;
    pindexLast.nTime = 1279297671;  // Block #68543
    pindexLast.nBits = 0x1c05a3f4;

    // retarget time for test
    int64_t nLastRetargetTime = pindexLast.nTime - (params.nPowTargetSpacing * params.DifficultyAdjustmentInterval());

    // force retargeting in CalculateMVFNextWorkRequired
    SoftSetBoolArg("-force-retarget", true);

    // test for drop factor
    FinalDifficultyDropFactor = HARDFORK_DROPFACTOR_REGTEST;
    BOOST_CHECK_EQUAL(CalculateMVFResetWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c168fcf);
}
// MVF-BU end

BOOST_AUTO_TEST_SUITE_END()


#include <boost/crc.hpp>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

const size_t BUFFER_SIZE = 4096;

//https://codereview.stackexchange.com/questions/133483/calculate-the-crc32-of-the-contents-of-a-file-using-boost
std::size_t fileSize(std::ifstream& file)
{
   std::streampos current = file.tellg();
   file.seekg(0, std::ios::end);
   std::size_t result = (std::size_t)file.tellg();
   file.seekg(current, std::ios::beg);
   return result;
}

string FileChecksum(std::string filePath)
{
   boost::crc_32_type crc; //TODO: use a bigger checksum than CRC to avoid 1:4.2 billion collions

   char buffer[BUFFER_SIZE];

   ifstream in(filePath, ios::in | ios::binary);
   if (!in.is_open())
      return "FAILED TO OPEN";

   size_t size = fileSize(in);

   while (!in.eof())
   {
      in.read(buffer, BUFFER_SIZE);
      size_t count = (size_t)in.gcount();
      crc.process_bytes(buffer, count);
   }
   //while (in.read(buffer, BUFFER_SIZE))

   stringstream ss;
   ss << std::dec << size << "_" << std::hex << crc.checksum();
   return ss.str();
}


// Copyright University of Warwick 2014
// 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)

// Authors:
// John Back

/*! \file LpcBranch.hh
    \brief File containing the declaration of the LpcBranch class
*/

/*! \class LpcBranch
    \brief Class that stores the result of a branch of the main principal curve
*/

#ifndef LPC_BRANCH_HH
#define LPC_BRANCH_HH

#include "LACE/LpcAbsCurve.hh"

#include "LACE/LpcPathLength.hh"
#include "LACE/LpcPoint.hh"

#include <Eigen/Dense>
#include <vector>

class LpcBranch : public LpcAbsCurve {

public:

    //! Constructor storing the local principal curve branch result
    /*!
      \param [in] index The index number of the lpc branch
      \param [in] startPoint The scaled starting position for the branch
      \param [in] lpcPoints The calculated scaled branch points
      \param [in] eigenVectors The largest eigenvectors (row = lpc point, col = x,y,z,...)
      \param [in] cosAngles The cosine of the angles between adjacent eigenvectors
      \param [in] lpcPath The cumulative path length object along the curve
      \param [in] rho The ratio of the eigenvalues (2nd/1st) for each branch point
      \param [in] c0 The adjusted kernel function denominator exponent scale factors
      \param [in] highRhoPoints The scaled local neighbourhood points when rho > rho0 (~0.4)
      \param [in] theHits The pointer to the constant hit collection used to find the curve
      \param [in] flag The status flag set to be the index of the main curve
     */
    LpcBranch(int index, const LpcPoint& startPoint,
	      const std::vector<LpcPoint>& lpcPoints,
	      const Eigen::MatrixXd& eigenVectors,
	      const Eigen::VectorXd& cosAngles,
	      const LpcPathLength& lpcPath,
	      const Eigen::VectorXd& rho,
	      const Eigen::VectorXd& c0,
	      const std::vector<LpcPoint>& highRhoPoints,
	      const LpcHitCollection* theHits,
	      int flag);

    //! Empty constructor
    LpcBranch();

    //! Destructor
    virtual ~LpcBranch();

protected:

private:

    //! Copy constructor
    LpcBranch(const LpcBranch& other);

    //! Assignment operator
    LpcBranch& operator=(const LpcBranch& other);
};

#endif


/*
// Copyright (c) 2000-2009, Texas Engineering Experiment Station (TEES), a
// component of the Texas A&M University System.

// All rights reserved.

// The information and source code contained herein is the exclusive
// property of TEES and may not be disclosed, examined or reproduced
// in whole or in part without explicit written authorization from TEES.
*/

#ifndef STAPL_BENCHMARK_LONESTAR_CLUSTER_TESTING_HPP
#define STAPL_BENCHMARK_LONESTAR_CLUSTER_TESTING_HPP

#include <stapl/utility/do_once.hpp>
#include <stapl/containers/array/array.hpp>
#include <stapl/views/array_view.hpp>
#include <boost/random.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include "agglomerativeclustering.hpp"

using namespace stapl;

/////////////////////////////////////////////////////////////////////
/// @brief Used in the generation of the test data and stores static
///        data and information about each local process.
/////////////////////////////////////////////////////////////////////
struct local_loc_data
{
  size_t m_num_elems;
  size_t m_num_locs;
  size_t m_loc_id;
  double m_loc_range;
  double m_loc_range_start;
  double m_data_skip;
  size_t m_offset_start;

  local_loc_data(size_t num_elems, size_t num_locs, size_t loc_id)
    : m_num_elems(num_elems), m_num_locs(num_locs), m_loc_id(loc_id)
  {
    // Generated values are between [0.25, 0.75).
    double range_start = 0.25;
    double range_end = 0.75;
    double range = range_end - range_start;
    double factor = get_factor(m_num_locs, m_loc_id);
    m_loc_range = range / (2.0*m_num_locs-1);
    m_loc_range_start = 2.0*m_loc_id*m_loc_range*factor + range_start;
    m_data_skip = (double)m_num_locs * m_loc_range / m_num_elems;

    size_t elem_per_loc = m_num_elems / m_num_locs;
    m_offset_start = elem_per_loc * m_loc_id;

    if (m_loc_id < (m_num_elems % m_num_locs)) {
      m_offset_start += m_loc_id;
    } else {
      m_offset_start += m_num_elems % m_num_locs;
    }
  }

  /////////////////////////////////////////////////////////////////////
  /// @brief Returns a coefficient factor based on the number of iterations
  ///        it takes to reach a value given range using a binary search. Used
  ///        to make pairs of points closer in space to eliminate issues with
  ///        floating point comparisons and to guarantee ordering.
  /////////////////////////////////////////////////////////////////////
  static double get_factor(size_t range, size_t val)
  {
    range /= 2;
    double depth = 0.0;
    while (val != range && range > 0) {
      if (val > range) {
        val -= range;
      }
      range /= 2;
      ++depth;
    }
    return pow(0.999, depth);
  }

  double data_range_offset(size_t offset)
  {
    double factor = get_factor(m_num_elems, offset);
    return (offset - m_offset_start) * m_data_skip * factor;
  }

  void define_type(stapl::typer& t)
  {
    t.member(m_num_elems);
    t.member(m_num_locs);
    t.member(m_loc_id);
    t.member(m_loc_range);
    t.member(m_loc_range_start);
    t.member(m_data_skip);
    t.member(m_offset_start);
  }
};

/////////////////////////////////////////////////////////////////////
/// @brief Generates testing point.
///
/// For each point:
///     The X dimension stores the index of the point in the array. The value
///   is scaled down so that it does not impact the clustering processing, but
///   can still be used to determine the original index.
///     The Y dimension contains values that are generated in such a way that
///   the resulting clustering will group points in deterministic pairs.
///     The Z dimension contains a value that remains constant for each
///   location. Therefore for each process there should exist one major cluster.
///
/// If the number of processes and the number of elements are powers of two,
/// the resulting clustering should be a perfect binary tree.
/////////////////////////////////////////////////////////////////////
struct wf_test_data
{
  using state_type = std::true_type;

  local_loc_data m_local_data;
  size_t         m_offset;

  wf_test_data(local_loc_data local_data)
    : m_local_data(local_data), m_offset(0)
  { }

  wf_test_data(wf_test_data const& wf, size_t offset)
    : m_local_data(wf.m_local_data), m_offset(offset)
  { }

  my_point operator()()
  {
    double data_range_offset = m_local_data.data_range_offset(m_offset);
    my_point point;
    point.m_x = 0.00001 * m_offset / m_local_data.m_num_elems;
    point.m_y = m_local_data.m_loc_range_start + data_range_offset;
    point.m_z = m_local_data.m_loc_range_start;
    return point;
  }

  void define_type(stapl::typer& t)
  {
    t.member(m_local_data);
    t.member(m_offset);
  }
};

/////////////////////////////////////////////////////////////////////
/// @brief Fills an array with test points
/// @todo Crashes with random inputs but passes for input generated by seed 0,
///       needs to be debugged and fixed.
/////////////////////////////////////////////////////////////////////
template <typename ArrayView>
void fill_with_test_points(ArrayView& av)
{
  local_loc_data local_data(av.size(), get_num_locations(), get_location_id());
  wf_test_data wf(local_data);
  stapl::generate(av, wf);

  #if 0
  srand(time(0));
  #else
  srand(0);
  #endif
  typedef typename ArrayView::const_iterator::difference_type difference_type;
  random_shuffle(av,
    algo_details::default_random_number_generator<difference_type>(
      av.get_location_id()+rand()));
}

/////////////////////////////////////////////////////////////////////
/// @brief Used to simplify accessing elements of a cluster.
/////////////////////////////////////////////////////////////////////
template<typename Clusters, typename Cluster>
struct cluster_wrapper
  : public Cluster
{
  Clusters& m_clusters;
  size_t m_depth;

  cluster_wrapper(Clusters& clusters, Cluster cluster, size_t depth)
    : Cluster(cluster), m_clusters(clusters), m_depth(depth)
  { }

  size_t get_num_children()
  { return (*this).property().children.size(); }

  size_t get_num_elements_in_cluster()
  { return (*this).property().property.get_Count(); }

  size_t get_child_id(size_t child_index)
  { return (*this).property().children[child_index]; }

  cluster_wrapper get_child(size_t child_index)
  {
    size_t id = get_child_id(child_index);
    return cluster_wrapper(m_clusters, m_clusters[m_depth-1][id], m_depth-1);
  }

  cluster_wrapper get_left_cluster()
  {
    if (get_num_children() == 0) {
      return (*this);
    } else if (get_num_children() == 1) {
      return get_child(0).get_left_cluster();
    } else {
      return get_child(0);
    }
  }

  cluster_wrapper get_right_cluster()
  {
    if (get_num_children() == 0) {
      return (*this);
    } else if (get_num_children() == 1) {
      return get_child(0).get_right_cluster();
    } else {
      return get_child(1);
    }
  }
};

/////////////////////////////////////////////////////////////////////
/// @brief Constructs a wrapper for a cluster vertex.
/////////////////////////////////////////////////////////////////////
template<typename Clusters, typename Cluster>
cluster_wrapper<Clusters, Cluster> wrap_cluster(Clusters& clusters,
                                                Cluster cluster, size_t depth)
{
  return cluster_wrapper<Clusters, Cluster>(clusters, cluster, depth);
}

/////////////////////////////////////////////////////////////////////////////
/// @brief Recursive function that checks if the clustering is a perfect
///        binary tree.
/////////////////////////////////////////////////////////////////////////////
template <typename ClusterWrapper>
void test_pow2(ClusterWrapper cluster, bool& passed, size_t size)
{
  size_t num_children = cluster.get_num_children();
  if (num_children == 0 || !passed) {
    return;
  } else if (cluster.get_num_elements_in_cluster() != size) {
    passed = false;
    return;
  } else {
    test_pow2(cluster.get_left_cluster(), passed, size / 2);
    if (num_children == 2) {
      test_pow2(cluster.get_right_cluster(), passed, size / 2);
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
/// @brief If number of elements and processors are powers of two, then the
///        resulting clustering should be a perfect binary tree.
//////////////////////////////////////////////////////////////////////////////
template <typename Clusters>
bool test_pow2(Clusters clusters)
{
  size_t num_elems = clusters[0].size();
  size_t depth = clusters.size()-1;
  bool passed = true;

  auto root = clusters[depth][0];
  test_pow2(wrap_cluster(clusters, root, depth), passed, num_elems);

  return passed;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief Checks that pairs of points were clustered correctly.
//////////////////////////////////////////////////////////////////////////////
template <typename Clusters>
struct pair_test_wf
{
  typedef bool result_type;

  Clusters const& m_clusters;
  local_loc_data m_local_data;

  pair_test_wf(Clusters const& clusters, local_loc_data local_data)
    : m_clusters(clusters), m_local_data(local_data)
  { }

  template <typename Vertex>
  result_type operator()(Vertex v)
  {
    if (v.property().children.size() > 2) {
      return false;
    } else if (v.property().children.size() == 2) {
      size_t id0 = v.property().children[0];
      size_t id1 = v.property().children[1];
      my_point p0 = m_clusters[0][id0].property().property.get_Centroid();
      my_point p1 = m_clusters[0][id1].property().property.get_Centroid();
      double diff = std::abs(p0.m_x - p1.m_x);
      if (diff > 0.000011 / m_local_data.m_num_elems) {
        return false;
      }
    }
    return true;
  }

  /////////////////////////////////////////////////////////////////////
  /// @bug Packing reference (m_clusters).
  /////////////////////////////////////////////////////////////////////
  void define_type(stapl::typer& t)
  {
    t.member(m_clusters);
    t.member(m_local_data);
  }
};

/////////////////////////////////////////////////////////////////////
/// @brief Prints pass/fail message on single location.
/////////////////////////////////////////////////////////////////////
void print_test_msg(char const* msg, bool passed)
{
  if (get_num_locations() == 1) {
    if (passed) {
      std::cout << msg << ": \x1b[;32m[PASSED]\x1b[;0m\n";
    } else {
      std::cout << msg << ": \x1b[;31m[FAILED]\x1b[;0m\n";
    }
  } else {
    do_once([&](void) {
      print_test_msg(msg, passed);
    });
  }
}

//////////////////////////////////////////////////////////////////////////////
/// @brief Performs various tests to check if clustering is correct.
//////////////////////////////////////////////////////////////////////////////
template <typename Clusters>
void cluster_testing(Clusters& clusters)
{
  size_t num_elems = clusters[0].size();
  size_t num_locs =  get_num_locations();
  local_loc_data local_data(num_elems, num_locs, get_location_id());

  // Check that pairs of points were clustered correctly.
  if (clusters.size() >= 2) {
    pair_test_wf<Clusters> wf(clusters, local_data);
    bool passed = nc_map_reduce(wf, stapl::logical_and<bool>(), clusters[1]);
    print_test_msg("Pair Test", passed);
  }

  // If num_elems and num_locs are both power of two's, perform extensive test
  if (!(num_elems & (num_elems - 1)) && !(num_locs & (num_locs - 1))) {
    do_once([&clusters](void) {
      bool passed = test_pow2(clusters);
      print_test_msg("Extensive Test", passed);
    });
  }
}

#endif


/* Copyright (c) 2015, Julian Straub <jstraub@csail.mit.edu>
 * Licensed under the MIT license. See the license file LICENSE.
 */
#pragma once

#include <iostream>
#include <time.h>
#include <Eigen/Dense>

#include <boost/random/mersenne_twister.hpp>
//#include <boost/random/uniform_int_distribution.hpp>
//#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_01.hpp>

#include <dpMM/global.hpp>
#include <dpMM/cat.hpp>

using namespace Eigen;
using std::cout;
using std::endl;

/* Sampler for CPU */
template<typename T=double>
class Sampler
{
protected:
  boost::mt19937* pRndGen_;
  bool selfManaged_;
  boost::uniform_01<> unif_;

public:
  Sampler(boost::mt19937* pRndGen=NULL);
  virtual ~Sampler();

  virtual void sampleUnif(Matrix<T,Dynamic,1>& r);
  virtual Matrix<T,Dynamic,1> sampleUnif(uint32_t N)
  {
    Matrix<T,Dynamic,1> u(N);
    sampleUnif(u);
    return u;
  };

  virtual void sampleDiscLogPdfUnNormalized(const Matrix<T,Dynamic,Dynamic>& pdfs,
    VectorXu& z);
  virtual VectorXu sampleDiscLogPdfUnNormalized(
    const Matrix<T,Dynamic,Dynamic>& pdfs)
  {
    VectorXu z(pdfs.rows());
    sampleDiscLogPdfUnNormalized(pdfs,z);
    return z;
  };

  virtual void sampleDiscPdf(T *d_pdfs, const spVectorXu& z){ assert(false);};
  virtual void sampleDiscPdf(const Matrix<T,Dynamic,Dynamic>& pdfs, VectorXu& z);
  virtual VectorXu sampleDiscPdf(const Matrix<T,Dynamic,Dynamic>& pdfs)
  {
    VectorXu z(pdfs.rows());
    sampleDiscPdf(pdfs,z);
    return z;
  };
};

#ifdef CUDA
#include <dpMM/gpuMatrix.hpp>

extern void choiceMultGpu(double* d_pdf, uint32_t* d_z, uint32_t N,
    uint32_t M, uint32_t seed);
extern void choiceMultGpu(float* d_pdf, uint32_t* d_z, uint32_t N,
    uint32_t M, uint32_t seed);
extern void choiceMultLogPdfGpu(double* d_logPdf, uint32_t* d_z, uint32_t N,
    uint32_t M, uint32_t seed);
extern void choiceMultLogPdfGpu(float* d_logPdf, uint32_t* d_z, uint32_t N,
    uint32_t M, uint32_t seed);
extern void choiceMultLogPdfUnNormalizedGpu(double* d_pdf, uint32_t* d_z,
  uint32_t N, uint32_t M, uint32_t seed);
extern void choiceMultLogPdfUnNormalizedGpu(float* d_pdf, uint32_t* d_z,
  uint32_t N, uint32_t M, uint32_t seed);
extern void unifGpu(double* d_u, uint32_t N, uint32_t seed);
extern void unifGpu(float* d_u, uint32_t N, uint32_t seed);

extern void logNormalizerGpu(float* d_logPdf, float* d_logNormalizer,
    uint32_t dk, uint32_t K, uint32_t N);
extern void logNormalizerGpu(double* d_logPdf, double* d_logNormalizer,
    uint32_t dk, uint32_t K, uint32_t N);
extern void logNormalizeGpu(float* d_logPdf, uint32_t dk, uint32_t K, uint32_t N);
extern void logNormalizeGpu(double* d_logPdf, uint32_t dk, uint32_t K, uint32_t N);
extern void logAddTopLevelGpu(float* d_logPdf, float* d_logNormalizer,
    float* d_logPi, uint32_t dk, uint32_t K, uint32_t N);
extern void logAddTopLevelGpu(double* d_logPdf, double* d_logNormalizer,
    double* d_logPi, uint32_t dk, uint32_t K, uint32_t N);

/* Sampler for GPU */
template<typename T=float>
class SamplerGpu : public Sampler<T>
{
  boost::shared_ptr<GpuMatrix<T> > pdfs_; // one pdf per row
  GpuMatrix<T> logNormalizers_; // one pdf per row
  GpuMatrix<uint32_t> z_; // samples from pdfs
  GpuMatrix<T> r_; // unif random numbers

public:
  SamplerGpu(uint32_t N, uint32_t K, boost::mt19937* pRndGen=NULL);
  ~SamplerGpu();

  void sampleUnif(Matrix<T,Dynamic,1>& r);
  Matrix<T,Dynamic,1> sampleUnif()
  {
    Matrix<T,Dynamic,1> u(r_.rows());
    sampleUnif(u);
    return u;
  };

  virtual void setPdfs(const boost::shared_ptr<GpuMatrix<T> >& pdfs,
      bool logScale);

  virtual void sampleDiscLogPdfUnNormalized(
      const Matrix<T,Dynamic,Dynamic>& pdfs, VectorXu& z);
  /* use pdfs already prestored in GPU memory */
  void sampleDiscPdf(T *d_pdfs, const spVectorXu& z, bool logScale=false);
//  void sampleDiscPdf(const Matrix<T,Dynamic,Dynamic>& pdfs, const spVectorXu& z);
  void sampleDiscPdf(const Matrix<T,Dynamic,Dynamic>& pdfs, VectorXu& z,
      bool logScale = false);
  VectorXu sampleDiscPdf(const Matrix<T,Dynamic,Dynamic>& pdfs,
      bool logScale=false)
  {
    VectorXu z(pdfs.rows());
    sampleDiscPdf(pdfs,z,logScale);
    return z;
  };
  // sample from internal pdfs_
  void sampleDiscPdf();

  // compute logNormalizer over blocks of dk columns
  void logNormalizer(uint32_t dk, uint32_t K);
  // log normalize the distributions in pdfs_ in blocks of dk cols
  void logNormalize(uint32_t dk, uint32_t K);
  // add logNormalizer+pi to pdfs_ -> add one layer of hierarchy
  void addTopLevel(const Matrix<T,Dynamic,1>& pi,uint32_t dk);

  // get Z from memory
  void getZ( VectorXu& z){ z_.get(z);};
};
#endif


// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <pow.h>

#include <arith_uint256.h>

#include <boost/multiprecision/cpp_int.hpp>
#include <chain.h>
#include <primitives/block.h>
#include <uint256.h>
#include <chainparams.h>
#include <crypto/equihash.h>
#include <streams.h>
#include <util.h>
#include <ed25519/ed25519.h>
#include "validation.h"

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
    assert(pindexLast != nullptr);

    // Only change once per difficulty adjustment interval
    if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
    {
		unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
        if (pindexLast->nHeight < 60500)
		{
            if (params.fPowAllowMinDifficultyBlocks)
            {
                // Special difficulty rule for testnet:
                // If the new block's timestamp is more than 2* 10 minutes
                // then allow mining of a min-difficulty block.
                if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
                    return nProofOfWorkLimit;
                else
                {
                    // Return the last non-special-min-difficulty-rules-block
                    const CBlockIndex* pindex = pindexLast;
                    while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
                        pindex = pindex->pprev;
                    return pindex->nBits;
                }
            }
            return pindexLast->nBits;
        } else {
            // Return the last non-special-min-difficulty-rules-block
            const CBlockIndex* pindex = pindexLast;
            while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
                pindex = pindex->pprev;
            return pindex->nBits;
        }
    }

    // Go back by what we want to be 14 days worth of blocks
    int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
    assert(nHeightFirst >= 0);
    const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
    assert(pindexFirst);

    return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}

static boost::multiprecision::uint512_t UintToCpp512(const uint256 & n)
{
	std::string n_string = n.ToString();
	return boost::multiprecision::uint512_t("0x" + n_string);
}

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
    if (params.fPowNoRetargeting)
        return pindexLast->nBits;

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
    if (nActualTimespan < params.nPowTargetTimespan/4)
        nActualTimespan = params.nPowTargetTimespan/4;
    if (nActualTimespan > params.nPowTargetTimespan*4)
        nActualTimespan = params.nPowTargetTimespan*4;

    // Retarget
    auto bnPowLimit = UintToCpp512(params.powLimit);
    arith_uint256 bnNewtmp;

	unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();

	// Use the last non-special-min-difficulty-rules-block
	if (pindexLast->nHeight > 51840)
	{
		const CBlockIndex* pindex = pindexLast;
		while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
			pindex = pindex->pprev;
			bnNewtmp.SetCompact(pindex->nBits);
	}
	else
	{
		bnNewtmp.SetCompact(pindexLast->nBits);
	}

	boost::multiprecision::uint512_t bnNew = UintToCpp512(ArithToUint256(bnNewtmp));

//	bnNew.SetCompact(pindexLast->nBits);
    bnNew *= nActualTimespan;
    bnNew /= params.nPowTargetTimespan;

    if (bnNew > bnPowLimit)
        bnNew = bnPowLimit;

	std::stringstream converted_stream;
	converted_stream << std::hex << std::showbase << bnNew;

	std::string converted_string = converted_stream.str();
	return UintToArith256(uint256S(converted_string)).GetCompact();
}

bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
{
    unsigned int n = params.EquihashN();
    unsigned int k = params.EquihashK();

    // Hash state
    blake2b_state state;
    EhInitialiseState(n, k, state);

    // I = the block header minus nonce and solution.
    CEquihashInput I{*pblock};
    // I||V
    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
    ss << I;
    ss << pblock->nNonce;

    // H(I||V||...
    blake2b_update(&state, (unsigned char*)&ss[0], ss.size());

    bool isValid;
    EhIsValidSolution(n, k, state, pblock->nSolution, isValid);
    if (!isValid)
        return error("CheckEquihashSolution(): invalid solution");

    return true;
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
{
    bool fNegative;
    bool fOverflow;
    arith_uint256 bnTarget;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
        return false;

    // Check proof of work matches claimed amount
    if (UintToArith256(hash) > bnTarget)
        return false;

    return true;
}

bool CheckAuthorization(const CBlock *pblock, const CChainParams& params)
{
    CBlockIndex * chainIndex = chainActive.Tip();
    if (chainIndex == nullptr ||
            params.GetConsensus().authorizationForkHeight <= 0 ||
            chainIndex->nHeight + 1 < params.GetConsensus().authorizationForkHeight) {
        return true;
    }
    if (!params.GetConsensus().authorizationKey.IsFullyValid()) {
        return true;
    }

    if (pblock->vtx.empty() || !pblock->vtx[0]->IsCoinBase()) {
        return false;
    }

    const CTransaction& coinbase = *pblock->vtx[0];
    CScript scriptSig = coinbase.vin[0].scriptSig;
    // 0x40 + 64个字节的signature
    if (scriptSig.size() < 65) {
        return false;
    }
    CScript::const_iterator pc = scriptSig.begin();

    // 第一个元素是区块高度
    const int nHeight = chainIndex->nHeight + 1;
    CScript nHeightScript = CScript() << nHeight;
    // 第二个元素是timestamp
    CScript nTimeScript = CScript() << pblock->nTime;
    pc = pc + nHeightScript.size() + nTimeScript.size();

    std::vector<unsigned char> sig;
    opcodetype opcode;
    if (!scriptSig.GetOp(pc, opcode, sig)) {
        return false;
    }
    // signature长度是64
    if (opcode != 64) {
        return false;
    }
    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    for(auto vout : coinbase.vout) {
        ss << vout;
    }
    auto hash = ss.GetHash();
    return params.GetConsensus().authorizationKey.Verify(hash, sig);
}


#include "temperature.h"
#include "../basic.h"

#include <algorithm>
#include <random>

#include <boost/log/trivial.hpp>
#include <boost/random.hpp>

#include <OpenSimplexNoise.h>

namespace WorldEngine
{

static const float SQRT_2XLN2 = sqrtf(2 * logf(2));

static void TemperatureCalculation(World&              world,
                                   uint32_t            seed,
                                   ElevationArrayType& elevation,
                                   float               mountainLevel);

void TemperatureSimulation(World& world, uint32_t seed)
{
   BOOST_LOG_TRIVIAL(info) << "Temperature simulation start";

   ElevationArrayType& elevation = world.GetElevationData();
   float mountainLevel = world.GetThreshold(ElevationThreshold::Mountain);
   const OceanArrayType&       ocean = world.GetOceanData();
   const TemperatureArrayType& t     = world.GetTemperatureData();

   TemperatureCalculation(world, seed, elevation, mountainLevel);

   world.SetThreshold(TemperatureLevel::Polar,
                      FindThresholdF(t, world.temps()[0], &ocean));
   world.SetThreshold(TemperatureLevel::Alpine,
                      FindThresholdF(t, world.temps()[1], &ocean));
   world.SetThreshold(TemperatureLevel::Boreal,
                      FindThresholdF(t, world.temps()[2], &ocean));
   world.SetThreshold(TemperatureLevel::Cool,
                      FindThresholdF(t, world.temps()[3], &ocean));
   world.SetThreshold(TemperatureLevel::Warm,
                      FindThresholdF(t, world.temps()[4], &ocean));
   world.SetThreshold(TemperatureLevel::Subtropical,
                      FindThresholdF(t, world.temps()[5], &ocean));
   world.SetThreshold(TemperatureLevel::Tropical,
                      std::numeric_limits<float>::max());

   BOOST_LOG_TRIVIAL(info) << "Temperature simulation finish";
}

static void TemperatureCalculation(World&              world,
                                   uint32_t            seed,
                                   ElevationArrayType& elevation,
                                   float               mountainLevel)
{
   BOOST_LOG_TRIVIAL(debug) << "Seed: " << seed;

   std::mt19937                                      generator(seed);
   boost::random::uniform_int_distribution<uint32_t> distribution;

   OpenSimplexNoise::Noise noise(distribution(generator));

   const int32_t width  = world.width();
   const int32_t height = world.height();

   TemperatureArrayType& temperature = world.GetTemperatureData();
   temperature.resize(boost::extents[height][width]);

   /*
    * Set up variables to take care of some orbital paramters:
    * distanceToSun:
    *     - Earth-like planet = 1.0
    *     - Valid range between ~0.7 and ~1.3
    *       See https://en.wikipedia.org/wiki/Circumstellar_habitable_zone
    *     - Random value chosen via normal (Gaussian) distribution
    *       See https://en.wikipedia.org/wiki/Gaussian_function
    *     - Width of distrubiton around 1.0 is determined by HWHM (half width at
    *       half maximum)
    *     - HWHM is used to calculate the random scale
    *       sigma = HWHM / sqrt(2*ln(2))
    *     - *only HWHM* should be considered a parameter
    *     - most likely outcomes can be estimated
    *       HWHM * sqrt(2*ln(10)) / sqrt(2*ln(2)) = HWHM * 1.822615728
    *       e.g., for HWHM = 0.12: 0.78 < distanceToSun < 1.22
    * axialTilt:
    *     - The world/planet may move around its star at an angle
    *       See https://en.wikipedia.org/wiki/Axial_tilt
    *     - A value of 0.5 here would refer to an angle of 90 degrees,
    *       Uranus-style
    *       See https://en.wikipedia.org/wiki/Uranus
    *     - This value should usually be in the range -0.15 < axialTilt < 0.15
    *       for a habitable planet
    */

   const float distanceToSunHWHM = 0.12f;
   const float axialTiltHWHM     = 0.07f;

   // Derive parameters
   float distanceToSun = boost::random::normal_distribution<float>(
      1.0f, distanceToSunHWHM / SQRT_2XLN2)(generator);
   // Clamp value, no planets inside the star
   distanceToSun = std::max(0.1f, distanceToSun);
   // Prepare for later usage, use inverse-square law
   distanceToSun *= distanceToSun;
   // An atmosphere would soften the effect of distanceToSun by *some* factor

   float axialTilt = boost::random::normal_distribution<float>(
      0.0f, axialTiltHWHM / SQRT_2XLN2)(generator);
   axialTilt = std::clamp(axialTilt, -0.5f, 0.5f);

   BOOST_LOG_TRIVIAL(debug) << "Axial tilt: " << axialTilt;

   int32_t  border  = width / 4;
   uint32_t octaves = 8; // Number of passes for noise generator
   float    freq    = 16.0f * octaves;
   float    nScale  = 1024.0f / static_cast<float>(height);

   std::vector<std::pair<float, float>> points = {{axialTilt - 0.5f, 0.0f}, //
                                                  {axialTilt, 1.0f},
                                                  {axialTilt + 0.5f, 0.0f}};

   for (int32_t y = 0; y < height; y++)
   {
      // yScaled = -0.5..0.5
      float yScaled = static_cast<float>(y) / static_cast<float>(height) - 0.5f;

      // Map/linearly interpolate yScaled to latitude measured from where the
      // most sunlight hits the world:
      //     1.0 = hottest zone
      //     0.0 = coldest zone
      float latitudeFactor = Interpolate(yScaled, points);

      for (int32_t x = 0; x < width; x++)
      {
         double n = Noise(noise, //
                          x * nScale / freq,
                          y * nScale / freq,
                          octaves);

         // Added to allow noise pattern to wrap around right and left
         if (x <= border)
         {
            n *= static_cast<double>(x) / border;
            n += Noise(noise,
                       (x * nScale + width) / freq,
                       y * nScale / freq,
                       octaves) *
                 (border - x) / border;
         }

         float t = static_cast<float>((latitudeFactor * 12 + n) / 13.0 /
                                      distanceToSun);

         // Vary temperature based on height
         if (elevation[y][x] > mountainLevel)
         {
            float altitudeFactor;

            if (elevation[y][x] > mountainLevel + 29)
            {
               altitudeFactor = 0.033f;
            }
            else
            {
               altitudeFactor =
                  1.0f - (elevation[y][x] - mountainLevel) / 30.0f;
            }

            t *= altitudeFactor;
         }

         temperature[y][x] = t;
      }
   }
}

} // namespace WorldEngine