/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * 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.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */
#include "sqlite3.h"
#include <iostream>
#include <boost/format.hpp>
#include <map>
#include <vector>
#include <cmath>

#define sqlOk(code) assertSql(code, __FILE__, __LINE__)

void assertSql(int code, const char* file, int line) {
    if (code != SQLITE_OK) {
            auto msg = (boost::format("ERROR (%1%:%2%): %3%") % file % line % sqlite3_errstr(code)).str();
            throw std::runtime_error(msg.c_str());
        }
}

uint   tpFactor   = 50;
double onemillion = 1000000.0;

template<class T>
double tp(const std::string& txName, const std::vector<T>& res, long min, long max) {
    double tp = double(res.size())/(double((max - min))/onemillion);
    if (txName == "BatchOp" || txName == "Populate") {
        return floor(tpFactor*tp);
    }
    return tp;
}

float avg(const std::vector<float>& res) {
    float r = 0.0;
    for (auto rt : res) {
        r += rt;
    }
    return r/float(res.size());
}

std::pair<float, float> avgstdev(const std::vector<float>& res) {
    auto a = avg(res);
    float r = 0.0;
    for (auto rt : res) {
        r += rt * rt;
    }
    float avgsq = r/float(res.size());
    float s = sqrtf(avgsq - a*a);
    return std::make_pair(a, s);
}

float quantile(int percentage, const std::vector<float>& resp) {
    return resp[percentage * resp.size() / 100];
}

void printResults(const char* file) {
    sqlite3* db;
    sqlOk(sqlite3_open(file, &db));
    sqlite3_stmt* stmt;
    sqlOk(sqlite3_prepare_v2(db, "SELECT min(start), max(end) FROM results", -1, &stmt, nullptr));
    int s;
    long min, max;
    while ((s = sqlite3_step(stmt)) != SQLITE_DONE) {
        if (s == SQLITE_ERROR) throw std::runtime_error(sqlite3_errmsg(db));
        min = sqlite3_column_int64(stmt, 0);
        max = sqlite3_column_int64(stmt, 1);
    }
    sqlite3_finalize(stmt);
    auto fetchQuery = boost::str(boost::format(
        "SELECT tx, rt/%1% "
        "FROM results "
        //"WHERE start > %2% AND end < %3% AND success LIKE 'true' "
    ) % onemillion);// % min % max);
    sqlOk(sqlite3_prepare_v2(db, fetchQuery.c_str(), -1, &stmt, nullptr));
    std::map<std::string, std::vector<float>> results;
    while ((s = sqlite3_step(stmt)) != SQLITE_DONE) {
        if (s != SQLITE_ROW) throw std::runtime_error(sqlite3_errmsg(db));
        auto str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
        std::string tx = "";
        if (str)
            tx = str;
        float rt = sqlite3_column_double(stmt, 1);
        results[tx].push_back(rt);
    }
    for (auto& p : results) {
        std::sort(p.second.begin(), p.second.end());
    }
    sqlite3_finalize(stmt);
    for (auto& p : results) {
        float a, s;
        std::tie(a, s) = avgstdev(p.second);
        auto fmt = boost::format("%1%,%2%,%3%,%4%,%5%,%6%,%7%,%8%,%9%,%10%,%11%,%12%,%13%")
            % p.first
            % tp(p.first, p.second, min, max)
            % a
            % s
            % quantile(50, p.second)
            % quantile(99, p.second)
            % quantile(95, p.second)
            % quantile(1, p.second)
            % quantile(5, p.second)
            % quantile(25, p.second)
            % quantile(75, p.second)
            % p.second.front()
            % p.second.back()
            ;
        std::cout << fmt << std::endl;
    }
    sqlite3_close(db);
}

int main(int argc, const char* argv[]) {
    if (argc < 2) {
        std::cerr << "USAGE: resaggr sqlitedb\n";
        return 1;
    }
    std::cout << "[WARNING] Number assume a tx batch size of " << tpFactor << ". Make sure this aligns with your experiment config.\n";
    sqlOk(sqlite3_config(SQLITE_CONFIG_SINGLETHREAD));
    std::cout << "Transaction,Throughput,Response Time, Standard Deviation,Median,99% Quantile,95% Quantile,1% Quantile,5% Quantile,25% Quantile,75% Quantile,Min,Max\n";
    for (int i = 1; i < argc; ++i) {
        printResults(argv[i]);
    }
}


//
// Created by przemek on 27.03.2020.
//

#include <AST/expression/base_math_expr.h>
#include <AST/expression/multiply_expr.h>
#include <boost/test/unit_test.hpp>
#include <error/exeception.h>

using namespace vecc;
using namespace vecc::error;
using namespace vecc::ast;

using std::make_unique;
using std::move;
using std::unique_ptr;

BOOST_AUTO_TEST_SUITE(AST_Test_Suite)

BOOST_AUTO_TEST_SUITE(Multiply_Expr_Test_Suite)

BOOST_AUTO_TEST_CASE(GivenMathExpr_ValueIsCorrect) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  BOOST_CHECK_EQUAL(expr.calculate(), var);
}

BOOST_AUTO_TEST_CASE(GivenMultiply_ValueIsCorrect) {
  Variable var = Variable({-5});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2})),
                  MultiplyExpr::OperatorType::Multiply);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({-10}));
}

BOOST_AUTO_TEST_CASE(GivenModulo_ValueIsCorrect) {
  Variable var = Variable({1});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({3})),
                  MultiplyExpr::OperatorType::Modulo);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({1}));
}

BOOST_AUTO_TEST_CASE(GivenDivide_ValueIsCorrect) {
  Variable var = Variable({20});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({5})),
                  MultiplyExpr::OperatorType::Divide);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({4}));
}

BOOST_AUTO_TEST_CASE(GivenVec2Multiply_ValueIsCorrect) {
  Variable var = Variable({1, 2});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2})),
                  MultiplyExpr::OperatorType::Multiply);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({2, 4}));
}

BOOST_AUTO_TEST_CASE(GivenVec2Modulo_ValueIsCorrect) {
  Variable var = Variable({1, 2});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({3})),
                  MultiplyExpr::OperatorType::Modulo);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({1, 2}));
}

BOOST_AUTO_TEST_CASE(GivenVec2Divide_ValueIsCorrect) {
  Variable var = Variable({2, 5});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2})),
                  MultiplyExpr::OperatorType::Divide);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({1, 2}));
}

BOOST_AUTO_TEST_CASE(GivenVec3Multiply_ValueIsCorrect) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2})),
                  MultiplyExpr::OperatorType::Multiply);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({2, 4, 6}));
}

BOOST_AUTO_TEST_CASE(GivenVec3Modulo_ValueIsCorrect) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({3})),
                  MultiplyExpr::OperatorType::Modulo);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({1, 2, 0}));
}

BOOST_AUTO_TEST_CASE(GivenVec3Divide_ValueIsCorrect) {
  Variable var = Variable({2, 5, 4});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2})),
                  MultiplyExpr::OperatorType::Divide);

  BOOST_CHECK_EQUAL(expr.calculate(), Variable({1, 2, 2}));
}

BOOST_AUTO_TEST_CASE(GivenZeroDivision_Throws) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({0})),
                  MultiplyExpr::OperatorType::Divide);
  Variable temp;
  BOOST_CHECK_THROW(temp = expr.calculate(), MathException);
}

BOOST_AUTO_TEST_CASE(GivenZeroModulo_Throws) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({0})),
                  MultiplyExpr::OperatorType::Modulo);
  Variable temp;
  BOOST_CHECK_THROW(temp = expr.calculate(), MathException);
}

BOOST_AUTO_TEST_CASE(GivenWrongDimMultiply_Throws) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2, 2})),
                  MultiplyExpr::OperatorType::Multiply);
  Variable temp;
  BOOST_CHECK_THROW(temp = expr.calculate(), MathException);
}

BOOST_AUTO_TEST_CASE(GivenWrongDimDivision_Throws) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2, 2})),
                  MultiplyExpr::OperatorType::Divide);
  Variable temp;
  BOOST_CHECK_THROW(temp = expr.calculate(), MathException);
}

BOOST_AUTO_TEST_CASE(GivenWrongDimModulo_Throws) {
  Variable var = Variable({1, 2, 3});
  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  expr.addOperand(make_unique<BaseMathExpr>(Variable({2, 2})),
                  MultiplyExpr::OperatorType::Modulo);
  Variable temp;
  BOOST_CHECK_THROW(temp = expr.calculate(), MathException);
}

BOOST_AUTO_TEST_CASE(GivenVal_ToStringCorrect) {
  Variable var = Variable({1, 2});

  MultiplyExpr expr(make_unique<BaseMathExpr>(var));

  BOOST_CHECK_EQUAL(expr.toString(), "vec(1, 2)");
}

