#define BOOST_TEST_MODULE
#include <boost/test/unit_test.hpp>
#include <core/util/test_macros.hpp>
#include <string>
#include <iostream>
#include <set>
#include <unordered_map>
#include <core/data/flexible_type/flexible_type.hpp>
#include <ml/sketches/space_saving_flextype.hpp>
#include <core/random/random.hpp>
#include <core/util/cityhash_tc.hpp>
#include <core/parallel/lambda_omp.hpp>
#include <core/logging/logger.hpp>

using namespace turi;
using namespace turi::sketches;

struct space_saving_test {
  template <typename SketchType>
  double random_integer_length_test(size_t len,
                                    size_t random_range,
                                    double epsilon) {
    SketchType ss(epsilon);

    std::vector<size_t> v(len);
    std::map<size_t, size_t> true_counter;
    for (size_t i = 0;i < len; ++i) {
      v[i] = turi::random::fast_uniform<size_t>(0, random_range - 1);
      ++true_counter[v[i]];
    }
    turi::timer ti;
    for (size_t i = 0;i < len; ++i) {
      if(v[i] % 2 == 0) {
        ss.add(v[i]);
      } else {
        ss.add(double(v[i]));  // So the types get a bit mixed up
      }
    }
    double rt = ti.current_time();
    std::vector<size_t> frequent_items;
    for(auto x : true_counter) {
      if (x.second >= epsilon * len) {
        frequent_items.push_back(x.first);
      }
    }
    // check that we did indeed find all the items with count >= epsilon * N
    auto ret = ss.frequent_items();
    std::sort(ret.begin(), ret.end());
    std::set<turi::flexible_type> ss_returned_values;
    for(auto x : ret) {
      ss_returned_values.insert(x.first);
    }

    for(auto x: frequent_items) {
      TS_ASSERT(ss_returned_values.count(x) != 0);
    }
    return rt;
  }

  template <typename SketchType>
  double parallel_combine_test(size_t len,
                               size_t random_range,
                               double epsilon) {
    std::vector<SketchType> ssarr(16, SketchType(epsilon));

    std::vector<size_t> v(len);
    std::unordered_map<size_t, size_t> true_counter;
    for (size_t i = 0;i < len; ++i) {
      v[i] = turi::random::fast_uniform<size_t>(0, random_range - 1);
      ++true_counter[v[i]];
    }
    turi::timer ti;
    for (size_t i = 0;i < len; ++i) {
      ssarr[i % ssarr.size()].add(v[i]);
    }
    // merge
    SketchType ss;
    for (size_t i = 0;i < ssarr.size(); ++i) {
      ss.combine(ssarr[i]);
    }
    double rt = ti.current_time();
    // check that we did indeed find all the items with count >= epsilon * N
    std::vector<size_t> frequent_items;
    for(auto x : true_counter) {
      if (x.second >= epsilon * len) {
        frequent_items.push_back(x.first);
      }
    }
    auto ret = ss.frequent_items();
    std::set<turi::flexible_type> ss_returned_values;
    for(auto x : ret) {
      ss_returned_values.insert(x.first);
    }
    for(auto x: frequent_items) {
      TS_ASSERT(ss_returned_values.count(x) != 0);
    }
    return rt;
  }
 public:
  void test_perf() {
    turi::sketches::space_saving_flextype ss(0.0001);
    turi::timer ti;
    for (size_t i = 0;i < 10*1024*1024; ++i) {
      ss.add(i);
    }
    std::cout << "\n Time: " << ti.current_time() << "\n";
  }

  void test_stuff() {
    turi::random::seed(1001);
    std::vector<size_t> lens{1024, 65536, 256*1024};
    std::vector<size_t> ranges{128, 1024, 65536, 256*1024};
    std::vector<double> epsilon{0.1,0.01,0.005};
    global_logger().set_log_level(LOG_INFO);

    size_t n_idx = lens.size() * ranges.size() * epsilon.size();

    in_parallel([&](size_t thread_idx, size_t n_threads) {
        for(size_t run_idx = thread_idx; run_idx < n_idx; run_idx += n_threads) {

          auto len   = lens[ run_idx / (epsilon.size() * ranges.size()) ];
          auto range = ranges[ (run_idx / epsilon.size()) % ranges.size()];
          auto eps   = epsilon[run_idx % epsilon.size()];

          auto result1 = random_integer_length_test<space_saving<flex_int> >(len, range, eps);
          logstream(LOG_INFO) << "integer:   Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result1
                    << std::endl;

          auto result2 = random_integer_length_test<space_saving<flexible_type> >(len, range, eps);

          logstream(LOG_INFO) << "flex type: Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result2
                    << std::endl;

          auto result3 = random_integer_length_test<space_saving_flextype>(len, range, eps);

          logstream(LOG_INFO) << "_flextype: Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result3
                    << std::endl;
        }
      });

    std::cout << "\n\nReset random seed and repeating with \'parallel\' test\n";
    turi::random::seed(1001);

    in_parallel([&](size_t thread_idx, size_t n_threads) {
        for(size_t run_idx = thread_idx; run_idx < n_idx; run_idx += n_threads) {

          auto len   = lens[ run_idx / (epsilon.size() * ranges.size()) ];
          auto range = ranges[ (run_idx / epsilon.size()) % ranges.size()];
          auto eps   = epsilon[run_idx % epsilon.size()];

          auto result1 = parallel_combine_test<space_saving<flex_int> >(len, range, eps);
          logstream(LOG_INFO) << "integer:   Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result1
                    << std::endl;

          auto result2 = parallel_combine_test<space_saving<flexible_type> >(len, range, eps);
          logstream(LOG_INFO) << "flex type: Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result2
                    << std::endl;

          auto result3 = parallel_combine_test<space_saving_flextype>(len, range, eps);
          logstream(LOG_INFO) << "_flextype: Array length: " << len << "\t"
                    << "Numeric Range: " << range << "\t"
                    << "Epsilon:   " << eps << "  \t"
                    << result3
                    << std::endl;
        }
      });

  }

};

BOOST_FIXTURE_TEST_SUITE(_space_saving_test, space_saving_test)
BOOST_AUTO_TEST_CASE(test_perf) {
  space_saving_test::test_perf();
}
BOOST_AUTO_TEST_CASE(test_stuff) {
  space_saving_test::test_stuff();
}
BOOST_AUTO_TEST_SUITE_END()


static bool eigen_did_assert = false;
#define eigen_assert(X) if(!eigen_did_assert && !(X)){ std::cout << "### Assertion raised in " << __FILE__ << ":" << __LINE__ << ":\n" #X << "\n### The following would happen without assertions:\n"; eigen_did_assert = true;}

#include <iostream>
#include <Eigen/Eigen>

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

using namespace Eigen;
using namespace std;

int main(int, char**)
{
  cout.precision(3);
  MatrixXf M1 = MatrixXf::Random(3,8);
cout << "Column major input:" << endl << M1 << "\n";
Map<MatrixXf,0,OuterStride<> > M2(M1.data(), M1.rows(), (M1.cols()+2)/3, OuterStride<>(M1.outerStride()*3));
cout << "1 column over 3:" << endl << M2 << "\n";

typedef Matrix<float,Dynamic,Dynamic,RowMajor> RowMajorMatrixXf;
RowMajorMatrixXf M3(M1);
cout << "Row major input:" << endl << M3 << "\n";
Map<RowMajorMatrixXf,0,Stride<Dynamic,3> > M4(M3.data(), M3.rows(), (M3.cols()+2)/3,
                                              Stride<Dynamic,3>(M3.outerStride(),3));
cout << "1 column over 3:" << endl << M4 << "\n";
  return 0;
}


#include <stdexcept>
#include <iostream>
#include <cmath>
#include <limits>
#include <fstream>
#include <string>
#include <boost/filesystem.hpp>
#include <UnitTest++/UnitTest++.h>

#include "../emccd_model.h"

using namespace coela;
using namespace std;

SUITE(CCD_model)
{
    using namespace emccd_detail;

    string test_suite_output_dir= string(UnitTestSuite::GetSuiteName()) + "_tests/";

    TEST(Run_Standard_Suite_Setup) {
        cout << "*** \""<< UnitTestSuite::GetSuiteName() <<"\" unit tests running ***" <<endl;
        boost::filesystem::create_directories(test_suite_output_dir);
    }

    TEST(integer_factorial) {
        CHECK_EQUAL(1ul, integer_factorial(0));
        CHECK_EQUAL(1ul, integer_factorial(1));
        CHECK_EQUAL(2ul, integer_factorial(2));
        CHECK_EQUAL(6ul, integer_factorial(3));
        CHECK_EQUAL(24ul, integer_factorial(4));

//        cout<<"Unsigned long max: " << numeric_limits<unsigned long>::max() <<endl;
//
//        double max_int_fac =1;
//        while (approx_factorial_double(max_int_fac) < numeric_limits<unsigned long>::max())
//            max_int_fac++;
//
//        cout<<"Implies max input for integer_factorial:"<<max_int_fac<<endl;

    }

    TEST(EMCCD_pars_write_to_file) {
        EmccdModelParams pars;

        pars.bias_pedestal=1.1;
        pars.readout_sigma=2.1;
        pars.photon_gain=3.1;
        pars.serial_CIC_rate=4.1;
        pars.N_EM_serial_register_stages=604;

        pars.write_to_file(test_suite_output_dir+"sample_EMCCD_model_pars.xml");
        EmccdModelParams loaded(test_suite_output_dir+"sample_EMCCD_model_pars.xml");
        CHECK_EQUAL(pars.photon_gain, loaded.photon_gain);
    }

    TEST(EMCCD_gain_PMF) {
        double gain = 100;

        CHECK_CLOSE(exp(-1/gain)/gain , low_flux_gain_pmf(1, gain, 1) , 1e-6);

        for (int n_photons = 1; n_photons<=10; ++n_photons) {
            double sum_probability=0;
            for (int x_out=n_photons; x_out<10000; ++x_out) {
                double PMF_val = low_flux_gain_pmf(n_photons, gain, x_out);
                CHECK(PMF_val>0);
                CHECK(PMF_val<1);
                sum_probability+=PMF_val;
            }
            //Any more stringent tests (than 1 percent) fail due to numerical roundoff in sum.
            CHECK_CLOSE(1.0, sum_probability,
                        0.01);
        }

    }

//
//    TEST(Write_gain_PMFs_to_file_for_inspection){
//        double gain =100;
//        for (int n_photons = 1; n_photons<=10; ++n_photons){
//            ofstream datfile(string(test_suite_output_dir+"EMCCD_gain_PMF_for_"+string_utils::itoa(n_photons)+"_photons.txt").c_str());
//            for (int x_out=n_photons; x_out<10000; ++x_out){
//                double PMF_val = EMCCD_gain_PMF_at_value(n_photons, gain, x_out);
//                datfile<<x_out<<" "<<PMF_val<<"\n";
//            }
//            datfile.close();
//        }
//    }

    int hist_max = 10000;
    void count_result(vector<unsigned int>& hist, int result){
        if (fixed < 0) {
            throw logic_error(
                "emccd gain variate should not produce negative values");
        }
        if (result < hist_max) {
            ++hist[result];
        }
    }

    TEST(gain_variates) {
        vector<unsigned long> seed;
        seed.push_back(11);
        seed.push_back(25);
        seed.push_back(35);
        seed.push_back(44);
        seed.push_back(55);
        seed.push_back(66);
        unuran::StreamWrapper::set_unuran_package_seed(seed,
                false);

        unuran::StreamWrapper rns1;
        double gain=100.0;

        size_t n_its_per_hist = 1e6;

        GainVariate var_gen(gain, rns1);

        //Test for low flux:
        for (int n_photons=1;
                n_photons!=FixedLowFluxGainVariate::n_photons_limit_for_low_flux; ++n_photons) {
            vector<unsigned int> fixed_results(hist_max, 0);
            vector<unsigned int> var_results(hist_max, 0);

            FixedLowFluxGainVariate fixed_gen(n_photons, gain, rns1);

////            check default constructor followed by assignment:
//            EMCCD_fixed_low_flux_gain_variate gen;
//            gen = EMCCD_fixed_low_flux_gain_variate(n_photons, gain, rns1);

            for (size_t i=0; i!=n_its_per_hist; ++i) {
                count_result(fixed_results, fixed_gen());
                count_result(var_results, var_gen(n_photons));
            }

            if (n_photons==0) {
                CHECK_EQUAL(n_its_per_hist, fixed_results[0]);
                CHECK_EQUAL(n_its_per_hist, var_results[0]);
            }

            for (int ind=0; ind<100; ++ind) {
                double predicted_num = n_its_per_hist *
                                        low_flux_gain_pmf(n_photons, gain, ind);

                CHECK_CLOSE(predicted_num, (double)fixed_results[ind] ,
                        max(5*sqrt(predicted_num), 5.0));
                CHECK_CLOSE(predicted_num, (double)var_results[ind] ,
                                        max(5*sqrt(predicted_num), 5.0));
            }

        }

        //Test for high flux:

        n_its_per_hist = 1e5;
        int n_photons =55; //test high flux
        {
            vector<unsigned int> high_flux_results(hist_max, 0);
            for (size_t i=0; i!=n_its_per_hist; ++i) {
                count_result(high_flux_results, var_gen(n_photons));
            }

//            actual_hist.write_to_file(
//                    test_suite_output_dir+"EMCCD_gain_var_"+
//                        to_string(n_photons)+"_actual_hist.txt");
        }
    }

}//end of test suite


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
Copyright (C) 2007 Ferdinando Ametrano
Copyright (C) 2007 Marco Bianchetti
Copyright (C) 2007 Cristina Duminuco
Copyright (C) 2007 Mark Joshi
Copyright (C) 2015 CompatibL

