/*
Copyright 2017 InitialDLab

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "aggragate_experiments.h"

#include <vector>
#include <random>

#include <boost/date_time/posix_time/posix_time.hpp>

#include "mongo_types.h"
#include "experiments/Data_Source_Information.h"
#include "experiments/experiment_utilities.h"
#include "rtree/rtree.h"

// this experiment is using chernoff bounds to calculate expected error
// delta is the expected probability of failure
// alpha is the expected variation between the actual value and aggregated value
// spread is the maximum - minimum value
// omega is 2 * alpha / spread  (this is used to quantify error under various spreads)
// r is the number of samples used for an aggregation.

void aggragate_experiments::perform_listed_experiments_GEO()
{
    // experiment settings for easy modification
    int n = 100; // the number of regions to test
    long seed = 1L; // the seed to use.  Change for actual experiment;
    float min_query_size = 0.01;
    float max_query_size = 0.30;
    std::uniform_real_distribution<float> cover_distribution(min_query_size, max_query_size);
    std::default_random_engine generator;
    generator.seed(seed);

    std::vector<double> delta_to_test{ 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80 };
    std::vector<double> omega_to_test{ 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80 };

    // open the data
    auto data_source = Data_Source_Information::get_data_information(Geolife);

    std::vector<mongo_types::box3d> regions_to_test;

    // randomly select several regions which we will test
    for (int i = 0; i < n; i++)
        regions_to_test.push_back(utilities::get_random_query_box(cover_distribution(generator), *data_source));

    // test the listed experiments
    perform_listed_experiments(data_source, regions_to_test, delta_to_test, omega_to_test);
}

void aggragate_experiments::perform_listed_experiments_OSM()
{
    // experiment settings for easy modification
    int n = 1000; // the number of regions to test
    long seed = 1L; // the seed to use.  Change for actual experiment;
    float min_query_size = 0.01;
    float max_query_size = 0.30;
    std::uniform_real_distribution<float> cover_distribution(min_query_size, max_query_size);
    std::default_random_engine generator;
    generator.seed(seed);

    std::vector<double> delta_to_test{ 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80 };
    std::vector<double> omega_to_test{ 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80 };

    // open the data
    auto data_source = Data_Source_Information::get_data_information(OSM_nodes);

    std::vector<mongo_types::box3d> regions_to_test;

    // randomly select several regions which we will test
    for (int i = 0; i < n; i++)
        regions_to_test.push_back(utilities::get_random_query_box(cover_distribution(generator), *data_source));

    // test the listed experiments
    perform_listed_experiments(data_source, regions_to_test, delta_to_test, omega_to_test);
}

void aggragate_experiments::perform_listed_experiments(std::shared_ptr<Data_Source_Information> data_source,
                                                       std::vector<mongo_types::box3d> &sample_ranges,
                                                       std::vector<double> &delta_values,
                                                       std::vector<double> &omega_values)
{
    // generate the exact queries for the experiments.
    std::vector<streaming_aggragate_query_time> exact_results;
    for (auto range : sample_ranges)
    {
        exact_results.emplace_back(range);
    }

    // scan through the data, gathering exact query data //
    // (also printing the progress of the scan, because it can take a very long time) //
    auto convert_function = data_source->get_convert_function();
    long elements_to_read = data_source->get_element_count();
    long elements_read = 0;
    // open input file
    std::fstream in_file(data_source->get_source_raw().c_str(), std::ios_base::in);
    std::string str;
    while (!in_file.eof())
    {
        std::getline(in_file, str);

        // empty string are considered null, so don't enter any data from a zero length string
        if (str.size() == 0)
            continue;
        mongo_types::sample_entry current_item(convert_function(str));

        for (int i = 0; i < exact_results.size(); i++)
            exact_results[i].submit(current_item);
        //for (auto exact_query : exact_results)
        //    exact_query.submit(current_item);

        ++elements_read;

        if (elements_read % 1000000 == 0)
            std::cout << ((0.0 + elements_read) / elements_to_read) << std::endl;
    }

    // open the sampling tree
    using rtree_t = rtree::rtree <
        mongo_types::entry,
        mongo_types::sample_entry,
        mongo_types::box3d,
        256,
        256
    >;
    std::unique_ptr<rtree_t> rtree_ptr;
    rtree_ptr.reset(new rtree_t(data_source->get_source_created()));

    // perform the experiments for each delta and omega values
    for (auto delta : delta_values) {
        for (auto omega : omega_values) {
            for (auto region : exact_results) {
                boost::posix_time::ptime start_time{ boost::posix_time::second_clock::local_time() };

                double spread = region.get_queryBox().max_corner().get<2>() - region.get_queryBox().min_corner().get<2>();
                double alpha = omega * spread / 2.0;
                int r = std::ceil(-(spread * spread / (2.0 * alpha)) * std::log(delta / 2.0));

                // setup query which we will be doing the aggregation over
                streaming_aggragate_query_time sampled_query(region.get_queryBox());
                auto cursor = rtree_ptr->sample_query(sampled_query.get_queryBox());

                 std::vector<mongo_types::sample_entry> samples;
                samples.reserve(r);

                // fulfill query and get submitted aggregation
                int count = cursor.estimate_count();
                // std::cerr << (1.0 * r / count) << std::endl;
                cursor.get_samples(r, std::back_inserter(samples));
                for (auto element : samples)
                    sampled_query.submit(element);

                write_experiment_entry(data_source->get_source_created(),
                    start_time,
                    delta,
                    spread,
                    r,
                    omega,
                    alpha,
                    region,
                    sampled_query);
            }
        }
    }

}

void aggragate_experiments::open_outputfile()
{
    m_output.reset(new std::fstream{ m_outputFilename, std::fstream::out | std::fstream::app });

    if (!m_output->tellp())
    {
        write_header();
    }
}

void aggragate_experiments::write_header()
{
    *m_output << "input file" << m_dataSeperator
        << "Start time"       << m_dataSeperator
        << "query box min"    << m_dataSeperator
        << "query box max"    << m_dataSeperator
        << "actual min"       << m_dataSeperator
        << "actual max"       << m_dataSeperator
        << "actual spread"    << m_dataSeperator
        << "delta"            << m_dataSeperator
        << "alpha"            << m_dataSeperator
        << "spread"           << m_dataSeperator
        << "r"                << m_dataSeperator
        << "omega"            << m_dataSeperator
        << "actual mean"      << m_dataSeperator
        << "est mean"         << m_dataSeperator
        << "within alpha"
        << std::endl;
}

void aggragate_experiments::write_experiment_entry(std::string inputFile,
                                                   boost::posix_time::ptime start_time,
                                                   double delta,
                                                   double spread,
                                                   int r,
                                                   double omega,
                                                   double alpha,
                                                   streaming_aggragate_query_time actual,
                                                   streaming_aggragate_query_time sampled)
{
    *m_output << start_time << m_dataSeperator
        << start_time << m_dataSeperator
         << '(' << actual.get_queryBox().min_corner().get<0>() << ',' << actual.get_queryBox().min_corner().get<1>() << ',' << actual.get_queryBox().min_corner().get<2>() << ')' << m_dataSeperator
         << '(' << actual.get_queryBox().max_corner().get<0>() << ',' << actual.get_queryBox().max_corner().get<1>() << ',' << actual.get_queryBox().max_corner().get<2>() << ')' << m_dataSeperator
        << actual.get_min()  << m_dataSeperator
        << actual.get_max()  << m_dataSeperator
        << (actual.get_max() - actual.get_min()) << m_dataSeperator
        << delta             << m_dataSeperator
        << alpha             << m_dataSeperator
        << spread            << m_dataSeperator
        << r                 << m_dataSeperator
        << omega             << m_dataSeperator
        << std::setprecision(10) << actual.get_avg()  << m_dataSeperator
        << std::setprecision(10) << sampled.get_avg() << m_dataSeperator
        << ((std::abs(actual.get_avg() - sampled.get_avg()) < alpha) ? "1" : "0")
        << std::endl;

}


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

  Copyright 2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/function/scalar/bitwise_ornot.hpp>
#include <simd_test.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>
#include <boost/simd/constant/mone.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>
#include <boost/simd/constant/bitincrement.hpp>
#include <boost/simd/constant/valmin.hpp>
#include <boost/simd/constant/valmax.hpp>

STF_CASE_TPL (" bitwise_ornot real",  STF_IEEE_TYPES)
{
  namespace bs = boost::simd;

  using bs::bitwise_ornot;
  using r_t = decltype(bitwise_ornot(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
#ifndef STF_NO_INVALIDS
  STF_IEEE_EQUAL(bitwise_ornot(bs::Inf<T>(), bs::Inf<T>()), bs::Nan<r_t>());
  STF_IEEE_EQUAL(bitwise_ornot(bs::Minf<T>(), bs::Minf<T>()), bs::Nan<r_t>());
  STF_IEEE_EQUAL(bitwise_ornot(bs::Nan<T>(), bs::Nan<T>()), bs::Nan<r_t>());
#endif
  STF_IEEE_EQUAL(bitwise_ornot(bs::Zero<T>(), bs::Zero<T>()), bs::Nan<r_t>());
} // end of test for floating_

STF_CASE_TPL (" bitwise_ornot integer",  STF_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;

  using bs::bitwise_ornot;
  using r_t = decltype(bitwise_ornot(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
  STF_EQUAL(bitwise_ornot(bs::Mone<T>(),bs::Zero<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_ornot(bs::One<T>(), bs::One<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_ornot(bs::One<T>(),bs::Zero<T>()), bs::Mone<r_t>());
  STF_EQUAL(bitwise_ornot(bs::Zero<T>(), bs::Zero<T>()), bs::Mone<r_t>());
} // end of test for integer_

STF_CASE_TPL("bitwise_ornot mix", STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::bitwise_ornot;

  using siT = bd::as_integer_t<T>;
  using uiT = bd::as_integer_t<T, unsigned>;

  // return type conformity test
  STF_EXPR_IS(bitwise_ornot(T(),uiT()), T);
  STF_EXPR_IS(bitwise_ornot(T(),siT()), T);
  STF_EXPR_IS(bitwise_ornot(uiT(), T()), uiT);
  STF_EXPR_IS(bitwise_ornot(siT(), T()), siT);

  // specific values tests
  STF_IEEE_EQUAL(bitwise_ornot(bs::Zero<T>(),bs::Zero<uiT>()), bs::Nan<T>());
  STF_IEEE_EQUAL(bitwise_ornot(bs::Zero<T>(), bs::Zero<siT>()), bs::Nan<T>());
  STF_EQUAL(bitwise_ornot(bs::Valmin<siT>(),bs::Nan<T>()), bs::Valmin<siT>());
  STF_EQUAL(bitwise_ornot(bs::Zero<uiT>(), bs::Nan<T>()), bs::Zero<uiT>());
}


#ifndef NT2_TOOLBOX_MATLAB_FUNCTION_FEVAL_HPP_INCLUDED
#define NT2_TOOLBOX_MATLAB_FUNCTION_FEVAL_HPP_INCLUDED

#include <nt2/toolbox/matlab/details/array.hpp>
#include <nt2/toolbox/matlab/details/mcr.hpp>

#include <nt2/extension/parameters.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>

namespace nt2
{
    namespace matlab
    {
        // not exception-safe, hard to fix in C++03

        #define M1(z, n, text) traits::to_matlab(a##n)

        #define M0(z, n, text)                                                 \
        template<typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename T)>\
        R feval(const char* s BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & a))\
        {                                                                      \
            details::mcr::instance();                                          \
                                                                               \
            mxArray* in[] = { mxCreateString(s) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, M1, ~) };\
            mxArray* out[1];                                                   \
                                                                               \
            mlxFeval(sizeof out / sizeof *out, out, sizeof in / sizeof *in, in);\
                                                                               \
            for(int i=0; i<sizeof in / sizeof *in; ++i)                        \
                mxDestroyArray(in[i]);                                         \
                                                                               \
            R r = traits::from_matlab<R>(out[0]);                              \
                                                                               \
            for(int i=0; i<sizeof out / sizeof *out; ++i)                      \
                mxDestroyArray(out[i]);                                        \
                                                                               \
            return r;                                                          \
        }

        BOOST_PP_REPEAT(NT2_MAX_ARITY, M0, ~)
        #undef M0
        #undef M1
    }
}

#endif


//
// Created by Amir Masoud Abdol on 2019-05-03.
//

#define BOOST_TEST_DYN_LINK

#define BOOST_TEST_MODULE HackingStrategy Tests

#include <boost/test/unit_test.hpp>
namespace tt = boost::test_tools;

#include <armadillo>
#include <iostream>
#include <vector>
#include <algorithm>

#include "sam.h"
#include "Experiment.h"
#include "ExperimentSetup.h"
#include "ResearchStrategy.h"
#include "HackingStrategy.h"

#include "test_fixtures.h"

using namespace arma;
using namespace sam;
using namespace std;

bool FLAGS::VERBOSE = false;
bool FLAGS::PROGRESS = false;
bool FLAGS::DEBUG = false;
bool FLAGS::UPDATECONFIG = false;

BOOST_FIXTURE_TEST_SUITE( optional_stopping, SampleResearch );

//    BOOST_AUTO_TEST_CASE( constructors )
//    {
//        OptionalStopping::Parameters hsp;
//        hsp.name = HackingMethod::OptionalStopping;
//    }

    BOOST_AUTO_TEST_CASE( testing_measurements_size )
    {
    	// Using PatientDecision Maker because he'd satisfy the hacking strategy

        initResearch();

        de_s_conf["preference"] = "PreRegisteredOutcome";
        auto patient_dec_maker = ResearchStrategy::build(de_s_conf);

        auto optional_stopping = OptionalStopping("dv", 3, 1, 1);

        experiment->generateData();
        experiment->calculateStatistics();

        for (int i = 0; i < setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() == setup.nobs()[i]);

        optional_stopping.perform(experiment, patient_dec_maker.get());

        for (int i = 0; i < setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() != setup.nobs()[i]);

    }

    BOOST_AUTO_TEST_CASE ( testing_updated_statistics )
    {

    }

BOOST_AUTO_TEST_SUITE_END();

BOOST_FIXTURE_TEST_SUITE( outliers_removal, SampleResearch );

//    BOOST_AUTO_TEST_CASE( constructors )
//    {
//        HackingStrategyParameters hsp;
//        hsp.name = HackingMethod::OutliersRemoval;
//
//    }

    BOOST_AUTO_TEST_CASE( testing_measurements_size )
    {
        initResearch();

        de_s_conf["preference"] = "PreRegisteredOutcome";
        auto patient_dec_maker = ResearchStrategy::build(de_s_conf);

        auto outliers_removal = OutliersRemoval("dv", "max first", 3, 1, 1, 20, {1});

        experiment->generateData();
        experiment->calculateStatistics();

        for (int i = 0; i < setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() == setup.nobs()[i]);

        // Adding 3 very far values
//        RandomNumberGenerator rng;

        arma::Row<float> outliers(3);
        for (int i = 0; i < setup.ng(); ++i) {

            // adding three new outliers
            outliers.each_col([](arma::Col<float> &v){
                v = Random::get<std::normal_distribution<float>>(2.0, 0.1);
            });

            experiment->measurements[i].insert_cols(experiment->measurements[i].size(), outliers);
        }

        // Performing the hack
        outliers_removal.perform(experiment, patient_dec_maker.get());

        // Expecting them to be removed!
        for (int i = 0; i < setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() == setup.nobs()[i]);
    }

BOOST_AUTO_TEST_SUITE_END();

BOOST_FIXTURE_TEST_SUITE( groups_pooling, SampleResearch );

//    BOOST_AUTO_TEST_CASE( constructors )
//    {
//        HackingStrategyParameters hsp;
//        hsp.name = HackingMethod::GroupPooling;
//
//    }

    BOOST_AUTO_TEST_CASE( testing_measurements_size )
    {
        // Using PatientDecision Maker because he'd satisfy the hacking strategy
        initResearch();

        de_s_conf["preference"] = "PreRegisteredOutcome";
        auto patient_dec_maker = ResearchStrategy::build(de_s_conf);

        auto groups_pooling = GroupPooling({2});

        experiment->generateData();
        experiment->calculateStatistics();

        for (int i = 0; i < setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() == setup.nobs()[i]);

        // Performing the hack
        groups_pooling.perform(experiment, patient_dec_maker.get());

        int n_new_groups = 3;
        BOOST_TEST( experiment->measurements.size() == n_new_groups + setup.ng() );

        for (int i = setup.ng(); i < n_new_groups + setup.ng(); ++i)
            BOOST_TEST( experiment->measurements[i].size() == 2 * nobs);
    }

BOOST_AUTO_TEST_SUITE_END();


//==============================================================================
//         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 <boost/simd/ieee/include/functions/predecessor.hpp>

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

#include <boost/simd/include/constants/mone.hpp>
#include <boost/simd/include/constants/one.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/include/constants/two.hpp>
#include <boost/simd/include/constants/four.hpp>
#include <boost/simd/include/constants/mthree.hpp>
#include <boost/simd/include/constants/minf.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/constants/nan.hpp>
#include <boost/simd/include/constants/valmax.hpp>
#include <boost/simd/include/constants/valmin.hpp>
#include <boost/simd/include/constants/bitincrement.hpp>
#include <boost/simd/include/constants/eps.hpp>
#include <boost/simd/include/constants/halfeps.hpp>

NT2_TEST_CASE_TPL ( predecessor_real_1,  BOOST_SIMD_REAL_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::call<predecessor_(T)>::type r_t;
  typedef T wished_r_t;

  NT2_TEST_TYPE_IS(r_t, wished_r_t);

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(predecessor(boost::simd::Inf<T>()), boost::simd::Valmax<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Minf<T>()), boost::simd::Nan<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Nan<T>()), boost::simd::Nan<r_t>());
#endif
  NT2_TEST_EQUAL(predecessor(boost::simd::Mone<T>()), boost::simd::Mone<r_t>()-boost::simd::Eps<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>()), boost::simd::One<r_t>()-boost::simd::Halfeps<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>()), boost::simd::Minf<r_t>());
#if !defined(BOOST_SIMD_NO_DENORMALS)
  NT2_TEST_EQUAL(predecessor(boost::simd::Zero<T>()), -boost::simd::Bitincrement<T>());
#endif
} // end of test for floating_

NT2_TEST_CASE_TPL ( predecessor_ui_1,  BOOST_SIMD_UNSIGNED_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::call<predecessor_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS(r_t, wished_r_t);

  // specific values tests
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>()), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>()), boost::simd::Valmin<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Zero<T>()), boost::simd::Zero<r_t>());
} // end of test for unsigned_int_

NT2_TEST_CASE_TPL ( predecessor_si_1,  BOOST_SIMD_INTEGRAL_SIGNED_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::call<predecessor_(T)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS(r_t, wished_r_t);

  // specific values tests
  NT2_TEST_EQUAL(predecessor(boost::simd::Mone<T>()), -boost::simd::Two<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>()), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>()), boost::simd::Valmin<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Zero<T>()), boost::simd::Mone<r_t>());
} // end of test for signed_int_

NT2_TEST_CASE_TPL ( predecessor_real_2,  BOOST_SIMD_REAL_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::as_integer<T>::type iT;
  typedef typename boost::dispatch::meta::call<predecessor_(T,iT)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS(r_t, wished_r_t);

#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(predecessor(boost::simd::Minf<T>(), boost::simd::Two<iT>()), boost::simd::Nan<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Nan<T>(), boost::simd::Two<iT>()), boost::simd::Nan<r_t>());
#endif
  NT2_TEST_EQUAL(predecessor(boost::simd::Mone<T>(), boost::simd::Two<iT>()), boost::simd::Mone<r_t>()-boost::simd::Eps<r_t>()-boost::simd::Eps<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>(), boost::simd::Two<iT>()), boost::simd::One<r_t>()-boost::simd::Eps<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Two<iT>()), boost::simd::Nan<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Four<iT>()), boost::simd::Nan<r_t>());
#if !defined(BOOST_SIMD_NO_DENORMALS)
  NT2_TEST_EQUAL(predecessor(boost::simd::Zero<T>(), boost::simd::Two<iT>()), -boost::simd::Bitincrement<r_t>()-boost::simd::Bitincrement<r_t>());
#endif
}

NT2_TEST_CASE_TPL ( predecessor_ui_2,  BOOST_SIMD_UNSIGNED_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::as_integer<T>::type iT;
  typedef typename boost::dispatch::meta::call<predecessor_(T,iT)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS(r_t, wished_r_t);
  NT2_TEST_EQUAL(predecessor(boost::simd::Four<T>(), boost::simd::Two<iT>()), boost::simd::Two<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>(), boost::simd::Two<iT>()), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Two<iT>()), boost::simd::Valmin<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Four<iT>()), boost::simd::Valmin<r_t>());
}

NT2_TEST_CASE_TPL ( predecessor_si_2,  BOOST_SIMD_INTEGRAL_SIGNED_TYPES)
{

  using boost::simd::predecessor;
  using boost::simd::tag::predecessor_;
  typedef typename boost::dispatch::meta::as_integer<T>::type iT;
  typedef typename boost::dispatch::meta::call<predecessor_(T,iT)>::type r_t;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST_TYPE_IS(r_t, wished_r_t);
  NT2_TEST_EQUAL(predecessor(boost::simd::Mone<T>(), boost::simd::Two<iT>()), boost::simd::Mthree<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::One<T>(), boost::simd::Two<iT>()), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Two<iT>()), boost::simd::Valmin<r_t>());
  NT2_TEST_EQUAL(predecessor(boost::simd::Valmin<T>(), boost::simd::Four<iT>()), boost::simd::Valmin<r_t>());
} // end of test for signed_int_


/*
 * perturb_attractor.hpp
 *
 *  Created on: May 1, 2011
 *      Author: stewie
 */