BOOST_AUTO_TEST_CASE(GivenAdd_ToStringCorrect) {
  Variable var = Variable({1, 2});

  MultiplyExpr expr(make_unique<BaseMathExpr>(var));
  expr.addOperand(make_unique<BaseMathExpr>((Variable({-2, 2}))),
                  MultiplyExpr::OperatorType::Multiply);

  BOOST_CHECK_EQUAL(expr.toString(), "(vec(1, 2)*vec(-2, 2))");
}

BOOST_AUTO_TEST_CASE(GivenMultiple_ToStringCorrect) {
  Variable var = Variable({1, 2});

  MultiplyExpr expr(make_unique<BaseMathExpr>(var));
  expr.addOperand(make_unique<BaseMathExpr>((Variable({-1, 2}))),
                  MultiplyExpr::OperatorType::Modulo);
  expr.addOperand(make_unique<BaseMathExpr>((Variable({-2, 2}))),
                  MultiplyExpr::OperatorType::Divide);

  BOOST_CHECK_EQUAL(expr.toString(), "(vec(1, 2)%vec(-1, 2)/vec(-2, 2))");
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


//          Copyright Carl Philipp Reh 2009 - 2016.
// 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 <fcppt/algorithm/fold.hpp>
#include <fcppt/preprocessor/disable_gcc_warning.hpp>
#include <fcppt/preprocessor/pop_warning.hpp>
#include <fcppt/preprocessor/push_warning.hpp>
#include <fcppt/config/external_begin.hpp>
#include <boost/test/unit_test.hpp>
#include <functional>
#include <vector>
#include <fcppt/config/external_end.hpp>

FCPPT_PP_PUSH_WARNING
FCPPT_PP_DISABLE_GCC_WARNING(-Weffc++)

BOOST_AUTO_TEST_CASE(
	algorithm_fold
)
{
FCPPT_PP_POP_WARNING

	typedef
	std::vector<
		int
	>
	int_vector;

	typedef
	std::vector<
		int_vector
	>
	int_vector_vector;

	int_vector_vector const vectors{
		int_vector{
			1,
			2
		},
		int_vector{
			3,
			4
		}
	};

	int const sum(
		fcppt::algorithm::fold(
			vectors,
			0,
			[](
				int_vector const &_vec,
				int const _sum
			)
			{
				return
					fcppt::algorithm::fold(
						_vec,
						_sum,
						std::plus<
							int
						>()
					);
			}
		)
	);

	BOOST_CHECK_EQUAL(
		sum,
		10
	);
}


/*
 boost/numeric/odeint/stepper/detail/controlled_adams_bashforth_moulton.hpp

 [begin_description]
 Implemetation of an controlled adams bashforth moulton stepper.
 [end_description]

 Copyright 2017 Valentin Noah Hartmann

 Distributed under the Boost Software License, Version 1.0.
 (See accompanying file LICENSE_1_0.txt or
 copy at http://www.boost.org/LICENSE_1_0.txt)
*/

#ifndef BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED
#define BOOST_NUMERIC_ODEINT_STEPPER_CONTROLLED_ADAMS_BASHFORTH_MOULTON_HPP_INCLUDED

#include <boost/numeric/odeint/stepper/stepper_categories.hpp>
#include <boost/numeric/odeint/stepper/controlled_step_result.hpp>

#include <boost/numeric/odeint/stepper/adaptive_adams_bashforth_moulton.hpp>
#include <boost/numeric/odeint/stepper/detail/pid_step_adjuster.hpp>

#include <boost/numeric/odeint/util/unwrap_reference.hpp>
#include <boost/numeric/odeint/util/is_resizeable.hpp>
#include <boost/numeric/odeint/util/resizer.hpp>

#include <boost/numeric/odeint/util/copy.hpp>
#include <boost/numeric/odeint/util/bind.hpp>

#include <iostream>

namespace boost {
namespace numeric {
namespace odeint {

template<
size_t MaxOrder,
class State,
class Value = double,
class Algebra = typename algebra_dispatcher< State >::algebra_type
>
class default_order_adjuster
{
public:
    typedef State state_type;
    typedef Value value_type;
    typedef state_wrapper< state_type > wrapped_state_type;

    typedef Algebra algebra_type;

    default_order_adjuster( const algebra_type &algebra = algebra_type() )
    : m_algebra( algebra )
    {};

    size_t adjust_order(size_t order, size_t init, boost::array<wrapped_state_type, 4> &xerr)
    {
        using std::abs;

        value_type errc = abs(m_algebra.norm_inf(xerr[2].m_v));

        value_type errm1 = 3*errc;
        value_type errm2 = 3*errc;

        if(order > 2)
        {
            errm2 = abs(m_algebra.norm_inf(xerr[0].m_v));
        }
        if(order >= 2)
        {
            errm1 = abs(m_algebra.norm_inf(xerr[1].m_v));
        }

        size_t o_new = order;

        if(order == 2 && errm1 <= 0.5*errc)
        {
            o_new = order - 1;
        }
        else if(order > 2 && errm2 < errc && errm1 < errc)
        {
            o_new = order - 1;
        }

        if(init < order)
        {
            return order+1;
        }
        else if(o_new == order - 1)
        {
            return order-1;
        }
        else if(order <= MaxOrder)
        {
            value_type errp = abs(m_algebra.norm_inf(xerr[3].m_v));

            if(order > 1 && errm1 < errc && errp)
            {
                return order-1;
            }
            else if(order < MaxOrder && errp < (0.5-0.25*order/MaxOrder) * errc)
            {
                return order+1;
            }
        }

        return order;
    };
private:
    algebra_type m_algebra;
};

template<
class ErrorStepper,
class StepAdjuster = detail::pid_step_adjuster< typename ErrorStepper::state_type,
    typename ErrorStepper::value_type,
    typename ErrorStepper::deriv_type,
    typename ErrorStepper::time_type,
    typename ErrorStepper::algebra_type,
    typename ErrorStepper::operations_type,
    detail::H211PI
    >,
class OrderAdjuster = default_order_adjuster< ErrorStepper::order_value,
    typename ErrorStepper::state_type,
    typename ErrorStepper::value_type,
    typename ErrorStepper::algebra_type
    >,
class Resizer = initially_resizer
>
class controlled_adams_bashforth_moulton
{
public:
    typedef ErrorStepper stepper_type;

    static const typename stepper_type::order_type order_value = stepper_type::order_value;

    typedef typename stepper_type::state_type state_type;
    typedef typename stepper_type::value_type value_type;
    typedef typename stepper_type::deriv_type deriv_type;
    typedef typename stepper_type::time_type time_type;

    typedef typename stepper_type::algebra_type algebra_type;
    typedef typename stepper_type::operations_type operations_type;
    typedef Resizer resizer_type;

    typedef StepAdjuster step_adjuster_type;
    typedef OrderAdjuster order_adjuster_type;
    typedef controlled_stepper_tag stepper_category;

    typedef typename stepper_type::wrapped_state_type wrapped_state_type;
    typedef typename stepper_type::wrapped_deriv_type wrapped_deriv_type;
    typedef boost::array< wrapped_state_type , 4 > error_storage_type;

    typedef typename stepper_type::coeff_type coeff_type;
    typedef controlled_adams_bashforth_moulton< ErrorStepper , StepAdjuster , OrderAdjuster , Resizer > controlled_stepper_type;

    controlled_adams_bashforth_moulton(step_adjuster_type step_adjuster = step_adjuster_type())
    :m_stepper(),
    m_dxdt_resizer(), m_xerr_resizer(), m_xnew_resizer(),
    m_step_adjuster( step_adjuster ), m_order_adjuster()
    {};

    template< class ExplicitStepper, class System >
    void initialize(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type dt)
    {
        m_stepper.initialize(stepper, system, inOut, t, dt);
    };

    template< class System >
    void initialize(System system, state_type &inOut, time_type &t, time_type dt)
    {
        m_stepper.initialize(system, inOut, t, dt);
    };

    template< class ExplicitStepper, class System >
    void initialize_controlled(ExplicitStepper stepper, System system, state_type &inOut, time_type &t, time_type &dt)
    {
        reset();
        coeff_type &coeff = m_stepper.coeff();

        m_dxdt_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) );

        controlled_step_result res = fail;

        for( size_t i=0 ; i<order_value; ++i )
        {
            do
            {
                res = stepper.try_step( system, inOut, t, dt );
            }
            while(res != success);

            system( inOut , m_dxdt.m_v , t );

            coeff.predict(t-dt, dt);
            coeff.do_step(m_dxdt.m_v);
            coeff.confirm();

            if(coeff.m_eo < order_value)
            {
                ++coeff.m_eo;
            }
        }
    }

    template< class System >
    controlled_step_result try_step(System system, state_type & inOut, time_type &t, time_type &dt)
    {
        m_xnew_resizer.adjust_size( inOut , detail::bind( &controlled_stepper_type::template resize_xnew_impl< state_type > , detail::ref( *this ) , detail::_1 ) );

        controlled_step_result res = try_step(system, inOut, t, m_xnew.m_v, dt);

        if(res == success)
        {
            boost::numeric::odeint::copy( m_xnew.m_v , inOut);
        }

        return res;
    };

    template< class System >
    controlled_step_result try_step(System system, const state_type & in, time_type &t, state_type & out, time_type &dt)
    {
        m_xerr_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_xerr_impl< state_type > , detail::ref( *this ) , detail::_1 ) );
        m_dxdt_resizer.adjust_size( in , detail::bind( &controlled_stepper_type::template resize_dxdt_impl< state_type > , detail::ref( *this ) , detail::_1 ) );

        m_stepper.do_step_impl(system, in, t, out, dt, m_xerr[2].m_v);

        coeff_type &coeff = m_stepper.coeff();

        time_type dtPrev = dt;
        dt = m_step_adjuster.adjust_stepsize(coeff.m_eo, dt, m_xerr[2].m_v, out, m_stepper.dxdt() );

        if(dt / dtPrev >= step_adjuster_type::threshold())
        {
            system(out, m_dxdt.m_v, t+dtPrev);

            coeff.do_step(m_dxdt.m_v);
            coeff.confirm();

            t += dtPrev;

            size_t eo = coeff.m_eo;

            // estimate errors for next step
            double factor = 1;
            algebra_type m_algebra;

            m_algebra.for_each2(m_xerr[2].m_v, coeff.phi[1][eo].m_v,
                typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo])));

            if(eo > 1)
            {
                m_algebra.for_each2(m_xerr[1].m_v, coeff.phi[1][eo-1].m_v,
                    typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo-1])));
            }
            if(eo > 2)
            {
                m_algebra.for_each2(m_xerr[0].m_v, coeff.phi[1][eo-2].m_v,
                    typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo-2])));
            }
            if(eo < order_value && coeff.m_eo < coeff.m_steps_init-1)
            {
                m_algebra.for_each2(m_xerr[3].m_v, coeff.phi[1][eo+1].m_v,
                    typename operations_type::template scale_sum1<double>(factor*dt*(coeff.gs[eo+1])));
            }

            // adjust order
            coeff.m_eo = m_order_adjuster.adjust_order(coeff.m_eo, coeff.m_steps_init-1, m_xerr);

            return success;
        }
        else
        {
            return fail;
        }
    };

    void reset() { m_stepper.reset(); };