This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/

QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

// Based on marketmodel_smmcapletalphacalibration.cpp from test-suite

// Algorithm of calibration can be found here:
// http://fbe.unimelb.edu.au/__data/assets/pdf_file/0019/806302/172.pdf

#ifndef cl_adjoint_market_model_calibration_impl_hpp
#define cl_adjoint_market_model_calibration_impl_hpp
#pragma once

#include "adjointmarketmodelcalibrationtest.hpp"
#include "utilities.hpp"
#include "adjointtestutilities.hpp"
#include "adjointtestbase.hpp"
#include <ql/models/marketmodels/products/multiproductcomposite.hpp>
#include <ql/quantlib.hpp>
#include <boost/make_shared.hpp>
#include <iostream>

using namespace QuantLib;
using namespace std;
using namespace boost::unit_test_framework;

#define OUTPUT_FOLDER_NAME "AdjointMarketModelCalibration"

namespace
{
    enum
    {
#if defined CL_GRAPH_GEN
        // Number of points for dependency plots.
        pointNo = 10,
        // Start size.
        startSize = 4,
        // Number of points for performance plot.
        iterNo = 14,
        // Step for portfolio size for performance testing .
        step = 1,
        // Defines performance accuracy. Its value is a minimum number
        // of calling of O(1) complexity methods per one performance test.
        iterNumFactor = 1000,
#else
        // Number of points for dependency plots.
        pointNo = 1,
        // Start size.
        startSize = 12,
        // Number of points for performance plot.
        iterNo = 1,
        // Step for portfolio size for performance testing .
        step = 1,
        // Defines performance accuracy. Its value is a minimum number
        // of calling of O(1) complexity methods per one performance test.
        iterNumFactor = 1,
#endif
    };

    struct RealPair
    {
        static std::deque<std::string> get_columns()
        {
            static std::deque<std::string> columns = { " ", "" };
            return columns;
        }

        template <typename stream_type>
        friend inline stream_type& operator << (stream_type& stm, RealPair& p)
        {
            stm << p.x_ << ";" << p.y_ << std::endl;
            return stm;
        }

        Real x_, y_;

    };

    struct CommonVars
    {
        explicit CommonVars(Size size):
          size_(size)
        , displacement_(0.0)
        , rateTimes_(initRateTimes())
        , evolution_(EvolutionDescription(rateTimes_))
        , cs_(createCS())
        , corr_(calcCorrelation())
        , swapVariances_(initSwapVariance())
        , alphaInitial_(size, 0.0)
        , alphaMax_(size, 1.0)
        , alphaMin_(size, -1.0)
        {
        }

        std::vector<Real> initRateTimes()
        {
            Date todaysDate = Date(3, June, 2015);
            Date endDate = todaysDate + (size_ + 1) * Weeks;

            Schedule dates(
                todaysDate,
                endDate,
                Period(Weekly),
                NullCalendar(),
                Following,
                Following,
                DateGeneration::Backward,
                false);

            std::vector<Real> rateTimes(dates.size() - 1);
            DayCounter dayCounter = SimpleDayCounter();
            for (size_t i = 1; i < dates.size(); ++i)
                rateTimes[i - 1] = dayCounter.yearFraction(todaysDate, dates[i]);
            return rateTimes;
        }

        boost::shared_ptr<LMMCurveState> createCS()
        {
            std::vector<Rate> todaysForwards(rateTimes_.size() - 1);
            for (Size i = 0; i < todaysForwards.size(); ++i)
            {
                todaysForwards[i] = 0.03 + 0.0025 * i / size_;
            }
            boost::shared_ptr<LMMCurveState> cs = boost::make_shared<LMMCurveState>(rateTimes_);
            cs->setOnForwardRates(todaysForwards);
            return cs;
        }

        boost::shared_ptr<PiecewiseConstantCorrelation> calcCorrelation()
        {
            Real longTermCorrelation = 0.5;
            Real beta = 0.2;

            boost::shared_ptr<PiecewiseConstantCorrelation> fwdCorr =
                boost::make_shared<ExponentialForwardCorrelation>(
                rateTimes_, longTermCorrelation, beta);

            return boost::make_shared<CotSwapFromFwdCorrelation>(fwdCorr, *cs_, displacement_);
        }

        std::vector<boost::shared_ptr<PiecewiseConstantVariance>> initSwapVariance()
        {
            Real a_ = 0.0, b_ = 0.17, c_ = 1.0, d_ = 0.10;
            std::vector<boost::shared_ptr<PiecewiseConstantVariance>> swapVariances(size_);
            for (Size i = 0; i < size_; ++i)
            {
                swapVariances[i] = boost::make_shared< PiecewiseConstantAbcdVariance>(a_, b_, c_, d_, i, rateTimes_);
            }
            return swapVariances;
        }

        std::vector<Volatility> generateCapletVolatilities()
        {
            std::vector<Real> volsDelta(13, 0.01);
            volsDelta.resize(19);
            volsDelta[13] = 0.0090;
            volsDelta[14] = 0.0057;
            volsDelta[15] = 0.0045;
            volsDelta[16] = 0.0044;
            volsDelta[17] = 0.0015;
            volsDelta[18] = 0.0004;

            std::vector<Volatility> capletVols(size_);
            capletVols[size_ - 1] = swapVariances_[size_ - 1]->totalVolatility(size_ - 1);
            Real delta = (size_ <= 18) ? volsDelta[size_] : 0;
            for (int i = size_ - 2; i >= 0; --i)
            {
                if (i >= size_ / 3)
                    capletVols[i] = capletVols[i + 1] + delta;
                else
                    capletVols[i] = capletVols[i + 1] - delta;
            }
            return capletVols;
        }

        std::vector<Real> calibrationVolatilitiesAndErrors(const std::vector<Volatility>& capletVols)
        {
            // Create calibrator
            CTSMMCapletAlphaFormCalibration calibrator(evolution_,
                                                       corr_,
                                                       swapVariances_,
                                                       capletVols,
                                                       cs_,
                                                       displacement_,
                                                       alphaInitial_,
                                                       alphaMax_,
                                                       alphaMin_,
                                                       false);

            // Calibrate
            Natural numberOfFactors = 3;
            Natural maxIterations = 10;
            Real capletTolerance = 1e-4;
            Natural innerMaxIterations = 100;
            Real innerTolerance = 1e-8;

            bool result = calibrator.calibrate(numberOfFactors,
                                               maxIterations,
                                               capletTolerance,
                                               innerMaxIterations,
                                               innerTolerance);
            if (!result)
                BOOST_ERROR("Calibration failed");

            const std::vector<Matrix>& swapPseudoRoots = calibrator.swapPseudoRoots();
            boost::shared_ptr<MarketModel> smm = boost::make_shared<PseudoRootFacade>(
                swapPseudoRoots,
                rateTimes_,
                cs_->coterminalSwapRates(),
                std::vector<Spread>(size_, displacement_));
            CotSwapToFwdAdapter flmm(smm);
            Matrix capletTotCovariance = flmm.totalCovariance(size_ - 1);

            std::vector<Volatility> capletVolsAndErrors(size_ + 2);
            for (Size i = 0; i < size_; ++i)
            {
                capletVolsAndErrors[i] = std::sqrt(capletTotCovariance[i][i] / rateTimes_[i]);
            }
            capletVolsAndErrors[size_] = calibrator.capletRmsError();
            capletVolsAndErrors[size_ + 1] = calibrator.capletMaxError();

            return capletVolsAndErrors;
        }

        Size size_;
        Spread displacement_;
        std::vector<Time> rateTimes_;
        EvolutionDescription evolution_;
        boost::shared_ptr<LMMCurveState> cs_;
        boost::shared_ptr<PiecewiseConstantCorrelation> corr_;
        std::vector<boost::shared_ptr<PiecewiseConstantVariance>> swapVariances_;
        std::vector<Real> alphaInitial_, alphaMax_, alphaMin_;
    };

    struct TestData
    {
        struct MarketModelTest
        : public cl::AdjointTest<MarketModelTest>
        {
            static const CalcMethod default_method = other;

            explicit MarketModelTest(Size size, TestData* data)
            : size_(size)
            , data_(data)
            , capletVols_(size)
            , doubleCapletVols_(size)
            , volsAndErrs_()
            , vars(size)
            {
                setLogger(&data_->outPerform_);
                capletVols_ = vars.generateCapletVolatilities();
                for (Size i = 0; i < size_; i++)
                    doubleCapletVols_[i] = double(capletVols_[i]);
            }

            Size indepVarNumber() { return size_; }

            Size depVarNumber() { return size_ + 2; }

            Size minPerfIteration() { return iterNumFactor; }

            void recordTape()
            {
                cl::Independent(capletVols_);
                calibrate();
                f_ = std::make_unique<cl::tape_function<double>>(capletVols_, volsAndErrs_);
            }

            // Calculates price of portfolio and each option.
            void calibrate()
            {
                volsAndErrs_ = vars.calibrationVolatilitiesAndErrors(capletVols_);
            }

            void calcAdjoint()
            {
                adjointResults_ = f_->Jacobian(doubleCapletVols_);
            }

            // Calculates derivatives using finite difference method.
            void calcAnalytical()
            {
                double h = 1.0e-7;  // shift for finite diff. method
                analyticalResults_.resize(size_*(size_+2));
                for (size_t i = 0; i < size_ - 1; ++i)
                {
                    capletVols_[i] += h;
                    std::vector<Real> volsAndErrsRight = vars.calibrationVolatilitiesAndErrors(capletVols_);
                    capletVols_[i] -= 2*h;
                    std::vector<Real> volsAndErrsLeft = vars.calibrationVolatilitiesAndErrors(capletVols_);
                    for (size_t j = 0; j < volsAndErrsLeft.size(); ++j)
                    {
                        analyticalResults_[i + j * size_] = (volsAndErrsRight[j] - volsAndErrsLeft[j]) / (2*h);
                    }
                    capletVols_[i] += h;
                }
            }

            double relativeTol() const { return 1.0e-2; }

            double absTol() const { return 1.0e-3; }

            Size size_;
            TestData* data_;
            std::vector<cl::tape_double> capletVols_;
            std::vector<double> doubleCapletVols_;
            std::vector<cl::tape_double> volsAndErrs_;
            CommonVars vars;
        };