#ifndef PERTURB_ATTRACTOR_HPP_
#define PERTURB_ATTRACTOR_HPP_

#include <cstddef>
#include <utility>
#include <map>

#include <boost/iterator/transform_iterator.hpp>

#include "../util/Counter.hpp"
#include "../core/Attractor.hpp"
#include "cycle_finder.hpp"

namespace bn {

namespace detail {

struct Normalize {
	template<class Sig> struct result;
	template<class K> struct result<Normalize(std::pair<const K, std::size_t>&)> {
		typedef std::pair<K, double> type;
	};
	const std::size_t n;
	Normalize(const std::size_t n) :
		n(n) {
	}
	template<class K> std::pair<K, double> operator()(
			const std::pair<const K, std::size_t>& p) const {
		return std::make_pair(p.first, static_cast<double> (p.second) / n);
	}
};

} // namespace detail

template<class CycleFinder> std::map<Attractor, double> perturb_attractor(
		const Attractor& a, CycleFinder f) {
	util::Counter<Attractor> c;
	for (Attractor::const_iterator it = a.begin(), end = a.end(); it != end; ++it) {
		for (std::size_t i = 0; i < it->size(); ++i) {
			const Attractor x = f(State(*it).flip(i));
			if (x != EMPTY_ATTRACTOR) {
				c.insert(x);
			}
		}
	}
	const detail::Normalize func(c.insertions());
	return std::map<Attractor, double>(
			boost::make_transform_iterator(c.begin(), func),
			boost::make_transform_iterator(c.end(), func));
}

} // namespace bn

