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

/*
 Copyright (C) 2004, 2005, 2006, 2007 Ferdinando Ametrano
 Copyright (C) 2004, 2005, 2006, 2007, 2008 StatPro Italia srl
 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.
*/

#include <ql/types.hpp>
#include <ql/settings.hpp>
#include <ql/version.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/timer.hpp>

/* Use BOOST_MSVC instead of _MSC_VER since some other vendors (Metrowerks,
   for example) also #define _MSC_VER
*/
#ifdef BOOST_MSVC
#  include <ql/auto_link.hpp>
#  define BOOST_LIB_NAME boost_unit_test_framework
#  include <boost/config/auto_link.hpp>
#  undef BOOST_LIB_NAME

/* uncomment the following lines to unmask floating-point exceptions.
   See http://www.wilmott.com/messageview.cfm?catid=10&threadid=9481
*/
//#  include <float.h>
//   namespace { unsigned int u = _controlfp(_EM_INEXACT, _MCW_EM); }

#endif

#include <iostream>
#include <iomanip>
#include "utilities.hpp"

#include "adjointcreditdefaultswaptest.hpp"
#include "adjointzerospreadedtermstructuretest.hpp"
#include "adjointtermstructuretest.hpp"
#include "adjointbermudanswaptiontest.hpp"
#include "adjointeuropeanoptionportfoliotest.hpp"
#include "adjointmatricestest.hpp"
#include "adjointswaptionvolatilitycubetest.hpp"
#include "adjointpathgeneratortest.hpp"
#include "adjointpiecewiseyieldcurvetest.hpp"
#include "adjointmarketmodelcalibrationtest.hpp"
#include "adjointswaptiontest.hpp"
#include "adjointgjrgarchmodeltest.hpp"
#include "adjointgreekstest.hpp"
#include "adjointpiecewiseyieldcurvetest.hpp"
#include "adjointshortratemodelstest.hpp"
#include "adjointblackformulatest.hpp"
#include "adjointbondportfoliotest.hpp"
#include "adjointdistributiontest.hpp"
#include "adjointrealmathtest.hpp"
#include "adjointdefaultprobabilitycurvetest.hpp"
#include "adjointswaptest.hpp"
#include "adjointvariategeneratorstest.hpp"
#include "adjointfraportfoliotest.hpp"

#include "adjointarraytest.hpp"

#include "adjointcomplextest.hpp"
#include "adjointfastfouriertransformtest.hpp"
#include "adjointhestonprocesstest.hpp"
#include "adjointbatesmodeltest.hpp"
#include "adjointspecialfunctionstest.hpp"

using namespace boost::unit_test_framework;

namespace {

    boost::timer t;

    void startTimer() { t.restart(); }
    void stopTimer() {
        double seconds = t.elapsed();
        int hours = int(seconds/3600);
        seconds -= hours * 3600;
        int minutes = int(seconds/60);
        seconds -= minutes * 60;
        std::cout << " \nTests completed in ";
        if (hours > 0)
            std::cout << hours << " h ";
        if (hours > 0 || minutes > 0)
            std::cout << minutes << " m ";
        std::cout << std::fixed << std::setprecision(0)
                  << seconds << " s\n" << std::endl;
    }

    void configure() {
        /* if needed, either or both the lines below can be
           uncommented and/or changed to run the test suite with a
           different configuration. In the future, we'll need a
           mechanism that doesn't force us to recompile (possibly a
           couple of command-line flags for the test suite?)
        */

        //QuantLib::Settings::instance().includeReferenceDateCashFlows() = true;
        //QuantLib::Settings::instance().includeTodaysCashFlows() = boost::none;
    }

}

#if defined(QL_ENABLE_SESSIONS)
namespace QuantLib {

    Integer sessionId() { return 0; }

}
#endif

test_suite* init_unit_test_suite(int, char* []) {

    std::string header =
        " Testing "
            #ifdef BOOST_MSVC
            QL_LIB_NAME
            #else
            "QuantLib " QL_VERSION
            #endif
        "\n  QL_NEGATIVE_RATES "
            #ifdef QL_NEGATIVE_RATES
            "       defined"
            #else
            "     undefined"
            #endif
        "\n  QL_EXTRA_SAFETY_CHECKS "
            #ifdef QL_EXTRA_SAFETY_CHECKS
            "  defined"
            #else
            "undefined"
            #endif
        "\n  QL_USE_INDEXED_COUPON "
            #ifdef QL_USE_INDEXED_COUPON
            "   defined"
            #else
            " undefined"
            #endif
         ;

    std::string rule = std::string(35, '=');

    BOOST_TEST_MESSAGE(rule);
    BOOST_TEST_MESSAGE(header);
    BOOST_TEST_MESSAGE(rule);
    test_suite* test = BOOST_TEST_SUITE("QuantLib test suite");

    test->add(QUANTLIB_TEST_CASE(startTimer));
    test->add(QUANTLIB_TEST_CASE(configure));

//#   define CL_CERTAIN_TEST AdjointArrayTest

#if defined CL_CERTAIN_TEST
    test->add(CL_CERTAIN_TEST::suite());
#endif

#if !defined CL_ENABLE_BOOST_TEST_ADAPTER && !defined CL_CERTAIN_TEST
    test->add(AdjointBondPortfolioTest::suite());
    test->add(AdjointCreditDefaultSwapTest::suite());
    test->add(AdjointEuropeanOptionPortfolioTest::suite());
    test->add(AdjointGjrgarchModelTest::suite());
    test->add(AdjointFRAPortfolioTest::suite());
    test->add(AdjointMarketModelCalibrationTest::suite());
    test->add(AdjointMatricesTest::suite());
    test->add(AdjointPathGeneratorTest::suite());
    test->add(AdjointPiecewiseYieldCurveTest::suite());
    test->add(AdjointZeroSpreadedTermStructureTest::suite());
    test->add(AdjointShortRateModelsTest::suite());
    test->add(AdjointSwaptionTest::suite());
    test->add(AdjointSwaptionVolatilityCubeTest::suite());
    test->add(AdjointDistributionTest::suite());
    test->add(AdjointRealMathTest::suite());
    test->add(AdjointDefaultProbabilityCurveTest::suite());
    test->add(AdjointSwapTest::suite());
    test->add(AdjointVariateGeneratorsTest::suite());

# if defined FIXED_
    test->add(AdjointArrayTest::suite());
# endif

    //!!! Temporarily commented out until compilation error is fixed
    // test->add(AdjointGreeksTest::suite());

    test->add(AdjointHestonProcessTest::suite());

    // Complex Differentiation test
#if defined CL_TAPE_COMPLEX_ENABLED
    test->add(AdjointComplexTest::suite());
    test->add(AdjointFastFourierTransformTest::suite());
    test->add(AdjointBatesModelTest::suite());
    test->add(AdjointSpecialFunctionsTest::suite());
#endif

    // very slow
    test->add(AdjointBermudanSwaptionTest::suite());
    test->add(AdjointBlackFormulaTest::suite());
    test->add(AdjointTermStructureTest::suite());
#endif

    test->add(QUANTLIB_TEST_CASE(stopTimer));

    return test;
}


///////////////////////////////////////////////////////////////////////////////
// ordered_sample.hpp                                                        //
//                                                                           //
//  Copyright 2010 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_DETAIL_NON_PARAMETRIC_EMPIRICAL_DISTRIBUTION_ORDERED_SAMPLE_HPP_ER_2010
#define BOOST_STATISTICS_DETAIL_NON_PARAMETRIC_EMPIRICAL_DISTRIBUTION_ORDERED_SAMPLE_HPP_ER_2010
#include <map>
#include <functional>

#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/accumulators/statistics_fwd.hpp>

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

    // Usage:
    //     namespace ns = empirical_distribution;
    //     accumulator_set<T,stats<ns::tag::ordered_sample> > acc;
    //     acc = boost:for_each(samples,acc);
    //     ns::extract::ordered_sample(acc);
    // The result of the last statement is a sorted map associating each value
    // in the sample (of type T) with their number of occurences in the sample.

namespace impl{

    template<typename T>
    class ordered_sample : public boost::accumulators::accumulator_base{
        typedef std::less<T> comp_;
        typedef std::size_t size_;
        typedef boost::accumulators::dont_care dont_care_;
        typedef std::map<T,size_,comp_> map_;

        public:

        // See accumulator_set for convention naming sample_type
        typedef T 		sample_type;
        typedef size_ 	size_type;

        // non-const because map::operator[](key) returns a non-const
        typedef map_& result_type;

        ordered_sample(dont_care_){}

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

        // Returns the entire distribution, represented by a map
        result_type result(dont_care_)const{
            return (this->freq);
        }

        private:
        mutable map_ freq;
	};

}// impl

namespace tag
{

    struct ordered_sample
      : boost::accumulators::depends_on<>
    {
      typedef statistics::detail::empirical_distribution::
      	impl::ordered_sample<boost::mpl::_1> impl;
    };
}// tag

namespace result_of{

    template<typename AccSet>
    struct ordered_sample : boost::accumulators::detail::extractor_result<
        AccSet,
        boost::statistics::detail::empirical_distribution::tag::ordered_sample
    >{};

}// result_of

namespace extract
{

  	template<typename AccSet>
    typename boost::statistics::detail::empirical_distribution
    	::result_of::template ordered_sample<AccSet>::type
  	ordered_sample(AccSet const& acc)
    {
    	typedef boost::statistics::detail::empirical_distribution
    		::tag::ordered_sample the_tag;
        return boost::accumulators::extract_result<the_tag>(acc);
  	}

}// extract

using extract::ordered_sample;

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

#endif


////////////////////////////////////////////////////////////////////////////////
//  Copyright (c) 2015 Bryce Adelstein Lelbach aka wash
//
//  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 <mdspan>

#include <vector>
#include <tuple>

#include <boost/core/lightweight_test.hpp>

using std::vector;
using std::tuple;

using std::experimental::dyn;
using std::experimental::dimensions;
using std::experimental::layout_mapping_right;

template <
    std::size_t StepX, std::size_t StepY
  , std::size_t PadX, std::size_t PadY
  , std::size_t X, std::size_t Y
    >