        TestData()
            : outPerform_(OUTPUT_FOLDER_NAME "//",
            { { "filename", "AdjointPerformance" }
            , { "not_clear", "Not" }
            , { "title", "Caplet volatilities from CTSMMCapletAlphaFormCalibration \\ndifferentiation performance" }
            , { "xlabel", "Number of caplet volatilities" }
            , { "ylabel", "Time (s)" }
            , { "line_box_width", "-5" }
            , { "smooth", "default" }
            , { "cleanlog", "true" }
            })
            , outAdjoint_(OUTPUT_FOLDER_NAME "//",
            {{ "filename", "Adjoint" }
            , { "not_clear", "Not" }
            , { "title", "Caplet volatilities from CTSMMCapletAlphaFormCalibration \\nadjoint differentiation performance" }
            , { "xlabel", "Number of caplet volatilities" }
            , { "ylabel", "Time (s)" }
            , { "smooth", "default" }
            , { "cleanlog", "false" }
            })
            , outSize_(OUTPUT_FOLDER_NAME "//",
            { { "filename", "TapeSize" }
            , { "not_clear", "Not" }
            , { "title", "Tape size dependence on number of caplet volatilities" }
            , { "xlabel", "Number of caplet volatilities" }
            , { "ylabel", "Size (MB)" }
            , { "cleanlog", "false" }
            })
            , out_(OUTPUT_FOLDER_NAME "//output//",
            { { "filename", "VolOnCapletVol" }
            , { "not_clear", "Not" }
            , { "title", "Volatility on caplet volatilities from CTSMMCapletAlphaFormCalibration" }
            , { "xlabel", "Caplet volatility" }
            , { "ylabel", "Volatility" }
            , { "smooth", "default" }
            , { "cleanlog", "false" }
            })
            {
            }

        bool makeOutput()
        {
            bool ok = true;
            if (pointNo > 0)
            {
                ok &= recordDependencePlot();
            }
            ok &= cl::recordPerformance(*this, iterNo, step);
            return ok;
        }

        std::shared_ptr<MarketModelTest> getTest(size_t size)
        {
            return std::make_shared<MarketModelTest>(startSize + size, this);
        }

        bool recordDependencePlot()
        {
            std::vector<RealPair> outData(pointNo);
            auto test = getTest(pointNo);
            for (Size i = 0; i < pointNo; i++)
            {
                test->capletVols_[0] += 0.00001;
                test->calibrate();
                outData[i] = { test->capletVols_[0], test->volsAndErrs_[0] };

            }
            out_ << outData;
            return true;
        }
        cl::tape_empty_test_output outPerform_;
        cl::tape_empty_test_output outAdjoint_;
        cl::tape_empty_test_output outSize_;
        cl::tape_empty_test_output out_;
    };

    typedef TestData::MarketModelTest MarketModelTest;
}
#endif


#ifndef GL_WRAPPER_HPP
#define GL_WRAPPER_HPP

#include <three-dim-util/opengl2/gl.hpp>
#include <Eigen/Core>

namespace threedimutil
{
    inline void clear_color_3d(const Eigen::Vector3d& c) { gl()->glClearColor(c(0), c(1), c(2), 1.0); }
    inline void color_3d(const Eigen::Vector3d& c) { gl()->glColor3d(c(0), c(1), c(2)); }
    inline void color_4d(const Eigen::Vector3d& c, double a) { gl()->glColor4d(c(0), c(1), c(2), a); }

    inline void vertex_2d(const Eigen::Vector2d& v) { gl()->glVertex2d(v(0), v(1)); }
    inline void vertex_3d(const Eigen::Vector3d& v) { gl()->glVertex3d(v(0), v(1), v(2)); }

    inline void translate(const Eigen::Vector2d& t) { gl()->glTranslated(t(0), t(1), 0.0); }
    inline void translate(const Eigen::Vector3d& t) { gl()->glTranslated(t(0), t(1), t(2)); }
    inline void rotate(double angle, const Eigen::Vector3d& axis) { gl()->glRotated(angle, axis(0), axis(1), axis(2)); }

    inline void load_matrix(const Eigen::Matrix4d& m) { gl()->glLoadMatrixd(m.data()); }
    inline void mult_matrix(const Eigen::Matrix4d& m) { gl()->glMultMatrixd(m.data()); }

    inline void read_pixels(int width,
                            int height,
                            Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>& R,
                            Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>& G,
                            Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>& B,
                            Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>& A)
    {
        Eigen::Matrix<GLuint, Eigen::Dynamic, Eigen::Dynamic> buffer(width, height);
        gl()->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        R = Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>(width, height);
        G = Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>(width, height);
        B = Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>(width, height);
        A = Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic>(width, height);
        for (int x = 0; x < width; ++ x)
        {
            for (int y = 0; y < height; ++ y)
            {
                R(x, y) = (buffer(x, y) & 0xff000000) >> 24;
                G(x, y) = (buffer(x, y) & 0x00ff0000) >> 16;
                B(x, y) = (buffer(x, y) & 0x0000ff00) >> 8;
                A(x, y) = (buffer(x, y) & 0x000000ff) >> 0;
            }
        }
    }
}

#endif // GL_WRAPPER_HPP


#include <boost/math/tools/minima.hpp>


///////////////////////////////////////////////////////////////////////////////
// accumulator::statistics::count_less_than.hpp                              //
//                                                                           //
//  Copyright 2008 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_DETAIL_ACCUMULATOR_STATISTICS_COUNT_LESS_THAN_HPP_ER_2009
#define BOOST_STATISTICS_DETAIL_ACCUMULATOR_STATISTICS_COUNT_LESS_THAN_HPP_ER_2009
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/accumulators/framework/extractor.hpp>
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/depends_on.hpp>

#include <boost/statistics/detail/accumulator/statistics/keyword/threshold.hpp>

namespace boost {
namespace statistics{
namespace detail{
namespace accumulator{

namespace impl
{

    template<typename T>
    struct count_less_than : public boost::accumulators::accumulator_base
    {
        typedef boost::accumulators::dont_care dont_care_;

        typedef std::size_t result_type;

        template<typename Args>
        count_less_than(const Args& args)
            : cnt(0), t(args[keyword::threshold|static_cast<T>(0)]){}

        count_less_than(const count_less_than& that)
            : cnt(that.cnt), t(that.t){}

        template<typename Args>
        void operator ()(const Args& args)
        {
            if(args[boost::accumulators::sample]<this->t)
            {
                ++this->cnt;
            }
        }

        result_type result(dont_care_) const
        {
            return this->cnt;
        }

    private:
        result_type cnt;
        T t;
    };

}//impl

namespace tag
{
    struct count_less_than
      : boost::accumulators::depends_on<>
    {
      typedef statistics::detail::accumulator::
      	impl::count_less_than<boost::mpl::_1> impl;

    };
}

namespace extract
{

  	template<typename AccumulatorSet>
  	typename
  	boost::mpl::apply<
    	AccumulatorSet,
        statistics::detail::accumulator::tag::count_less_than
	>::type::result_type
  	count_less_than(AccumulatorSet const& acc){
    	typedef statistics::detail::accumulator::tag::count_less_than the_tag;
    	return boost::accumulators::extract_result<the_tag>(acc);
  	}

}

using extract::count_less_than;

}// accumulator
}// detail
}// statistics
}// boost

#endif


#pragma once

#include <string>
#include <Eigen/Core>
#include <Eigen/Geometry>

#include "../Config/config.hh"
#include "../Math/math.hh"

namespace bold
{
  typedef std::function<Eigen::Vector2d(Eigen::Vector3d const&)> Projector;

  class CameraModel
  {
  public:
    /// Initialises a CameraModel using parameters defined in configuration.
    CameraModel()
    : CameraModel(Config::getStaticValue<int>("camera.image-width"),
                  Config::getStaticValue<int>("camera.image-height"),
                  Config::getStaticValue<double>("camera.field-of-view.vertical-degrees"),
                  Config::getStaticValue<double>("camera.field-of-view.horizontal-degrees"))
    {}

    /// Initialises a CameraModel using the specified parameters.
    CameraModel(ushort imageWidth, ushort imageHeight, double rangeVerticalDegs, double rangeHorizontalDegs);

    ushort imageWidth() const { return d_imageWidth; }
    ushort imageHeight() const { return d_imageHeight; }

    double focalLength() const { return d_focalLength; }
    double rangeVerticalDegs() const { return d_rangeVerticalDegs; }
    double rangeVerticalRads() const { return Math::degToRad(d_rangeVerticalDegs); }
    double rangeHorizontalDegs() const { return d_rangeHorizontalDegs; }
    double rangeHorizontalRads() const { return Math::degToRad(d_rangeHorizontalDegs); }

    /** Gets the direction, in camera coordinates, of the specified pixel.
     * Returns a unit vector.
     */
    Eigen::Vector3d directionForPixel(Eigen::Vector2d const& pixel) const;

    Maybe<Eigen::Vector2d> pixelForDirection(Eigen::Vector3d const& direction) const;

    /** Gets a projection matrix
     *
     * This matrix projects from camera frame onto image frame, up to
     * a scaling factor, which is given in the z element of the
     * transformed vector. i.e to get the pixel coordinate p of a
     * point v with projection matrix T: p' = Tv, p = p'/p'_z.
     */
    Eigen::Affine3d getImageCameraTransform() const { return d_projectionTransform; }

    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;

  private:
    ushort d_imageWidth;
    ushort d_imageHeight;
    double d_focalLength;
    double d_rangeVerticalDegs;
    double d_rangeHorizontalDegs;
    Eigen::Affine3d d_projectionTransform;
  };
}


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

  @copyright 2016 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)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_CUMMAX_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_CUMMAX_HPP_INCLUDED

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

 /*!

    @ingroup group-reduction
    Function object implementing cummax capabilities

    Computes the cumulate maximum of the vector elements

    @par Semantic:

    For every pack parameter of type @c T

    @code
    T r = cummax(x);
    @endcode

    is similar to:

    @code
    T r =x;
    for(int i=0;i < T::static_size; ++i)
      r[i] = max(r[i-1], r[i]);
    @endcode

  **/
  Value cummax(Value const & v0);
} }
#endif

#include <boost/simd/function/scalar/cummax.hpp>
#include <boost/simd/function/simd/cummax.hpp>

#endif


/* Copyright (C) 2017 IBM Corp.
 * 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.
 */
/*****************************************************************
 * test_CRTmatrix: a program for testing the CRTmatrix module
 *****************************************************************/
//#include <mpfr.h>
#include <NTL/lzz_p.h>

NTL_CLIENT
#include "../utils/argmap.h"
#include "../TDMatrix.h"

#if defined(__unix__) || defined(__unix) || defined(unix)
#include <sys/time.h>
#include <sys/resource.h>
#endif

#include <NTL/BasicThreadPool.h>

#define NFACTORS 8

long tinyFactors[NFACTORS] = { 2, 3, 5, 7, 11, 13, 17, 19 };