#endif /* PERTURB_ATTRACTOR_HPP_ */


//
// we only list the latest check up for the codes
//
// full test is made after we revise code in
// github commit a2d3c0d61d94f9d8c0f7eaeaf112d6658415bcf5
//
// we checked the gradient for NAI, two body overlap, KI
// and normal ERI for maxL = 4
//
// all of calculation are passed. the result is in gradient_double.log
//
// we checked the second derivatives for NAI, two body overlap, KI
// and normal ERI for maxL = 3
//
// all of calculation are passed. the result is in hessian_double.log
//

#include "libgen.h"
#include "ov.h"
#include "ki.h"
#include "nai.h"
#include "eritest.h"
#include <boost/algorithm/string.hpp>   // string handling
#include <boost/lexical_cast.hpp>
using namespace ov;
using namespace ki;
using namespace nai;
using namespace eritest;

Int main(int argc, char* argv[])
{
	/////////////////////////////////////////////////////////////////////////////
	// setting the testing jobs
	// we note that the maxL must be in accordance with the hgp codes
	// so as the auxMaxL, order etc.
	/////////////////////////////////////////////////////////////////////////////
	bool testOV  = false;
	bool testKI  = false;
	bool testNAI = false;
	bool testERI = false;
	bool test2BodyERI = false;
	bool test3BodyERI = false;

	// settings you may need to change here
	// here is default value
	Int order   = 1;
#ifdef ORDER2
	order       = 2;
#endif
	Int maxL    = 4;
	if (order == 2) maxL = 3;
	Int auxMaxL = 5;
	Int momL    = 5;

	// parse the input parameter
	for(Int i=1; i<argc; i++) {
		string com = argv[i];
		boost::algorithm::to_lower(com);
		if (com == "ov"   ) testOV  = true;
		if (com == "ki"   ) testKI  = true;
		if (com == "nai"  ) testNAI = true;
		if (com == "eri"  ) testERI = true;
		if (com == "2eri" ) test2BodyERI = true;
		if (com == "3eri" ) test3BodyERI = true;
	}

	// now print out the input information
	cout << "********job testing list********" << endl;
	if (order == 0) cout << "integral testing for energy calculation" << endl;
	if (order == 1) cout << "integral testing for gradient calculation" << endl;
	if (order == 2) cout << "integral testing for Hessian calculation" << endl;
	cout << "maximum angular momentum for integrals is " << maxL << endl;
	cout << "maximum aux angular momentum for integrals is " << auxMaxL << endl;
	cout << "maximum angular momentum for MOM integrals is " << momL << endl;
	if (testOV) cout <<  "two body overlap" << endl;
	if (testKI) cout  << "two body kinetic" << endl;
	if (testNAI) cout << "two body nuclear attraction" << endl;
	if (testERI) cout << "normal ERI" << endl;
	if (test2BodyERI) cout << "two body ERI" << endl;
	if (test3BodyERI) cout << "three body ERI" << endl;
	cout << "********************************" << endl;

	/////////////////////////////////////////////////////////////////////////////
	// now setting the shell data
	// all of shell data are in default to be composite shell
	// which contains two sub-shells
	/////////////////////////////////////////////////////////////////////////////

	// shell 1
	Int inp = 1;
	vector<Double> iexp(inp);
	vector<Double> icoe(2*inp);
	iexp[0] = 0.1442493;
	icoe[0] = 1.0;
	icoe[1] = 1.0;
	Double A[3];
	A[0]    = 1.0;
	A[1]    = 0.0;
	A[2]    = 0.0;

	// shell 2
	Int jnp = 1;
	vector<Double> jexp(jnp);
	vector<Double> jcoe(2*jnp);
	jexp[0] = 0.0914760;
	jcoe[0] = 1.0;
	jcoe[1] = 1.0;
	Double B[3];
	B[0]    = 0.0;
	B[1]    = 1.0;
	B[2]    = 0.0;

	// shell 3
	Int knp = 1;
	vector<Double> kexp(knp);
	vector<Double> kcoe(2*knp);
	kexp[0] = 0.04808870;
	kcoe[0] = 1.0;
	kcoe[1] = 1.0;
	Double C[3];
	C[0]    = 0.0;
	C[1]    = 0.0;
	C[2]    = 1.0;

	// shell 4
	Int lnp = 1;
	vector<Double> lexp(lnp);
	vector<Double> lcoe(2*lnp);
	lexp[0] = 0.23695610;
	lcoe[0] = 1.0;
	lcoe[1] = 1.0;
	Double D[3];
	D[0]    = 0.0;
	D[1]    = 1.0;
	D[2]    = 1.0;

	// create the dummy shell
	// the most important thing for the
	// shell is that its exp is all zero
	Int dnp = 1;
	vector<Double> dexp(dnp,ZERO);
	vector<Double> dcoe(dnp,ONE);
	Double dummy[3];
	dummy[0] = 0.0;
	dummy[1] = 0.0;
	dummy[2] = 0.0;

	// nuclear centers as well as atomic numbers
	Int nAtoms = 3;
	vector<Double> coord(3*nAtoms);
	vector<Int> atomicNumbers(nAtoms);
	coord[0] = 0.0;
	coord[1] = 0.0;
	coord[2] = 1.0;
	coord[3] = 0.0;
	coord[4] = 1.0;
	coord[5] = 0.0;
	coord[6] = 1.0;
	coord[7] = 0.0;
	coord[8] = 0.0;
	atomicNumbers[0] = 1;
	atomicNumbers[1] = 2;
	atomicNumbers[2] = 3;

	/////////////////////////////////////////////////////////////////////////////
	//                  now this is the real working section
	/////////////////////////////////////////////////////////////////////////////
	if (testOV) {
		string derivFile = "deriv_infor_twobodyoverlap_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_twobodyoverlap_2.txt";
		}
		ov_test(derivFile,maxL,order,inp,icoe,iexp,A,jnp,jcoe,jexp,B);
	}
	if (testKI) {
		string derivFile = "deriv_infor_kinetic_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_kinetic_2.txt";
		}
		ki_test(derivFile,maxL,order,inp,icoe,iexp,A,jnp,jcoe,jexp,B);
	}
	if (testNAI) {
		string derivFile = "deriv_infor_nai_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_nai_2.txt";
		}
		nai_test(derivFile,maxL,order,inp,icoe,iexp,A,jnp,jcoe,jexp,B,coord,atomicNumbers);
	}
	if (testERI) {
		string derivFile = "deriv_infor_eri_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_eri_2.txt";
		}
		eri_test(derivFile,maxL,auxMaxL,order,NORMAL_ERI,
				inp,icoe,iexp,A,
				jnp,jcoe,jexp,B,
				knp,kcoe,kexp,C,
				lnp,lcoe,lexp,D);
	}
	if (test2BodyERI) {
		string derivFile = "deriv_infor_eri_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_eri_2.txt";
		}
		eri_test(derivFile,maxL,auxMaxL,order,TWO_BODY_ERI,
				inp,icoe,iexp,A,
				dnp,dcoe,dexp,dummy,
				knp,kcoe,kexp,C,
				dnp,dcoe,dexp,dummy);
	}
	if (test3BodyERI) {
		string derivFile = "deriv_infor_eri_1.txt";
		if (order == 2) {
			derivFile = "deriv_infor_eri_2.txt";
		}
		eri_test(derivFile,maxL,auxMaxL,order,THREE_BODY_ERI,
				inp,icoe,iexp,A,
				jnp,jcoe,jexp,B,
				knp,kcoe,kexp,C,
				dnp,dcoe,dexp,dummy);
	}

	cout << "all of jobs are finished " << endl;
	return 0;

}