void test_2d_static()
{ // {{{
    static_assert(0 == (X % StepX), "X must be divisable by StepX");
    static_assert(0 == (Y % StepY), "Y must be divisable by StepY");

    layout_mapping_right<
        dimensions<X, Y>
      , dimensions<1, 1>
      , dimensions<PadX, PadY>
    > const l{};

    BOOST_TEST_EQ((l.is_regular()), true);

    BOOST_TEST_EQ((l.stride(0)), 1);
    BOOST_TEST_EQ((l.stride(1)), 1);

    BOOST_TEST_EQ((l.size()), X * Y);
    BOOST_TEST_EQ((l.span()), (X + PadX) * (Y + PadY));

    layout_mapping_right<
        dimensions<X / StepX, Y / StepY>
      , dimensions<StepX, StepY>
      , dimensions<PadX, PadY>
    > const sub_l{};

    BOOST_TEST_EQ((sub_l.is_regular()), true);

    BOOST_TEST_EQ((sub_l.stride(0)), StepX);
    BOOST_TEST_EQ((sub_l.stride(1)), StepY);

    BOOST_TEST_EQ((sub_l.size()), (X / StepX) * (Y / StepY));
    BOOST_TEST_EQ((sub_l.span()), (X + PadX) * (Y + PadY));

    int dptr[(X + PadX) * (Y + PadY)];

    // Set all real elements to 42.
    for (auto j = 0; j < l[1]; ++j)
    for (auto i = 0; i < l[0]; ++i)
    {
        auto const true_idx = (l[1] + l.padding()[1]) * (i) + (j);

        BOOST_TEST_EQ((l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[l.index(i, j)]), &(dptr[true_idx]));

        dptr[l.index(i, j)] = 42;

        BOOST_TEST_EQ((dptr[l.index(i, j)]), 42);
    }

    // Set X pad elements to 17 and Y pad elements to 24.
    for (auto j = 0; j < l[1] + l.padding()[1]; ++j)
    for (auto i = 0; i < l[0] + l.padding()[0]; ++i)
    {
        auto const true_idx = (l[1] + l.padding()[1]) * (i) + (j);

        BOOST_TEST_EQ((l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[l.index(i, j)]), &(dptr[true_idx]));

        // X-pad element.
        if      ((l[0] <= i) && (i < (l[0] + l.padding()[0])))
        {
            dptr[l.index(i, j)] = 17;

            BOOST_TEST_EQ((dptr[l.index(i, j)]), 17);
        }

        // Y-pad element.
        else if ((l[1] <= j) && (j < (l[1] + l.padding()[1])))
        {
            dptr[l.index(i, j)] = 24;

            BOOST_TEST_EQ((dptr[l.index(i, j)]), 24);
        }
    }

    // Set every (StepXth, StepYth) element to 71.
    for (auto j = 0; j < sub_l[1]; ++j)
    for (auto i = 0; i < sub_l[0]; ++i)
    {
        auto const p = l.padding();
        auto const s = sub_l.stepping();
        auto const true_idx = (sub_l[1] * s[1] + p[1]) * (s[0] * i) + (s[1] * j);

        BOOST_TEST_EQ((sub_l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[sub_l.index(i, j)]), &(dptr[true_idx]));

        dptr[sub_l.index(i, j)] = 71;

        BOOST_TEST_EQ((dptr[sub_l.index(i, j)]), 71);
    }

    // Check final structure.
    for (auto j = 0; j < l[1] + l.padding()[1]; ++j)
    for (auto i = 0; i < l[0] + l.padding()[0]; ++i)
    {
        auto const true_idx = (l[1] + l.padding()[1]) * (i) + (j);

        BOOST_TEST_EQ((l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[l.index(i, j)]), &(dptr[true_idx]));

        // X-pad element.
        if      ((l[0] <= i) && (i < (l[0] + l.padding()[0])))
        {
            BOOST_TEST_EQ((dptr[l.index(i, j)]), 17);
        }

        // Y-pad element.
        else if ((l[1] <= j) && (j < (l[1] + l.padding()[1])))
        {
            BOOST_TEST_EQ((dptr[l.index(i, j)]), 24);
        }

        // Real element.
        else
        {
            // Real element in the strided sub-box.
            if (  (0 == (i % sub_l.stepping()[0]))
               && (0 == (j % sub_l.stepping()[1]))
               )
            {
                BOOST_TEST_EQ((dptr[l.index(i, j)]), 71);
            }
            // Real element not in the strided sub-box.
            else
            {
                BOOST_TEST_EQ((dptr[l.index(i, j)]), 42);
            }
        }
    }
} // }}}

template <
    std::size_t StepX, std::size_t StepY
  , std::size_t PadX, std::size_t PadY
  , std::size_t X, std::size_t Y
    >
void test_2d_dynamic()
{ // {{{
    layout_mapping_right<
        dimensions<dyn, dyn>
      , dimensions<dyn, dyn>
      , dimensions<dyn, dyn>
    > const l{{X, Y}, {1, 1}, {PadX, PadY}};

    BOOST_TEST_EQ((l.is_regular()), true);

    BOOST_TEST_EQ((l.stride(0)), 1);
    BOOST_TEST_EQ((l.stride(1)), 1);

    BOOST_TEST_EQ((l.size()), X * Y);
    BOOST_TEST_EQ((l.span()), (X + PadX) * (Y + PadY));

    layout_mapping_right<
        dimensions<dyn, dyn>
      , dimensions<dyn, dyn>
      , dimensions<dyn, dyn>
    > const sub_l{{X / StepX, Y / StepY}, {StepX, StepY}, {PadX, PadY}};

    BOOST_TEST_EQ((sub_l.is_regular()), true);

    BOOST_TEST_EQ((sub_l.stride(0)), StepX);
    BOOST_TEST_EQ((sub_l.stride(1)), StepY);

    BOOST_TEST_EQ((sub_l.size()), (X / StepX) * (Y / StepY));
    BOOST_TEST_EQ((sub_l.span()), (X + PadX) * (Y + PadY));

    // Initialize all elements to 42.
    std::vector<int> data(
        (l[0] + l.padding()[0]) * (l[1] + l.padding()[1]), 42
    );
    int* dptr = data.data();

    // Set X pad elements to 17 and Y pad elements to 24.
    for (auto j = 0; j < l[1] + l.padding()[1]; ++j)
    for (auto i = 0; i < l[0] + l.padding()[0]; ++i)
    {
        auto const true_idx = (l[1] + l.padding()[1]) * (i) + (j);

        BOOST_TEST_EQ((l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[l.index(i, j)]), &(dptr[true_idx]));

        // X-pad element.
        if      ((l[0] <= i) && (i < (l[0] + l.padding()[0])))
        {
            dptr[l.index(i, j)] = 17;

            BOOST_TEST_EQ((dptr[l.index(i, j)]), 17);

            // Bounds-checking.
            BOOST_TEST_EQ((data.at(l.index(i, j))), 17);
        }

        // Y-pad element.
        else if ((l[1] <= j) && (j < (l[1] + l.padding()[1])))
        {
            dptr[l.index(i, j)] = 24;

            BOOST_TEST_EQ((dptr[l.index(i, j)]), 24);

            // Bounds-checking.
            BOOST_TEST_EQ((data.at(l.index(i, j))), 24);
        }
    }

    // Set every (StepXth, StepYth) element to 71.
    for (auto j = 0; j < sub_l[1]; ++j)
    for (auto i = 0; i < sub_l[0]; ++i)
    {
        auto const p = l.padding();
        auto const s = sub_l.stepping();
        auto const true_idx = (sub_l[1] * s[1] + p[1]) * (s[0] * i) + (s[1] * j);

        BOOST_TEST_EQ((sub_l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[sub_l.index(i, j)]), &(dptr[true_idx]));

        dptr[sub_l.index(i, j)] = 71;

        BOOST_TEST_EQ((dptr[sub_l.index(i, j)]), 71);

        // Bounds-checking.
        BOOST_TEST_EQ((data.at(sub_l.index(i, j))), 71);
    }

    // Check final structure.
    for (auto j = 0; j < l[1] + l.padding()[1]; ++j)
    for (auto i = 0; i < l[0] + l.padding()[0]; ++i)
    {
        auto const true_idx = (l[1] + l.padding()[1]) * (i) + (j);

        BOOST_TEST_EQ((l.index(i, j)), true_idx);

        BOOST_TEST_EQ(&(dptr[l.index(i, j)]), &(dptr[true_idx]));

        // X-pad element.
        if      ((l[0] <= i) && (i < (l[0] + l.padding()[0])))
        {
            BOOST_TEST_EQ((dptr[l.index(i, j)]), 17);

            // Bounds-checking.
            BOOST_TEST_EQ((data.at(l.index(i, j))), 17);
        }

        // Y-pad element.
        else if ((l[1] <= j) && (j < (l[1] + l.padding()[1])))
        {
            BOOST_TEST_EQ((dptr[l.index(i, j)]), 24);

            // Bounds-checking.
            BOOST_TEST_EQ((data.at(l.index(i, j))), 24);
        }

        // Real element.
        else
        {
            // Real element in the strided sub-box.
            if (  (0 == (i % sub_l.stepping()[0]))
               && (0 == (j % sub_l.stepping()[1]))
               )
            {
                BOOST_TEST_EQ((dptr[l.index(i, j)]), 71);

                // Bounds-checking.
                BOOST_TEST_EQ((data.at(l.index(i, j))), 71);
            }
            // Real element not in the strided sub-box.
            else
            {
                BOOST_TEST_EQ((dptr[l.index(i, j)]), 42);

                // Bounds-checking.
                BOOST_TEST_EQ((data.at(l.index(i, j))), 42);
            }
        }
    }
} // }}}

int main()
{
    ///////////////////////////////////////////////////////////////////////////
    // 2D Static

    //             Stepping   Padding   Dimensions
    test_2d_static<5, 1,      1, 0,     30, 30>();
    test_2d_static<1, 5,      1, 0,     30, 30>();
    test_2d_static<5, 5,      1, 0,     30, 30>();
    test_2d_static<5, 1,      0, 1,     30, 30>();
    test_2d_static<1, 5,      0, 1,     30, 30>();
    test_2d_static<5, 5,      0, 1,     30, 30>();
    test_2d_static<5, 1,      1, 0,     30, 30>();
    test_2d_static<1, 5,      1, 0,     30, 30>();
    test_2d_static<5, 5,      1, 0,     30, 30>();
    test_2d_static<5, 1,      1, 1,     30, 30>();
    test_2d_static<1, 5,      1, 1,     30, 30>();

    test_2d_static<5, 5,      1, 1,     30, 30>();
    test_2d_static<5, 1,      1, 0,     30, 30>();
    test_2d_static<1, 5,      1, 0,     30, 30>();
    test_2d_static<5, 5,      1, 0,     30, 30>();
    test_2d_static<5, 1,      0, 1,     30, 30>();
    test_2d_static<1, 5,      0, 1,     30, 30>();
    test_2d_static<5, 5,      0, 1,     30, 30>();
    test_2d_static<5, 1,      1, 0,     30, 30>();
    test_2d_static<1, 5,      1, 0,     30, 30>();
    test_2d_static<5, 5,      1, 0,     30, 30>();
    test_2d_static<5, 1,      1, 1,     30, 30>();
    test_2d_static<1, 5,      1, 1,     30, 30>();
    test_2d_static<5, 5,      1, 1,     30, 30>();

    ///////////////////////////////////////////////////////////////////////////
    // 2D Dynamic

    //              Stepping   Padding   Dimensions
    test_2d_dynamic<5, 1,      1, 0,     30, 30>();
    test_2d_dynamic<1, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 1,      0, 1,     30, 30>();
    test_2d_dynamic<1, 5,      0, 1,     30, 30>();
    test_2d_dynamic<5, 5,      0, 1,     30, 30>();
    test_2d_dynamic<5, 1,      1, 0,     30, 30>();
    test_2d_dynamic<1, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 1,      1, 1,     30, 30>();
    test_2d_dynamic<1, 5,      1, 1,     30, 30>();

    test_2d_dynamic<5, 5,      1, 1,     30, 30>();
    test_2d_dynamic<5, 1,      1, 0,     30, 30>();
    test_2d_dynamic<1, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 1,      0, 1,     30, 30>();
    test_2d_dynamic<1, 5,      0, 1,     30, 30>();
    test_2d_dynamic<5, 5,      0, 1,     30, 30>();
    test_2d_dynamic<5, 1,      1, 0,     30, 30>();
    test_2d_dynamic<1, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 5,      1, 0,     30, 30>();
    test_2d_dynamic<5, 1,      1, 1,     30, 30>();
    test_2d_dynamic<1, 5,      1, 1,     30, 30>();
    test_2d_dynamic<5, 5,      1, 1,     30, 30>();

    return boost::report_errors();
}


/* Copyright (C) 2012-2017 IBM Corp.
 * This program is 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. See accompanying LICENSE file.
 */
namespace std {} using namespace std;
namespace NTL {} using namespace NTL;

#include <NTL/BasicThreadPool.h>

#include "EvalMap.h"
#include "hypercube.h"
#include "powerful.h"

NTL_CLIENT

static bool dry = false; // a dry-run flag
static bool noPrint = true;