int main(int argc, char *argv[])
{
#ifdef DEBUG
    NTL::SetSeed((unsigned char*)"test_CRTmatrix",15);
#endif
    ArgMapping amap;
    long k = 3; //2
    amap.arg("k", k, "number of factors (~ log q)");
    long n = 5; //2
    amap.arg("n", n, "the small dimension");
    long e=3; //2
    amap.arg("e", e, "the power of each factor");
    long m=100; //0
    amap.arg("m", m, "the dimension m", "0: set as n*(2+k*e)");
    long threads = 2;
    amap.arg("threads", threads, "how many threads to run");

    amap.parse(argc, argv); // parses and overrides initail values
    // for each parameter, one per line,

    TDMatrixParams prms(n,k,e,m);
    m = prms.m;
    cout << "n="<<n<<", m="<<m<<", k="<<k<<", e="<<e<<", q="<<prms.getQ()
         << endl << endl;

    // Setup a htread pool with almost as many threads as there are cores
    if (threads<1) threads=1;
    else if (threads > numCores()-2) { // numCores() defined in utils/tools.h
      threads = numCores()-2;
      if (threads<1) threads=1;
    }
    NTL::SetNumThreads(threads);
    cout << "Using "<<threads<< " threads\n";

    CRTmatrix A(&prms);
    CRTmatrix B(&prms);
    CRTmatrix C(&prms);
    CRTmatrix I(&prms);
    CRTmatrix T1(&prms);
    CRTmatrix T2(&prms);
    CRTmatrix T3(&prms);
    CRTmatrix T4(&prms);

    generateMultiPair(A, B, prms.m);

    generateMatrixPair(A, B, n);
    C.invert(B);
    bool bTestRes = A==C;
    if (bTestRes==false)
    {
        cout << "Failed Generate Matrix Pair" << endl;
    }
    else
        cout << "Passed Generate Matrix Pair" << endl;

    bTestRes = A==A;

    if (bTestRes==false)
    {
        cout << "Failed Equality (==) Test" << endl;
    }
    else
         cout << "Passed Equality (==) Test" << endl;

    I.identity(n);

    //identity test

    bool bFailedIDTest = false;
    bool bFailedColumnTest = false;

    for (long lFactor=0; lFactor < prms.kFactors; lFactor++)
    {
        const mat_zz_p& aMod = I[lFactor];
        prms.zzp_context[lFactor].restore();

        for (long i = 0; i < n; i++)
        {
            CRTvector crtCol;
            I.getColumn(crtCol, i);
            for (long j = 0; j < n; j++)
            {
                if (i==j)
                {
                    if (aMod[i][j]!=1)
                    {
                        cout << "Failed Identity Test" << endl;
                        bFailedIDTest = true;
                    }
                    if (!IsOne(crtCol[lFactor][j]))
                    {
                        cout << "Failed Get Column Test" << endl;
                        bFailedColumnTest = true;
                    }
                }
                else
                {
                    if (aMod[i][j]!=0)
                    {
                        cout << "Failed Identity Test" << endl;
                        bFailedIDTest = true;
                    }
                    if (!IsZero(crtCol[lFactor][j]))
                    {
                        cout << "Failed Get Column Test" << endl;
                        bFailedColumnTest = true;
                    }
                }
            }
        }
    }

    if (bFailedIDTest == false)
        cout << "Passed Identity Test" << endl;
    if (bFailedColumnTest == false)
        cout << "Passed Get Column Test" << endl;

//cout << "A="<<A<<endl;
//cout << "I =" << I << endl;

// sanity-check
//    assert(A != I);

    A *= B;
    if (A == I) cout << "PASSED generate Matrix Pair\n";
    else        cout << "FAILED generate Matrix Pair\n";

    if (!(T1.NumCols() ==n))   //test NumCols()
        bTestRes = false;

    if (!(T1.NumRows() ==n))   //test NumRowls
        bTestRes = false;

    if (bTestRes==false)
        cout << "FAILED rows/cols num checking" << endl;
    else cout << "PASSED rows/cols num checking" << endl;

    mat_l longA;
    do
    {
        setSmall(longA, prms.n, prms.n, prms.r);
    }
    while (!B.invert(longA)); // Repeat until you get an invertible A mod q
    //cout << "longA=" << longA << "\n" << "B=" <<B << endl;

    A = B;

    B.leftMultBy(longA); //test left multiply by
    A *= longA; //test the *= multiplication

    if (A==I && B==I) cout << "PASSED create invertible matrix\n";
    else              cout << "FAILED create invertible matrix\n";

    T1.randomFill(prms.n,prms.n);
    //cout << "T1=" << T1 << endl;
    T2.randomFill(prms.n,prms.n);
    //cout << "T2=" << T2 << endl;
    // bool bIsSmall= T1.isSmall(prms.r);
    // bIsSmall= B.isSmall(prms.r);

    Vec<vec_zz_p> TestCol;
    B.getColumn(TestCol,1);
    //cout << TestCol << "\n";

    T3= T1;
    //cout << "T3=" << T3 << endl;
    //cout << "T1=" << T1 << endl;
    T1-=I;          //test -= multiplication
    T3-=I;

    //cout << "I=" << I << endl;
    //cout << "T1=" << T1 << endl;

    bool bPassedPMtests = true;

    if (!(T3==T1))
    {
        cout << "FAILED -= test" << endl;
        bPassedPMtests = false;
    }
    T1+=I;          //test += multiplication
    T3+=I;

    if (T3!=T1)
    {
        cout << "FAILED += test" << endl;
        bPassedPMtests = false;
    }
    //cout << "T1=" << T1 << ", T2=" << T2 << "\n";
    T1-=T2;
    //cout << "T1=" << T1 << "\n";
    T1+=T2;

    if (T3!=T1)
    {
        cout << "FAILED +=, -= tests" << endl;
        bPassedPMtests = false;
    }
    if (bPassedPMtests)
         cout << "PASSED +=, -= tests" << endl;

    FILE* handle = fopen("CRMatrixTest.dat", "wb");
    T2.writeToFile(handle);
    fclose(handle);

    handle = fopen("CRMatrixTest.dat", "rb");
    T4.readFromFile(handle,&prms);

    if (bTestRes)
        cout << "PASSED function test" << endl;
    else
        cout << "FAILED functions test" << endl;

   // cout << "T2=" << T2 << ", T4=" << T4 << endl;
    if (T2==T4)
        cout << "Read/Write Passed!" << endl;
    else
        cout << "Read/Write CRTmatrix failed" << endl;
    //assert(T2==T3);

    cout << "!"<< endl;
    printAllTimers(cout);

#ifdef CodeBlocks
    cin.get();
#endif
}


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

    @copyright 2016 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)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_FIX_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_FIX_HPP_INCLUDED

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

  /*!

    @ingroup group-arithmetic
    This function object computes the truncation toward @ref Zero
    of its parameter.

    @par Header <boost/simd/function/fix.hpp>

    It is an alias of @ref trunc

    @see ceil, floor, round,  nearbyint, trunc, ifix, itrunc

    @par Example:

      @snippet fix.cpp fix

    @par Possible output:

      @snippet fix.txt fix

  **/
  Value fix(Value const& x);
} }
#endif

#include <boost/simd/function/scalar/trunc.hpp>
#include <boost/simd/function/simd/fix.hpp>

#endif


//==============================================================================
//         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
//==============================================================================
#define NT2_UNIT_MODULE "nt2 complex.exponential toolbox - acosh/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of exponential components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created by jt the 08/12/2010
///
#include <nt2/include/functions/acosh.hpp>
#include <boost/type_traits/is_same.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/meta/as_floating.hpp>
#include <nt2/sdk/meta/as_signed.hpp>
#include <nt2/sdk/meta/upgrade.hpp>
#include <nt2/sdk/meta/downgrade.hpp>
#include <nt2/sdk/meta/scalar_of.hpp>
#include <boost/dispatch/meta/as_floating.hpp>
#include <boost/type_traits/common_type.hpp>
#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/memory/buffer.hpp>
#include <nt2/constant/constant.hpp>
#include <boost/math/complex/acosh.hpp>

NT2_TEST_CASE_TPL ( acosh_real__1_0,  (double))//NT2_REAL_TYPES)
{

  using nt2::acosh;
  using nt2::tag::acosh_;
  typedef std::complex<T> cT;
  typedef typename nt2::meta::call<acosh_(cT)>::type r_t;
  typedef typename nt2:: meta::as_complex<T>::type wished_r_t;

  // return type conformity test
//   NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::One<T>(), nt2::Zero<T>())),  cT(nt2::Zero<T>(), nt2::Zero<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Zero<T>(), nt2::Zero<T>())),  cT(nt2::Zero<T>(), nt2::Pio_2<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Mzero<T>(), nt2::Zero<T>())), cT(nt2::Zero<T>(), nt2::Pio_2<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::One  <T>(), nt2::Nan <T>())), cT(nt2::Nan<T>(),  nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Minf <T>(), nt2::Nan<T>())),  cT(nt2::Inf<T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Inf  <T>(), nt2::Nan<T>())),  cT(nt2::Inf <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Nan  <T>(), nt2::One<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Nan  <T>(), nt2::Inf<T>())),  cT(nt2::Inf <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Nan  <T>(), nt2::Nan<T>())),  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);

// cacosh(+inf + iy) returns +inf + i0, for positive-signed finite y. --- matlab : Inf
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Inf  <T>(), nt2::One <T>())), cT(nt2::Inf <T>(), nt2::Zero<T>()), 0.75);
  // cacosh(~inf + iy) returns +inf + i pi , for positive-signed finite y. --- matlab :  Inf + 3.1416i
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Minf <T>(), nt2::One <T>())), cT(nt2::Inf<T>(), nt2::Pi<T>()), 0.75);
  // cacosh(x + i inf) returns +inf + i pi /2, for finite x.               --- matlab : Inf +    NaNi
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::One  <T>(), nt2::Inf <T>())), cT(nt2::Inf<T>(),  nt2::Pio_2<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::One <T>(), nt2::Inf<T>())),  boost::math::acosh(cT(nt2::One <T>(), nt2::Inf<T>())), 0.75);
  // cacosh(~inf + i inf) returns +inf + i3 pi /4.                         --- matlab : Inf +    NaNi
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Minf <T>(), nt2::Inf<T>())),  cT(nt2::Inf<T>(), 3*nt2::Pi<T>()/4), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Minf <T>(), nt2::Inf<T>())),  boost::math::acosh(cT(nt2::Minf <T>(), nt2::Inf<T>())), 0.75);

  //  cacosh(+inf + i inf) returns +inf + i pi /4.
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Inf  <T>(), nt2::Inf<T>())),  cT(nt2::Inf <T>(),  nt2::Pi<T>()/4), 0.75);
  //  cacosh(NaN + i0) returns NaN + iNan.
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(nt2::Nan  <T>(), nt2::Zero<T>())), cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(1, 1)),  boost::math::acosh(cT(1, 1)), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(1, 10)),  boost::math::acosh(cT(1, 10)), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(10, 10)),  boost::math::acosh(cT(10, 10)), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::acosh(cT(10, 1)),  boost::math::acosh(cT(10, 1)), 0.75);

} // end of test for floating_

// cacosh(conj(z)) = conj(cacosh(z)).
//  cacosh((+/-)0 + i0) returns +0 + i pi /2.
//  cacosh(x + i inf) returns +inf + i pi /2, for finite x.
//  cacosh(x + iNaN) returns NaN + iNaN and optionally raises the invalid floating-point exception, for finite x.
//  cacosh(~inf + iy) returns +inf + i pi , for positive-signed finite y.
//  cacosh(+inf + iy) returns +inf + i0, for positive-signed finite y.
//  cacosh(~inf + i inf) returns +inf + i3 pi /4.
//  cacosh(+inf + i inf) returns +inf + i pi /4.
//  cacosh((+/-)inf + iNaN) returns +inf + iNaN.
//  cacosh(NaN + iy) returns NaN + iNaN and optionally raises the invalid floating-point exception, for finite y.
//  cacosh(NaN + i inf) returns +inf + iNaN.
//  cacosh(NaN + iNaN) returns NaN + iNaN.