/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, PAL Robotics, S.L.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the PAL Robotics nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/*
 * Author: Luca Marchionni
 * Author: Bence Magyar
 * Author: Enrique Fernández
 * Author: Paul Mathieu
 */

#include "odometry.h"

#include <tf/transform_datatypes.h>

#include <boost/bind.hpp>

namespace mecanum_drive_controller
{

namespace bacc = boost::accumulators;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Odometry::Odometry(size_t velocity_rolling_window_size)
: timestamp_(0.0)
, x_(0.0)
, y_(0.0)
, heading_(0.0)
, linearX_(0.0)
, linearY_(0.0)
, angular_(0.0)
, wheels_k_(0.0)
, wheels_radius_(0.0)
, velocity_rolling_window_size_(velocity_rolling_window_size)
, linearX_acc_(RollingWindow::window_size = velocity_rolling_window_size)
, linearY_acc_(RollingWindow::window_size = velocity_rolling_window_size)
, angular_acc_(RollingWindow::window_size = velocity_rolling_window_size)
, integrate_fun_(boost::bind(&Odometry::integrateExact, this, _1, _2, _3))
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Odometry::init(const ros::Time& time)
{
  // Reset accumulators:
  linearX_acc_ = RollingMeanAcc(RollingWindow::window_size = velocity_rolling_window_size_);
  linearY_acc_ = RollingMeanAcc(RollingWindow::window_size = velocity_rolling_window_size_);
  angular_acc_ = RollingMeanAcc(RollingWindow::window_size = velocity_rolling_window_size_);

  // Reset timestamp:
  timestamp_ = time;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Odometry::update(double wheel0_vel, double wheel1_vel, double wheel2_vel, double wheel3_vel, const ros::Time &time)
{
  /// We cannot estimate the speed with very small time intervals:
  const double dt = (time - timestamp_).toSec();
  if (dt < 0.0001)
    return false; // Interval too small to integrate with

  timestamp_ = time;

  /// Compute forward kinematics (i.e. compute mobile robot's body twist out of its wheels velocities):
  /// NOTE: we use the IK of the mecanum wheels which we invert using a pseudo-inverse.
  /// NOTE: in the diff drive the velocity is filtered out, but we prefer to return it raw and let the user perform
  ///       post-processing at will. We prefer this way of doing as filtering introduces delay (which makes it
  ///       difficult to interpret and compare behavior curves).
  linearX_ = 0.25 * wheels_radius_              * ( wheel0_vel + wheel1_vel + wheel2_vel + wheel3_vel);
  linearY_ = 0.25 * wheels_radius_              * (-wheel0_vel + wheel1_vel - wheel2_vel + wheel3_vel);
  angular_ = 0.25 * wheels_radius_  / wheels_k_ * (-wheel0_vel - wheel1_vel + wheel2_vel + wheel3_vel);

  /// Integrate odometry.
  integrate_fun_(linearX_ * dt, linearY_ * dt, angular_ * dt);

  return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Odometry::updateOpenLoop(double linearX, double linearY, double angular, const ros::Time &time)
{
  /// Save last linear and angular velocity:
  linearX_ = linearX;
  linearY_ = linearY;
  angular_ = angular;

  /// Integrate odometry:
  const double dt = (time - timestamp_).toSec();
  timestamp_ = time;
  integrate_fun_(linearX * dt, linearY * dt, angular * dt);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Odometry::setWheelsParams(double wheels_k, double wheels_radius)
{
  wheels_k_ = wheels_k;
  wheels_radius_ = wheels_radius;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Odometry::integrateExact(double linearX, double linearY, double angular)
{
  /// Integrate angular velocity.
  heading_ += angular;

  /// The odometry pose should be published in the /odom frame (unlike the odometry twist which is a body twist).
  /// Project the twist in the odometry basis (we cannot integrate linearX, linearY, angular 'as are' because they correspond to a body twist).
  tf::Matrix3x3 R_m_odom = tf::Matrix3x3(tf::createQuaternionFromYaw(heading_));
  tf::Vector3 vel_inOdom = R_m_odom * tf::Vector3(linearX, linearY, 0.0);

  /// Integrate linear velocity.
  x_ += vel_inOdom.x();
  y_ += vel_inOdom.y();
}

} // namespace mecanum_drive_controller


#include <boost/simd/memory/aligned_output_iterator.hpp>
#include <boost/simd/memory/allocator.hpp>
#include <boost/simd/include/functions/enumerate.hpp>

#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>

boost::simd::pack<float,4> splatted_iota()
{
  static int seed = 0;
  return seed++;
}

int main()
{
  using boost::simd::pack;
  using boost::simd::allocator;
  using boost::simd::aligned_output_end;
  using boost::simd::aligned_output_begin;
  using boost::simd::aligned_output_iterator;

  std::vector<float, allocator<float> > data(16);
  typedef std::vector<float, allocator<float> >::iterator it_t;

  aligned_output_iterator<it_t,4> vb = aligned_output_begin<4>(data.begin());
  aligned_output_iterator<it_t,4> ve = aligned_output_end<4>(data.end());

  std::generate(vb, ve, splatted_iota);

  std::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " "));
  std::cout << std::endl;
}


/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "phml.h"

#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include "database.h"

#define BOOST_TEST_MODULE test_nc
#include "test.h"

struct F : public test::MemoryFixture {

	void Phml(const char *file) {
		SaveGivenFile(driver_.db(), file);
		BOOST_REQUIRE(phml::Read(driver_.db(), boost::filesystem::current_path()));
	}

	void GenerateAndCheck(const char *output, const char *expected)
	{
		BOOST_REQUIRE(phml::Nc(driver_.db(), output));
		BOOST_REQUIRE(boost::filesystem::is_regular_file(output));
		boost::filesystem::remove(output);

		test::Sql sql(driver_.db());
		std::vector<std::string> rows;
		rows.push_back(expected);
		sql.CheckRows("SELECT method FROM config", rows);
	}
};

BOOST_FIXTURE_TEST_SUITE(test_nc, F)

BOOST_AUTO_TEST_CASE(bogus_td) {
	Phml(TEST_MODELS("bogus-td.phml"));
	GenerateAndCheck("bogus-td.phml.nc",
					 "rk4");
}

BOOST_AUTO_TEST_CASE(Izhikevich_2003_model) {
	Phml(TEST_MODELS("Izhikevich_2003_model.isml"));
	GenerateAndCheck("Izhikevich_2003_model.isml.nc",
					 "rk4");
}

BOOST_AUTO_TEST_CASE(LR1_ring_reentry_initiate) {
	Phml(TEST_MODELS("LR1-ring_reentry_initiate.isml"));
	GenerateAndCheck("LR1-ring_reentry_initiate.isml.nc",
					 "4th-rungekutta");
}

BOOST_AUTO_TEST_CASE(Rybak_2006_with_static_instance_and_multiple_input) {
	Phml(TEST_MODELS("Rybak_2006_with_static_instance_and_multiple_input.isml"));
	GenerateAndCheck("Rybak_2006_with_static_instance_and_multiple_input.isml.nc",
					 "euler");
}

BOOST_AUTO_TEST_SUITE_END()


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IF_ADD_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IF_ADD_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-boolean
    Function object implementing if_add capabilities

    The function returns the second entry or the sum of the second
    and third entries, according to the first entry being @ref False or
    @ref True

    This is a convenient alias of @ref seladd
  **/
  const boost::dispatch::functor<tag::if_add_> if_add = {};
} }
#endif