void  TestIt(long p, long r, long c, long _k,
             long L, Vec<long>& mvec,
             Vec<long>& gens, Vec<long>& ords, long useCache)
{
  if (lsize(mvec)<1) { // use default values
    mvec.SetLength(3); gens.SetLength(3); ords.SetLength(3);
    mvec[0] = 7;    mvec[1] = 3;    mvec[2] = 221;
    gens[0] = 3979; gens[1] = 3095; gens[2] = 3760;
    ords[0] = 6;    ords[1] = 2;    ords[2] = -8;
  }
  if (!noPrint)
    cout << "*** TestIt"
       << (dry? " (dry run):" : ":")
       << " p=" << p
       << ", r=" << r
       << ", c=" << c
       << ", k=" << _k
       << ", L=" << L
       << ", mvec=" << mvec << ", "
       << ", useCache = " << useCache
       << endl;

  setTimersOn();
  setDryRun(false); // Need to get a "real context" to test EvalMap

  // mvec is supposed to include the prime-power factorization of m
  long nfactors = mvec.length();
  for (long i = 0; i < nfactors; i++)
    for (long j = i+1; j < nfactors; j++)
      assert(GCD(mvec[i], mvec[j]) == 1);

  // multiply all the prime powers to get m itself
  long m = computeProd(mvec);
  assert(GCD(p, m) == 1);

  // build a context with these generators and orders
  vector<long> gens1, ords1;
  convert(gens1, gens);
  convert(ords1, ords);
  FHEcontext context(m, p, r, gens1, ords1);
  buildModChain(context, L, c);

  if (!noPrint) {
    context.zMStar.printout(); // print structure of Zm* /(p) to cout
    cout << endl;
  }
  long d = context.zMStar.getOrdP();
  long phim = context.zMStar.getPhiM();
  long nslots = phim/d;

  setDryRun(dry); // Now we can set the dry-run flag if desired

  FHESecKey secretKey(context);
  const FHEPubKey& publicKey = secretKey;
  secretKey.GenSecKey(); // A Hamming-weight-w secret key
  addSome1DMatrices(secretKey); // compute key-switching matrices that we need
  addFrbMatrices(secretKey); // compute key-switching matrices that we need

  // GG defines the plaintext space Z_p[X]/GG(X)
  ZZX GG;
  GG = context.alMod.getFactorsOverZZ()[0];
  EncryptedArray ea(context, GG);

  zz_p::init(context.alMod.getPPowR());
  zz_pX F;
  random(F, phim); // a random polynomial of degree phi(m)-1 modulo p

  // convert F to powerful representation: cube represents a multi-variate
  // polynomial with as many variables Xi as factors mi in mvec. cube has
  // degree phi(mi) in the variable Xi, and the coefficients are given
  // in lexicographic order.

  // compute tables for converting between powerful and zz_pX
  PowerfulTranslationIndexes ind(mvec); // indpendent of p
  PowerfulConversion pConv(ind);        // depends on p

  HyperCube<zz_p> cube(pConv.getShortSig());
  pConv.polyToPowerful(cube, F);

  // Sanity check: convert back and compare
  zz_pX F2;
  pConv.powerfulToPoly(F2, cube);
  if (F != F2) {
    cout << "BAD\n";
    if (!noPrint) cout << " @@@ conversion error ):\n";
  }
  // pack the coefficients from cube in the plaintext slots: the j'th
  // slot contains the polynomial pj(X) = \sum_{t=0}^{d-1} cube[jd+t] X^t
  vector<ZZX> val1;
  val1.resize(nslots);
  for (long i = 0; i < phim; i++) {
    val1[i/d] += conv<ZZX>(conv<ZZ>(cube[i])) << (i % d);
  }
  PlaintextArray pa1(ea);
  encode(ea, pa1, val1);

  Ctxt ctxt(publicKey);
  ea.encrypt(ctxt, publicKey, pa1);

  resetAllTimers();
  FHE_NTIMER_START(ALL);

  // Compute homomorphically the transformation that takes the
  // coefficients packed in the slots and produces the polynomial
  // corresponding to cube

  if (!noPrint) CheckCtxt(ctxt, "init");

  if (!noPrint) cout << "build EvalMap\n";
  EvalMap map(ea, /*minimal=*/false, mvec,
    /*invert=*/false, /*build_cache=*/false, /*normal_basis=*/false);
  // compute the transformation to apply

  if (!noPrint) cout << "apply EvalMap\n";
  if (useCache) map.upgrade();
  map.apply(ctxt); // apply the transformation to ctxt
  if (!noPrint) CheckCtxt(ctxt, "EvalMap");
  if (!noPrint) cout << "check results\n";

  ZZX FF1;
  secretKey.Decrypt(FF1, ctxt);
  zz_pX F1 = conv<zz_pX>(FF1);

  if (F1 == F)
    cout << "GOOD\n";
  else
    cout << "BAD\n";

  publicKey.Encrypt(ctxt, FF1);
  if (!noPrint) CheckCtxt(ctxt, "init");

  // Compute homomorphically the inverse transformation that takes the
  // polynomial corresponding to cube and produces the coefficients
  // packed in the slots

  if (!noPrint) cout << "build EvalMap\n";
  EvalMap imap(ea, /*minimal=*/false, mvec,
    /*invert=*/true, /*build_cache=*/false, /*normal_basis=*/false);
  // compute the transformation to apply
  if (!noPrint) cout << "apply EvalMap\n";
  if (useCache) imap.upgrade();
  imap.apply(ctxt); // apply the transformation to ctxt
  if (!noPrint) {
    CheckCtxt(ctxt, "EvalMap");
    cout << "check results\n";
  }
  PlaintextArray pa2(ea);
  ea.decrypt(ctxt, secretKey, pa2);

  if (equals(ea, pa1, pa2))
    cout << "GOOD\n";
  else
    cout << "BAD\n";
  FHE_NTIMER_STOP(ALL);

  if (!noPrint) {
    cout << "\n*********\n";
    printAllTimers();
    cout << endl;
  }
}

/* Usage: Test_EvalMap_x.exe [ name=value ]...
 *  p       plaintext base  [ default=2 ]
 *  r       lifting  [ default=1 ]
 *  c       number of columns in the key-switching matrices  [ default=2 ]
 *  k       security parameter  [ default=80 ]
 *  L       # of bits in the modulus chain
 *  s       minimum number of slots  [ default=0 ]
 *  seed    PRG seed  [ default=0 ]
 *  mvec    use specified factorization of m
 *             e.g., mvec='[5 3 187]'
 *  gens    use specified vector of generators
 *             e.g., gens='[562 1871 751]'
 *  ords    use specified vector of orders
 *             e.g., ords='[4 2 -4]', negative means 'bad'
 */
int main(int argc, char *argv[])
{
  ArgMapping amap;

  long p=2;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  long c=2;
  amap.arg("c", c, "number of columns in the key-switching matrices");

  long k=80;
  amap.arg("k", k, "security parameter");

  long L=300;
  amap.arg("L", L, "# of bits in the modulus chain");

  long s=0;
  amap.arg("s", s, "minimum number of slots");

  long seed=0;
  amap.arg("seed", seed, "PRG seed");

  Vec<long> mvec;
  amap.arg("mvec", mvec, "use specified factorization of m", NULL);
  amap.note("e.g., mvec='[7 3 221]'");

  Vec<long> gens;
  amap.arg("gens", gens, "use specified vector of generators", NULL);
  amap.note("e.g., gens='[3979 3095 3760]'");

  Vec<long> ords;
  amap.arg("ords", ords, "use specified vector of orders", NULL);
  amap.note("e.g., ords='[6 2 -8]', negative means 'bad'");

  amap.arg("dry", dry, "a dry-run flag to check the noise");

  long nthreads=1;
  amap.arg("nthreads", nthreads, "number of threads");

  amap.arg("noPrint", noPrint, "suppress printouts");

  long useCache=0;
  amap.arg("useCache", useCache, "0: zzX cache, 2: DCRT cache");

  amap.parse(argc, argv);

  SetNumThreads(nthreads);

  SetSeed(conv<ZZ>(seed));
  TestIt(p, r, c, k, L, mvec, gens, ords, useCache);
}

// ./Test_EvalMap_x mvec="[73 433]" gens="[18620 12995]" ords="[72 -6]"


/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @file testExpressionFactor.cpp
 * @date September 18, 2014
 * @author Frank Dellaert
 * @author Paul Furgale
 * @brief unit tests for Block Automatic Differentiation
 */

#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/Testable.h>
#include <gtsam/nonlinear/ExpressionFactor.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/nonlinear/PriorFactor.h>
#include <gtsam/nonlinear/expressionTesting.h>
#include <gtsam/slam/GeneralSFMFactor.h>
#include <gtsam/slam/ProjectionFactor.h>
#include <gtsam/slam/expressions.h>

#include <boost/assign/list_of.hpp>
using boost::assign::list_of;
using namespace std::placeholders;

using namespace std;
using namespace gtsam;

Point2 measured(-17, 30);
SharedNoiseModel model = noiseModel::Unit::Create(2);

// This deals with the overload problem and makes the expressions factor
// understand that we work on Point3
Point2 (*Project)(const Point3&, OptionalJacobian<2, 3>) = &PinholeBase::Project;

namespace leaf {
// Create some values
struct MyValues: public Values {
  MyValues() {
    insert(2, Point2(3, 5));
  }
} values;

// Create leaf
Point2_ p(2);
}

/* ************************************************************************* */
// Leaf
TEST(ExpressionFactor, Leaf) {
  using namespace leaf;

  // Create old-style factor to create expected value and derivatives.
  PriorFactor<Point2> old(2, Point2(0, 0), model);

  // Create the equivalent factor with expression.
  ExpressionFactor<Point2> f(model, Point2(0, 0), p);

  // Check values and derivatives.
  EXPECT_DOUBLES_EQUAL(old.error(values), f.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f.dim());
  boost::shared_ptr<GaussianFactor> gf2 = f.linearize(values);
  EXPECT(assert_equal(*old.linearize(values), *gf2, 1e-9));
}

/* ************************************************************************* */
// Test leaf expression with noise model of different variance.
TEST(ExpressionFactor, Model) {
  using namespace leaf;

  SharedNoiseModel model = noiseModel::Diagonal::Sigmas(Vector2(0.1, 0.01));

  // Create old-style factor to create expected value and derivatives.
  PriorFactor<Point2> old(2, Point2(0, 0), model);

  // Create the equivalent factor with expression.
  ExpressionFactor<Point2> f(model, Point2(0, 0), p);

  // Check values and derivatives.
  EXPECT_DOUBLES_EQUAL(old.error(values), f.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f.dim());
  boost::shared_ptr<GaussianFactor> gf2 = f.linearize(values);
  EXPECT(assert_equal(*old.linearize(values), *gf2, 1e-9));
  EXPECT_CORRECT_FACTOR_JACOBIANS(f, values, 1e-5, 1e-5); // another way
}

/* ************************************************************************* */
// Test leaf expression with constrained noise model.
TEST(ExpressionFactor, Constrained) {
  using namespace leaf;

  SharedDiagonal model = noiseModel::Constrained::MixedSigmas(Vector2(0.2, 0));

  // Create old-style factor to create expected value and derivatives
  PriorFactor<Point2> old(2, Point2(0, 0), model);

  // Concise version
  ExpressionFactor<Point2> f(model, Point2(0, 0), p);
  EXPECT_DOUBLES_EQUAL(old.error(values), f.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f.dim());
  boost::shared_ptr<GaussianFactor> gf2 = f.linearize(values);
  EXPECT(assert_equal(*old.linearize(values), *gf2, 1e-9));
}

/* ************************************************************************* */
// Unary(Leaf))
TEST(ExpressionFactor, Unary) {

  // Create some values
  Values values;
  values.insert(2, Point3(0, 0, 1));

  JacobianFactor expected( //
      2, (Matrix(2, 3) << 1, 0, 0, 0, 1, 0).finished(), //
      Vector2(-17, 30));

  // Create leaves
  Point3_ p(2);

  // Concise version
  ExpressionFactor<Point2> f(model, measured, project(p));
  EXPECT_LONGS_EQUAL(2, f.dim());
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  boost::shared_ptr<JacobianFactor> jf = //
      boost::dynamic_pointer_cast<JacobianFactor>(gf);
  EXPECT(assert_equal(expected, *jf, 1e-9));
}

/* ************************************************************************* */
// Unary(Leaf)) and Unary(Unary(Leaf)))
// wide version (not handled in fixed-size pipeline)
typedef Eigen::Matrix<double,9,3> Matrix93;
Vector9 wide(const Point3& p, OptionalJacobian<9,3> H) {
  Vector9 v;
  v << p, p, p;
  if (H) *H << I_3x3, I_3x3, I_3x3;
  return v;
}