#ifndef UnitConvert_Dimension_hpp
#define UnitConvert_Dimension_hpp

/** @file Dimension.hpp
 * @brief
 * @author C.D. Clark III
 * @date 09/02/18
 */

#include <array>
#include <ostream>

#include <boost/units/base_dimension.hpp>
#include <boost/units/physical_dimensions/amount.hpp>
#include <boost/units/physical_dimensions/current.hpp>
#include <boost/units/physical_dimensions/length.hpp>
#include <boost/units/physical_dimensions/luminance.hpp>
#include <boost/units/physical_dimensions/mass.hpp>
#include <boost/units/physical_dimensions/plane_angle.hpp>
#include <boost/units/physical_dimensions/solid_angle.hpp>
#include <boost/units/physical_dimensions/temperature.hpp>
#include <boost/units/physical_dimensions/time.hpp>

namespace UnitConvert {
/**
 * A class representing a physical dimension. A physicsl dimension
 * consists of 0 or more of the seven SI base dimensions
 * (see https://en.wikipedia.org/wiki/SI_base_unit):
 *
 * Length
 * Mass
 * Time
 * Electrical Current
 * Temperature
 * Amount
 * Lumnous Intensity
 *
 * @todo Use expression templates to improve dimension algebra performance
 */
class Dimension
{
 public:
  enum class Name {
    Length = 0,
    Mass,
    Time,
    ElectricalCurrent,
    Temperature,
    Amount,
    LuminousIntensity,
    Dimensionless  // WARNING: This needs to be the last entry so that the two
                   // lines below work.
  };
  static const int           N = static_cast<int>(Name::Dimensionless) + 1;
  typedef std::array<int, N> ArrayType;

 protected:
  ArrayType m_Powers;

 public:
 public:
  Dimension();
  Dimension(Name dim);

  int operator[](Name dim)
      const;  //<<< Return the power of a base dimension for this dimension
  ArrayType powers() const;  //<<< Return the powers for each base dimension for
                             // this dimension in an array

  friend std::ostream& operator<<(std::ostream&    out,
                                  const Dimension& dim);  //<<< Output operator.

  Dimension operator*(const Dimension& other)
      const;  //<<< Return the dimension resulting in
              // multiplying this dimension with another.

  Dimension& operator*=(const Dimension& other);

  Dimension operator/(
      const Dimension& other) const;  //<<< Return the dimension resulting in
                                      // dividing this dimension by another.

  Dimension& operator/=(const Dimension& other);

  bool operator==(const Dimension& other)
      const;  //<<< Return true if dimensions are the same. i.e. all powers of
              // base dimensions are the same.

  bool operator!=(const Dimension& other)
      const;  //<<< Return true if dimensions are not the same
};

/**
 * A class for constructing base dimensions.
 *
 * The Dimension class cannot constructed directly. This class
 * is used to construct base dimensions, which can then be used
 * to build non-base dimensions.
 */
template<Dimension::Name DIM>
class BaseDimension : public Dimension
{
 public:
  BaseDimension() : Dimension(DIM) {}
};

/**
 * Specialization for dimensionless base dimension.
 */
template<>
class BaseDimension<Dimension::Name::Dimensionless> : public Dimension
{
 public:
  BaseDimension() : Dimension() {}
};

/**
 * A template meta-function for getting the Dimension::Name value
 * corresponding to a Boost.Units dimensino
 */
template<typename D>
struct get_dimension_name {
};

template<>
struct get_dimension_name<boost::units::length_dimension> {
  static const Dimension::Name value = Dimension::Name::Length;
};
template<>
struct get_dimension_name<boost::units::mass_dimension> {
  static const Dimension::Name value = Dimension::Name::Mass;
};
template<>
struct get_dimension_name<boost::units::time_dimension> {
  static const Dimension::Name value = Dimension::Name::Time;
};
template<>
struct get_dimension_name<boost::units::current_dimension> {
  static const Dimension::Name value = Dimension::Name::ElectricalCurrent;
};
template<>
struct get_dimension_name<boost::units::temperature_dimension> {
  static const Dimension::Name value = Dimension::Name::Temperature;
};
template<>
struct get_dimension_name<boost::units::amount_dimension> {
  static const Dimension::Name value = Dimension::Name::Amount;
};
template<>
struct get_dimension_name<boost::units::luminous_intensity_dimension> {
  static const Dimension::Name value = Dimension::Name::LuminousIntensity;
};

// boost defines separate dimensions for plane angles and solid angles.
// in the SI system, these are dimensionless.
template<>
struct get_dimension_name<boost::units::plane_angle_dimension> {
  static const Dimension::Name value = Dimension::Name::Dimensionless;
};
template<>
struct get_dimension_name<boost::units::solid_angle_dimension> {
  static const Dimension::Name value = Dimension::Name::Dimensionless;
};
template<>
struct get_dimension_name<boost::units::dimensionless_type> {
  static const Dimension::Name value = Dimension::Name::Dimensionless;
};

/**
 * Meta-function to get the Dimension::Name for a boost unit
 */
template<class D, class S>
struct get_dimension_name<boost::units::unit<D, S>> {
  static const Dimension::Name value = get_dimension_name<D>::value;
};

template<class D, class S>
struct get_dimension_name<boost::units::absolute<boost::units::unit<D, S>>> {
  static const Dimension::Name value = get_dimension_name<D>::value;
};
}

#endif  // include protector


// Copyright Louis Dionne 2013-2016
// 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/hana/product.hpp>
#include <boost/hana/range.hpp>

int main() {
    constexpr auto range = boost::hana::range_c<
        unsigned long long, 1, <%= input_size %>
    >;
    constexpr auto result = boost::hana::product<>(range);
    (void)result;
}


// Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
// 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 ETH Zurich and UNC Chapel Hill 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 HOLDERS 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: Johannes L. Schoenberger (jsch-at-demuc-dot-de)

#include "base/polynomial.h"

#include <Eigen/Eigenvalues>

#include "util/logging.h"

namespace colmap {
namespace {

// Remove leading zero coefficients.
Eigen::VectorXd RemoveLeadingZeros(const Eigen::VectorXd& coeffs) {
  Eigen::VectorXd::Index num_zeros = 0;
  for (; num_zeros < coeffs.size(); ++num_zeros) {
    if (coeffs(num_zeros) != 0) {
      break;
    }
  }
  return coeffs.tail(coeffs.size() - num_zeros);
}

// Remove trailing zero coefficients.
Eigen::VectorXd RemoveTrailingZeros(const Eigen::VectorXd& coeffs) {
  Eigen::VectorXd::Index num_zeros = 0;
  for (; num_zeros < coeffs.size(); ++num_zeros) {
    if (coeffs(coeffs.size() - 1 - num_zeros) != 0) {
      break;
    }
  }
  return coeffs.head(coeffs.size() - num_zeros);
}

}  // namespace

bool FindLinearPolynomialRoots(const Eigen::VectorXd& coeffs,
                               Eigen::VectorXd* real, Eigen::VectorXd* imag) {
  CHECK_EQ(coeffs.size(), 2);

  if (coeffs(0) == 0) {
    return false;
  }

  if (real != nullptr) {
    real->resize(1);
    (*real)(0) = -coeffs(1) / coeffs(0);
  }

  if (imag != nullptr) {
    imag->resize(1);
    (*imag)(0) = 0;
  }

  return true;
}

bool FindQuadraticPolynomialRoots(const Eigen::VectorXd& coeffs,
                                  Eigen::VectorXd* real,
                                  Eigen::VectorXd* imag) {
  CHECK_EQ(coeffs.size(), 3);

  const double a = coeffs(0);
  if (a == 0) {
    return FindLinearPolynomialRoots(coeffs.tail(2), real, imag);
  }

  const double b = coeffs(1);
  const double c = coeffs(2);
  if (b == 0 && c == 0) {
    if (real != nullptr) {
      real->resize(1);
      (*real)(0) = 0;
    }
    if (imag != nullptr) {
      imag->resize(1);
      (*imag)(0) = 0;
    }
    return true;
  }

  const double d = b * b - 4 * a * c;

  if (d >= 0) {
    const double sqrt_d = std::sqrt(d);
    if (real != nullptr) {
      real->resize(2);
      if (b >= 0) {
        (*real)(0) = (-b - sqrt_d) / (2 * a);
        (*real)(1) = (2 * c) / (-b - sqrt_d);
      } else {
        (*real)(0) = (2 * c) / (-b + sqrt_d);
        (*real)(1) = (-b + sqrt_d) / (2 * a);
      }
    }
    if (imag != nullptr) {
      imag->resize(2);
      imag->setZero();
    }
  } else {
    if (real != nullptr) {
      real->resize(2);
      real->setConstant(-b / (2 * a));
    }
    if (imag != nullptr) {
      imag->resize(2);
      (*imag)(0) = std::sqrt(-d) / (2 * a);
      (*imag)(1) = -(*imag)(0);
    }
  }

  return true;
}

bool FindPolynomialRootsDurandKerner(const Eigen::VectorXd& coeffs_all,
                                     Eigen::VectorXd* real,
                                     Eigen::VectorXd* imag) {
  CHECK_GE(coeffs_all.size(), 2);

  const Eigen::VectorXd coeffs = RemoveLeadingZeros(coeffs_all);

  const int degree = coeffs.size() - 1;

  if (degree <= 0) {
    return false;
  } else if (degree == 1) {
    return FindLinearPolynomialRoots(coeffs, real, imag);
  } else if (degree == 2) {
    return FindQuadraticPolynomialRoots(coeffs, real, imag);
  }

  // Initialize roots.
  Eigen::VectorXcd roots(degree);
  roots(degree - 1) = std::complex<double>(1, 0);
  for (int i = degree - 2; i >= 0; --i) {
    roots(i) = roots(i + 1) * std::complex<double>(1, 1);
  }

  // Iterative solver.
  const int kMaxNumIterations = 100;
  const double kMaxRootChange = 1e-10;
  for (int iter = 0; iter < kMaxNumIterations; ++iter) {
    double max_root_change = 0.0;
    for (int i = 0; i < degree; ++i) {
      const std::complex<double> root_i = roots(i);
      std::complex<double> numerator = coeffs[0];
      std::complex<double> denominator = coeffs[0];
      for (int j = 0; j < degree; ++j) {
        numerator = numerator * root_i + coeffs[j + 1];
        if (i != j) {
          denominator = denominator * (root_i - roots(j));
        }
      }
      const std::complex<double> root_i_change = numerator / denominator;
      roots(i) = root_i - root_i_change;
      max_root_change =
          std::max(max_root_change, std::abs(root_i_change.real()));
      max_root_change =
          std::max(max_root_change, std::abs(root_i_change.imag()));
    }

    // Break, if roots do not change anymore.
    if (max_root_change < kMaxRootChange) {
      break;
    }
  }

  if (real != nullptr) {
    real->resize(degree);
    *real = roots.real();
  }
  if (imag != nullptr) {
    imag->resize(degree);
    *imag = roots.imag();
  }

  return true;
}

bool FindPolynomialRootsCompanionMatrix(const Eigen::VectorXd& coeffs_all,
                                        Eigen::VectorXd* real,
                                        Eigen::VectorXd* imag) {
  CHECK_GE(coeffs_all.size(), 2);

  Eigen::VectorXd coeffs = RemoveLeadingZeros(coeffs_all);

  const int degree = coeffs.size() - 1;

  if (degree <= 0) {
    return false;
  } else if (degree == 1) {
    return FindLinearPolynomialRoots(coeffs, real, imag);
  } else if (degree == 2) {
    return FindQuadraticPolynomialRoots(coeffs, real, imag);
  }

  // Remove the coefficients where zero is a solution.
  coeffs = RemoveTrailingZeros(coeffs);

  // Check if only zero is a solution.
  if (coeffs.size() == 1) {
    if (real != nullptr) {
      real->resize(1);
      (*real)(0) = 0;
    }
    if (imag != nullptr) {
      imag->resize(1);
      (*imag)(0) = 0;
    }
    return true;
  }

  // Fill the companion matrix.
  Eigen::MatrixXd C(coeffs.size() - 1, coeffs.size() - 1);
  C.setZero();
  for (Eigen::MatrixXd::Index i = 1; i < C.rows(); ++i) {
    C(i, i - 1) = 1;
  }
  C.row(0) = -coeffs.tail(coeffs.size() - 1) / coeffs(0);

  // Solve for the roots of the polynomial.
  Eigen::EigenSolver<Eigen::MatrixXd> solver(C, false);
  if (solver.info() != Eigen::Success) {
    return false;
  }

  // If there are trailing zeros, we must add zero as a solution.
  const int effective_degree =
      coeffs.size() - 1 < degree ? coeffs.size() : coeffs.size() - 1;

  if (real != nullptr) {
    real->resize(effective_degree);
    real->head(coeffs.size() - 1) = solver.eigenvalues().real();
    if (effective_degree > coeffs.size() - 1) {
      (*real)(real->size() - 1) = 0;
    }
  }
  if (imag != nullptr) {
    imag->resize(effective_degree);
    imag->head(coeffs.size() - 1) = solver.eigenvalues().imag();
    if (effective_degree > coeffs.size() - 1) {
      (*imag)(imag->size() - 1) = 0;
    }
  }

  return true;
}

// Stolen from PoseLib implementation
/* Solves the quadratic equation a*x^2 + b*x + c = 0 */
inline double sign(const double z) { return z < 0 ? -1.0 : 1.0; }

int SolveQuadraticReal(double a, double b, double c, double roots[2]) {
  double b2m4ac = b * b - 4 * a * c;
  if (b2m4ac < 0) return 0;

  double sq = std::sqrt(b2m4ac);

  // Choose sign to avoid cancellations
  roots[0] = (b > 0) ? (2 * c) / (-b - sq) : (2 * c) / (-b + sq);
  roots[1] = c / (a * roots[0]);

  return 2;
}
void SolveCubicRealSingleRoot(double c2, double c1, double c0, double& root) {
  double a = c1 - c2 * c2 / 3.0;
  double b = (2.0 * c2 * c2 * c2 - 9.0 * c2 * c1) / 27.0 + c0;
  double c = b * b / 4.0 + a * a * a / 27.0;
  if (c > 0) {
    c = std::sqrt(c);
    b *= -0.5;
    root = std::cbrt(b + c) + std::cbrt(b - c) - c2 / 3.0;
  } else {
    c = 3.0 * b / (2.0 * a) * std::sqrt(-3.0 / a);
    root = 2.0 * std::sqrt(-a / 3.0) * std::cos(std::acos(c) / 3.0) - c2 / 3.0;
  }
}
/* Solves the quartic equation x^4 + b*x^3 + c*x^2 + d*x + e = 0 */
int SolveQuarticReal(double b, double c, double d, double e, double roots[4]) {
  // Find depressed quartic
  double p = c - 3.0 * b * b / 8.0;
  double q = b * b * b / 8.0 - 0.5 * b * c + d;
  double r =
      (-3.0 * b * b * b * b + 256.0 * e - 64.0 * b * d + 16.0 * b * b * c) /
      256.0;

  // Resolvent cubic is now
  // U^3 + 2*p U^2 + (p^2 - 4*r) * U - q^2
  double bb = 2.0 * p;
  double cc = p * p - 4.0 * r;
  double dd = -q * q;

  // Solve resolvent cubic
  double u2;
  SolveCubicRealSingleRoot(bb, cc, dd, u2);

  if (u2 < 0) return 0;

  double u = sqrt(u2);

  double s = -u;
  double t = (p + u * u + q / u) / 2.0;
  double v = (p + u * u - q / u) / 2.0;

  int sols = 0;
  double disc = u * u - 4.0 * v;
  if (disc > 0) {
    roots[0] = (-u - sign(u) * std::sqrt(disc)) / 2.0;
    roots[1] = v / roots[0];
    sols += 2;
  }
  disc = s * s - 4.0 * t;
  if (disc > 0) {
    roots[sols] = (-s - sign(s) * std::sqrt(disc)) / 2.0;
    roots[sols + 1] = t / roots[sols];
    sols += 2;
  }

  for (int i = 0; i < sols; i++) {
    roots[i] = roots[i] - b / 4.0;

    // do one step of newton refinement
    double x = roots[i];
    double x2 = x * x;
    double x3 = x * x2;
    double dx = -(x2 * x2 + b * x3 + c * x2 + d * x + e) /
                (4.0 * x3 + 3.0 * b * x2 + 2.0 * c * x + d);
    roots[i] = x + dx;
  }
  return sols;
}

}  // namespace colmap