private:
    template< class StateType >
    bool resize_dxdt_impl( const StateType &x )
    {
        return adjust_size_by_resizeability( m_dxdt, x, typename is_resizeable<deriv_type>::type() );
    };
    template< class StateType >
    bool resize_xerr_impl( const StateType &x )
    {
        bool resized( false );

        for(size_t i=0; i<m_xerr.size(); ++i)
        {
            resized |= adjust_size_by_resizeability( m_xerr[i], x, typename is_resizeable<state_type>::type() );
        }
        return resized;
    };
    template< class StateType >
    bool resize_xnew_impl( const StateType &x )
    {
        return adjust_size_by_resizeability( m_xnew, x, typename is_resizeable<state_type>::type() );
    };

    stepper_type m_stepper;

    wrapped_deriv_type m_dxdt;
    error_storage_type m_xerr;
    wrapped_state_type m_xnew;

    resizer_type m_dxdt_resizer;
    resizer_type m_xerr_resizer;
    resizer_type m_xnew_resizer;

    step_adjuster_type m_step_adjuster;
    order_adjuster_type m_order_adjuster;
};

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

#endif


//
// Created by meital on 15/11/16.
//

#include <libscapi/include/primitives/Mersenne.hpp>
#include "ZpKaratsubaElement.h"
#include <NTL/GF2E.h>
#include<NTL/GF2XFactoring.h>

using namespace NTL;

template <>
TemplateField<ZZ_p>::TemplateField(long fieldParam) {

    this->fieldParam = fieldParam;
    this->elementSizeInBytes = NumBytes(fieldParam);//round up to the next byte
    this->elementSizeInBits = this->elementSizeInBytes*8;

    ZZ_p::init(ZZ(fieldParam));

    auto randomKey = prg.generateKey(128);
    prg.setKey(randomKey);

    m_ZERO = new ZZ_p(0);
    m_ONE = new ZZ_p(1);
}

template <>
TemplateField<ZpKaratsubaElement>::TemplateField(long fieldParam) {

    this->elementSizeInBytes = 5;//round up to the next byte
    this->elementSizeInBits = 40;

    auto randomKey = prg.generateKey(128);
    prg.setKey(randomKey);

    m_ZERO = new ZpKaratsubaElement(0);
    m_ONE = new ZpKaratsubaElement(1);
}

/*
 * The i-th field element. The ordering is arbitrary, *except* that
 * the 0-th field element must be the neutral w.r.t. addition, and the
 * 1-st field element must be the neutral w.r.t. multiplication.
 */
template <>
GF2E TemplateField<GF2E>::GetElement(long b) {

    if(b == 1)
    {
        return *GetOne();
    }
    if(b == 0)
    {
        return *GetZero();
    }
    GF2X element;

    for(int i=0; i < fieldParam; i++) {
        // set the coefficient of x^i to 1
        SetCoeff(element,i,(b >> i) & 1);
    }

    return to_GF2E(element);
}

template <>
ZpKaratsubaElement TemplateField<ZpKaratsubaElement>::GetElement(long b) {

    if(b == 1)
    {
        return *m_ONE;
    }
    if(b == 0)
    {
        return *m_ZERO;
    }
    else{
        ZpKaratsubaElement element(b);
        return element;
    }
}

template <>
ZZ_p TemplateField<ZZ_p>::GetElement(long b) {

    if(b == 1)
    {
        return *m_ONE;
    }
    if(b == 0)
    {
        return *m_ZERO;
    }
    else{
        ZZ_p element(b);
        return element;
    }
}

/**
 * the function create a field by:
 * generate the irreducible polynomial x^8 + x^4 + x^3 + x + 1 to work with
 * init the field with the newly generated polynomial
 */
template <>
TemplateField<GF2E>::TemplateField(long fieldParam) {

    this->fieldParam = fieldParam;
    this->elementSizeInBytes = fieldParam/8;
    this->elementSizeInBits = elementSizeInBytes*8;
    GF2X irreduciblePolynomial = BuildSparseIrred_GF2X(fieldParam);
    GF2E::init(irreduciblePolynomial);

    auto randomKey = prg.generateKey(128);
    prg.setKey(randomKey);

    m_ZERO = new GF2E(0);
    m_ONE = new GF2E(1);
}

template <>
void TemplateField<GF2E>::elementToBytes(unsigned char* elemenetInBytes, GF2E& element){

    BytesFromGF2X(elemenetInBytes,rep(element),fieldParam/8);
}

template <>
void TemplateField<ZpKaratsubaElement>::elementToBytes(unsigned char* elemenetInBytes, ZpKaratsubaElement& element){

    memcpy(elemenetInBytes, (byte*)(&element.elem), 5);
}

template <>
ZpKaratsubaElement TemplateField<ZpKaratsubaElement>::bytesToElement(unsigned char* elemenetInBytes){

    long elemVal = 0;

    //copy the 5 bytes to a long element
    memcpy((byte*)&elemVal, elemenetInBytes, 5);

    return ZpKaratsubaElement(elemVal);
}

template <>
GF2E TemplateField<GF2E>::bytesToElement(unsigned char* elemenetInBytes){

    //first create a GF2X
    GF2X polynomialElement;

    //translate the bytes into a GF2X element
    GF2XFromBytes(polynomialElement, elemenetInBytes, fieldParam/8);

    //convert the GF2X to GF2E
    return to_GF2E(polynomialElement);
}

template <>
void TemplateField<ZZ_p>::elementToBytes(unsigned char* elemenetInBytes, ZZ_p& element){

    BytesFromZZ(elemenetInBytes,rep(element),elementSizeInBytes);
}

template <>
ZZ_p TemplateField<ZZ_p>::bytesToElement(unsigned char* elemenetInBytes){

    //first create a ZZ
    ZZ zz;

    //translate the bytes into a ZZ element
    ZZFromBytes(zz, elemenetInBytes, elementSizeInBytes);

    //convert the ZZ to ZZ_p
    return to_ZZ_p(zz);
}


#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>

using namespace boost::gregorian;