typedef Eigen::Matrix<double,9,9> Matrix9;
Vector9 id9(const Vector9& v, OptionalJacobian<9,9> H) {
  if (H) *H = Matrix9::Identity();
  return v;
}

TEST(ExpressionFactor, Wide) {
  // Create some values
  Values values;
  values.insert(2, Point3(0, 0, 1));
  Point3_ point(2);
  Vector9 measured;
  measured.setZero();
  Expression<Vector9> expression(wide,point);
  SharedNoiseModel model = noiseModel::Unit::Create(9);

  ExpressionFactor<Vector9> f1(model, measured, expression);
  EXPECT_CORRECT_FACTOR_JACOBIANS(f1, values, 1e-5, 1e-9);

  Expression<Vector9> expression2(id9,expression);
  ExpressionFactor<Vector9> f2(model, measured, expression2);
  EXPECT_CORRECT_FACTOR_JACOBIANS(f2, values, 1e-5, 1e-9);
}

/* ************************************************************************* */
static Point2 myUncal(const Cal3_S2& K, const Point2& p,
    OptionalJacobian<2,5> Dcal, OptionalJacobian<2,2> Dp) {
  return K.uncalibrate(p, Dcal, Dp);
}

// Binary(Leaf,Leaf)
TEST(ExpressionFactor, Binary) {

  typedef internal::BinaryExpression<Point2, Cal3_S2, Point2> Binary;

  Cal3_S2_ K_(1);
  Point2_ p_(2);
  Binary binary(myUncal, K_, p_);

  // Create some values
  Values values;
  values.insert(1, Cal3_S2());
  values.insert(2, Point2(0, 0));

  // Check size
  size_t size = binary.traceSize();
  // Use Variable Length Array, allocated on stack by gcc
  // Note unclear for Clang: http://clang.llvm.org/compatibility.html#vla
  internal::ExecutionTraceStorage traceStorage[size];
  internal::ExecutionTrace<Point2> trace;
  Point2 value = binary.traceExecution(values, trace, traceStorage);
  EXPECT(assert_equal(Point2(0,0),value, 1e-9));
  // trace.print();

  // Expected Jacobians
  Matrix25 expected25;
  expected25 << 0, 0, 0, 1, 0, 0, 0, 0, 0, 1;
  Matrix2 expected22;
  expected22 << 1, 0, 0, 1;

  // Check matrices
  boost::optional<Binary::Record*> r = trace.record<Binary::Record>();
  CHECK(r);
  EXPECT(assert_equal(expected25, (Matrix ) (*r)->dTdA1, 1e-9));
  EXPECT(assert_equal(expected22, (Matrix ) (*r)->dTdA2, 1e-9));
}

/* ************************************************************************* */
// Unary(Binary(Leaf,Leaf))
TEST(ExpressionFactor, Shallow) {

  // Create some values
  Values values;
  values.insert(1, Pose3());
  values.insert(2, Point3(0, 0, 1));

  // Create old-style factor to create expected value and derivatives
  GenericProjectionFactor<Pose3, Point3> old(measured, model, 1, 2,
      boost::make_shared<Cal3_S2>());
  double expected_error = old.error(values);
  GaussianFactor::shared_ptr expected = old.linearize(values);

  // Create leaves
  Pose3_ x_(1);
  Point3_ p_(2);

  // Construct expression, concise evrsion
  Point2_ expression = project(transformTo(x_, p_));

  // Get and check keys and dims
  KeyVector keys;
  FastVector<int> dims;
  boost::tie(keys, dims) = expression.keysAndDims();
  LONGS_EQUAL(2,keys.size());
  LONGS_EQUAL(2,dims.size());
  LONGS_EQUAL(1,keys[0]);
  LONGS_EQUAL(2,keys[1]);
  LONGS_EQUAL(6,dims[0]);
  LONGS_EQUAL(3,dims[1]);

  // traceExecution of shallow tree
  typedef internal::UnaryExpression<Point2, Point3> Unary;
  size_t size = expression.traceSize();
  internal::ExecutionTraceStorage traceStorage[size];
  internal::ExecutionTrace<Point2> trace;
  Point2 value = expression.traceExecution(values, trace, traceStorage);
  EXPECT(assert_equal(Point2(0,0),value, 1e-9));
  // trace.print();

  // Expected Jacobians
  Matrix23 expected23;
  expected23 << 1, 0, 0, 0, 1, 0;

  // Check matrices
  boost::optional<Unary::Record*> r = trace.record<Unary::Record>();
  CHECK(r);
  EXPECT(assert_equal(expected23, (Matrix)(*r)->dTdA1, 1e-9));

  // Linearization
  ExpressionFactor<Point2> f2(model, measured, expression);
  EXPECT_DOUBLES_EQUAL(expected_error, f2.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f2.dim());
  boost::shared_ptr<GaussianFactor> gf2 = f2.linearize(values);
  EXPECT(assert_equal(*expected, *gf2, 1e-9));
}

/* ************************************************************************* */
// Binary(Leaf,Unary(Binary(Leaf,Leaf)))
TEST(ExpressionFactor, tree) {

  // Create some values
  Values values;
  values.insert(1, Pose3());
  values.insert(2, Point3(0, 0, 1));
  values.insert(3, Cal3_S2());

  // Create old-style factor to create expected value and derivatives
  GeneralSFMFactor2<Cal3_S2> old(measured, model, 1, 2, 3);
  double expected_error = old.error(values);
  GaussianFactor::shared_ptr expected = old.linearize(values);

  // Create leaves
  Pose3_ x(1);
  Point3_ p(2);
  Cal3_S2_ K(3);

  // Create expression tree
  Point3_ p_cam(x, &Pose3::transformTo, p);
  Point2_ xy_hat(Project, p_cam);
  Point2_ uv_hat(K, &Cal3_S2::uncalibrate, xy_hat);

  // Create factor and check value, dimension, linearization
  ExpressionFactor<Point2> f(model, measured, uv_hat);
  EXPECT_DOUBLES_EQUAL(expected_error, f.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f.dim());
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  EXPECT(assert_equal(*expected, *gf, 1e-9));

  // Concise version
  ExpressionFactor<Point2> f2(model, measured,
      uncalibrate(K, project(transformTo(x, p))));
  EXPECT_DOUBLES_EQUAL(expected_error, f2.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f2.dim());
  boost::shared_ptr<GaussianFactor> gf2 = f2.linearize(values);
  EXPECT(assert_equal(*expected, *gf2, 1e-9));

  // Try ternary version
  ExpressionFactor<Point2> f3(model, measured, project3(x, p, K));
  EXPECT_DOUBLES_EQUAL(expected_error, f3.error(values), 1e-9);
  EXPECT_LONGS_EQUAL(2, f3.dim());
  boost::shared_ptr<GaussianFactor> gf3 = f3.linearize(values);
  EXPECT(assert_equal(*expected, *gf3, 1e-9));
}

/* ************************************************************************* */
TEST(ExpressionFactor, Compose1) {

  // Create expression
  Rot3_ R1(1), R2(2);
  Rot3_ R3 = R1 * R2;

  // Create factor
  ExpressionFactor<Rot3> f(noiseModel::Unit::Create(3), Rot3(), R3);

  // Create some values
  Values values;
  values.insert(1, Rot3());
  values.insert(2, Rot3());

  // Check unwhitenedError
  std::vector<Matrix> H(2);
  Vector actual = f.unwhitenedError(values, H);
  EXPECT(assert_equal(I_3x3, H[0],1e-9));
  EXPECT(assert_equal(I_3x3, H[1],1e-9));

  // Check linearization
  JacobianFactor expected(1, I_3x3, 2, I_3x3, Z_3x1);
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  boost::shared_ptr<JacobianFactor> jf = //
      boost::dynamic_pointer_cast<JacobianFactor>(gf);
  EXPECT(assert_equal(expected, *jf,1e-9));
}

/* ************************************************************************* */
// Test compose with arguments referring to the same rotation
TEST(ExpressionFactor, compose2) {

  // Create expression
  Rot3_ R1(1), R2(1);
  Rot3_ R3 = R1 * R2;

  // Create factor
  ExpressionFactor<Rot3> f(noiseModel::Unit::Create(3), Rot3(), R3);

  // Create some values
  Values values;
  values.insert(1, Rot3());

  // Check unwhitenedError
  std::vector<Matrix> H(1);
  Vector actual = f.unwhitenedError(values, H);
  EXPECT_LONGS_EQUAL(1, H.size());
  EXPECT(assert_equal(2*I_3x3, H[0],1e-9));

  // Check linearization
  JacobianFactor expected(1, 2 * I_3x3, Z_3x1);
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  boost::shared_ptr<JacobianFactor> jf = //
      boost::dynamic_pointer_cast<JacobianFactor>(gf);
  EXPECT(assert_equal(expected, *jf,1e-9));
}

/* ************************************************************************* */
// Test compose with one arguments referring to a constant same rotation
TEST(ExpressionFactor, compose3) {

  // Create expression
  Rot3_ R1(Rot3::identity()), R2(3);
  Rot3_ R3 = R1 * R2;

  // Create factor
  ExpressionFactor<Rot3> f(noiseModel::Unit::Create(3), Rot3(), R3);

  // Create some values
  Values values;
  values.insert(3, Rot3());

  // Check unwhitenedError
  std::vector<Matrix> H(1);
  Vector actual = f.unwhitenedError(values, H);
  EXPECT_LONGS_EQUAL(1, H.size());
  EXPECT(assert_equal(I_3x3, H[0],1e-9));

  // Check linearization
  JacobianFactor expected(3, I_3x3, Z_3x1);
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  boost::shared_ptr<JacobianFactor> jf = //
      boost::dynamic_pointer_cast<JacobianFactor>(gf);
  EXPECT(assert_equal(expected, *jf,1e-9));
}

/* ************************************************************************* */
// Test compose with three arguments
Rot3 composeThree(const Rot3& R1, const Rot3& R2, const Rot3& R3,
    OptionalJacobian<3, 3> H1, OptionalJacobian<3, 3> H2, OptionalJacobian<3, 3> H3) {
  // return dummy derivatives (not correct, but that's ok for testing here)
  if (H1)
    *H1 = I_3x3;
  if (H2)
    *H2 = I_3x3;
  if (H3)
    *H3 = I_3x3;
  return R1 * (R2 * R3);
}

TEST(ExpressionFactor, composeTernary) {

  // Create expression
  Rot3_ A(1), B(2), C(3);
  Rot3_ ABC(composeThree, A, B, C);

  // Create factor
  ExpressionFactor<Rot3> f(noiseModel::Unit::Create(3), Rot3(), ABC);

  // Create some values
  Values values;
  values.insert(1, Rot3());
  values.insert(2, Rot3());
  values.insert(3, Rot3());

  // Check unwhitenedError
  std::vector<Matrix> H(3);
  Vector actual = f.unwhitenedError(values, H);
  EXPECT_LONGS_EQUAL(3, H.size());
  EXPECT(assert_equal(I_3x3, H[0],1e-9));
  EXPECT(assert_equal(I_3x3, H[1],1e-9));
  EXPECT(assert_equal(I_3x3, H[2],1e-9));

  // Check linearization
  JacobianFactor expected(1, I_3x3, 2, I_3x3, 3, I_3x3, Z_3x1);
  boost::shared_ptr<GaussianFactor> gf = f.linearize(values);
  boost::shared_ptr<JacobianFactor> jf = //
      boost::dynamic_pointer_cast<JacobianFactor>(gf);
  EXPECT(assert_equal(expected, *jf,1e-9));
}

TEST(ExpressionFactor, tree_finite_differences) {

  // Create some values
  Values values;
  values.insert(1, Pose3());
  values.insert(2, Point3(0, 0, 1));
  values.insert(3, Cal3_S2());

  // Create leaves
  Pose3_ x(1);
  Point3_ p(2);
  Cal3_S2_ K(3);

  // Create expression tree
  Point3_ p_cam(x, &Pose3::transformTo, p);
  Point2_ xy_hat(Project, p_cam);
  Point2_ uv_hat(K, &Cal3_S2::uncalibrate, xy_hat);

  const double fd_step = 1e-5;
  const double tolerance = 1e-5;
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(uv_hat, values, fd_step, tolerance);
}