#include <boost/graph/adjacency_list.hpp>
#include <glog/logging.h>
#include <gtest/gtest.h>

#include "segmatch/recognizers/graph_utilities.hpp"
using namespace boost;
using namespace segmatch;

// Initialize common objects needed by multiple tests.
class GraphUtilitiesTest : public ::testing::Test {
 protected:
  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph;
  typedef graph_traits<Graph>::vertex_descriptor Vertex;
  typedef std::vector<Vertex> Vertices;

  Graph graph_1;
  Graph graph_2;
  Graph graph_3;

  void SetUp() override {
    graph_1 = buildGraph(4, { { 0, 2 }, { 1, 2 }, { 1, 3 }, { 2, 3 } });
    graph_2 = buildGraph(8, {
        { 0, 5 }, { 0, 7 }, { 1, 3 }, { 1, 5 }, { 2, 3 }, { 2, 4 }, { 2, 6 }, { 2, 7 }, { 3, 4 },
        { 3, 6 }, { 4, 6 }
    });
    // Graph from page 2 of http://hbanaszak.mjr.uw.edu.pl/TempTxt/Batagelj/cores.pdf
    graph_3 = buildGraph(21, {
        { 0, 5 }, { 0, 7 }, { 0, 9 }, { 0, 12 }, { 1, 3 }, { 1, 6 }, { 2, 8 }, { 2, 10 },
        { 2, 16 }, { 3, 6 }, { 3, 7 }, { 3, 13 }, { 3, 15 }, { 3, 20 }, { 4, 17 }, { 5, 7 },
        { 5, 12 }, { 6, 7 }, { 6, 11 }, { 7, 12 }, { 8, 19 }, { 9, 15 }, { 9, 17 }, { 13, 15 },
        { 13, 20 }, { 14, 17 }, { 15, 17 }, { 15, 20 }, { 16, 19 }
    });
  }

  // Build a BGL graph from a vector of edges.
  Graph buildGraph(const size_t num_vertices,
                   const std::vector<std::pair<size_t, size_t>>& edges) {
    Graph graph(num_vertices);
    for (const auto& edge : edges) {
      boost::add_edge(edge.first, edge.second, graph);
    }
    return graph;
  }
};

TEST_F(GraphUtilitiesTest, test_find_max_clique_1) {
  // Arrange
  Vertices expected_max_clique = { 1, 2, 3 };

  // Act
  Vertices max_clique = GraphUtilities::findMaximumClique(graph_1, 3);

  // Assert
  std::sort(max_clique.begin(), max_clique.end());
  EXPECT_EQ(expected_max_clique, max_clique);
}

TEST_F(GraphUtilitiesTest, test_find_max_clique_2) {
  // Arrange
  Vertices expected_max_clique = { 2, 3, 4, 6 };

  // Act
  Vertices max_clique = GraphUtilities::findMaximumClique(graph_2, 3);

  // Assert
  std::sort(max_clique.begin(), max_clique.end());
  EXPECT_EQ(expected_max_clique, max_clique);
}

TEST_F(GraphUtilitiesTest, test_find_max_clique_3) {
  // Arrange
  Vertices expected_max_clique = { 3, 13, 15, 20 };
  // The graph contains two maximum cliques. Which one is found depends on the algorithm.
  // Vertices expected_max_clique = { 0, 5, 7, 12 };

  // Act
  Vertices max_clique = GraphUtilities::findMaximumClique(graph_3, 4);

  // Assert
  std::sort(max_clique.begin(), max_clique.end());
  EXPECT_EQ(expected_max_clique, max_clique);
}

TEST_F(GraphUtilitiesTest, test_find_max_clique_no_such_clique) {
  // Arrange
  Vertices expected_max_clique = { };

  // Act
  Vertices max_clique = GraphUtilities::findMaximumClique(graph_3, 5);

  // Assert
  std::sort(max_clique.begin(), max_clique.end());
  EXPECT_EQ(expected_max_clique, max_clique);
}


//=======================================================================
// 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 iterative_rounding_test.cpp
 * @brief
 * @author Piotr Wygocki, Piotr Godlewski
 * @version 1.0
 * @date 2013-02-04
 */

#include "test_utils/logger.hpp"

#include "iterative_rounding/log_visitor.hpp"

#include "paal/data_structures/metric/basic_metrics.hpp"
#include "paal/iterative_rounding/generalised_assignment/generalised_assignment.hpp"
#include "paal/utils/irange.hpp"

#include <boost/test/unit_test.hpp>

#include <vector>

using namespace paal;
using namespace paal::ir;

BOOST_AUTO_TEST_SUITE(generalised_assignment)
BOOST_AUTO_TEST_CASE(generalised_assignment_test) {
    // sample problem
    LOGLN("sample problem:");
    auto machines = paal::irange(2);
    auto jobs = paal::irange(2);

    paal::data_structures::array_metric<int> cost{ 2 };
    cost(0, 0) = 2;
    cost(0, 1) = 3;
    cost(1, 0) = 1;
    cost(1, 1) = 3;

    paal::data_structures::array_metric<int> time{ 2 };
    time(0, 0) = 2;
    time(0, 1) = 2;
    time(1, 0) = 1;
    time(1, 1) = 1;

     auto T = [&](int i){return 2;};

     std::unordered_map<int, int> jobs_to_machines;

     paal::ir::generalised_assignment_iterative_rounding(
         machines.begin(), machines.end(),
         jobs.begin(), jobs.end(),
         cost, time, T, std::inserter(jobs_to_machines, jobs_to_machines.begin()),
         paal::ir::ga_ir_components<>{}, log_visitor{});

     ON_LOG(for(const std::pair<int, int> & jm : jobs_to_machines) {
         LOGLN("Job " << jm.first << " assigned to Machine " << jm.second);
     })

    auto j0 = jobs_to_machines.find(0);
    BOOST_CHECK(j0 != jobs_to_machines.end() && j0->second == 0);

    auto j1 = jobs_to_machines.find(1);
    BOOST_CHECK(j1 != jobs_to_machines.end() && j1->second == 0);

    // compile with trivial visitor
    {
         jobs_to_machines.clear();
         paal::ir::generalised_assignment_iterative_rounding(
            machines.begin(), machines.end(),
            jobs.begin(), jobs.end(),
            cost, time, T, std::inserter(jobs_to_machines, jobs_to_machines.begin()));
    }
}