#include <boost/simd/function/scalar/seladd.hpp>
#include <boost/simd/function/simd/if_add.hpp>

#endif


//#include <complex.h>
//#include <stdlib.h>

//#include <boost/python/numpy.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>

namespace p = boost::python;
//namespace np = boost::python::numpy;

int mandelbrot(int x){
    return x;
}

//np::ndarray mandelbrot(int ppoints, int qpoints) {
//    double pmin, pmax, qmin, qmax;
//    pmin = -2.5; pmax = 1.5; qmin = -2; qmax = 2;
//    int max_iterations = 400;
//    double infinity_border = 100;
//    double p, q;
//    p = pmin;
//    q = qmin;
//    double step_p = (pmax - pmin)/(ppoints-1);
//    double step_q = (qmax - qmin)/(qpoints-1);
//    double complex z;
//    double complex c;
//
//
//    p::tuple shape = p::make_tuple(ppoints, qpoints);
//    np::dtype dtype = np::dtype::get_builtin<int>();
//    np::ndarray image = np::zeros(shape, dtype);
//
//    for (int i =0; i < ppoints; ++i){
//        for (int j = 0; j < qpoints; ++j){
//            c = p + I*q;
//
//            z = 0;
//            q += step_q;
//            for (int k = 0; k< max_iterations; ++k){
//                z = z*z + c;
//                if (cabs(z) > infinity_border){
//                    image[i][j] = 1;
//                    break;
//                }
//            }
//        }
//        p += step_p;
//        q = qmin;
//    }
//
//    return image;
//};

BOOST_PYTHON_MODULE(boost_mandelbrot_ext)
{
    p::def("mandelbrot", &mandelbrot);
}