int main()
{
  date d{2014, 1, 30};
  months ms{1};
  date d2 = d + ms;
  std::cout << d2 << '\n';
  date d3 = d2 - ms;
  std::cout << d3 << '\n';
}


//  less.hpp
//
//  (C) Copyright 2011 Vicente J. Botet Escriba
//  Use, modification and distribution are subject to the Boost Software License,
//  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt).
//

#ifndef BOOST_RATIO_MPL_LESS_HPP
#define BOOST_RATIO_MPL_LESS_HPP

#include <boost/ratio/ratio.hpp>
#include <boost/ratio/mpl/numeric_cast.hpp>
#include <boost/mpl/less.hpp>

namespace boost {
namespace mpl {

template<>
struct less_impl< rational_c_tag,rational_c_tag >
{
    template< typename R1, typename R2 > struct apply
        : ratio_less<R1, R2>
    {
    };
};
}
}

#endif  // BOOST_RATIO_MPL_LESS_HPP


#include <UnitTest++/UnitTest++.h>
#include "../drizzle.h"

#include <iostream>
#include <sstream>
#include <boost/filesystem.hpp>

#include <cmath>
using namespace coela;
using namespace std;

SUITE(drizzle)
{

    //run tests at float precision
//    typedef PixelArray2d<float> PixelArray2d_of_real;
//    double precision_limit = 1e-3; //Float precision results in errors around the 1e-3 level
    // (OK for lucky imaging single exposure purposes, but not great)

    //run tests at double precision
    typedef PixelArray2d<double> PixelArray2d_of_real;
    double precision_limit = 1e-11; //Double precision is accurate to much better tolerances.

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

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

    TEST(single_input_identity_drizzle) {
        PixelArray2d_of_real input(10,10, 3.14);
        PixelArray2d_of_real input_weights(10,10, 1.0);

        //Add a hot pixel, downweight it:
        input(5,5)=50;
        double downweighted_input_sum = input(5,5);
        input_weights(5,5)=0;

        PixelArray2d_of_real output(10,10,0.0);
        PixelArray2d_of_real output_weights(10,10,0.0);

        PixelShift null_translation(0,0);

        double drizzle_scale =1.0;
        double pixfrac = 1.0;

        drizzle::translate_and_drizzle_frame(
            input, input_weights,
            output, output_weights,
            null_translation,
            drizzle_scale,
            pixfrac);

        PixelArray2d_of_real drz_img = drizzle::unweight_drizzle_results(output,output_weights);

        CHECK_CLOSE(input.sum() - downweighted_input_sum, output.sum(), precision_limit);
        CHECK_CLOSE(input.sum() - downweighted_input_sum,
                    drz_img.sum() *drizzle_scale*drizzle_scale, precision_limit);
        CHECK_CLOSE(input_weights.sum(), output_weights.sum(), precision_limit);

        for (PixelIterator i(drz_img.range()); i!=i.end; ++i) {
            if (input_weights(i)!=0.0) { CHECK_CLOSE(input(i), drz_img(i), precision_limit); }
            if (input_weights(i)==0.0) { CHECK_CLOSE(0.0 , drz_img(i), precision_limit); }
        }
    }

    TEST(single_input_null_shift_resample_drizzle) {
        PixelArray2d_of_real input(10,10, 3.14);
        PixelArray2d_of_real input_weights(10,10, 1.0);

        double drizzle_scale =0.5;
        double pixfrac = 0.9;
        double zoom = 1.0 / drizzle_scale;

        PixelArray2d_of_real output(input.range().x_dim()*zoom ,
                                    input.range().y_dim()*zoom,
                                    0.0);

        PixelArray2d_of_real output_weights(output);

        PixelShift null_translation(0,0);

        drizzle::translate_and_drizzle_frame(
            input, input_weights,
            output, output_weights,
            null_translation,
            drizzle_scale,
            pixfrac);

        PixelArray2d_of_real drz_img = drizzle::unweight_drizzle_results(output,output_weights);

        CHECK_CLOSE(input.sum(), output.sum(), precision_limit);
        CHECK_CLOSE(input.sum(), drz_img.sum() *drizzle_scale*drizzle_scale, precision_limit);
        CHECK_CLOSE(input_weights.sum(), output_weights.sum(), precision_limit);

        for (PixelIterator i(input.range()); i!=i.end; ++i) {
            CHECK_CLOSE(input(i),  drz_img(i.x*2, i.y*2)   , precision_limit);
        }
        for (PixelIterator i(drz_img.range()); i!=i.end; ++i) {
            CHECK_CLOSE(3.14,  drz_img(i)   , precision_limit);
        }

    }

    TEST(drizzle_output_weighting_correct_for_non_int_shift) {

        PixelArray2d_of_real input(5,5, 0.0);
        PixelArray2d_of_real input_weights(input);
        input_weights.assign(1.0);

        input(3,3)=50;

        double drizzle_scale =1.0;
        double pixfrac = 0.6;
        double zoom = 1.0 / drizzle_scale;

        PixelShift input_translation(0.45,0.45);

        PixelArray2d_of_real output((input.range().x_dim() + ceil(input_translation.x)) *zoom ,
                                    (input.range().y_dim() + ceil(input_translation.y)) *zoom ,
                                    0.0);

        PixelArray2d_of_real output_weights(output);

        drizzle::translate_and_drizzle_frame(
            input, input_weights,
            output, output_weights,
            input_translation,
            drizzle_scale,
            pixfrac);

        PixelArray2d_of_real drz_img = drizzle::unweight_drizzle_results(output,output_weights);

        CHECK_CLOSE(input.sum(), output.sum(), precision_limit);
        CHECK_CLOSE(input.sum(), drz_img.sum() *drizzle_scale*drizzle_scale, precision_limit);
        CHECK_CLOSE(input_weights.sum(), output_weights.sum(), precision_limit);

    }

    TEST(generalized_drizzle_check_no_bounds_overflow) {
        PixelArray2d_of_real input(15,15, 0.0);
        PixelArray2d_of_real input_weights(input);
        input_weights.assign(1.0);

        input(5,5)=50;

        input_weights(2,2)=0;
        input_weights(7,7)=0.5;

        double drizzle_scale =0.5;
        double pixfrac = 1.0;
        double zoom = 1.0/drizzle_scale;

        PixelShift input_translation(2.0,-1.25);

        PixelArray2d_of_real output(input.range().x_dim()*zoom,
                                    input.range().y_dim()*zoom,
                                    0.0);
        PixelArray2d_of_real output_weights(output);

        drizzle::translate_and_drizzle_frame(
            input, input_weights,
            output, output_weights,
            input_translation,
            drizzle_scale,
            pixfrac);

        PixelArray2d_of_real drz_img = drizzle::unweight_drizzle_results(output,output_weights);

        CHECK_CLOSE(input.sum(), drz_img.sum()*drizzle_scale*drizzle_scale, precision_limit);

        input.write_to_file("drz_input.fits");
        input_weights.write_to_file("drz_input_weights.fits");
        output.write_to_file("drz_output_raw.fits");
        output_weights.write_to_file("drz_output_weights.fits");
        drz_img.write_to_file("drz_output_unweighted.fits");
    }

    TEST(dual_drizzle_test1) {
        PixelArray2d_of_real input(15,15, 3.14);
        PixelArray2d_of_real input_weights(input);
        input_weights.assign(1.0);

        input(5,5)=50;

        input_weights(2,2)=0;
        input_weights(7,7)=0.5;

        double drizzle_scale =0.5;
        double pixfrac = 1.0;
        double zoom = 1.0/drizzle_scale;

        PixelShift input_translation(2.0,-1.25);

        PixelArray2d_of_real output(input.range().x_dim()*zoom,
                                    input.range().y_dim()*zoom,
                                    0.0);
        PixelArray2d_of_real output_weights(output);

        PixelArray2d_of_real dual_output(output);

        drizzle::dual_translate_and_drizzle_frame( //test with same input to both outputs
            input, input, input_weights,
            output, dual_output, output_weights,
            input_translation,
            drizzle_scale,
            pixfrac);

        PixelArray2d_of_real drz_img1 = drizzle::unweight_drizzle_results(output,output_weights);
        PixelArray2d_of_real drz_img2 = drizzle::unweight_drizzle_results(dual_output,
                                        output_weights);

        CHECK(drz_img1==drz_img2);
    }

//    TEST(combine_drizzles){
//        PixelArray2d_of_real input1(15,15, 3.14);
//        PixelArray2d_of_real input1_weights(input1);
//        input1_weights.assign(1.0);
//
//        PixelArray2d_of_real input2(15,15, 0);
//        PixelArray2d_of_real input2_weights(input2);
//        input2_weights.assign(0.5);
//
//        input1(5,5)=50;
//
//        input2(6,8)=13;
//
//        input1_weights(2,2)=0;
//        input2_weights(7,7)=5.0;
//
//
//
//        double drizzle_scale =0.5;
//        double pixfrac = 0.9;
//        double zoom = 1.0/drizzle_scale;
//
//        pixel_shift input_translation1(2.0,-1.25), input_translation2(1.0,0.666);
//
//        PixelArray2d_of_real output1(   input1.range().x_dim()*zoom,
//                                                input1.range().y_dim()*zoom,
//                                                    0.0 );
//        PixelArray2d_of_real output2( output1 );
//
//        PixelArray2d_of_real output1_weights(output1);
//        PixelArray2d_of_real output2_weights(output2);
//
//        PixelArray2d_of_real output_double_drizzle( output1 );
//        PixelArray2d_of_real output_double_drizzle(output1);
//
//
//        drizzle::translate_and_drizzle_frame(
//                input1,  input1_weights,
//                output1, output1_weights,
//                input_translation1,
//                drizzle_scale,
//                pixfrac);
//
//        drizzle::translate_and_drizzle_frame(
//                input2,  input2_weights,
//                output2, output2_weights,
//                input_translation2,
//                drizzle_scale,
//                pixfrac);
//
//        drizzle::translate_and_drizzle_frame(
//                input1,  input1_weights,
//                output_double_drizzle, output_double_drizzle,
//                input_translation1,
//                drizzle_scale,
//                pixfrac);
//
//        drizzle::translate_and_drizzle_frame(
//                input2,  input2_weights,
//                output_double_drizzle, output_double_drizzle,
//                input_translation2,
//                drizzle_scale,
//                pixfrac);
//    }
}