TEST(ExpressionFactor, push_back) {
  NonlinearFactorGraph graph;
  graph.addExpressionFactor(model, Point2(0, 0), leaf::p);
}

/* ************************************************************************* */
// Test with multiple compositions on duplicate keys
struct Combine {
  double a, b;
  Combine(double a, double b) : a(a), b(b) {}
  double operator()(const double& x, const double& y, OptionalJacobian<1, 1> H1,
                    OptionalJacobian<1, 1> H2) {
    if (H1) (*H1) << a;
    if (H2) (*H2) << b;
    return a * x + b * y;
  }
};

TEST(Expression, testMultipleCompositions) {
  const double tolerance = 1e-5;
  const double fd_step = 1e-5;

  Values values;
  values.insert(1, 10.0);
  values.insert(2, 20.0);

  Expression<double> v1_(Key(1));
  Expression<double> v2_(Key(2));

  // BinaryExpression(1,2)
  //   Leaf, key = 1
  //   Leaf, key = 2
  Expression<double> sum1_(Combine(1, 2), v1_, v2_);
  EXPECT(sum1_.keys() == list_of(1)(2));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum1_, values, fd_step, tolerance);

  // BinaryExpression(3,4)
  //   BinaryExpression(1,2)
  //     Leaf, key = 1
  //     Leaf, key = 2
  //   Leaf, key = 1
  Expression<double> sum2_(Combine(3, 4), sum1_, v1_);
  EXPECT(sum2_.keys() == list_of(1)(2));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum2_, values, fd_step, tolerance);

  // BinaryExpression(5,6)
  //   BinaryExpression(3,4)
  //     BinaryExpression(1,2)
  //       Leaf, key = 1
  //       Leaf, key = 2
  //     Leaf, key = 1
  //   BinaryExpression(1,2)
  //     Leaf, key = 1
  //     Leaf, key = 2
  Expression<double> sum3_(Combine(5, 6), sum1_, sum2_);
  EXPECT(sum3_.keys() == list_of(1)(2));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum3_, values, fd_step, tolerance);
}

/* ************************************************************************* */
// Another test, with Ternary Expressions
static double combine3(const double& x, const double& y, const double& z,
                        OptionalJacobian<1, 1> H1, OptionalJacobian<1, 1> H2,
                        OptionalJacobian<1, 1> H3) {
  if (H1) (*H1) << 1.0;
  if (H2) (*H2) << 2.0;
  if (H3) (*H3) << 3.0;
  return x + 2.0 * y + 3.0 * z;
}

TEST(Expression, testMultipleCompositions2) {
  const double tolerance = 1e-5;
  const double fd_step = 1e-5;

  Values values;
  values.insert(1, 10.0);
  values.insert(2, 20.0);
  values.insert(3, 30.0);

  Expression<double> v1_(Key(1));
  Expression<double> v2_(Key(2));
  Expression<double> v3_(Key(3));

  Expression<double> sum1_(Combine(4,5), v1_, v2_);
  EXPECT(sum1_.keys() == list_of(1)(2));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum1_, values, fd_step, tolerance);

  Expression<double> sum2_(combine3, v1_, v2_, v3_);
  EXPECT(sum2_.keys() == list_of(1)(2)(3));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum2_, values, fd_step, tolerance);

  Expression<double> sum3_(combine3, v3_, v2_, v1_);
  EXPECT(sum3_.keys() == list_of(1)(2)(3));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum3_, values, fd_step, tolerance);

  Expression<double> sum4_(combine3, sum1_, sum2_, sum3_);
  EXPECT(sum4_.keys() == list_of(1)(2)(3));
  EXPECT_CORRECT_EXPRESSION_JACOBIANS(sum4_, values, fd_step, tolerance);
}

/* ************************************************************************* */
// Test multiplication with the inverse of a matrix
TEST(ExpressionFactor, MultiplyWithInverse) {
  auto model = noiseModel::Isotropic::Sigma(3, 1);

  // Create expression
  Vector3_ f_expr(MultiplyWithInverse<3>(), Expression<Matrix3>(0), Vector3_(1));

  // Check derivatives
  Values values;
  Matrix3 A = Vector3(1, 2, 3).asDiagonal();
  A(0, 1) = 0.1;
  A(0, 2) = 0.1;
  const Vector3 b(0.1, 0.2, 0.3);
  values.insert<Matrix3>(0, A);
  values.insert<Vector3>(1, b);
  ExpressionFactor<Vector3> factor(model, Vector3::Zero(), f_expr);
  EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-5, 1e-5);
}

/* ************************************************************************* */
// Test multiplication with the inverse of a matrix function
namespace test_operator {
Vector3 f(const Point2& a, const Vector3& b, OptionalJacobian<3, 2> H1,
          OptionalJacobian<3, 3> H2) {
  Matrix3 A = Vector3(1, 2, 3).asDiagonal();
  A(0, 1) = a.x();
  A(0, 2) = a.y();
  A(1, 0) = a.x();
  if (H1) *H1 << b.y(), b.z(), b.x(), 0, 0, 0;
  if (H2) *H2 = A;
  return A * b;
};
}

TEST(ExpressionFactor, MultiplyWithInverseFunction) {
  auto model = noiseModel::Isotropic::Sigma(3, 1);

  using test_operator::f;
  Vector3_ f_expr(MultiplyWithInverseFunction<Point2, 3>(f),
                  Expression<Point2>(0), Vector3_(1));

  // Check derivatives
  Point2 a(1, 2);
  const Vector3 b(0.1, 0.2, 0.3);
  Matrix32 H1;
  Matrix3 A;
  const Vector Ab = f(a, b, H1, A);
  CHECK(assert_equal(A * b, Ab));
  CHECK(assert_equal(
      numericalDerivative11<Vector3, Point2>(
          std::bind(f, std::placeholders::_1, b, boost::none, boost::none), a),
      H1));

  Values values;
  values.insert<Point2>(0, a);
  values.insert<Vector3>(1, b);
  ExpressionFactor<Vector3> factor(model, Vector3::Zero(), f_expr);
  EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-5, 1e-5);
}

/* ************************************************************************* */
// Test N-ary variadic template
class TestNaryFactor
    : public gtsam::ExpressionFactorN<gtsam::Point3 /*return type*/,
                                      gtsam::Rot3, gtsam::Point3,
                                      gtsam::Rot3, gtsam::Point3> {
private:
  using This = TestNaryFactor;
  using Base =
      gtsam::ExpressionFactorN<gtsam::Point3 /*return type*/,
        gtsam::Rot3, gtsam::Point3, gtsam::Rot3, gtsam::Point3>;

public:
  /// default constructor
  TestNaryFactor() = default;
  ~TestNaryFactor() override = default;

  TestNaryFactor(gtsam::Key kR1, gtsam::Key kV1,  gtsam::Key kR2, gtsam::Key kV2,
    const gtsam::SharedNoiseModel &model, const gtsam::Point3& measured)
      : Base({kR1, kV1, kR2, kV2}, model, measured) {
    this->initialize(expression({kR1, kV1, kR2, kV2}));
  }

  /// @return a deep copy of this factor
  gtsam::NonlinearFactor::shared_ptr clone() const override {
    return boost::static_pointer_cast<gtsam::NonlinearFactor>(
        gtsam::NonlinearFactor::shared_ptr(new This(*this)));
  }

  // Return measurement expression
  gtsam::Expression<gtsam::Point3> expression(
      const std::array<gtsam::Key, NARY_EXPRESSION_SIZE> &keys) const override {
    gtsam::Expression<gtsam::Rot3>   R1_(keys[0]);
    gtsam::Expression<gtsam::Point3> V1_(keys[1]);
    gtsam::Expression<gtsam::Rot3>   R2_(keys[2]);
    gtsam::Expression<gtsam::Point3> V2_(keys[3]);
    return {gtsam::rotate(R1_, V1_) - gtsam::rotate(R2_, V2_)};
  }

  /** print */
  void print(const std::string &s,
             const gtsam::KeyFormatter &keyFormatter =
                 gtsam::DefaultKeyFormatter) const override {
    std::cout << s << "TestNaryFactor("
              << keyFormatter(Factor::keys_[0]) << ","
              << keyFormatter(Factor::keys_[1]) << ","
              << keyFormatter(Factor::keys_[2]) << ","
              << keyFormatter(Factor::keys_[3]) << ")\n";
    gtsam::traits<gtsam::Point3>::Print(measured_, "  measured: ");
    this->noiseModel_->print("  noise model: ");
  }

  /** equals */
  bool equals(const gtsam::NonlinearFactor &expected,
              double tol = 1e-9) const override {
    const This *e = dynamic_cast<const This *>(&expected);
    return e != nullptr && Base::equals(*e, tol) &&
      gtsam::traits<gtsam::Point3>::Equals(measured_,e->measured_, tol);
  }

private:
  /** Serialization function */
  friend class boost::serialization::access;
  template <class ARCHIVE>
  void serialize(ARCHIVE &ar, const unsigned int /*version*/) {
    ar &boost::serialization::make_nvp(
        "TestNaryFactor",
        boost::serialization::base_object<Base>(*this));
    ar &BOOST_SERIALIZATION_NVP(measured_);
  }
};

TEST(ExpressionFactor, variadicTemplate) {
  using gtsam::symbol_shorthand::R;
  using gtsam::symbol_shorthand::V;

  // Create factor
  TestNaryFactor f(R(0),V(0), R(1), V(1), noiseModel::Unit::Create(3), Point3(0,0,0));

  // Create some values
  Values values;
  values.insert(R(0), Rot3::Ypr(0.1, 0.2, 0.3));
  values.insert(V(0), Point3(1, 2, 3));
  values.insert(R(1), Rot3::Ypr(0.2, 0.5, 0.2));
  values.insert(V(1), Point3(5, 6, 7));

  // Check unwhitenedError
  std::vector<Matrix> H(4);
  Vector actual = f.unwhitenedError(values, H);
  EXPECT_LONGS_EQUAL(4, H.size());
  EXPECT(assert_equal(Eigen::Vector3d(-5.63578115, -4.85353243, -1.4801204), actual, 1e-5));

  EXPECT_CORRECT_FACTOR_JACOBIANS(f, values, 1e-8, 1e-5);
}

TEST(ExpressionFactor, crossProduct) {
  auto model = noiseModel::Isotropic::Sigma(3, 1);

  // Create expression
  const auto a = Vector3_(1);
  const auto b = Vector3_(2);
  Vector3_ f_expr = cross(a, b);

  // Check derivatives
  Values values;
  values.insert(1, Vector3(0.1, 0.2, 0.3));
  values.insert(2, Vector3(0.4, 0.5, 0.6));
  ExpressionFactor<Vector3> factor(model, Vector3::Zero(), f_expr);
  EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-5, 1e-5);
}

TEST(ExpressionFactor, dotProduct) {
  auto model = noiseModel::Isotropic::Sigma(1, 1);

  // Create expression
  const auto a = Vector3_(1);
  const auto b = Vector3_(2);
  Double_ f_expr = dot(a, b);

  // Check derivatives
  Values values;
  values.insert(1, Vector3(0.1, 0.2, 0.3));
  values.insert(2, Vector3(0.4, 0.5, 0.6));
  ExpressionFactor<double> factor(model, .0, f_expr);
  EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-5, 1e-5);
}