BOOST_AUTO_TEST_CASE(generalised_assignment_infeasible_test) {
    // infeasible problem
    LOGLN("infeasible problem:");
    auto machines = paal::irange(2);
    auto jobs = paal::irange(2);

    paal::data_structures::array_metric<int> cost{ 2 };
    cost(0, 0) = 2;
    cost(0, 1) = 3;
    cost(1, 0) = 1;
    cost(1, 1) = 3;

    paal::data_structures::array_metric<int> time{ 2 };
    time(0, 0) = 2;
    time(0, 1) = 4;
    time(1, 0) = 3;
    time(1, 1) = 3;

    auto T = [&](int i) { return 2; };

    std::vector<std::pair<int, int>> jobs_to_machines;

    auto result = paal::ir::generalised_assignment_iterative_rounding(
        machines.begin(), machines.end(),
        jobs.begin(), jobs.end(),
        cost, time, T, std::back_inserter(jobs_to_machines));

    BOOST_CHECK(result.first == lp::INFEASIBLE);
    BOOST_CHECK(!result.second);
}
BOOST_AUTO_TEST_SUITE_END()


//==================================================================================================
/*!
  @file
    @copyright 2016 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)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_GAMMA_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_GAMMA_HPP_INCLUDED

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

  /*!
    @ingroup group-euler
    This function object computes the gamma function:
   \f$\displaystyle \int_0^{\infty} t^{x-1}e^{-t}\mbox{d}t\f$

    @par Header <boost/simd/function/gamma.hpp>

    @par Decorators

     - std_ calls @c std::tgamma

    @see gammaln

    @par Example:

      @snippet gamma.cpp gamma

    @par Possible output:

      @snippet gamma.txt gamma
  **/
  IEEEValue gamma(IEEEValue const& x);
} }
#endif

#include <boost/simd/function/scalar/gamma.hpp>
#include <boost/simd/function/simd/gamma.hpp>

#endif


// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>

template<typename T>
using term = boost::yap::terminal<boost::yap::expression, T>;

namespace yap = boost::yap;
namespace bh = boost::hana;

namespace user {

    struct number
    {
        double value;

        friend number operator+(number lhs, number rhs)
        {
            return number{lhs.value + rhs.value};
        }

        friend number operator*(number lhs, number rhs)
        {
            return number{lhs.value * rhs.value};
        }
    };

    // A more efficient fused multiply-add operation would normally go here.
    number naxpy(number a, number x, number y)
    {
        return number{a.value * x.value + y.value};
    }

    // Transforms expressions of the form "a * x + y" to "naxpy(a, x, y)" via
    // the implicit transform customiztion point.
    template<typename Expr1, typename Expr2, typename Expr3>
    decltype(auto) transform_expression(yap::expression<
                                        yap::expr_kind::plus,
                                        bh::tuple<
                                            yap::expression<
                                                yap::expr_kind::multiplies,
                                                bh::tuple<Expr1, Expr2>>,
                                            Expr3>> const & expr)
    {
        return naxpy(
            evaluate(expr.left().left()),
            evaluate(expr.left().right()),
            evaluate(expr.right()));
    }
}

term<user::number> a{{1.0}};
term<user::number> x{{42.0}};
term<user::number> y{{3.0}};

user::number
eval_as_yap_expr(decltype((a * x + y) * (a * x + y) + (a * x + y)) & expr)
{
    return yap::evaluate(expr);
}

user::number eval_as_yap_expr_4x(decltype(
    (a * x + y) * (a * x + y) + (a * x + y) + (a * x + y) * (a * x + y) +
    (a * x + y) + (a * x + y) * (a * x + y) + (a * x + y) +
    (a * x + y) * (a * x + y) + (a * x + y)) & expr)
{
    return yap::evaluate(expr);
}

user::number eval_as_cpp_expr(user::number a, user::number x, user::number y)
{
    return (a * x + y) * (a * x + y) + (a * x + y);
}

user::number eval_as_cpp_expr_4x(user::number a, user::number x, user::number y)
{
    return (a * x + y) * (a * x + y) + (a * x + y) + (a * x + y) * (a * x + y) +
           (a * x + y) + (a * x + y) * (a * x + y) + (a * x + y) +
           (a * x + y) * (a * x + y) + (a * x + y);
}

int main()
{
    auto expr = (a * x + y) * (a * x + y) + (a * x + y);
    user::number result_1 = eval_as_yap_expr(expr);
    user::number result_2 =
        eval_as_cpp_expr(yap::value(a), yap::value(x), yap::value(y));

    (void)result_1;
    (void)result_2;

    return 0;
}


#include <boost/math/constants/constants.hpp>
#include "EnergyResolutionC.hh"
#include "TypesFunctions.hh"
#include <fmt/format.h>
#include <string.h>

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

EnergyResolutionC::EnergyResolutionC( bool single ) : m_single(single) {
  variable_(&m_a, "Eres_a");
  variable_(&m_b, "Eres_b");
  variable_(&m_c, "Eres_c");
  callback_([this] { fillCache(); });

  if (single) {
    add();
  }
}

void EnergyResolutionC::add(){
  int index=static_cast<int>(transformations.size());
  std::string label="smear";
  if(!m_single){
    label = fmt::format("smear_{0}", index);
  }
  transformation_(label)
    .input("Nvis")
    .output("Nrec")
    .types(TypesFunctions::pass<0>,TypesFunctions::ifHist<0>,
           [index](EnergyResolutionC *obj, TypesFunctionArgs& fargs) {
             if(index==0){
               obj->m_datatype = fargs.args[0];
               obj->fillCache();
             }
             else{
               if( fargs.args[0]!=obj->m_datatype ) {
                 throw std::runtime_error("Inconsistent histogram in EnergyResolutionC");
               }
             }
           })
  .func(&EnergyResolutionC::calcSmear);
}

void EnergyResolutionC::add(SingleOutput& hist){
  if( m_single ){
    throw std::runtime_error("May have only single energy resolution transformation in this class instance");
  }
  add();
  transformations.back().inputs[0]( hist.single() );
}

double EnergyResolutionC::relativeSigma(double Etrue) const noexcept{
  return sqrt(pow(m_a, 2)+ pow(m_b, 2)/Etrue + pow(m_c/Etrue, 2));
}

double EnergyResolutionC::resolution(double Etrue, double Erec) const noexcept {
  static const double twopisqr = std::sqrt(2*pi);
  const double sigma = Etrue * relativeSigma(Etrue);
  const double reldiff = (Etrue - Erec)/sigma;

  return std::exp(-0.5*pow(reldiff, 2))/(twopisqr*sigma);
}

void EnergyResolutionC::fillCache() {
  m_size = m_datatype.hist().bins();
  if (m_size == 0) {
    return;
  }
  m_sparse_cache.resize(m_size, m_size);

  /* fill the cache matrix with probalilities for number of events to leak to other bins */
  /* colums corressponds to reconstrucred energy and rows to true energy */
  auto bin_center = [&](size_t index){ return (m_datatype.edges[index+1] + m_datatype.edges[index])/2; };
  for (size_t etrue = 0; etrue < m_size; ++etrue) {
    double Etrue = bin_center(etrue);
    double dEtrue = m_datatype.edges[etrue+1] - m_datatype.edges[etrue];

    bool right_edge_reached{false};
    /* precalculating probabilities for events in given bin to leak to
     * neighbor bins  */
    for (size_t erec = 0; erec < m_size; ++erec) {
      double Erec = bin_center(erec);
      double rEvents = dEtrue*resolution(Etrue, Erec);

      if (rEvents < 1E-10) {
        if (right_edge_reached) {
           break;
        }
        continue;
      }
      m_sparse_cache.insert(erec, etrue) = rEvents;
      if (!right_edge_reached) {
        right_edge_reached = true;
      }
    }
  }
  m_sparse_cache.makeCompressed();
}

/* Apply precalculated cache and actually smear */
void EnergyResolutionC::calcSmear(FunctionArgs& fargs) {
  fargs.rets[0].x = m_sparse_cache * fargs.args[0].vec;
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_ARITHMETIC_FUNCTIONS_GENERIC_ARG_HPP_INCLUDED
#define BOOST_SIMD_ARITHMETIC_FUNCTIONS_GENERIC_ARG_HPP_INCLUDED
#include <boost/simd/arithmetic/functions/arg.hpp>
#include <boost/simd/include/constants/pi.hpp>
#include <boost/simd/include/functions/simd/is_nan.hpp>
#include <boost/simd/include/functions/simd/is_ltz.hpp>
#include <boost/simd/include/functions/simd/if_else_zero.hpp>
#include <boost/simd/include/functions/simd/if_allbits_else.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_SIMD_FUNCTOR_IMPLEMENTATION( boost::simd::tag::arg_, tag::cpu_
                            , (A0)
                            , (generic_< floating_<A0> >)
                            )
  {
    typedef A0 result_type;
    BOOST_SIMD_FUNCTOR_CALL(1)
    {
      // a0 >= 0 -> 0, a0 < 0 ->Pi, a0 Nan -> Nan
      return if_nan_else(
        is_nan(a0),
        if_else_zero(is_ltz(a0),Pi<result_type>())
      );
    }
  };
} } }

#endif


#include <fstream>
#include <ros/ros.h>
#include <ros/package.h>
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>
#include <opencv2/core/eigen.hpp>

int main(int argc, char **argv)
{
  // Get path and file name
  std::string package_path = ros::package::getPath("crowdbot_active_slam");
  std::string sdf_path = package_path + "/" + argv[1];
  std::string sdf_true_path = package_path + "/" + argv[2];

  std::ifstream sdf_file(sdf_path.c_str());
  std::ifstream sdf_true_file(sdf_true_path.c_str());

  std::vector<std::vector<float>> pre_mat;
  std::string line;
  if (sdf_file.is_open()){
    while (std::getline(sdf_file, line)){
      std::stringstream ss;
      ss << line;
      float dist;
      std::vector<float> temp_vec;
      while (ss >> dist){
        temp_vec.push_back(dist);
      }
      pre_mat.push_back(temp_vec);
    }
  }
  else {
    ROS_INFO("Failed to open SDF file!");
  }

  int width = pre_mat.size();
  int height = pre_mat[0].size();
  Eigen::MatrixXf sdf_mat(width, height);
  for (int i = 0; i < width; i++){
    for (int j = 0; j < height; j++){
      sdf_mat(i, j) = pre_mat[i][j];
    }
  }

  std::vector<std::vector<float>> pre_true_mat;
  if (sdf_true_file.is_open()){
    while (std::getline(sdf_true_file, line)){
      std::stringstream ss;
      ss << line;
      float dist;
      std::vector<float> temp_vec;
      while (ss >> dist){
        temp_vec.push_back(dist);
      }
      pre_true_mat.push_back(temp_vec);
    }
  }
  else {
    ROS_INFO("Failed to open SDF file!");
  }

  Eigen::MatrixXf sdf_true_mat(width, height);
  for (int i = 0; i < width; i++){
    for (int j = 0; j < height; j++){
      sdf_true_mat(i, j) = pre_true_mat[i][j];
    }
  }

  Eigen::MatrixXf sdf_diff(width, height);
  sdf_diff = sdf_true_mat - sdf_mat;
  sdf_diff = sdf_diff.cwiseAbs();

  double max_error = 0;
  double min_error = 1000;
  for (int i = 0; i < width; i++){
    for (int j = 0; j < height; j++){
      // if (sdf_true_mat(i, j) < 0) sdf_diff(i, j) = 0;
      // if (sdf_diff(i, j) <= 1) sdf_diff(i, j) = 0;
      // else sdf_diff(i, j) -= 1;
      if (sdf_diff(i, j) > max_error) max_error = sdf_diff(i, j);
      if (sdf_diff(i, j) < min_error) min_error = sdf_diff(i, j);
    }
  }

  std::cout << "max_error: " << max_error << std::endl;
  std::cout << "min_error: " << min_error << std::endl;

  // Show SDF as image
  cv::Mat sdf_cv(width, height, CV_64F);
  cv::eigen2cv(sdf_diff, sdf_cv);

  cv::Mat image;
  cv::normalize(sdf_cv, image, 0, 1, cv::NORM_MINMAX);

  cv::namedWindow("Display window", cv::WINDOW_AUTOSIZE);
  cv::imshow("Display window", image);
  cv::waitKey(0);

  return 0;
}