#ifndef TRACTOR_CONVERTER_VANGERS_MODELS_CONSTANTS_H
#define TRACTOR_CONVERTER_VANGERS_MODELS_CONSTANTS_H

#include "defines.hpp"

#include "volInt.hpp"

#include <boost/bimap/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/tags/tagged.hpp>
#include <boost/assign.hpp>

#include <string>
#include <unordered_map>

namespace tractor_converter{

namespace c3d{

  const int scaling_max_extreme_radius = 123;
  const double vector_scale_val = 123.0;

  enum class c3d_type
  {
    regular,
    main_of_mechos,
    bound,
  };

  const int version_req = 8;

  const std::vector<int> default_phi_psi_tetta = std::vector<int>(3, 83);

  const std::size_t regular_model_vertices_per_polygon = 3;
  const std::size_t bound_model_vertices_per_polygon = 4;

  namespace header{
    // 0   int
    const std::size_t version_pos = 0;
    // 4   int
    const std::size_t num_vert_pos = version_pos + sizeof(int);
    // 8   int
    const std::size_t num_norm_pos = num_vert_pos + sizeof(int);
    // 12  int
    const std::size_t num_poly_pos = num_norm_pos + sizeof(int);
    // 16  int
    const std::size_t num_vert_total_pos = num_poly_pos + sizeof(int);

    // 20  int
    const std::size_t xmax_pos = num_vert_total_pos + sizeof(int);
    // 24  int
    const std::size_t ymax_pos = xmax_pos + sizeof(int);
    // 28  int
    const std::size_t zmax_pos = ymax_pos + sizeof(int);

    // 32  int
    const std::size_t xmin_pos = zmax_pos + sizeof(int);
    // 36  int
    const std::size_t ymin_pos = xmin_pos + sizeof(int);
    // 40  int
    const std::size_t zmin_pos = ymin_pos + sizeof(int);

    // 44  int
    const std::size_t x_off_pos = zmin_pos + sizeof(int);
    // 48  int
    const std::size_t y_off_pos = x_off_pos + sizeof(int);
    // 52  int
    const std::size_t z_off_pos = y_off_pos + sizeof(int);

    // 56  int
    const std::size_t rmax_pos = z_off_pos + sizeof(int);

    // 60  int
    const std::size_t phi_pos = rmax_pos + sizeof(int);
    // 64  int
    const std::size_t psi_pos = phi_pos + sizeof(int);
    // 68  int
    const std::size_t tetta_pos = psi_pos + sizeof(int);

    // 72  double
    const std::size_t volume_pos = tetta_pos + sizeof(int);
    // 80  double vector
    const std::size_t rcm_pos = volume_pos + sizeof(double);
    // 104 double matrix
    const std::size_t J_pos = rcm_pos + sizeof(double) * volInt::axes_num;

    // 176
    const std::size_t size =
      J_pos + sizeof(double) * volInt::axes_num * volInt::axes_num;
  } // namespace header

  const std::size_t data_pos = header::size;

  namespace vertex{
    const int default_sort_info = 0;

    // 4   float
    const std::size_t full_coord_size = sizeof(float);
    // 12
    const std::size_t full_coords_size =
      full_coord_size * volInt::axes_num;

    // 1   char
    const std::size_t compact_coord_size = sizeof(char);
    // 3
    const std::size_t compact_coords_size =
      compact_coord_size * volInt::axes_num;

    // 4   int
    const std::size_t sort_info_size = sizeof(int);

    // 7
    const std::size_t size_no_full_coords = compact_coords_size +
                                            sort_info_size;

    // 19
    const std::size_t size = full_coords_size +
                             compact_coords_size +
                             sort_info_size;

    // 0
    const std::size_t full_coord_x_rel_pos = full_coord_size * 0;
    // 4
    const std::size_t full_coord_y_rel_pos = full_coord_size * 1;
    // 8
    const std::size_t full_coord_z_rel_pos = full_coord_size * 2;

    // 12
    const std::size_t compact_coord_x_rel_pos = full_coords_size +
                                                compact_coord_size * 0;
    // 13
    const std::size_t compact_coord_y_rel_pos = full_coords_size +
                                                compact_coord_size * 1;
    // 14
    const std::size_t compact_coord_z_rel_pos = full_coords_size +
                                                compact_coord_size * 2;

    // 15
    const std::size_t sort_info_rel_pos = full_coords_size +
                                          compact_coords_size;
  } // namespace vertex

  namespace normal{
    const int default_sort_info = 0;
    const unsigned char default_n_power = 0;

    // 1   char
    const std::size_t coord_size = sizeof(char);
    // 3
    const std::size_t coords_size = coord_size * volInt::axes_num;

    // 1   unsigned char
    const std::size_t n_power_size = sizeof(unsigned char);

    // 4   int
    const std::size_t sort_info_size = sizeof(int);

    // 5
    const std::size_t size_no_coords = n_power_size + sort_info_size;

    // 8
    const std::size_t size = coords_size + n_power_size + sort_info_size;

    // 0
    const std::size_t coord_x_rel_pos = vertex::full_coord_size * 0;
    // 1
    const std::size_t coord_y_rel_pos = vertex::full_coord_size * 1;
    // 2
    const std::size_t coord_z_rel_pos = vertex::full_coord_size * 2;

    // 3
    const std::size_t n_power_rel_pos = coords_size;

    // 4
    const std::size_t sort_info_rel_pos = coords_size + n_power_size;
  } // namespace normal

  namespace polygon{
    const unsigned int default_color_shift = 0;
    const int default_sort_info = 0;
    const unsigned char default_flat_norm_n_power = 0;

    // 4   int
    const std::size_t vertex_num_size = sizeof(int);
    // 4   int
    const std::size_t sort_info_size = sizeof(int);
    // 4   unsigned int
    const std::size_t color_id_size = sizeof(unsigned int);
    // 4   unsigned int
    const std::size_t color_shift_size = sizeof(unsigned int);
    // 1   char
    const std::size_t flat_normal_coord_size = sizeof(char);
    // 1   unsigned char
    const std::size_t flat_normal_n_power_size = sizeof(unsigned char);
    // 4
    const std::size_t flat_normal_size =
      flat_normal_coord_size * volInt::axes_num + flat_normal_n_power_size;
    // 1   char
    const std::size_t middle_point_coord_size = sizeof(char);
    // 3
    const std::size_t middle_point_size =
      middle_point_coord_size * volInt::axes_num;

    // 4   int
    const std::size_t vert_ind_size = sizeof(int);
    // 4   int
    const std::size_t norm_ind_size = sizeof(int);

    // 0
    const std::size_t vertex_num_rel_pos = 0;
    // 4
    const std::size_t sort_info_rel_pos = vertex_num_size;
    // 8
    const std::size_t color_id_rel_pos =
      sort_info_rel_pos + sort_info_size;
    // 12
    const std::size_t color_shift_rel_pos =
      color_id_rel_pos + color_id_size;
    // 16
    const std::size_t flat_normal_x_rel_pos =
      color_shift_rel_pos + color_shift_size;
    // 17
    const std::size_t flat_normal_y_rel_pos =
      flat_normal_x_rel_pos + flat_normal_coord_size;
    // 18
    const std::size_t flat_normal_z_rel_pos =
      flat_normal_y_rel_pos + flat_normal_coord_size;
    // 19
    const std::size_t flat_normal_n_power_rel_pos =
      flat_normal_z_rel_pos + flat_normal_coord_size;
    // 20
    const std::size_t middle_point_x_rel_pos =
      flat_normal_n_power_rel_pos + flat_normal_n_power_size;
    // 21
    const std::size_t middle_point_y_rel_pos =
      middle_point_x_rel_pos + middle_point_coord_size;
    // 22
    const std::size_t middle_point_z_rel_pos =
      middle_point_y_rel_pos + middle_point_coord_size;