/* ************************************************************************* */
int main() {
  TestResult tr;
  return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */


// Copyright 2017 Peter Dimov.
//
// 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/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/function.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>

int main()
{
    using boost::mp11::mp_nth_element;
    using boost::mp11::mp_nth_element_c;
    using boost::mp11::mp_list_c;
    using boost::mp11::mp_sort;
    using boost::mp11::mp_less;
    using boost::mp11::mp_at_c;
    using boost::mp11::mp_size_t;
    using boost::mp11::mp_rename;

    {
        using L1 = mp_list_c<int, 7, 1, 11, 3, 2, 2, 4>;
        using L2 = mp_sort<L1, mp_less>;

        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 0, mp_less>, mp_at_c<L2, 0>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 1, mp_less>, mp_at_c<L2, 1>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 2, mp_less>, mp_at_c<L2, 2>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 3, mp_less>, mp_at_c<L2, 3>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 4, mp_less>, mp_at_c<L2, 4>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 5, mp_less>, mp_at_c<L2, 5>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 6, mp_less>, mp_at_c<L2, 6>>));

        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<0>, mp_less>, mp_at_c<L2, 0>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<1>, mp_less>, mp_at_c<L2, 1>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<2>, mp_less>, mp_at_c<L2, 2>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<3>, mp_less>, mp_at_c<L2, 3>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<4>, mp_less>, mp_at_c<L2, 4>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<5>, mp_less>, mp_at_c<L2, 5>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<6>, mp_less>, mp_at_c<L2, 6>>));
    }

    {
        using L1 = mp_rename<mp_list_c<int, 7, 1, 11, 3, 2, 2, 4>, std::tuple>;
        using L2 = mp_sort<L1, mp_less>;

        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 0, mp_less>, mp_at_c<L2, 0>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 1, mp_less>, mp_at_c<L2, 1>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 2, mp_less>, mp_at_c<L2, 2>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 3, mp_less>, mp_at_c<L2, 3>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 4, mp_less>, mp_at_c<L2, 4>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 5, mp_less>, mp_at_c<L2, 5>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element_c<L1, 6, mp_less>, mp_at_c<L2, 6>>));

        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<0>, mp_less>, mp_at_c<L2, 0>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<1>, mp_less>, mp_at_c<L2, 1>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<2>, mp_less>, mp_at_c<L2, 2>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<3>, mp_less>, mp_at_c<L2, 3>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<4>, mp_less>, mp_at_c<L2, 4>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<5>, mp_less>, mp_at_c<L2, 5>>));
        BOOST_TEST_TRAIT_TRUE((std::is_same<mp_nth_element<L1, mp_size_t<6>, mp_less>, mp_at_c<L2, 6>>));
    }

    return boost::report_errors();
}


#ifndef BUSV_CREATE_ALPHA_SHAPE_HPP
#define BUSV_CREATE_ALPHA_SHAPE_HPP

#include "cgal_typedefs.hpp"
#include "point_transform_function.hpp"
#include "init_edge_data.hpp"
#include "process_cells.hpp"
#include "weight_func_obj_default.hpp"
#include "alpha_shape_container.hpp"

#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>

namespace busv{

template <typename T, typename U>
AlphaShapeContainer<T,U> create_alpha_shape(
	U numPoints, T alpha,
	const T* points, const T* radii
)
{
	typedef typename cgal_typedefs<T,U>::Triangulation_3 Triangulation_3;
	typedef typename cgal_typedefs<T,U>::Fixed_alpha_shape_3 Fixed_alpha_shape_3;

	PointTransformFunction<Triangulation_3, VertexData<T, U>, T> tfunc(points, radii);
	//T (&coords)[numPoints][3] = (T (&)[numPoints][3])points;

	//build one alpha_shape with alpha=0
	Fixed_alpha_shape_3* as_ptr = new Fixed_alpha_shape_3(
		boost::make_transform_iterator(boost::counting_iterator<U>(0), tfunc),
		boost::make_transform_iterator(boost::counting_iterator<U>(numPoints), tfunc),
		alpha
	);

	//process edges and setup cell edge pointers
	EdgeData<T>* edgeData = init_edge_data<T>(*as_ptr);

	//process tetrahedra
	process_cells<T>(*as_ptr, weight_func_obj_default<T,U>());

	return AlphaShapeContainer<T,U>(as_ptr, edgeData);
}

} //namespace busv

#endif


/* test_poisson_distribution.cpp
 *
 * Copyright Steven Watanabe 2010
 * 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)
 *
 * $Id: test_poisson_distribution.cpp 71018 2011-04-05 21:27:52Z steven_watanabe $
 *
 */

#include <boost/random/poisson_distribution.hpp>

#include <limits>

#define BOOST_RANDOM_DISTRIBUTION boost::random::poisson_distribution<>
#define BOOST_RANDOM_ARG1 mean
#define BOOST_RANDOM_ARG1_DEFAULT 1.0
#define BOOST_RANDOM_ARG1_VALUE 7.5

#define BOOST_RANDOM_DIST0_MIN 0
#define BOOST_RANDOM_DIST0_MAX (std::numeric_limits<int>::max)()
#define BOOST_RANDOM_DIST1_MIN 0
#define BOOST_RANDOM_DIST1_MAX (std::numeric_limits<int>::max)()

#define BOOST_RANDOM_TEST1_PARAMS
#define BOOST_RANDOM_TEST1_MIN 0.0
#define BOOST_RANDOM_TEST1_MAX 10.0

#define BOOST_RANDOM_TEST2_PARAMS (1000.0)
#define BOOST_RANDOM_TEST2_MIN 10.0

#include "test_distribution.ipp"


// (C) Copyright Jeremy Siek 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// Sample output:
//  mask =      101010101010
//  Enter a 12-bit bitset in binary: 100110101101
//  x =        100110101101
//  As ulong:  2477
//  And with mask: 100010101000
//  Or with mask:  101110101111

#include <iostream>
#include <boost/dynamic_bitset.hpp>

int main(int, char*[]) {
  const boost::dynamic_bitset<> mask(12, 2730ul);
  std::cout << "mask = " << mask << std::endl;

  boost::dynamic_bitset<> x(12);
  std::cout << "x.size()=" << x.size() << std::endl;

  std::cout << "Enter a 12-bit bitset in binary: " << std::flush;
  if (std::cin >> x) {
    std::cout << "input number:     " << x << std::endl;
    std::cout << "As unsigned long: " << x.to_ulong() << std::endl;
    std::cout << "And with mask:    " << (x & mask) << std::endl;
    std::cout << "Or with mask:     " << (x | mask) << std::endl;
    std::cout << "Shifted left:     " << (x << 1) << std::endl;
    std::cout << "Shifted right:    " << (x >> 1) << std::endl;
  }
  return EXIT_SUCCESS;
}


// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2015 Conrad Sanderson (http://conradsanderson.id.au)
// Copyright 2015 National ICT Australia (NICTA)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------

#include <armadillo>
#include "catch.hpp"

using namespace arma;

TEST_CASE("fn_conj_1")
  {
  vec re =   linspace<vec>(1,5,6);
  vec im = 2*linspace<vec>(1,5,6);

  cx_vec a = cx_vec(re,im);
  cx_vec b = conj(a);

  REQUIRE( accu(abs(real(b) - ( re))) == Approx(0.0).margin(0.001) );
  REQUIRE( accu(abs(imag(b) - (-im))) == Approx(0.0).margin(0.001) );
  }

TEST_CASE("fn_conj2")
  {
  cx_mat A = randu<cx_mat>(5,6);

  cx_mat B = conj(A);

  REQUIRE( all(vectorise(real(B) ==  real(A))) == true );
  REQUIRE( all(vectorise(imag(B) == -imag(A))) == true );
  }


#include "CubicInterpolation/CubicSplines.h"
#include "CubicInterpolation/InterpolantBuilder.h"

#include <boost/math/differentiation/finite_difference.hpp>
#include <boost/math/interpolators/cardinal_cubic_b_spline.hpp>
#include <boost/serialization/access.hpp>
#include <vector>

namespace cubic_splines {

/**
 * @brief Storage class to write and load the interpolation tables from  disk.
 * After reading and writing the object will be destructed.
 */
template <typename T> struct CubicSplines<T>::StorageData {
  std::vector<T> y;
  T lower_lim_derivate;
  T upper_lim_derivate;

  friend class boost::serialization::access;
  template <class Archive> void serialize(Archive &ar, const unsigned int) {
    ar &y;
    ar &lower_lim_derivate;
    ar &upper_lim_derivate;
  };

public:
  StorageData() = default;

  template <typename T1>
  StorageData(T1 const &_y, T _lower_lim_derivate, T _upper_lim_derivate)
      : y(_y.begin(), _y.end()), lower_lim_derivate(_lower_lim_derivate),
        upper_lim_derivate(_upper_lim_derivate){};

  auto to_runtime_data() const {
    return RuntimeData(y, lower_lim_derivate, upper_lim_derivate);
  }
};

template <typename T>
struct CubicSplines<T>::RuntimeData : public CubicSplines<T>::StorageData {

  boost::math::interpolators::cardinal_cubic_b_spline<T> spline;

  RuntimeData() = default;

  template <typename T1>
  RuntimeData(T1 _data, T _lower_lim_derivate, T _upper_lim_derivate)
      : StorageData(_data, _lower_lim_derivate, _upper_lim_derivate),
        spline(_data.data(), _data.size(), 0, 1, _lower_lim_derivate,
               _upper_lim_derivate) {}

  auto to_storage_data() const { return StorageData(*this); };
};

template <typename T>
CubicSplines<T>::CubicSplines(CubicSplines::RuntimeData _data)
    : data(::std::make_unique<CubicSplines::RuntimeData>(_data)) {}

template <typename T>
CubicSplines<T>::CubicSplines(Definition const &def, std::string path,
                              std::string filename) {
  try {
    auto storage_data = load<CubicSplines>(path, filename);
    *this = CubicSplines(storage_data.to_runtime_data());
  } catch (std::system_error const &ex) {
    if (ex.code().value() != ENOENT)
      throw(ex);
    *this = CubicSplines(def);
    save(data->to_storage_data(), path, filename);
  }
}

template <typename T>
CubicSplines<T>::CubicSplines(Definition const &def)
    : data(::std::make_unique<CubicSplines::RuntimeData>()) {
  using boost::math::differentiation::finite_difference_derivative;
  auto func = [&def](T x) {
    auto fx = def.f(x);
    if (def.f_trafo)
      fx = def.f_trafo->transform(fx);
    return fx;
  };
  auto y = std::vector<T>(def.axis->required_nodes());
  for (size_t n = 0; n < y.size(); ++n)
    y[n] = func(def.axis->back_transform(n));
  auto f_derivate = [func, axis = def.axis.get()](T t) {
    return func(axis->back_transform(t));
  };
  auto diff_low = finite_difference_derivative(f_derivate, static_cast<T>(0));
  auto diff_up = finite_difference_derivative(f_derivate, static_cast<T>(y.size() - 1));
  data = ::std::make_unique<CubicSplines::RuntimeData>(y, diff_low, diff_up);
}

template <typename T> T CubicSplines<T>::evaluate(T x) const { return data->spline(x); };

template <typename T> T CubicSplines<T>::prime(T x) const {
  return data->spline.prime(x);
};

template <typename T> T CubicSplines<T>::double_prime(T x) const {
  return data->spline.double_prime(x);
};
} // namespace cubic_splines

template class cubic_splines::CubicSplines<float>;
template class cubic_splines::CubicSplines<double>;


#ifndef INCLUDED_scheme_nest_maps_ScaleMap_HH
#define INCLUDED_scheme_nest_maps_ScaleMap_HH

#include "scheme/util/template_loop.hh"
#include "scheme/util/SimpleArray.hh"
#include <boost/function.hpp>
#include <boost/type_traits/make_signed.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
#include <boost/static_assert.hpp>
#include <iostream>
#include <vector>

namespace scheme {
namespace nest {
namespace pmap {