//
//  Copyright (c) 2000-2002
//  Joerg Walter, Mathias Koch
//
//  Permission to use, copy, modify, distribute and sell this software
//  and its documentation for any purpose is hereby granted without fee,
//  provided that the above copyright notice appear in all copies and
//  that both that copyright notice and this permission notice appear
//  in supporting documentation.  The authors make no representations
//  about the suitability of this software for any purpose.
//  It is provided "as is" without express or implied warranty.
//
//  The authors gratefully acknowledge the support of
//  GeNeSys mbH & Co. KG in producing this work.
//

#ifdef BOOST_MSVC

#pragma warning (disable: 4355)
#pragma warning (disable: 4503)
#pragma warning (disable: 4786)

#endif

#include <iostream>
#include <string>

#include <boost/numeric/ublas/config.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_sparse.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>

#include <boost/timer.hpp>

#include "bench2.hpp"

template<class T, int N>
struct bench_c_matrix_prod {
    typedef T value_type;

    void operator () (int runs) const {
        try {
            static typename c_matrix_traits<T, N, N>::type m1, m2, m3;
            initialize_c_matrix<T, N, N> () (m1);
            initialize_c_matrix<T, N, N> () (m2);
            boost::timer t;
            for (int i = 0; i < runs; ++ i) {
                for (int j = 0; j < N; ++ j) {
                    for (int k = 0; k < N; ++ k) {
                        m3 [j] [k] = 0;
                        for (int l = 0; l < N; ++ l) {
                            m3 [j] [k] += m1 [j] [l] * m2 [l] [k];
                        }
                    }
                }
//                sink_c_matrix<T, N, N> () (m3);
            }
            footer<value_type> () (N * N * N, N * N * (N - 1), runs, t.elapsed ());
        }
        catch (std::exception &e) {
            std::cout << e.what () << std::endl;
        }
        catch (...) {
            std::cout << "unknown exception" << std::endl;
        }
    }
};
template<class M1, class M2, int N>
struct bench_my_matrix_prod {
    typedef typename M1::value_type value_type;

    void operator () (int runs, safe_tag) const {
        try {
            static M1 m1 (N, N, N * N), m3 (N, N, N * N);
            static M2 m2 (N, N, N * N);
            initialize_matrix (m1);
            initialize_matrix (m2);
            boost::timer t;
            for (int i = 0; i < runs; ++ i) {
                m3 = ublas::prod (m1, m2);
//                sink_matrix (m3);
            }
            footer<value_type> () (N * N * N, N * N * (N - 1), runs, t.elapsed ());
        }
        catch (std::exception &e) {
            std::cout << e.what () << std::endl;
        }
        catch (...) {
            std::cout << "unknown exception" << std::endl;
        }
    }
    void operator () (int runs, fast_tag) const {
        try {
            static M1 m1 (N, N, N * N), m3 (N, N, N * N);
            static M2 m2 (N, N, N * N);
            initialize_matrix (m1);
            initialize_matrix (m2);
            boost::timer t;
            for (int i = 0; i < runs; ++ i) {
                m3.assign (ublas::prod (m1, m2));
//                sink_matrix (m3);
            }
            footer<value_type> () (N * N * N, N * N * (N - 1), runs, t.elapsed ());
        }
        catch (std::exception &e) {
            std::cout << e.what () << std::endl;
        }
        catch (...) {
            std::cout << "unknown exception" << std::endl;
        }
    }
};
template<class M, int N>
struct bench_cpp_matrix_prod {
    typedef typename M::value_type value_type;

    void operator () (int runs) const {
        try {
            static M m1 (N * N), m2 (N * N), m3 (N * N);
            initialize_vector (m1);
            initialize_vector (m2);
            boost::timer t;
            for (int i = 0; i < runs; ++ i) {
                for (int j = 0; j < N; ++ j) {
                    std::valarray<value_type> row (m1 [std::slice (N * j, N, 1)]);
                    for (int k = 0; k < N; ++ k) {
                        std::valarray<value_type> column (m2 [std::slice (k, N, N)]);
                        m3 [N * j + k] = (row * column).sum ();
                    }
                }
//                sink_vector (m3);
            }
            footer<value_type> () (N * N * N, N * N * (N - 1), runs, t.elapsed ());
        }
        catch (std::exception &e) {
            std::cout << e.what () << std::endl;
        }
        catch (...) {
            std::cout << "unknown exception" << std::endl;
        }
    }
};

// Benchmark O (n ^ 3)
template<class T, int N>
void bench_3<T, N>::operator () (int runs) {
    header ("bench_3");

    header ("prod (matrix, matrix)");

    header ("C array");
    bench_c_matrix_prod<T, N> () (runs);

#ifdef USE_SPARSE_MATRIX
#ifdef USE_MAP_ARRAY
    header ("sparse_matrix<row_major, map_array>, sparse_matrix<column_major, map_array> safe");
    bench_my_matrix_prod<ublas::sparse_matrix<T, ublas::row_major, ublas::map_array<std::size_t, T> >,
                         ublas::sparse_matrix<T, ublas::column_major, ublas::map_array<std::size_t, T> >, N> () (runs, safe_tag ());

    header ("sparse_matrix<row_major, map_array>, sparse_matrix<column_major, map_array> fast");
    bench_my_matrix_prod<ublas::sparse_matrix<T, ublas::row_major, ublas::map_array<std::size_t, T> >,
                         ublas::sparse_matrix<T, ublas::column_major, ublas::map_array<std::size_t, T> >, N> () (runs, fast_tag ());
#endif

#ifdef USE_STD_MAP
    header ("sparse_matrix<row_major, std::map>, sparse_matrix<column_major, std::map> safe");
    bench_my_matrix_prod<ublas::sparse_matrix<T, ublas::row_major, std::map<std::size_t, T> >,
                         ublas::sparse_matrix<T, ublas::column_major, std::map<std::size_t, T> >, N> () (runs, safe_tag ());

    header ("sparse_matrix<row_major, std::map>, sparse_matrix<column_major, std::map> fast");
    bench_my_matrix_prod<ublas::sparse_matrix<T, ublas::row_major, std::map<std::size_t, T> >,
                         ublas::sparse_matrix<T, ublas::column_major, std::map<std::size_t, T> >, N> () (runs, fast_tag ());
#endif
#endif

#ifdef USE_COMPRESSED_MATRIX
    header ("compressed_matrix<row_major>, compressed_matrix<column_major> safe");
    bench_my_matrix_prod<ublas::compressed_matrix<T, ublas::row_major>,
                         ublas::compressed_matrix<T, ublas::column_major>, N> () (runs, safe_tag ());

    header ("compressed_matrix<row_major>, compressed_matrix<column_major> fast");
    bench_my_matrix_prod<ublas::compressed_matrix<T, ublas::row_major>,
                         ublas::compressed_matrix<T, ublas::column_major>, N> () (runs, fast_tag ());
#endif

#ifdef USE_COORDINATE_MATRIX
    header ("coordinate_matrix<row_major>, coordinate_matrix<column_major> safe");
    bench_my_matrix_prod<ublas::coordinate_matrix<T, ublas::row_major>,
                         ublas::coordinate_matrix<T, ublas::column_major>, N> () (runs, safe_tag ());

    header ("coordinate_matrix<row_major>, coordinate_matrix<column_major> fast");
    bench_my_matrix_prod<ublas::coordinate_matrix<T, ublas::row_major>,
                         ublas::coordinate_matrix<T, ublas::column_major>, N> () (runs, fast_tag ());
#endif

#ifdef USE_STD_VALARRAY
    header ("std::valarray");
    bench_cpp_matrix_prod<std::valarray<T>, N> () (runs);
#endif
}

#ifdef USE_FLOAT
template struct bench_3<float, 3>;
template struct bench_3<float, 10>;
template struct bench_3<float, 30>;
template struct bench_3<float, 100>;
#endif

#ifdef USE_DOUBLE
template struct bench_3<double, 3>;
template struct bench_3<double, 10>;
template struct bench_3<double, 30>;
template struct bench_3<double, 100>;
#endif

#ifdef USE_STD_COMPLEX
#ifdef USE_FLOAT
template struct bench_3<std::complex<float>, 3>;
template struct bench_3<std::complex<float>, 10>;
template struct bench_3<std::complex<float>, 30>;
template struct bench_3<std::complex<float>, 100>;
#endif

#ifdef USE_DOUBLE
template struct bench_3<std::complex<double>, 3>;
template struct bench_3<std::complex<double>, 10>;
template struct bench_3<std::complex<double>, 30>;
template struct bench_3<std::complex<double>, 100>;
#endif
#endif


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

#include <boost/test/unit_test.hpp>
#include "ParserFlatbuffersSerializeFixture.hpp"
#include "../Deserializer.hpp"

#include <string>
#include <iostream>

BOOST_AUTO_TEST_SUITE(Deserializer)

struct MeanFixture : public ParserFlatbuffersSerializeFixture
{
    explicit MeanFixture(const std::string &inputShape,
                         const std::string &outputShape,
                         const std::string &axis,
                         const std::string &dataType)
    {
        m_JsonString = R"(
            {
                inputIds: [0],
                outputIds: [2],
                layers: [
                    {
                        layer_type: "InputLayer",
                        layer: {
                            base: {
                                layerBindingId: 0,
                                base: {
                                    index: 0,
                                    layerName: "InputLayer",
                                    layerType: "Input",
                                    inputSlots: [{
                                        index: 0,
                                        connection: {sourceLayerIndex:0, outputSlotIndex:0 },
                                    }],
                                    outputSlots: [{
                                        index: 0,
                                        tensorInfo: {
                                            dimensions: )" + inputShape + R"(,
                                            dataType: )" + dataType + R"(
                                        }
                                    }]
                                }
                            }
                        }
                    },
                    {
                        layer_type: "MeanLayer",
                        layer: {
                            base: {
                                index: 1,
                                layerName: "MeanLayer",
                                layerType: "Mean",
                                inputSlots: [{
                                    index: 0,
                                    connection: {sourceLayerIndex:0, outputSlotIndex:0 },
                                }],
                                outputSlots: [{
                                    index: 0,
                                    tensorInfo: {
                                        dimensions: )" + outputShape + R"(,
                                        dataType: )" + dataType + R"(
                                    }
                                }]
                            },
                            descriptor: {
                                axis: )" + axis + R"(,
                                keepDims: true
                            }
                        }
                    },
                    {
                        layer_type: "OutputLayer",
                        layer: {
                            base:{
                                layerBindingId: 2,
                                base: {
                                    index: 2,
                                    layerName: "OutputLayer",
                                    layerType: "Output",
                                    inputSlots: [{
                                        index: 0,
                                        connection: {sourceLayerIndex:1, outputSlotIndex:0 },
                                    }],
                                    outputSlots: [{
                                        index: 0,
                                        tensorInfo: {
                                            dimensions: )" + outputShape + R"(,
                                            dataType: )" + dataType + R"(
                                        },
                                    }],
                                }
                            }
                        },
                    }
                ]
            }
        )";
        Setup();
    }
};

struct SimpleMeanFixture : MeanFixture
{
    SimpleMeanFixture()
        : MeanFixture("[ 1, 1, 3, 2 ]",     // inputShape
                      "[ 1, 1, 1, 2 ]",     // outputShape
                      "[ 2 ]",              // axis
                      "Float32")            // dataType
    {}
};

BOOST_FIXTURE_TEST_CASE(SimpleMean, SimpleMeanFixture)
{
    RunTest<4, armnn::DataType::Float32>(
         0,
         {{"InputLayer",  { 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f }}},
         {{"OutputLayer", { 2.0f, 2.0f }}});
}

BOOST_AUTO_TEST_SUITE_END()