    // 23
    const std::size_t vert_norm_ind_arr_rel_pos =
      middle_point_z_rel_pos + middle_point_coord_size;

    const std::size_t general_info_size = vert_norm_ind_arr_rel_pos;
    const std::size_t size_per_vertex = vert_ind_size + norm_ind_size;
  } // namespace polygon

  namespace polygon_sort_info{
    // 4   int
    const std::size_t poly_ind_size = sizeof(int);
    // 12
    const std::size_t size = poly_ind_size * 3;

    // 0
    const std::size_t poly_ind_rel_pos = 0;
  } // namespace polygon_sort_info

  namespace color{
    namespace string{
      const std::string zero_reserved =            "zero_reserved";
      const std::string body =                     "body";
      const std::string window =                   "window";
      const std::string wheel =                    "wheel";
      const std::string defense =                  "defense";
      const std::string weapon =                   "weapon";
      const std::string tube =                     "tube";
      const std::string body_red =                 "body_red";
      const std::string body_blue =                "body_blue";
      const std::string body_yellow =              "body_yellow";
      const std::string body_gray =                "body_gray";
      const std::string yellow_charged =           "yellow_charged";
      const std::string material_0 =               "material_0";
      const std::string material_1 =               "material_1";
      const std::string material_2 =               "material_2";
      const std::string material_3 =               "material_3";
      const std::string material_4 =               "material_4";
      const std::string material_5 =               "material_5";
      const std::string material_6 =               "material_6";
      const std::string material_7 =               "material_7";
      const std::string black =                    "black";
      const std::string body_green =               "body_green";
      const std::string skyfarmer_kernoboo =       "skyfarmer_kernoboo";
      const std::string skyfarmer_pipetka =        "skyfarmer_pipetka";
      const std::string rotten_item =              "rotten_item";
      // End of color id list in Vangers source.
      const std::string max_colors_ids =           "max_colors_ids";

      // Those don't exist in Vangers source.
      const std::string virtual_object_ids_begin = "virtual_object_ids_begin";
      const std::string center_of_mass =           "center_of_mass";
      const std::string attachment_point =         "attachment_point";
      const std::string invalid_color_id =         "invalid_color_id";
      const std::string virtual_object_ids_end =   "virtual_object_ids_end";
    } // namespace string

    namespace string_to_id{
      const unsigned int zero_reserved =            0;
      const unsigned int body =                     1;
      const unsigned int window =                   2;
      const unsigned int wheel =                    3;
      const unsigned int defense =                  4;
      const unsigned int weapon =                   5;
      const unsigned int tube =                     6;
      const unsigned int body_red =                 7;
      const unsigned int body_blue =                8;
      const unsigned int body_yellow =              9;
      const unsigned int body_gray =                10;
      const unsigned int yellow_charged =           11;
      const unsigned int material_0 =               12;
      const unsigned int material_1 =               13;
      const unsigned int material_2 =               14;
      const unsigned int material_3 =               15;
      const unsigned int material_4 =               16;
      const unsigned int material_5 =               17;
      const unsigned int material_6 =               18;
      const unsigned int material_7 =               19;
      const unsigned int black =                    20;
      const unsigned int body_green =               21;
      const unsigned int skyfarmer_kernoboo =       22;
      const unsigned int skyfarmer_pipetka =        23;
      const unsigned int rotten_item =              24;
      // End of color id list in Vangers source.
      const unsigned int max_colors_ids =           25;

      // Those don't exist in Vangers source.
      const unsigned int virtual_object_ids_begin = 1000000;
      const unsigned int center_of_mass =           1000001;
      const unsigned int attachment_point =         1000002;
      const unsigned int invalid_color_id =         1000003;
      const unsigned int virtual_object_ids_end =   1999999;
    } // namespace string_to_id

    namespace body{
      namespace string{
        const std::string separator = "_";
        const std::string offset =    "offset";
        const std::string shift =     "shift";
        const std::string el_1 =
          c3d::color::string::body + separator + offset + separator;
        const std::string el_2 = separator + shift + separator;
      } // namespace string
      namespace max{
        const int offset = 255;
        const int shift = 7;
      } // namespace max
      namespace min{
        const int offset = 0;
        const int shift = 0;
      } // namespace min
      namespace default_val{
        const int offset = 128;
        const int shift = 3;
      } // namespace default_val
    } // namespace body

    struct id{};
    struct name{};

    typedef boost::bimaps::bimap
    <
      boost::bimaps::unordered_set_of<
        boost::bimaps::tagged<unsigned int, id>>,
      boost::bimaps::unordered_set_of< boost::bimaps::tagged<
        std::string, name>>,
      boost::bimaps::unconstrained_set_of_relation
    > ids_type;

    const ids_type ids = boost::assign::list_of<ids_type::relation>
      (string_to_id::zero_reserved, string::zero_reserved)
      (string_to_id::body, string::body)
      (string_to_id::window, string::window)
      (string_to_id::wheel, string::wheel)
      (string_to_id::defense, string::defense)
      (string_to_id::weapon, string::weapon)
      (string_to_id::tube, string::tube)
      (string_to_id::body_red, string::body_red)
      (string_to_id::body_blue, string::body_blue)
      (string_to_id::body_yellow, string::body_yellow)
      (string_to_id::body_gray, string::body_gray)
      (string_to_id::yellow_charged, string::yellow_charged)
      (string_to_id::material_0, string::material_0)
      (string_to_id::material_1, string::material_1)
      (string_to_id::material_2, string::material_2)
      (string_to_id::material_3, string::material_3)
      (string_to_id::material_4, string::material_4)
      (string_to_id::material_5, string::material_5)
      (string_to_id::material_6, string::material_6)
      (string_to_id::material_7, string::material_7)
      (string_to_id::black, string::black)
      (string_to_id::body_green, string::body_green)
      (string_to_id::skyfarmer_kernoboo, string::skyfarmer_kernoboo)
      (string_to_id::skyfarmer_pipetka, string::skyfarmer_pipetka)
      (string_to_id::rotten_item, string::rotten_item)
      // End of color id list in Vangers source.
      (string_to_id::max_colors_ids, string::max_colors_ids)
      // Those don't exist in Vangers source.
      (string_to_id::virtual_object_ids_begin,
         string::virtual_object_ids_begin)
      (string_to_id::center_of_mass, string::center_of_mass)
      (string_to_id::attachment_point, string::attachment_point)
      (string_to_id::invalid_color_id, string::invalid_color_id)
      (string_to_id::virtual_object_ids_end, string::virtual_object_ids_end)
      ;
  } // namespace color

} // namespace c3d

namespace m3d{

  namespace header{
    // 4   int
    const std::size_t xmax_size = sizeof(int);
    // 4   int
    const std::size_t ymax_size = sizeof(int);
    // 4   int
    const std::size_t zmax_size = sizeof(int);
    // 4   int
    const std::size_t rmax_size = sizeof(int);

    // 4   int
    const std::size_t n_wheels_size = sizeof(int);
    // 4   int
    const std::size_t n_debris_size = sizeof(int);

    // 4   int
    const std::size_t body_color_offset_size = sizeof(int);
    // 4   int
    const std::size_t body_color_shift_size = sizeof(int);

    // 32
    const std::size_t size =
      xmax_size + ymax_size + zmax_size + rmax_size +
      n_wheels_size + n_debris_size + body_color_offset_size +
      body_color_shift_size;

    // 0   int
    const std::size_t xmax_pos = 0;
    // 4   int
    const std::size_t ymax_pos = xmax_pos + sizeof(int);
    // 8   int
    const std::size_t zmax_pos = ymax_pos + sizeof(int);
    // 12  int
    const std::size_t rmax_pos = zmax_pos + sizeof(int);

    // 16  int
    const std::size_t n_wheels_pos = rmax_pos + sizeof(int);
    // 20  int
    const std::size_t n_debris_pos = n_wheels_pos + sizeof(int);

    // 24  int
    const std::size_t body_color_offset_pos = n_debris_pos + sizeof(int);
    // 28  int
    const std::size_t body_color_shift_pos =
      body_color_offset_pos + sizeof(int);
  } // namespace header