	///@brief Parameter Mapping Policy for cartesian grids
	///@tparam DIM the dimension number of the input parameter space
	///@tparam Value the output value type, default
	///@tparam Index index type, default size_t
	///@tparam Float float type, default double
	///@note NEST num_cells MUST agree with cell_sizes_
	///@note bounds and cell indices are represented as SimpleArrays (like params) NOT Value Types
	template<
		int DIM,
		class Value = util::SimpleArray<DIM,double>,
		class Index = uint64_t,
		class Float = typename Value::Scalar
	>
	struct ScaleMap {
		static int const DIMENSION = DIM;
		typedef ScaleMap<DIM,Value,Index,Float> ThisType;
		typedef Value ValueType ;
		typedef Float FloatType ;
		typedef Index IndexType ;
		typedef typename boost::make_signed<Index>::type SignedIndex;
		typedef util::SimpleArray<DIM,Index> Indices;
		typedef util::SimpleArray<DIM,SignedIndex> SignedIndices;
		typedef util::SimpleArray<DIM,Float> Params;
		BOOST_STATIC_ASSERT_MSG(DIM>0,"ScaleMap DIM must be > 0");
	 private:
		///@brief lower bound on value space
		Params lower_bound_;
		///@brief upper bound on value space base size 1
		Params upper_bound_;
		///@brief distributes cell_index accross dimensions
		Params cell_width_;
		Indices cell_sizes_;
		Indices cell_sizes_pref_sum_;
		Index num_cells_;
	 public:

	 	Params const & lower_bound() const { return lower_bound_; }
	 	Params const & upper_bound() const { return upper_bound_; }
	 	Params const &  cell_width() const { return cell_width_; }
	 	Indices const & cell_sizes() const { return cell_sizes_; }

		static std::string pmap_name() { return "ScaleMap<"+boost::lexical_cast<std::string>(DIM)+">"; }

		///@brief construct with default lb, ub, bs
		ScaleMap(){	cell_sizes_.fill(1); lower_bound_.fill(0); upper_bound_.fill(1); init(); }
		///@brief construct with default lb, ub
		template< class I >
		ScaleMap(I const & bs) :
			cell_sizes_(bs) { lower_bound_.fill(0); upper_bound_.fill(1); init(); }
		///@brief construct with default bs
		template< class P >
		ScaleMap(P const & lb, P const & ub) :
			lower_bound_(lb), upper_bound_(ub) { cell_sizes_.fill(1); init(); }
		///@brief construct with specified lb, ub and bs
		template< class P, class I >
		ScaleMap(P const & lb, P const & ub, I const & bs) :
			lower_bound_(lb), upper_bound_(ub), cell_sizes_(bs) { init(); }

		template< class I >
		void init(I const & bs){
			cell_sizes_ = bs;
			lower_bound_.fill(0);
			upper_bound_.fill(1);
			init();
		}

		template< class P >
		void init(P const & lb, P const & ub){
			lower_bound_ = lb;
			upper_bound_ = ub;
			cell_sizes_.fill(1);
			init();
		}

		template< class P, class I >
		void init(P const & lb, P const & ub, I const & bs){
			lower_bound_ = lb;
			upper_bound_ = ub;
			cell_sizes_  = bs;
			init();
		}

		///@brief sets up cell_size_pref_sum
		void init(){
			num_cells_ = cell_sizes_.prod();
			for(size_t i = 0; i < DIM; ++i){
				cell_sizes_pref_sum_[i] = cell_sizes_.prod(i);
				cell_width_[i] = (upper_bound_[i]-lower_bound_[i])/(Float)cell_sizes_[i];
				assert(upper_bound_[i] > lower_bound_[i]);
			}
		}

		///@brief sets value based on cell_index and parameters using geometric bounds
		///@return false iff invalid parameters
		bool params_to_value(
			Params const & params,
			Index cell_index,
			Index resl,
			Value & value
		) const {
			for(size_t i = 0; i < DIM; ++i){
				assert(cell_sizes_[i] > 0);
				assert(cell_sizes_[i] < 100000);
				assert(lower_bound_[i] < upper_bound_[i]);
				Float bi = ( cell_index / cell_sizes_pref_sum_[i] ) % cell_sizes_[i];
				value[i] = lower_bound_[i] + cell_width_[i] * (bi + params[i]);
			}
			return true;
		}

		///@brief sets params/cell_index from value
		bool value_to_params(
			Value const & value,
			Index resl,
			Params & params,
			Index & cell_index
		) const {
			value_to_params_for_cell(value,resl,params,0);
			cell_index = 0;
			for(size_t i = 0; i < DIM; ++i){
				assert(cell_sizes_[i] > 0);
				assert(cell_sizes_[i] < 100000);
				assert(lower_bound_[i] < upper_bound_[i]);
				// Index cell_size_pref_sum = cell_sizes_.head(i).prod();
				Float ci = (Index)params[i];
				cell_index += cell_sizes_pref_sum_[i] * ci;
				params[i] -= (Float)ci;
				assert( 0.0 <= params[i] && params[i] <= 1.0);
			}
			return true;
		}

		///@brief sets params/cell_index from value
		void value_to_params_for_cell(
			Value const & value,
			Index resl,
			Params & params,
			Index cell_index
		) const {
			Indices cell_indices = cellindex_to_indices(cell_index);
			// std::cout << "CIDX " << cell_indices.transpose() << std::endl;
			for(size_t i = 0; i < DIM; ++i){
				assert(cell_sizes_[i] > 0);
				assert(cell_sizes_[i] < 100000);
				assert(lower_bound_[i] < upper_bound_[i]);
				// Index cell_size_pref_sum = cell_sizes_.head(i).prod();
				params[i] = ( value[i] - lower_bound_[i] ) / cell_width_[i];
				params[i] -= (Float)cell_indices[i];
			}
		}

		Index indices_to_cellindex(Indices const & indices) const {
			Index index = 0;
			for(size_t i = 0; i < DIM; ++i){
				assert(indices[i] < cell_sizes_[i]);
				index += indices[i]*cell_sizes_pref_sum_[i];
			}
			return index;
		}

		Indices cellindex_to_indices(Index index) const {
			Indices indices;
			for(size_t i = 0; i < DIM; ++i){
				indices[i] = ( index / cell_sizes_pref_sum_[i] ) % cell_sizes_[i];
				assert(indices[i] < cell_sizes_[i]);
			}
			return indices;
		}

		template<class OutIter>
		void push_cell_index(SignedIndices const & indices, OutIter out) const {
			*(out++) = indices_to_cellindex(indices.template cast<size_t>());
		}

		// template<class OutIter>
		// void get_neighbors(Indices const & indices, Index cell_index, Index resl, OutIter out)  {
		// 	// std::cout << indices.transpose() << std::endl;
		// 	SignedIndices lb = ((indices.template cast<int>()-1).max(     0     ));
		// 	SignedIndices ub = ((indices.template cast<int>()+1).min((1<<resl)-1));
		// 	// std::cout << "IX " << indices.transpose() << " cell " << cell_index << std::endl;
		// 	// std::cout << "LB " << lb.transpose() << std::endl;
		// 	// std::cout << "UB " << ub.transpose() << std::endl;
		// 	boost::function<void(SignedIndices)> functor;
		// 	functor = boost::bind( & ThisType::template push_index<OutIter>, this, _1, cell_index, resl, out );
		// 	util::NESTED_FOR<DIM>(lb,ub,functor);
		// }

		///@brief return the cell_index of neighboring cells within delta of value
		///@note delta parameter is in "Parameter Space"
		template<class OutIter>
		void get_neighboring_cells(
			Value const & value,
			Index resl,
			Float param_delta,
			OutIter out
		) const {
			// Float param_delta = 1.0 / (Float)(1<<resl);
			assert( param_delta > 0);
			// convert to value space, decided against this
			// Params delta_param;
			// for(size_t i = 0; i < DIM; ++i) delta_param[i] = delta / cell_width_[i];
			Params params;
			value_to_params_for_cell(value,resl,params,0);
			SignedIndex const BIG = 12345678;
			SignedIndices lb = (params-param_delta+(Float)BIG).max((Float)BIG).template cast<SignedIndex>() - BIG ;
			SignedIndices ub = (params+param_delta).template cast<Index>().min(cell_sizes_-(Index)1).template cast<SignedIndex>();
			// std::cout << "PM " << params.transpose() << std::endl;
			// std::cout << "DL " << delta_param.transpose() << std::endl;
			// std::cout << "LB " << lb.transpose() << std::endl;
			// std::cout << "UB " << ub.transpose() << std::endl;
			boost::function<void(SignedIndices)> functor;
			functor = boost::bind( & ThisType::template push_cell_index<OutIter>, this, _1, out );
			util::NESTED_FOR<DIM>(lb,ub,functor);
		}

		///@brief aka covering radius max distance from bin center to any value within bin
		Float bin_circumradius(Index resl) const {
			Params width = (upper_bound_-lower_bound_) / cell_sizes_.template cast<Float>();
			return 0.5/(Float)(1<<resl) * sqrt((width*width).sum()); // squaredNorm
		}

		///@brief maximum distance from the bin center which must be within the bin
		Float bin_inradius(Index resl) const {
			Params width = (upper_bound_-lower_bound_) / cell_sizes_.template cast<Float>();
			return 1.5/(Float)(1<<resl) * width.minCoeff(); // norm
		}

		///@brief cell size
		Index num_cells() const { return num_cells_; }
	 	virtual ~ScaleMap(){}
	};

	template<
		int DIM,
		class Value,
		class Index,
		class Float
	>
	std::ostream & operator << ( std::ostream & out, ScaleMap<DIM,Value,Index,Float> const & sm ){
		out << "ScaleMap cell_sizes = " << sm.cell_sizes() << " cell_widths = " << sm.cell_width();
		return out;
	}

}
}
}

#endif


// Copyright 2015-2018 Hans Dembinski
//
// 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)

//[ guide_histogram_serialization

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/serialization.hpp> // includes serialization code
#include <cassert>
#include <sstream>

int main() {
  using namespace boost::histogram;

  auto a = make_histogram(axis::regular<>(3, -1.0, 1.0, "axis 0"),
                          axis::integer<>(0, 2, "axis 1"));
  a(0.5, 1);

  std::string buf; // to hold persistent representation

  // store histogram
  {
    std::ostringstream os;
    boost::archive::text_oarchive oa(os);
    oa << a;
    buf = os.str();
  }

  auto b = decltype(a)(); // create a default-constructed second histogram

  assert(b != a); // b is empty, a is not

  // load histogram
  {
    std::istringstream is(buf);
    boost::archive::text_iarchive ia(is);
    ia >> b;
  }

  assert(b == a); // now b is equal to a
}

//]