  namespace wheel{
    const int default_bound_index = 0;

    // 4   int
    const std::size_t steer_size = sizeof(int);
    // 24  double vector
    const std::size_t r_size = sizeof(double) * volInt::axes_num;
    // 4   int
    const std::size_t width_size = sizeof(int);
    // 4   int
    const std::size_t radius_size = sizeof(int);
    // 4   int
    const std::size_t bound_index_size = sizeof(int);

    // 40
    const std::size_t size =
      steer_size + r_size + width_size + radius_size + bound_index_size;

    // 0   int
    const std::size_t steer_pos = 0;
    // 4   double vector
    const std::size_t r_pos = steer_pos + sizeof(int);
    // 28  int
    const std::size_t width_pos = r_pos + sizeof(double) * volInt::axes_num;
    // 32  int
    const std::size_t radius_pos = width_pos + sizeof(int);
    // 36  int
    const std::size_t bound_index_pos = radius_pos + sizeof(int);
  } // namespace wheel

  namespace weapon_slot{
    const std::size_t max_slots = 3;

    // 4   int
    const std::size_t slots_existence_size = sizeof(int);

    // 12  int vector
    const std::size_t R_slot_size = sizeof(int) * volInt::axes_num;
    // 4   int
    const std::size_t location_angle_of_slot_size = sizeof(int);

    // 16
    const std::size_t slot_data_size =
      R_slot_size + location_angle_of_slot_size;

    // 0   int
    const std::size_t slots_existence_pos = 0;

    // 0   int vector
    const std::size_t R_slot_rel_pos = 0;
    // 12  int
    const std::size_t location_angle_of_slot_rel_pos =
      R_slot_rel_pos + sizeof(int) * volInt::axes_num;
  } // namespace weapon_slot

} // namespace m3d

namespace a3d{

  namespace header{
    // 4   int
    const std::size_t n_models_size = sizeof(int);
    // 4   int
    const std::size_t xmax_size = sizeof(int);
    // 4   int
    const std::size_t ymax_size = sizeof(int);
    // 4   int
    const std::size_t zmax_size = sizeof(int);
    // 4   int
    const std::size_t rmax_size = sizeof(int);

    // 4   int
    const std::size_t body_color_offset_size = sizeof(int);
    // 4   int
    const std::size_t body_color_shift_size = sizeof(int);

    // 32
    const std::size_t size =
      n_models_size + xmax_size + ymax_size + zmax_size + rmax_size +
      body_color_offset_size + body_color_shift_size;

    // 0   int
    const std::size_t n_models_pos = 0;
    // 4   int
    const std::size_t xmax_pos = n_models_pos + sizeof(int);
    // 8   int
    const std::size_t ymax_pos = xmax_pos + sizeof(int);
    // 12  int
    const std::size_t zmax_pos = ymax_pos + sizeof(int);
    // 16  int
    const std::size_t rmax_pos = zmax_pos + sizeof(int);

    // 20  int
    const std::size_t body_color_offset_pos = rmax_pos + sizeof(int);
    // 24  int
    const std::size_t body_color_shift_pos =
      body_color_offset_pos + sizeof(int);
  } // namespace header

} // namespace a3d

namespace mat_tables{

  struct offset_pair
  {
    offset_pair()
    : offset(0), shift(0)
    {
    }

    offset_pair(int offset_arg, int shift_arg)
    : offset(offset_arg), shift(shift_arg)
    {
    }

    offset_pair(std::initializer_list<int> l)
    {
      offset = *l.begin();
      shift = *std::next(l.begin());
    }

    int offset;
    int shift;
  };

  typedef std::unordered_map<std::string, offset_pair> offset_map;

  namespace append_order_el{
    const std::string regular = "regular";
    const std::string special = "special";
    const std::string default_body = "default_body";
    const std::string additional_body = "additional_body";
  } // namespace append_order_el

  namespace html{
    const std::vector<std::string> append_order
      {
        append_order_el::regular,
        append_order_el::default_body,
        append_order_el::additional_body,
      };
  } // namespace html

  namespace mtl{
    const std::vector<std::string> append_order
      {
        append_order_el::regular,
        append_order_el::special,
        append_order_el::default_body,
        append_order_el::additional_body,
      };
  } // namespace mtl

  const offset_map regular_offsets
  {
    {c3d::color::string::zero_reserved,      {0  , 0}},
    {c3d::color::string::body,               {128, 3}},
    {c3d::color::string::window,             {176, 4}},
    {c3d::color::string::wheel,              {224, 7}},
    {c3d::color::string::defense,            {184, 4}},
    {c3d::color::string::weapon,             {224, 3}},
    {c3d::color::string::tube,               {224, 7}},
    {c3d::color::string::body_red,           {128, 3}},
    {c3d::color::string::body_blue,          {144, 3}},
    {c3d::color::string::body_yellow,        {160, 3}},
    {c3d::color::string::body_gray,          {228, 4}},
    {c3d::color::string::yellow_charged,     {112, 4}},
    {c3d::color::string::material_0,         {0  , 2}},
    {c3d::color::string::material_1,         {32 , 2}},
    {c3d::color::string::material_2,         {64 , 4}},
    {c3d::color::string::material_3,         {72 , 3}},
    {c3d::color::string::material_4,         {88 , 3}},
    {c3d::color::string::material_5,         {104, 4}},
    {c3d::color::string::material_6,         {112, 4}},
    {c3d::color::string::material_7,         {120, 4}},
    {c3d::color::string::black,              {184, 4}},
    {c3d::color::string::body_green,         {240, 3}},
    {c3d::color::string::skyfarmer_kernoboo, {136, 4}},
    {c3d::color::string::skyfarmer_pipetka,  {128, 4}},
    {c3d::color::string::rotten_item,        {224, 4}},
  };

  // Those don't exist in Vangers source.
  const offset_map special_offsets
  {
    {c3d::color::string::center_of_mass,     {128, 4}},
    {c3d::color::string::attachment_point,   {240, 4}},
  };

  const offset_map default_body_offsets
  {
    {c3d::color::body::string::el_1 + "0" +
       c3d::color::body::string::el_2 + "0", {0  , 0}},
    {c3d::color::body::string::el_1 + "34" +
       c3d::color::body::string::el_2 + "3", {34 , 3}},
    {c3d::color::body::string::el_1 + "112" +
       c3d::color::body::string::el_2 + "4", {112, 4}},
    {c3d::color::body::string::el_1 + "128" +
       c3d::color::body::string::el_2 + "3", {128, 3}},
    {c3d::color::body::string::el_1 + "128" +
       c3d::color::body::string::el_2 + "4", {128, 4}},
    {c3d::color::body::string::el_1 + "134" +
       c3d::color::body::string::el_2 + "4", {134, 4}},
    {c3d::color::body::string::el_1 + "136" +
       c3d::color::body::string::el_2 + "4", {136, 4}},
    {c3d::color::body::string::el_1 + "140" +
       c3d::color::body::string::el_2 + "5", {140, 5}},
    {c3d::color::body::string::el_1 + "144" +
       c3d::color::body::string::el_2 + "3", {144, 3}},
    {c3d::color::body::string::el_1 + "145" +
       c3d::color::body::string::el_2 + "3", {145, 3}},
    {c3d::color::body::string::el_1 + "152" +
       c3d::color::body::string::el_2 + "4", {152, 4}},
    {c3d::color::body::string::el_1 + "160" +
       c3d::color::body::string::el_2 + "3", {160, 3}},
    {c3d::color::body::string::el_1 + "160" +
       c3d::color::body::string::el_2 + "4", {160, 4}},
    {c3d::color::body::string::el_1 + "228" +
       c3d::color::body::string::el_2 + "4", {228, 4}},
    {c3d::color::body::string::el_1 + "240" +
       c3d::color::body::string::el_2 + "3", {240, 3}},
    {c3d::color::body::string::el_1 + "245" +
       c3d::color::body::string::el_2 + "4", {245, 4}},
  };

} // namespace mat_tables

} // namespace tractor_converter

#endif // TRACTOR_CONVERTER_VANGERS_MODELS_CONSTANTS_H


#include "KProbeResistantMatrix.h"

#include <NTL/GF2.h>
#include <NTL/GF2X.h>
#include <NTL/GF2E.h>
#include <NTL/GF2XFactoring.h>
#include <NTL/GF2EX.h>

using namespace NTL;

// private declarations
void calculate_k_resistant_matrix_row(jbyte *, int, int, int);
GF2E int_to_GF2E(int);

JNIEXPORT jobjectArray JNICALL Java_edu_biu_protocols_yao_primitives_KProbeResistantMatrixBuilder_createMatrix
(JNIEnv * env, jobject obj, jint n, jint t, jint K, jint N) {
    int m = N * t;

    //Define byte[] class
    jclass byteArrayClass = env->FindClass("[B");

    // create object array that will hold the matrix rows
    // each row is of size m = N * t, and there are n rows.
    // java: byte[][] matrix = new byte[n][];
    jobjectArray matrix = env->NewObjectArray(n, byteArrayClass, NULL); // matrix is currently holding n objects.

    // initialize the GF2 extension with an irreducible polynomial of size t as modulus.
    // essentially we are creating F_{2^t}
    GF2X gf2e_modulus = BuildIrred_GF2X(t);
    GF2E::init(gf2e_modulus);

    // for each row i in {0, ..., n-1}
    for (int i = 0; i < n; i++) {

	// java: java_row[i] = new byte[m];
	jbyteArray java_row_i = env->NewByteArray(m);

	// map the java row to a native row
	jbyte * native_row_i = env->GetByteArrayElements(java_row_i, 0);

	// native_row[i] = calculate_k_resistant_matrix_row(t, K, N);
	calculate_k_resistant_matrix_row(native_row_i, t, K, N);

	// release the native row (and copy back: java_row[i] <- native_row[i])
	env->ReleaseByteArrayElements(java_row_i, native_row_i, 0);

	// java: matrix[i] = java_row[i];
	env->SetObjectArrayElement(matrix, i, java_row_i);
    }

    return matrix;
}

void calculate_k_resistant_matrix_row(jbyte * matrix_row, int t, int K, int N) {
    GF2EX p = random_GF2EX(K-1); // gets a random polynomial in F_{2^t}[x] of degree K-1

    for (int i = 1; i <= N; i++) { // we calculate P(1)_2, ..., P(N)_2
	GF2E i_element = int_to_GF2E(i);

	// v = p(i)
	GF2X v = rep(eval(p, i_element));

	// matrix_row[j] = v;
	int first_index = (i - 1) * t;
	for (int j = 0; j < t; j++) {
	    if (IsOne(coeff(v, j))) {
		matrix_row[first_index + j] = 1;
	    } else {
		matrix_row[first_index + j] = 0;
	    }
	}
    }

    // at this point matrix_row is populated
    return;
}

GF2E int_to_GF2E(int num) {
    GF2X num_as_gf2x; // initially zero
    int bits = num;
    int i = 0;

    // for each bit in num, if the bit is 1, turn on the proper coeff in the gf2x polynomial
    while (bits) {
	if (bits & 1) {
	    SetCoeff(num_as_gf2x, i);
	}
	i++;
	bits >>= 1;
    }

    return to_GF2E(num_as_gf2x);
}


#pragma once

#include "collision_tensor_dense_base.hpp"
#include "collision_tensor_zlastAM_storage.hpp"
#include <cblas.h>
#include <immintrin.h>
#include <x86intrin.h>
#include <Eigen/Dense>
#include <boost/align/aligned_allocator.hpp>
#include <boost/assert.hpp>
#include <vector>

namespace boltzmann {
namespace ct_dense {

class CollisionTensorZLastAM : public CollisionTensorZLastAMstorage
{
 public:
  typedef std::vector<double, boost::alignment::aligned_allocator<double, 32>> aligned_vector;

 public:
  CollisionTensorZLastAM(const basis_t &basis, int bufsize)
      : CollisionTensorZLastAMstorage(basis, bufsize)
  {
    /* empty */
  }

  /**
   * @param[out] out   output array (col major, unpadded)
   * @param[in]  in    input array (col major, padded)
   * @param[in]  imax  apply slices up to and including index imax, if imax<=0, apply all
   */
  template <typename DERIVED1, typename DERIVED2>
  void apply(Eigen::DenseBase<DERIVED1> &out,
             const Eigen::DenseBase<DERIVED2> &in,
             int imax=0) const;

 public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW

};

template <typename DERIVED1, typename DERIVED2>
void
CollisionTensorZLastAM::apply(Eigen::DenseBase<DERIVED1> &out,
                              const Eigen::DenseBase<DERIVED2> &in,
                              int imax) const
{
  auto aligned_size = [](size_t size) {
    return size + (VBCRSSparsity<>::align - (size % VBCRSSparsity<>::align));
  };

  if (imax <= 0) {
    imax = N_;
  }

  typedef VBCRSSparsity<>::mem_size_t memsize_t;

  static_assert(!DERIVED1::IsRowMajor, "expect column major");
  static_assert(!DERIVED2::IsRowMajor, "expect column major");

  BOOST_ASSERT(out.cols() == in.cols());
  BOOST_ASSERT(buffer_.size() >= in.cols() * in.rows());

  double *buf = buffer_.data();
  const double *data = entries_;
  BOOST_ASSERT(buffer_.size() >= *(voffsets_.rbegin()));
  int Npadded = *(voffsets_.rbegin());

  BOOST_ASSERT(out.rows() == N_);
  BOOST_ASSERT(in.rows() == Npadded);

  memsize_t memoffset = 0;
  unsigned int z_offset = 0;
  for (unsigned int lt = 0; lt < sparsity_patterns_.size(); ++lt) {
    const auto &vbcrs = sparsity_patterns_[lt];

    for (unsigned int z = 0; z < vbcrs.dimz(); ++z) {
      // set buffer to zero (cblas_dgemv will add results (beta=1.0))
      std::fill(buffer_.begin(), buffer_.end(), 0.0);
      for (unsigned int i = 0; i < vbcrs.nblock_rows(); ++i) {
        size_t row_offset = vbcrs.get_row_info(i).offset;
        size_t row_extent = vbcrs.get_row_info(i).extent;
        if(row_offset > imax) continue;

        memsize_t padded_row_size = aligned_size(row_extent);
        memsize_t padded_row_offset = voffsets_[i];
        // set buf in current row to zero
        for (unsigned int blkidx = vbcrs.row_begin(i); blkidx < vbcrs.row_end(i); ++blkidx) {
          auto &subblock = vbcrs.get_block(blkidx);
          size_t col_offset = subblock.offset;
          if(col_offset > imax)
            continue;

          size_t col_extent = subblock.extent;
          // get padded column offset
          auto it = offset_map_.find(col_offset);
          BOOST_ASSERT(it != offset_map_.end());
          size_t padded_col_offset = it->second;
          const double *x1 = in.derived().data() + padded_col_offset;
          memsize_t sblocksize = padded_row_size * col_extent;
          const double *M = data + memoffset;
          cblas_dgemm(CblasColMajor,
                      CblasNoTrans,            /* trans A */
                      CblasNoTrans,            /* trans B */
                      row_extent,              /* m */
                      in.cols(),               /* n */
                      col_extent,              /* k */
                      1.0,                     /* alpha */
                      M,                       /* A* */
                      padded_row_size,         /* lda */
                      x1,                      /* B* */
                      Npadded,                 /* ldb */
                      1.0,                     /* beta */
                      buf + padded_row_offset, /* C */
                      Npadded /* ldc */);

          // increment data pointer
          memoffset += sblocksize;
        }  // end iterate over local row
      }    // end iterate over rows
      // compute dot product
      size_t slice_id = z_offset + z;
      double sinv = Sinv_.diagonal()(slice_id);
      for (int kk = 0; kk < in.cols(); ++kk) {
        out(slice_id, kk) =
            sinv *
            cblas_ddot(Npadded, in.derived().data() + kk * Npadded, 1, buf + kk * Npadded, 1);
      }
    }  // end iterate over z
    // update z-offset
    z_offset += vbcrs.dimz();
  }
}

}  // namespace ct_dense
}  // namespace boltzmann


/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You 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.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee --- CLIPP Random Support
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#ifndef __IRONBEE__CLIPP__RANDOM_SUPPORT__
#define __IRONBEE__CLIPP__RANDOM_SUPPORT__

#include <boost/function.hpp>
#include <boost/random.hpp>

namespace IronBee {
namespace CLIPP {

//! A random distribution.
typedef boost::function<size_t()> distribution_t;

//! The constant distribution.
inline
size_t constant_distribution(size_t n)
{
    return n;
}

//! Adapt a boost::random distribution to a distribution_t.
template <typename DistributionType>
class random_distribution
{
public:
    explicit
    random_distribution(DistributionType dist) :
        m_rng(clock()),
        m_distribution(dist)
    {
        // nop
    }

    size_t operator()()
    {
        size_t result = m_distribution(m_rng);
        if (result < 1) {
            result = 1;
        }
        return result;
    }

protected:
    boost::random::mt19937 m_rng;
    DistributionType       m_distribution;
};

//! Helper function to make @c random_distributions.
template <typename DistributionType>
random_distribution<DistributionType>
make_random_distribution(DistributionType dist)
{
    return random_distribution<DistributionType>(dist);
}

} // CLIPP
} // IronBee

#endif