/*    This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
 *    See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
 *    Author(s):       Clement Jamin
 *
 *    Copyright (C) 2016 Inria
 *
 *    Modification(s):
 *      - YYYY/MM Author: Description of the modification
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Tangential_complex - test tangential complex
#include <boost/test/unit_test.hpp>

#include <gudhi/Tangential_complex.h>
#include <gudhi/sparsify_point_set.h>

#include <CGAL/Epick_d.h>
#include <CGAL/Random.h>

#include <array>
#include <vector>

namespace tc = Gudhi::tangential_complex;

BOOST_AUTO_TEST_CASE(test_Spatial_tree_data_structure) {
  typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
  typedef Kernel::Point_d Point;
  typedef tc::Tangential_complex<
      Kernel, CGAL::Dynamic_dimension_tag,
      CGAL::Parallel_tag> TC;

  const int INTRINSIC_DIM = 2;
  const int AMBIENT_DIM = 3;
  const int NUM_POINTS = 50;

  Kernel k;

  // Generate points on a 2-sphere
  CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.);
  std::vector<Point> points;
  points.reserve(NUM_POINTS);
  for (int i = 0; i < NUM_POINTS; ++i)
    points.push_back(*generator++);

  // Compute the TC
  TC tc(points, INTRINSIC_DIM, k);
  tc.compute_tangential_complex();

  // Try to fix inconsistencies. Give it 60 seconds to succeed
  auto perturb_ret = tc.fix_inconsistencies_using_perturbation(0.01, 60);

  BOOST_CHECK(perturb_ret.success);

  // Export the TC into a Simplex_tree
  Gudhi::Simplex_tree<> stree;
  tc.create_complex(stree);
}

BOOST_AUTO_TEST_CASE(test_mini_tangential) {
  typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
  typedef Kernel::Point_d Point;
  typedef tc::Tangential_complex<Kernel, CGAL::Dynamic_dimension_tag, CGAL::Parallel_tag> TC;

  const int INTRINSIC_DIM = 1;

  // Generate points on a 2-sphere
  std::vector<Point> points;
  // [[0, 0], [1, 0], [0, 1], [1, 1]]
  std::vector<double> point = {0.0, 0.0};
  points.push_back(Point(point.size(), point.begin(), point.end()));
  point = {1.0, 0.0};
  points.push_back(Point(point.size(), point.begin(), point.end()));
  point = {0.0, 1.0};
  points.push_back(Point(point.size(), point.begin(), point.end()));
  point = {1.0, 1.0};
  points.push_back(Point(point.size(), point.begin(), point.end()));
  std::clog << "points = " << points.size() << std::endl;
  Kernel k;

  // Compute the TC
  TC tc(points, INTRINSIC_DIM, k);
  tc.compute_tangential_complex();
  TC::Num_inconsistencies num_inc = tc.number_of_inconsistent_simplices();
  std::clog << "TC vertices = " << tc.number_of_vertices() << " - simplices = " << num_inc.num_simplices <<
               " - inc simplices = " << num_inc.num_inconsistent_simplices <<
               " - inc stars = " << num_inc.num_inconsistent_stars << std::endl;

  BOOST_CHECK(tc.number_of_vertices() == 4);
  BOOST_CHECK(num_inc.num_simplices == 4);
  BOOST_CHECK(num_inc.num_inconsistent_simplices == 0);
  BOOST_CHECK(num_inc.num_inconsistent_stars == 0);

  // Export the TC into a Simplex_tree
  Gudhi::Simplex_tree<> stree;
  tc.create_complex(stree);
  std::clog << "ST vertices = " << stree.num_vertices() << " - simplices = " << stree.num_simplices() << std::endl;

  BOOST_CHECK(stree.num_vertices() == 4);
  BOOST_CHECK(stree.num_simplices() == 6);

  tc.fix_inconsistencies_using_perturbation(0.01, 30.0);

  BOOST_CHECK(tc.number_of_vertices() == 4);
  BOOST_CHECK(num_inc.num_simplices == 4);
  BOOST_CHECK(num_inc.num_inconsistent_simplices == 0);
  BOOST_CHECK(num_inc.num_inconsistent_stars == 0);

  // Export the TC into a Simplex_tree
  tc.create_complex(stree);
  std::clog << "ST vertices = " << stree.num_vertices() << " - simplices = " << stree.num_simplices() << std::endl;

  BOOST_CHECK(stree.num_vertices() == 4);
  BOOST_CHECK(stree.num_simplices() == 6);
}

#ifdef GUDHI_DEBUG
BOOST_AUTO_TEST_CASE(test_basic_example_throw) {
  typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
  typedef Kernel::FT FT;
  typedef Kernel::Point_d Point;
  typedef Kernel::Vector_d Vector;
  typedef tc::Tangential_complex<Kernel, CGAL::Dynamic_dimension_tag,CGAL::Parallel_tag> TC;

  const int INTRINSIC_DIM = 2;
  const int AMBIENT_DIM = 3;
  const int NUM_POINTS = 1000;

  Kernel k;

  // Generate points on a 2-sphere
  CGAL::Random_points_on_sphere_d<Point> generator(AMBIENT_DIM, 3.);
  std::vector<Point> points;
  points.reserve(NUM_POINTS);
  for (int i = 0; i < NUM_POINTS; ++i)
    points.push_back(*generator++);

  // Compute the TC
  TC tc(points, INTRINSIC_DIM, k);
  tc.set_max_squared_edge_length(0.01);
  std::clog << "test_basic_example_throw - set_max_squared_edge_length(0.01) to make GUDHI_CHECK fail" << std::endl;
  BOOST_CHECK_THROW(tc.compute_tangential_complex(), std::invalid_argument);

}
#endif


//---------------------------------------------------------------------------//
// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
//
// 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#ifndef BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP
#define BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP

#include <numeric>

#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>

#include <boost/compute/command_queue.hpp>
#include <boost/compute/function.hpp>
#include <boost/compute/algorithm/accumulate.hpp>
#include <boost/compute/algorithm/copy.hpp>
#include <boost/compute/algorithm/transform.hpp>
#include <boost/compute/detail/literal.hpp>
#include <boost/compute/types/fundamental.hpp>

namespace boost
{
    namespace compute
    {

        /// \class discrete_distribution
        /// \brief Produces random integers on the interval [0, n), where
        /// probability of each integer is given by the weight of the ith
        /// integer divided by the sum of all weights.
        ///
        /// The following example shows how to setup a discrete distribution to
        /// produce 0 and 1 with equal probability
        ///
        /// \snippet test/test_discrete_distribution.cpp generate
        ///
        template <class IntType = uint_>
        class discrete_distribution
        {
        public:
            typedef IntType result_type;

            /// Creates a new discrete distribution with a single weight p = { 1 }.
            /// This distribution produces only zeroes.
            discrete_distribution()
                : m_probabilities(1, double(1)),
                  m_scanned_probabilities(1, double(1))
            {
            }

            /// Creates a new discrete distribution with weights given by
            /// the range [\p first, \p last).
            template <class InputIterator>
            discrete_distribution(InputIterator first, InputIterator last)
                : m_probabilities(first, last),
                  m_scanned_probabilities(std::distance(first, last))
            {
                if (first != last)
                {
                    // after this m_scanned_probabilities.back() is a sum of all
                    // weights from the range [first, last)
                    std::partial_sum(first, last, m_scanned_probabilities.begin());

                    std::vector<double, mi_stl_allocator<double>>::iterator i = m_probabilities.begin();
                    std::vector<double, mi_stl_allocator<double>>::iterator j = m_scanned_probabilities.begin();
                    for (; i != m_probabilities.end(); ++i, ++j)
                    {
                        // dividing each weight by sum of all weights to
                        // get probabilities
                        *i = *i / m_scanned_probabilities.back();
                        // dividing each partial sum of weights by sum of
                        // all weights to get partial sums of probabilities
                        *j = *j / m_scanned_probabilities.back();
                    }
                }
                else
                {
                    m_probabilities.push_back(double(1));
                    m_scanned_probabilities.push_back(double(1));
                }
            }

            /// Destroys the discrete_distribution object.
            ~discrete_distribution()
            {
            }

            /// Returns the probabilities
            ::std::vector<double, mi_stl_allocator<double>> probabilities() const
            {
                return m_probabilities;
            }

            /// Returns the minimum potentially generated value.
            result_type min BOOST_PREVENT_MACRO_SUBSTITUTION() const
            {
                return result_type(0);
            }

            /// Returns the maximum potentially generated value.
            result_type max BOOST_PREVENT_MACRO_SUBSTITUTION() const
            {
                size_t type_max = static_cast<size_t>(
                    (std::numeric_limits<result_type>::max)());
                if (m_probabilities.size() - 1 > type_max)
                {
                    return (std::numeric_limits<result_type>::max)();
                }
                return static_cast<result_type>(m_probabilities.size() - 1);
            }

            /// Generates uniformly distributed integers and stores
            /// them to the range [\p first, \p last).
            template <class OutputIterator, class Generator>
            void generate(OutputIterator first,
                          OutputIterator last,
                          Generator &generator,
                          command_queue &queue)
            {
                std::string source = "inline IntType scale_random(uint x)\n";

                source = source +
                         "{\n" +
                         "float rno = convert_float(x) / UINT_MAX;\n";
                for (size_t i = 0; i < m_scanned_probabilities.size() - 1; i++)
                {
                    source = source +
                             "if(rno <= " + detail::make_literal<float>(m_scanned_probabilities[i]) + ")\n" +
                             "   return " + detail::make_literal(i) + ";\n";
                }

                source = source +
                         "return " + detail::make_literal(m_scanned_probabilities.size() - 1) + ";\n" +
                         "}\n";

                BOOST_COMPUTE_FUNCTION(IntType, scale_random, (const uint_ x), {});

                scale_random.set_source(source);
                scale_random.define("IntType", type_name<IntType>());

                generator.generate(first, last, scale_random, queue);
            }

        private:
            ::std::vector<double, mi_stl_allocator<double>> m_probabilities;
            ::std::vector<double, mi_stl_allocator<double>> m_scanned_probabilities;

            BOOST_STATIC_ASSERT_MSG(
                boost::is_integral<IntType>::value,
                "Template argument must be integral");
        };

    } // namespace compute
} // namespace boost

#endif // BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP


#include <vector>
#include <boost/math/distributions/uniform.hpp>
#include "uniform_dist.h"

stochastic::UniformDistribution::UniformDistribution(double lower, double upper)
  : Distribution(),
    lower_bound_{lower},
    upper_bound_{upper},
    distribution_{lower, upper}
{}

std::vector<double> stochastic::UniformDistribution::cumulative_dist_func(
    const std::vector<double>& locations) const {
  std::vector<double> evaluations(locations.size());

  for (unsigned int i = 0; i < locations.size(); ++i) {
    evaluations[i] = cdf(distribution_, locations[i]);
  }

  return evaluations;
}

std::vector<double> stochastic::UniformDistribution::inv_cumulative_dist_func(
    const std::vector<double>& probabilities) const {
  std::vector<double> evaluations(probabilities.size());

  for (unsigned int i = 0; i < probabilities.size(); ++i) {
    evaluations[i] = quantile(distribution_, probabilities[i]);
  }

  return evaluations;
}


/*
 * Author: Johannes M Dieterich
 */

#ifndef WANGGOVINDCARTER_HPP
#define WANGGOVINDCARTER_HPP

#include <armadillo>
#include <array>
#include <memory>
#include "KEDF.hpp"
#include "IntKernelODE.hpp"
using namespace std;
using namespace arma;

#include "TayloredWangGovindCarter.hpp"

class WangGovindCarterODE : public ODEKernel {

public:
    WangGovindCarterODE(const double beta, const double gamma);
    ~WangGovindCarterODE();
    void evaluate(const double t, double y[], double yp[]) override;

private:
    double _beta;
    double _gamma;
};

class AnalyticalWangGovindCarterKernel {

public:
    AnalyticalWangGovindCarterKernel(const double alpha, const double beta, const double gamma, const size_t numTermsAB = 100);
    ~AnalyticalWangGovindCarterKernel();

    void fillWGCKernel(unique_ptr<cx_cube>& kernel, unique_ptr<cx_cube>& betaKernel, const cube* gNorms);

private:

    void elementWGC(const double eta, array<int,3>& w);

    void fillAB();

    size_t _numTermsAB;
    double _pea;
    double _cue;
    double _ell;
    double _cOne;
    double _cTwo;
    double _aM1;
    vector<double> _an;
    vector<double> _bn;
};

class NumericalWangGovindCarterKernel {

public:
    NumericalWangGovindCarterKernel(const double alpha, const double beta, const double gamma, const double rhoS);
    ~NumericalWangGovindCarterKernel();

    void fillWGCKernel(cube* kernel0th, const cube* gNorms);

    void fillWGCKernel(cube* kernel0th, cube* kernel1st, const cube* gNorms);

    void fillWGCKernel(cube* kernel0th, cube* kernel1st, cube* kernel2nd, const cube* gNorms);

    void fillWGCKernel(cube* kernel0th, cube* kernel1st, cube* kernel2nd, cube* kernel3rd, const cube* gNorms);

private:
    double _tkFStar;
    double _alpha;
    double _beta;
    double _gamma;
    double _rhoS;

    unique_ptr<mat> _w;
    shared_ptr<vec> _eta;
    int _nVals;
    double *_nls_wpp;
    double *_nls_w1pp;
    double *_nls_w2pp;
};

class NumericalRealSpaceWangGovindCarterKernel {

public:
    NumericalRealSpaceWangGovindCarterKernel();
    ~NumericalRealSpaceWangGovindCarterKernel();

private:
    double _tkFStar;
    double _alpha;
    double _beta;
    double _gamma;
    double _rhoS;

    unique_ptr<mat> _w;
    shared_ptr<vec> _eta;
    int _nVals;
    shared_ptr<vec> _nls_wpp;
    shared_ptr<vec> _nls_w1pp;
    shared_ptr<vec> _nls_w2pp;
};

#endif /* WANGGOVINDCARTER_HPP */