//#########################################################//
//#                                                       #//
//# gaussian_mixture_models  gmm_regressor.cpp            #//
//# Roberto Capobianco  <capobianco@dis.uniroma1.it>      #//
//#                                                       #//
//#########################################################//

#include <Eigen/Core>
#include <iostream>
#include <set>
#include <stdexcept>
#include <vector>

#include <omp.h>

#include <particle_filter/gmm_regressor.h>
#include <particle_filter/matrix_io.h>

namespace gmms {
void GMMRegressor::train(const Eigen::MatrixXd& dataset,
        bool evaluate_bic,
        int gmm_components) {
    int num_components;
    double bic = 0.0;
    bool first_trial = true;
    input_size_ = dataset.cols();

    std::cout << "Training regressor" << std::endl;
    std::cout << "\t\tEvaluate BIC: ";

    if (evaluate_bic) {
        std::cout << "ON" << std::endl;
        num_components = 1;
    } else {
        std::cout << "OFF" << std::endl;
        num_components = gmm_components;
    }

#pragma parallel for
    for (int c = num_components; c <= gmm_components; ++c) {
        std::cout << "\t\t\t\tUsing " << c << " GMM components" << std::endl;

        std::shared_ptr<GaussianMixtureModel> model(new GaussianMixtureModel);
        model->setNumComponents(c);
        model->initialize(dataset);
        model->setNumIterations(max_iterations_);
        model->setDelta(delta_);

        try {
            model->expectationMaximization(dataset);
        } catch (std::runtime_error e) {
            std::cout << "\t\t\t\t" << c << " components are not usable"
                      << std::endl;
            break;
        }

        double trial_bic = model->bayesianInformationCriterion(dataset);

        std::cout << "\t\t\t\tTrial BIC: " << trial_bic << std::endl;

        if (first_trial || trial_bic < bic) {
            bic = trial_bic;
            gmm_ = model;

            if (first_trial) {
                first_trial = false;
            }
        }
    }

    std::cout << "\t\tFinal model with " << gmm_->numComponents() << "; ";
    std::cout << "BIC " << bic << std::endl;

    trained_ = true;
}

Eigen::MatrixXd GMMRegressor::predict(const Eigen::MatrixXd& dataset,
        const Eigen::VectorXi& output_indices) const {
    if (!trained_ || gmm_ == nullptr) {
        throw std::runtime_error(nottrained_());
    }

    int query_size = dataset.cols();
    int target_size = output_indices.size();

    if (query_size + target_size != input_size_) {
        throw std::runtime_error(notconsistent_());
    }

    if (target_size == 0) {
        throw std::runtime_error(notvalid_());
    }

    int dataset_size = dataset.rows();
    int num_components = gmm_->numComponents();
    Eigen::VectorXi input_indices(query_size);

    int idx = 0;
    for (int i = 0; i < input_size_; ++i) {
        if (!(output_indices.array() == i).any()) {
            input_indices(idx++) = i;
        }
    }

    Eigen::VectorXi indices(input_size_);
    indices.head(query_size) = input_indices;
    indices.tail(target_size) = output_indices;
    Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> P =
            indices.asPermutation().transpose();

    Eigen::MatrixXd regressions =
            Eigen::MatrixXd::Zero(dataset_size, target_size);

    std::vector<Gaussian> reduced_gaussians(num_components);
    std::vector<double> normalization_factor(dataset_size, 0.0);

    for (int k = 0; k < num_components; ++k) {
        Eigen::VectorXd mean_k = gmm_->component(k).mean();
        Eigen::MatrixXd covariance_k = gmm_->component(k).covariance();

        mean_k = P * mean_k;
        covariance_k = P * covariance_k * P.transpose();

        Eigen::VectorXd query_mean = mean_k.head(query_size);
        Eigen::VectorXd target_mean = mean_k.tail(target_size);
        Eigen::MatrixXd query_covariance =
                covariance_k.topLeftCorner(query_size, query_size);
        Eigen::MatrixXd target_covariance =
                covariance_k.bottomRightCorner(target_size, target_size);
        Eigen::MatrixXd query_target_covariance =
                covariance_k.topRightCorner(query_size, target_size);
        Eigen::MatrixXd target_query_covariance =
                query_target_covariance.transpose();
        Eigen::MatrixXd inv_query_covariance = query_covariance.inverse();

        reduced_gaussians[k].setMeanCovariance(query_mean, query_covariance);

        Eigen::MatrixXd conditional_covariance =
                target_covariance - target_query_covariance *
                                            inv_query_covariance *
                                            query_target_covariance;

#pragma omp parallel for
        for (int i = 0; i < dataset_size; ++i) {
            Eigen::VectorXd query = dataset.row(i);
            double query_probability =
                    reduced_gaussians[k].evaluate_point(query);

            Eigen::VectorXd tmp(target_size);
            tmp = target_mean + target_query_covariance * inv_query_covariance *
                                        (query - query_mean);
            tmp *= query_probability;

            regressions.row(i) += tmp;
            normalization_factor[i] += query_probability;

            if (k == num_components - 1) {
                regressions.row(i) /= normalization_factor[i];
            }
        }
    }

    return regressions;
}

void GMMRegressor::load(const std::string filename) {
    MatrixIO mio;
    Eigen::MatrixXd model;

    mio.readFromFile(filename, model);

    trained_ = model(0, 0);
    delta_ = model(1, 0);
    max_iterations_ = model(2, 0);
    input_size_ = model(3, 0);
    gmm_ = std::shared_ptr<GaussianMixtureModel>(new GaussianMixtureModel);
    gmm_->load(model.block(4, 0, model.rows() - 4, model.cols()));
}

void GMMRegressor::save(const std::string filename) {
    MatrixIO mio;
    Eigen::MatrixXd gmm_model = gmm_->save();
    Eigen::MatrixXd model =
            Eigen::MatrixXd::Zero(gmm_model.rows() + 4, gmm_model.cols());

    model(0, 0) = trained_;
    model(1, 0) = delta_;
    model(2, 0) = max_iterations_;
    model(3, 0) = input_size_;
    model.block(4, 0, gmm_model.rows(), gmm_model.cols()) = gmm_model;
    mio.writeToFile(filename, model);
}
}  // namespace gmms


/*
 * Created by: Joshua Latham. All of this work is my own.

        ######## N0641701's Route::netLength() Test File ########

netLength calculates the distance between the first and last points on the Route.

All log files used will be generated with the program that I built to generate log files unless stated otherwise.

All tests catagorised, and they are as follows:

### These are normal tests to check that the function is giving the correct output.

Test: CorrectOutput
Decscription:
This test will test the function for the correct
output given a number of points which have a known
distance between the first and last point.

Test: OnePoint
Description: This test will test the function on
how it handles a route with only one point. The expected
output should be 0, as there is no distance to measure.

Test: TwoPoints
Description: This test will test the function on
how it handles a route with just two points with
a distance. The expected output should be the distance
between the two points.

Test: BackToStart
Description: This test will test the function against
a route that loops back to its starting point. Therefore
the 0 is the expected output.

Test: TwoIdenticalPoints
Description: Two points with the same location. This test
should give a distance of 0.

Test: UpAndDown
Description: This test will present points that do not move
latitudinally or longitudinally but in elevation. The
distance expected is 0. I have manually created the log file for this.

### These tests are designed to catch any errors when it comes to handling positive and negative numbers.

Test: PosLatLong
Description: Testing the function against positive
latitudinal and positive longitudinal points which
shouldn't affect the output.

Test: PosLatNegLong
Description: Testing the function against positive
latitudinal data and negative longitudinal data.

Test: NegLatNegLong
Decscription: Testing the function against negative
longitudinal data and negative longitudinal data.

Test: NegLatPosLong
Description: Testing the function against negative
longitudinal data and positive longitudinal data.

### Edge cases

Test: BigNumbers
Description: Testing the function on how well it can handle large numbers.
I've manually created these log files with very large numbers to see how well
they'll be handled.

Test: SmallNumbers
Description Testing against very small numbers to see if the function
can handle them.

Test: BigData
Description: Testing the function against a large number of points to see if it will handle it.

*/

#include <boost/test/unit_test.hpp>

#include "logs.h"
#include "route.h"
#include "track.h"

using namespace GPS;

BOOST_AUTO_TEST_SUITE( NetLength )

const bool isFileName = true;

//Correct output test. The usual data to expect.
BOOST_AUTO_TEST_CASE(CorrectOutput)
{
    Route route = Route(LogFiles::GPXRoutesDir + "CorrectOutput_N0641701_MHCBA.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 2827.47, 0.01);
}
//One point. Testing just one point on its own.
BOOST_AUTO_TEST_CASE(OnePoint)
{
    Route route = Route(LogFiles::GPXRoutesDir + "OnePoint_N0641701_M.gpx", isFileName);
    BOOST_CHECK_EQUAL(route.netLength(), 0);
}
//Two Points. Testing two points with different locations.
BOOST_AUTO_TEST_CASE(TwoPoints)
{
    Route route = Route(LogFiles::GPXRoutesDir + "TwoPoints_N0641701_MN.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 999.111, 0.01);
}
//A route that circles back to the beginning resulting in a net length of 0.
BOOST_AUTO_TEST_CASE(BackToStart)
{
    Route route = Route(LogFiles::GPXRoutesDir + "BackToStart_N0641701_MHINSRM.gpx", isFileName);
    BOOST_CHECK_EQUAL(route.netLength(), 0);
}
//Testing two identical points which should give the expected result of 0.
BOOST_AUTO_TEST_CASE(TwoIdenticalPoints)
{
    Route route = Route(LogFiles::GPXRoutesDir + "TwoIdenticalPoints_N0641701_MM.gpx", isFileName);
    BOOST_CHECK_EQUAL(route.netLength(), 0);
}
//Testing a route that doesn't move anywhere but by elevation.
BOOST_AUTO_TEST_CASE(UpAndDown)
{
    Route route = Route(LogFiles::GPXRoutesDir + "UpAndDown_N0641701_MMMMM.gpx", isFileName);
    BOOST_CHECK_EQUAL(route.netLength(), 0);
}

//Positive and Negative test to make sure the function can handle them correctly.

//Testing a positive latitude and longitude.

BOOST_AUTO_TEST_CASE(PosLatLong)
{
    Route route = Route(LogFiles::GPXRoutesDir + "PosLatLong_N0641701_MIE.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 28276.2, 0.01);
}

//Testing Positive latitude but negative longitude
BOOST_AUTO_TEST_CASE(PosLatNegLong)
{
    Route route = Route(LogFiles::GPXRoutesDir + "PosLatNegLong_N0641701_MGA.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 28276.2, 0.01);
}

//Testing netagive latitude and negative longitude.
BOOST_AUTO_TEST_CASE(NegLatNegLong)
{
    Route route = Route(LogFiles::GPXRoutesDir + "NegLatNegLong_N0641701_MQU.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 28276.2, 0.01);
}

//Testing negative latitude and positive longitude
BOOST_AUTO_TEST_CASE(NegLatPosLong)
{
    Route route = Route(LogFiles::GPXRoutesDir + "NegLatPosLong_N0641701_MSY.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 28276.2, 0.01);
}

//Testing whether or not the function can handle large numbers.
BOOST_AUTO_TEST_CASE(BigNumbers)
{
    Route route = Route(LogFiles::GPXRoutesDir + "BigNumbers_N0641701_MHCDE.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 18398222.331737, 0.01);
}

//Testing whether or not the function can handle very small numbers.
BOOST_AUTO_TEST_CASE(SmallNumbers)
{
    Route route = Route(LogFiles::GPXRoutesDir + "SmallNumbers_N0641701_MHCDE.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 222390.160475, 0.01);
}

//Testing whether or not the function can handle extremely large data sets.
BOOST_AUTO_TEST_CASE(BigData)
{
    Route route = Route(LogFiles::GPXRoutesDir + "BigData_N0641701_MHCBA.gpx", isFileName);
    BOOST_CHECK_CLOSE(route.netLength(), 2827.47, 0.01);
}
BOOST_AUTO_TEST_SUITE_END()


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

  @copyright 2016 NumScale SAS

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

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

 /*!

    @ingroup group-arithmetic
    Function object implementing min capabilities

    Computes the smallest of its parameter.

    @par semantic:
    For any given value @c x and @c y of type @c T:

    @code
    T r = min(x, y);
    @endcode

    is similar to:

    @code
    T r = (x < y) ? x : y;
    @endcode

    @par Note:

    With this definition min(x, @ref Nan) should return x...

    On some systems (namely for example vmx in simd mode) the intrinsic used returns Nan as soon x or y is a nan.
    So the real definition of our min function must add: but if y is Nan the result is system dependent.

    This can be corrected using the pedantic_ decorator that ensures the standard behaviour at a cost.

    @see minnum, minnummag, minmag

  **/
  Value min(Value const & v0, Value const& y);
} }
#endif

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

#endif


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// 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/config.hpp>

#include <algorithm>
#include <vector>
#include <utility>
#include <iostream>

#include <boost/graph/graph_utility.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/neighbor_bfs.hpp>
#include <boost/property_map/property_map.hpp>

/*

  This examples shows how to use the breadth_first_search() GGCL
  algorithm, specifically the 3 argument variant of bfs that assumes
  the graph has a color property (property) stored internally.

  Two pre-defined visitors are used to record the distance of each
  vertex from the source vertex, and also to record the parent of each
  vertex. Any number of visitors can be layered and passed to a GGCL
  algorithm.

  The call to vertices(G) returns an STL-compatible container which
  contains all of the vertices in the graph.  In this example we use
  the vertices container in the STL for_each() function.

  Sample Output:

  0 --> 2
  1 --> 1 3 4
  2 --> 1 3 4
  3 --> 1 4
  4 --> 0 1
  distances: 1 2 1 2 0
  parent[0] = 4
  parent[1] = 2
  parent[2] = 0
  parent[3] = 2
  parent[4] = 0

*/

template <class ParentDecorator>
struct print_parent {
  print_parent(const ParentDecorator& p_) : p(p_) { }
  template <class Vertex>
  void operator()(const Vertex& v) const {
    std::cout << "parent[" << v << "] = " <<  p[v]  << std::endl;
  }
  ParentDecorator p;
};

template <class NewGraph, class Tag>
struct graph_copier
  : public boost::base_visitor<graph_copier<NewGraph, Tag> >
{
  typedef Tag event_filter;

  graph_copier(NewGraph& graph) : new_g(graph) { }

  template <class Edge, class Graph>
  void operator()(Edge e, Graph& g) {
    boost::add_edge(boost::source(e, g), boost::target(e, g), new_g);
  }
private:
  NewGraph& new_g;
};

template <class NewGraph, class Tag>
inline graph_copier<NewGraph, Tag>
copy_graph(NewGraph& g, Tag) {
  return graph_copier<NewGraph, Tag>(g);
}

int main(int , char* [])
{
  typedef boost::adjacency_list<
    boost::mapS, boost::vecS, boost::bidirectionalS,
    boost::property<boost::vertex_color_t, boost::default_color_type,
        boost::property<boost::vertex_degree_t, int,
          boost::property<boost::vertex_in_degree_t, int,
    boost::property<boost::vertex_out_degree_t, int> > > >
  > Graph;

  Graph G(5);
  boost::add_edge(0, 2, G);
  boost::add_edge(1, 1, G);
  boost::add_edge(1, 3, G);
  boost::add_edge(1, 4, G);
  boost::add_edge(2, 1, G);
  boost::add_edge(2, 3, G);
  boost::add_edge(2, 4, G);
  boost::add_edge(3, 1, G);
  boost::add_edge(3, 4, G);
  boost::add_edge(4, 0, G);
  boost::add_edge(4, 1, G);

  typedef Graph::vertex_descriptor Vertex;

  // Array to store predecessor (parent) of each vertex. This will be
  // used as a Decorator (actually, its iterator will be).
  std::vector<Vertex> p(boost::num_vertices(G));
  // VC++ version of std::vector has no ::pointer, so
  // I use ::value_type* instead.
  typedef std::vector<Vertex>::value_type* Piter;

  // Array to store distances from the source to each vertex .  We use
  // a built-in array here just for variety. This will also be used as
  // a Decorator.
  boost::graph_traits<Graph>::vertices_size_type d[5];
  std::fill_n(d, 5, 0);

  // The source vertex
  Vertex s = *(boost::vertices(G).first);
  p[s] = s;
  boost::neighbor_breadth_first_search
    (G, s,
     boost::visitor(boost::make_neighbor_bfs_visitor
     (std::make_pair(boost::record_distances(d, boost::on_tree_edge()),
                     boost::record_predecessors(&p[0],
                                                 boost::on_tree_edge())))));

  boost::print_graph(G);

  if (boost::num_vertices(G) < 11) {
    std::cout << "distances: ";
#ifdef BOOST_OLD_STREAM_ITERATORS
    std::copy(d, d + 5, std::ostream_iterator<int, char>(std::cout, " "));
#else
    std::copy(d, d + 5, std::ostream_iterator<int>(std::cout, " "));
#endif
    std::cout << std::endl;

    std::for_each(boost::vertices(G).first, boost::vertices(G).second,
                  print_parent<Piter>(&p[0]));
  }

  return 0;
}


#include "Common/Common.h"
#include "Demos/Visualization/MiniGL.h"
#include "Demos/Visualization/Selection.h"
#include "Simulation/TimeManager.h"
#include <Eigen/Dense>
#include "Simulation/SimulationModel.h"
#include "Simulation/TimeStepController.h"
#include <iostream>
#include "Demos/Visualization/Visualization.h"
#include "Utils/Logger.h"
#include "Utils/Timing.h"
#include "Utils/FileSystem.h"
#include "Demos/Common/DemoBase.h"
#include "Demos/Common/TweakBarParameters.h"
#include "Simulation/Simulation.h"

// Enable memory leak detection
#if defined(_DEBUG) && !defined(EIGEN_ALIGN)
	#define new DEBUG_NEW
#endif

using namespace PBD;
using namespace Eigen;
using namespace std;
using namespace Utilities;

void timeStep ();
void buildModel ();
void createMesh();
void render ();
void reset();
void TW_CALL setBendingMethod(const void *value, void *clientData);
void TW_CALL getBendingMethod(void *value, void *clientData);
void TW_CALL setSimulationMethod(const void *value, void *clientData);
void TW_CALL getSimulationMethod(void *value, void *clientData);
void TW_CALL setBendingStiffness(const void* value, void* clientData);
void TW_CALL getBendingStiffness(void* value, void* clientData);
void TW_CALL setDistanceStiffness(const void* value, void* clientData);
void TW_CALL getDistanceStiffness(void* value, void* clientData);
void TW_CALL setXXStiffness(const void* value, void* clientData);
void TW_CALL getXXStiffness(void* value, void* clientData);
void TW_CALL setYYStiffness(const void* value, void* clientData);
void TW_CALL getYYStiffness(void* value, void* clientData);
void TW_CALL setXYStiffness(const void* value, void* clientData);
void TW_CALL getXYStiffness(void* value, void* clientData);
void TW_CALL setXYPoissonRatio(const void* value, void* clientData);
void TW_CALL getXYPoissonRatio(void* value, void* clientData);
void TW_CALL setYXPoissonRatio(const void* value, void* clientData);
void TW_CALL getYXPoissonRatio(void* value, void* clientData);
void TW_CALL setNormalizeStretch(const void* value, void* clientData);
void TW_CALL getNormalizeStretch(void* value, void* clientData);
void TW_CALL setNormalizeShear(const void* value, void* clientData);
void TW_CALL getNormalizeShear(void* value, void* clientData);

const int nRows = 50;
const int nCols = 50;
const Real width = 10.0;
const Real height = 10.0;
short simulationMethod = 2;
short bendingMethod = 2;
Real distanceStiffness = 1.0;
Real xxStiffness = 1.0;
Real yyStiffness = 1.0;
Real xyStiffness = 1.0;
Real xyPoissonRatio = 0.3;
Real yxPoissonRatio = 0.3;
bool normalizeStretch = false;
bool normalizeShear = false;
Real bendingStiffness = 0.01;
DemoBase *base;

// main
int main( int argc, char **argv )
{
	REPORT_MEMORY_LEAKS

	base = new DemoBase();
	base->init(argc, argv, "Cloth demo");

	SimulationModel *model = new SimulationModel();
	model->init();
	Simulation::getCurrent()->setModel(model);

	buildModel();

	base->createParameterGUI();

	// OpenGL
	MiniGL::setClientIdleFunc (timeStep);
	MiniGL::addKeyFunc('r', reset);
	MiniGL::setClientSceneFunc(render);
	MiniGL::setViewport (40.0f, 0.1f, 500.0f, Vector3r (5.0, 10.0, 30.0), Vector3r (5.0, 0.0, 0.0));

	TwType enumType2 = TwDefineEnum("SimulationMethodType", NULL, 0);
	TwAddVarCB(MiniGL::getTweakBar(), "SimulationMethod", enumType2, setSimulationMethod, getSimulationMethod, &simulationMethod,
		" label='Simulation method' enum='0 {None}, 1 {Distance constraints}, 2 {FEM based PBD}, 3 {Strain based dynamics}, 4 {XPBD distance constraints}' group=Simulation");
	TwType enumType3 = TwDefineEnum("BendingMethodType", NULL, 0);
	TwAddVarCB(MiniGL::getTweakBar(), "BendingMethod", enumType3, setBendingMethod, getBendingMethod, &bendingMethod,
		" label='Bending method' enum='0 {None}, 1 {Dihedral angle}, 2 {Isometric bending}, 3 {XPBD isometric bending}' group=Bending");
	TwAddVarCB(MiniGL::getTweakBar(), "BendingStiffness", TW_TYPE_REAL, setBendingStiffness, getBendingStiffness, model, " label='Bending stiffness'  min=0.0 step=0.1 precision=4 group='Bending' ");
	TwAddVarCB(MiniGL::getTweakBar(), "DistanceStiffness", TW_TYPE_REAL, setDistanceStiffness, getDistanceStiffness, model, " label='Distance constraint stiffness'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "xxStiffness", TW_TYPE_REAL, setXXStiffness, getXXStiffness, model, " label='xx stiffness'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "yyStiffness", TW_TYPE_REAL, setYYStiffness, getYYStiffness, model, " label='yy stiffness'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "xyStiffness", TW_TYPE_REAL, setXYStiffness, getXYStiffness, model, " label='xy stiffness'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "xyPoissonRatio", TW_TYPE_REAL, setXYPoissonRatio, getXYPoissonRatio, model, " label='xy Poisson ratio'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "yxPoissonRatio", TW_TYPE_REAL, setYXPoissonRatio, getYXPoissonRatio, model, " label='yx Poisson ratio'  min=0.0 step=0.1 precision=4 group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "normalizeStretch", TW_TYPE_BOOL32, setNormalizeStretch, getNormalizeStretch, model, " label='Normalize stretch' group='Cloth' ");
	TwAddVarCB(MiniGL::getTweakBar(), "normalizeShear", TW_TYPE_BOOL32, setNormalizeShear, getNormalizeShear, model, " label='Normalize shear' group='Cloth' ");

	MiniGL::mainLoop();

	base->cleanup();

	Utilities::Timing::printAverageTimes();
	Utilities::Timing::printTimeSums();

	delete Simulation::getCurrent();
	delete base;
	delete model;

	return 0;
}

void reset()
{
	Utilities::Timing::printAverageTimes();
	Utilities::Timing::reset();

	Simulation::getCurrent()->reset();
	base->getSelectedParticles().clear();

	Simulation::getCurrent()->getModel()->cleanup();

	buildModel();
}

void timeStep ()
{
	const Real pauseAt = base->getValue<Real>(DemoBase::PAUSE_AT);
	if ((pauseAt > 0.0) && (pauseAt < TimeManager::getCurrent()->getTime()))
		base->setValue(DemoBase::PAUSE, true);

	if (base->getValue<bool>(DemoBase::PAUSE))
		return;

	// Simulation code
	SimulationModel *model = Simulation::getCurrent()->getModel();
	const unsigned int numSteps = base->getValue<unsigned int>(DemoBase::NUM_STEPS_PER_RENDER);
	for (unsigned int i = 0; i < numSteps; i++)
	{
		START_TIMING("SimStep");
		Simulation::getCurrent()->getTimeStep()->step(*model);
		STOP_TIMING_AVG;
	}

	for (unsigned int i = 0; i < model->getTriangleModels().size(); i++)
		model->getTriangleModels()[i]->updateMeshNormals(model->getParticles());
}

void buildModel ()
{
	TimeManager::getCurrent ()->setTimeStepSize (static_cast<Real>(0.005));

	createMesh();
}

void render ()
{
	base->render();
}

/** Create a particle model mesh
*/
void createMesh()
{
	SimulationModel *model = Simulation::getCurrent()->getModel();
	model->addRegularTriangleModel(nCols, nRows,
		Vector3r(0,1,0), AngleAxisr(M_PI*0.5, Vector3r(1,0,0)).matrix(), Vector2r(width, height));

	// Set mass of points to zero => make it static
	ParticleData& pd = model->getParticles();
	pd.setMass(0, 0.0);
	pd.setMass(nRows-1, 0.0);

	// init constraints
	for (unsigned int cm = 0; cm < model->getTriangleModels().size(); cm++)
	{
		distanceStiffness = 1.0;
		if (simulationMethod == 4)
			distanceStiffness = 100000;
		model->addClothConstraints(model->getTriangleModels()[cm], simulationMethod, distanceStiffness, xxStiffness,
			yyStiffness, xyStiffness, xyPoissonRatio, yxPoissonRatio, normalizeStretch, normalizeShear);

		bendingStiffness = 0.01;
		if (bendingMethod == 3)
			bendingStiffness = 100.0;
		model->addBendingConstraints(model->getTriangleModels()[cm], bendingMethod, bendingStiffness);
	}

	LOG_INFO << "Number of triangles: " << model->getTriangleModels()[0]->getParticleMesh().numFaces();
	LOG_INFO << "Number of vertices: " << nRows*nCols;

}

void TW_CALL setBendingMethod(const void *value, void *clientData)
{
	const short val = *(const short *)(value);
	*((short*)clientData) = val;
	reset();
}

void TW_CALL getBendingMethod(void *value, void *clientData)
{
	*(short *)(value) = *((short*)clientData);
}

void TW_CALL setSimulationMethod(const void *value, void *clientData)
{
	const short val = *(const short *)(value);
	*((short*)clientData) = val;
	reset();
}

void TW_CALL getSimulationMethod(void *value, void *clientData)
{
	*(short *)(value) = *((short*)clientData);
}

void TW_CALL setBendingStiffness(const void* value, void* clientData)
{
	bendingStiffness = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<DihedralConstraint, Real, &DihedralConstraint::m_stiffness>(bendingStiffness);
	((SimulationModel*)clientData)->setConstraintValue<IsometricBendingConstraint, Real, &IsometricBendingConstraint::m_stiffness>(bendingStiffness);
	((SimulationModel*)clientData)->setConstraintValue<IsometricBendingConstraint_XPBD, Real, &IsometricBendingConstraint_XPBD::m_stiffness>(bendingStiffness);
}

void TW_CALL getBendingStiffness(void* value, void* clientData)
{
	*(Real*)(value) = bendingStiffness;
}

void TW_CALL setDistanceStiffness(const void* value, void* clientData)
{
	distanceStiffness = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<DistanceConstraint, Real, &DistanceConstraint::m_stiffness>(distanceStiffness);
	((SimulationModel*)clientData)->setConstraintValue<DistanceConstraint_XPBD, Real, &DistanceConstraint_XPBD::m_stiffness>(distanceStiffness);
}

void TW_CALL getDistanceStiffness(void* value, void* clientData)
{
	*(Real*)(value) = distanceStiffness;
}

void TW_CALL setXXStiffness(const void* value, void* clientData)
{
	xxStiffness = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<FEMTriangleConstraint, Real, &FEMTriangleConstraint::m_xxStiffness>(xxStiffness);
	((SimulationModel*)clientData)->setConstraintValue<StrainTriangleConstraint, Real, &StrainTriangleConstraint::m_xxStiffness>(xxStiffness);
}

void TW_CALL getXXStiffness(void* value, void* clientData)
{
	*(Real*)(value) = xxStiffness;
}

void TW_CALL getYYStiffness(void* value, void* clientData)
{
	*(Real*)(value) = yyStiffness;
}

void TW_CALL setYYStiffness(const void* value, void* clientData)
{
	yyStiffness = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<FEMTriangleConstraint, Real, &FEMTriangleConstraint::m_yyStiffness>(yyStiffness);
	((SimulationModel*)clientData)->setConstraintValue<StrainTriangleConstraint, Real, &StrainTriangleConstraint::m_yyStiffness>(yyStiffness);
}

void TW_CALL getXYStiffness(void* value, void* clientData)
{
	*(Real*)(value) = xyStiffness;
}

void TW_CALL setXYStiffness(const void* value, void* clientData)
{
	xyStiffness = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<FEMTriangleConstraint, Real, &FEMTriangleConstraint::m_xyStiffness>(xyStiffness);
	((SimulationModel*)clientData)->setConstraintValue<StrainTriangleConstraint, Real, &StrainTriangleConstraint::m_xyStiffness>(xyStiffness);
}

void TW_CALL getXYPoissonRatio(void* value, void* clientData)
{
	*(Real*)(value) = xyPoissonRatio;
}

void TW_CALL setXYPoissonRatio(const void* value, void* clientData)
{
	xyPoissonRatio = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<FEMTriangleConstraint, Real, &FEMTriangleConstraint::m_xyPoissonRatio>(xyPoissonRatio);
}

void TW_CALL getYXPoissonRatio(void* value, void* clientData)
{
	*(Real*)(value) = yxPoissonRatio;
}

void TW_CALL setYXPoissonRatio(const void* value, void* clientData)
{
	yxPoissonRatio = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<FEMTriangleConstraint, Real, &FEMTriangleConstraint::m_yxPoissonRatio>(yxPoissonRatio);
}

void TW_CALL getNormalizeStretch(void* value, void* clientData)
{
	*(bool*)(value) = normalizeStretch;
}

void TW_CALL setNormalizeStretch(const void* value, void* clientData)
{
	normalizeStretch = *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<StrainTriangleConstraint, bool, &StrainTriangleConstraint::m_normalizeStretch>(normalizeStretch);
}

void TW_CALL getNormalizeShear(void* value, void* clientData)
{
	*(bool*)(value) = normalizeShear;
}

void TW_CALL setNormalizeShear(const void* value, void* clientData)
{
	normalizeShear= *(const Real*)(value);
	((SimulationModel*)clientData)->setConstraintValue<StrainTriangleConstraint, bool, &StrainTriangleConstraint::m_normalizeShear>(normalizeShear);
}


/*=============================================================================
Copyright 2020 Syed Ali Hasan <alihasan9922@gmail.com>

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

#define BOOST_TEST_MODULE horizon_coord_test

#include <iostream>
#include <boost/units/io.hpp>
#include <boost/units/systems/angle/degrees.hpp>
#include <boost/astronomy/coordinate/coord_sys/horizon_coord.hpp>

#include <boost/test/unit_test.hpp>

using namespace boost::units;
using namespace boost::units::si;
using namespace boost::astronomy::coordinate;

namespace bud = boost::units::degree;

BOOST_AUTO_TEST_SUITE(horizon_coord_constructors)

BOOST_AUTO_TEST_CASE(horizon_coord_default_constructor) {
    horizon_coord<
            double,
            quantity<bud::plane_angle>,
            quantity<bud::plane_angle>>
            hc;

    //Check set_altitude_azimuth
    hc.set_altitude_azimuth(45.0 * bud::degrees, 18.0 * bud::degrees);

    //Check values
    BOOST_CHECK_CLOSE(hc.get_altitude().value(), 45.0, 0.001);
    BOOST_CHECK_CLOSE(hc.get_azimuth().value(), 18.0, 0.001);

    //Quantities stored as expected?
    BOOST_TEST((std::is_same<decltype(hc.get_altitude()), quantity<bud::plane_angle>>::value));
    BOOST_TEST((std::is_same<decltype(hc.get_azimuth()), quantity<bud::plane_angle>>::value));
}

BOOST_AUTO_TEST_CASE(horizon_coord_quantities_constructor) {
    //Make Horizon Coordinate Check
    auto hc1 = make_horizon_coord
            (15.0 * bud::degrees, 39.0 * bud::degrees);

    //Check values
    BOOST_CHECK_CLOSE(hc1.get_altitude().value(), 15.0, 0.001);
    BOOST_CHECK_CLOSE(hc1.get_azimuth().value(), 39.0, 0.001);

    //Quantities stored as expected?
    BOOST_TEST((std::is_same<decltype(hc1.get_altitude()), quantity<bud::plane_angle>>::value));
    BOOST_TEST((std::is_same<decltype(hc1.get_azimuth()), quantity<bud::plane_angle>>::value));

    //Horizon Coord constructor
    horizon_coord<double, quantity<bud::plane_angle>, quantity<bud::plane_angle>>
            hc2(1.5 * bud::degrees, 9.0 * bud::degrees);

    //Check values
    BOOST_CHECK_CLOSE(hc2.get_altitude().value(), 1.5, 0.001);
    BOOST_CHECK_CLOSE(hc2.get_azimuth().value(), 9.0, 0.001);

    //Quantities stored as expected?
    BOOST_TEST((std::is_same<decltype(hc2.get_altitude()), quantity<bud::plane_angle>>::value));
    BOOST_TEST((std::is_same<decltype(hc2.get_azimuth()), quantity<bud::plane_angle>>::value));
}

BOOST_AUTO_TEST_SUITE_END()


/*  This file is part of libDAI - http://www.libdai.org/
 *
 *  Copyright (c) 2006-2011, The libDAI authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
 */

#include <dai/index.h>
#include <strstream>
#include <map>

using namespace dai;

#define BOOST_TEST_MODULE IndexTest

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( IndexForTest ) {
    IndexFor x;
    BOOST_CHECK( !x.valid() );
    x.reset();
    BOOST_CHECK( x.valid() );

    size_t nrVars = 5;
    std::vector<Var> vars;
    for( size_t i = 0; i < nrVars; i++ )
        vars.push_back( Var( i, i+2 ) );

    for( size_t repeat = 0; repeat < 10000; repeat++ ) {
        VarSet indexVars;
        VarSet forVars;
        for( size_t i = 0; i < 5; i++ ) {
            if( rnd(2) == 0 )
                indexVars |= vars[i];
            if( rnd(2) == 0 )
                forVars |= vars[i];
        }
        IndexFor ind( indexVars, forVars );
        size_t iter = 0;
        for( ; ind.valid(); ind++, iter++ )
            BOOST_CHECK_EQUAL( calcLinearState( indexVars, calcState( forVars, iter ) ), (size_t)ind );
        BOOST_CHECK_EQUAL( iter, forVars.nrStates() );
        iter = 0;
        ind.reset();
        for( ; ind.valid(); ++ind, iter++ )
            BOOST_CHECK_EQUAL( calcLinearState( indexVars, calcState( forVars, iter ) ), (size_t)ind );
        BOOST_CHECK_EQUAL( iter, forVars.nrStates() );
    }
}

BOOST_AUTO_TEST_CASE( PermuteTest ) {
    Permute x;

    Var x0(0, 2);
    Var x1(1, 3);
    Var x2(2, 2);
    std::vector<Var> V;
    V.push_back( x1 );
    V.push_back( x2 );
    V.push_back( x0 );
    VarSet X( V.begin(), V.end() );
    Permute sigma(V);
    BOOST_CHECK_EQUAL( sigma.sigma().size(), 3 );
    BOOST_CHECK_EQUAL( sigma.sigma()[0], 2 );
    BOOST_CHECK_EQUAL( sigma.sigma()[1], 0 );
    BOOST_CHECK_EQUAL( sigma.sigma()[2], 1 );
    BOOST_CHECK_EQUAL( sigma[0], 2 );
    BOOST_CHECK_EQUAL( sigma[1], 0 );
    BOOST_CHECK_EQUAL( sigma[2], 1 );
    BOOST_CHECK_EQUAL( sigma.ranges().size(), 3 );
    BOOST_CHECK_EQUAL( sigma.ranges()[0], 3 );
    BOOST_CHECK_EQUAL( sigma.ranges()[1], 2 );
    BOOST_CHECK_EQUAL( sigma.ranges()[2], 2 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 0 ), 0 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 1 ), 2 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 2 ), 4 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 3 ), 6 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 4 ), 8 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 5 ), 10 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 6 ), 1 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 7 ), 3 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 8 ), 5 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 9 ), 7 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 10 ), 9 );
    BOOST_CHECK_EQUAL( sigma.convertLinearIndex( 11 ), 11 );

    Permute sigmar(V, true);
    BOOST_CHECK_EQUAL( sigmar.sigma().size(), 3 );
    BOOST_CHECK_EQUAL( sigmar.sigma()[0], 0 );
    BOOST_CHECK_EQUAL( sigmar.sigma()[1], 2 );
    BOOST_CHECK_EQUAL( sigmar.sigma()[2], 1 );
    BOOST_CHECK_EQUAL( sigmar[0], 0 );
    BOOST_CHECK_EQUAL( sigmar[1], 2 );
    BOOST_CHECK_EQUAL( sigmar[2], 1 );
    BOOST_CHECK_EQUAL( sigmar.ranges().size(), 3 );
    BOOST_CHECK_EQUAL( sigmar.ranges()[0], 2 );
    BOOST_CHECK_EQUAL( sigmar.ranges()[1], 2 );
    BOOST_CHECK_EQUAL( sigmar.ranges()[2], 3 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 0 ), 0 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 1 ), 1 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 2 ), 6 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 3 ), 7 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 4 ), 2 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 5 ), 3 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 6 ), 8 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 7 ), 9 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 8 ), 4 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 9 ), 5 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 10 ), 10 );
    BOOST_CHECK_EQUAL( sigmar.convertLinearIndex( 11 ), 11 );

    std::vector<size_t> rs, sig;
    rs.push_back(3);
    rs.push_back(2);
    rs.push_back(2);
    sig.push_back(2);
    sig.push_back(0);
    sig.push_back(1);
    Permute tau( rs, sig );
    BOOST_CHECK( tau.sigma() == sig );
    BOOST_CHECK( tau.ranges() == rs );
    BOOST_CHECK_EQUAL( tau[0], 2 );
    BOOST_CHECK_EQUAL( tau[1], 0 );
    BOOST_CHECK_EQUAL( tau[2], 1 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 0 ), 0 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 1 ), 2 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 2 ), 4 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 3 ), 6 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 4 ), 8 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 5 ), 10 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 6 ), 1 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 7 ), 3 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 8 ), 5 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 9 ), 7 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 10 ), 9 );
    BOOST_CHECK_EQUAL( tau.convertLinearIndex( 11 ), 11 );

    Permute tauinv = tau.inverse();
    BOOST_CHECK_EQUAL( tauinv.sigma().size(), 3 );
    BOOST_CHECK_EQUAL( tauinv.ranges().size(), 3 );
    BOOST_CHECK_EQUAL( tauinv[0], 1 );
    BOOST_CHECK_EQUAL( tauinv[1], 2 );
    BOOST_CHECK_EQUAL( tauinv[2], 0 );
    BOOST_CHECK_EQUAL( tauinv.ranges()[0], 2 );
    BOOST_CHECK_EQUAL( tauinv.ranges()[1], 3 );
    BOOST_CHECK_EQUAL( tauinv.ranges()[2], 2 );
    for( size_t i = 0; i < 12; i++ ) {
        BOOST_CHECK_EQUAL( tau.convertLinearIndex( tauinv.convertLinearIndex( i ) ), i );
        BOOST_CHECK_EQUAL( tauinv.convertLinearIndex( tau.convertLinearIndex( i ) ), i );
    }
}

BOOST_AUTO_TEST_CASE( multiforTest ) {
    multifor x;
    BOOST_CHECK( x.valid() );

    std::vector<size_t> ranges;
    ranges.push_back( 3 );
    ranges.push_back( 4 );
    ranges.push_back( 5 );
    multifor S(ranges);
    size_t s = 0;
    for( size_t s2 = 0; s2 < 5; s2++ )
        for( size_t s1 = 0; s1 < 4; s1++ )
            for( size_t s0 = 0; s0 < 3; s0++, s++, S++ ) {
                BOOST_CHECK( S.valid() );
                BOOST_CHECK_EQUAL( s, (size_t)S );
                BOOST_CHECK_EQUAL( S[0], s0 );
                BOOST_CHECK_EQUAL( S[1], s1 );
                BOOST_CHECK_EQUAL( S[2], s2 );
            }
    BOOST_CHECK( !S.valid() );

    for( size_t repeat = 0; repeat < 10000; repeat++ ) {
        std::vector<size_t> dims;
        size_t total = 1;
        for( size_t i = 0; i < 4; i++ ) {
            dims.push_back( rnd(3) + 1 );
            total *= dims.back();
        }
        multifor ind( dims );
        size_t iter = 0;
        for( ; ind.valid(); ind++, iter++ ) {
            BOOST_CHECK_EQUAL( (size_t)ind, iter );
            BOOST_CHECK_EQUAL( ind[0], iter % dims[0] );
            BOOST_CHECK_EQUAL( ind[1], (iter / dims[0]) % dims[1] );
            BOOST_CHECK_EQUAL( ind[2], (iter / (dims[0] * dims[1])) % dims[2] );
            BOOST_CHECK_EQUAL( ind[3], (iter / (dims[0] * dims[1] * dims[2])) % dims[3] );
        }
        BOOST_CHECK_EQUAL( iter, total );
        iter = 0;
        ind.reset();
        for( ; ind.valid(); ++ind, iter++ ) {
            BOOST_CHECK_EQUAL( (size_t)ind, iter );
            BOOST_CHECK_EQUAL( ind[0], iter % dims[0] );
            BOOST_CHECK_EQUAL( ind[1], (iter / dims[0]) % dims[1] );
            BOOST_CHECK_EQUAL( ind[2], (iter / (dims[0] * dims[1])) % dims[2] );
            BOOST_CHECK_EQUAL( ind[3], (iter / (dims[0] * dims[1] * dims[2])) % dims[3] );
        }
        BOOST_CHECK_EQUAL( iter, total );
    }
}

BOOST_AUTO_TEST_CASE( StateTest ) {
    State x;
    BOOST_CHECK( x.valid() );

    Var v0( 0, 3 );
    Var v1( 1, 4 );
    Var v2( 3, 5 );
    VarSet vars;
    vars |= v2;
    vars |= v1;
    vars |= v0;
    State S( vars );
    size_t s = 0;
    for( size_t s2 = 0; s2 < 5; s2++ )
        for( size_t s1 = 0; s1 < 4; s1++ )
            for( size_t s0 = 0; s0 < 3; s0++, s++, S++ ) {
                BOOST_CHECK( S.valid() );
                BOOST_CHECK_EQUAL( s, (size_t)S );
                BOOST_CHECK_EQUAL( S(v0), s0 );
                BOOST_CHECK_EQUAL( S(v1), s1 );
                BOOST_CHECK_EQUAL( S(v2), s2 );
                BOOST_CHECK_EQUAL( S( Var( 2, 2 ) ), 0 );
            }
    BOOST_CHECK( !S.valid() );
    S.reset();
    std::vector<std::pair<Var, size_t> > ps;
    ps.push_back( std::make_pair( Var( 2, 2 ), 1 ) );
    ps.push_back( std::make_pair( Var( 4, 2 ), 1 ) );
    S.insert( ps.begin(), ps.end() );
    BOOST_CHECK( S.valid() );
    BOOST_CHECK_EQUAL( (size_t)S, 132 );

    for( size_t repeat = 0; repeat < 10000; repeat++ ) {
        std::vector<size_t> dims;
        size_t total = 1;
        for( size_t i = 0; i < 4; i++ ) {
            dims.push_back( rnd(3) + 1 );
            total *= dims.back();
        }
        std::vector<Var> vs;
        for( size_t i = 0; i < 4; i++ )
            vs.push_back( Var( i, dims[i] ) );
        State ind( VarSet( vs.begin(), vs.end() ) );
        size_t iter = 0;
        for( ; ind.valid(); ind++, iter++ ) {
            BOOST_CHECK_EQUAL( (size_t)ind, iter );
            BOOST_CHECK_EQUAL( ind(vs[0]), iter % dims[0] );
            BOOST_CHECK_EQUAL( ind(vs[1]), (iter / dims[0]) % dims[1] );
            BOOST_CHECK_EQUAL( ind(vs[2]), (iter / (dims[0] * dims[1])) % dims[2] );
            BOOST_CHECK_EQUAL( ind(vs[3]), (iter / (dims[0] * dims[1] * dims[2])) % dims[3] );
            BOOST_CHECK_EQUAL( ind(VarSet(vs[0], vs[1])), iter % (dims[0] * dims[1]) );
            BOOST_CHECK_EQUAL( ind(VarSet(vs[1], vs[2])), (iter / dims[0]) % (dims[1] * dims[2]) );
            BOOST_CHECK_EQUAL( ind(VarSet(vs[2], vs[3])), (iter / (dims[0] * dims[1])) % (dims[2] * dims[3]) );
            BOOST_CHECK_EQUAL( ind(VarSet(vs.begin(), vs.end())), iter );
            State indcopy( VarSet(vs.begin(), vs.end()), (size_t)ind );
            BOOST_CHECK_EQUAL( ind(vs[0]), indcopy(vs[0]) );
            BOOST_CHECK_EQUAL( ind(vs[1]), indcopy(vs[1]) );
            BOOST_CHECK_EQUAL( ind(vs[2]), indcopy(vs[2]) );
            BOOST_CHECK_EQUAL( ind(vs[3]), indcopy(vs[3]) );
            State indcopy2( indcopy.get() );
            BOOST_CHECK_EQUAL( ind(vs[0]), indcopy2(vs[0]) );
            BOOST_CHECK_EQUAL( ind(vs[1]), indcopy2(vs[1]) );
            BOOST_CHECK_EQUAL( ind(vs[2]), indcopy2(vs[2]) );
            BOOST_CHECK_EQUAL( ind(vs[3]), indcopy2(vs[3]) );
            std::map<Var,size_t> indmap( ind );
            State indcopy3( indmap );
            BOOST_CHECK_EQUAL( ind(vs[0]), indcopy3(vs[0]) );
            BOOST_CHECK_EQUAL( ind(vs[1]), indcopy3(vs[1]) );
            BOOST_CHECK_EQUAL( ind(vs[2]), indcopy3(vs[2]) );
            BOOST_CHECK_EQUAL( ind(vs[3]), indcopy3(vs[3]) );
        }
        BOOST_CHECK_EQUAL( iter, total );
        iter = 0;
        ind.reset();
        for( ; ind.valid(); ++ind, iter++ ) {
            BOOST_CHECK_EQUAL( (size_t)ind, iter );
            BOOST_CHECK_EQUAL( ind(vs[0]), iter % dims[0] );
            BOOST_CHECK_EQUAL( ind(vs[1]), (iter / dims[0]) % dims[1] );
            BOOST_CHECK_EQUAL( ind(vs[2]), (iter / (dims[0] * dims[1])) % dims[2] );
            BOOST_CHECK_EQUAL( ind(vs[3]), (iter / (dims[0] * dims[1] * dims[2])) % dims[3] );
            State::const_iterator ci = ind.begin();
            BOOST_CHECK_EQUAL( (ci++)->second, iter % dims[0] );
            BOOST_CHECK_EQUAL( (ci++)->second, (iter / dims[0]) % dims[1] );
            BOOST_CHECK_EQUAL( (ci++)->second, (iter / (dims[0] * dims[1])) % dims[2] );
            BOOST_CHECK_EQUAL( (ci++)->second, (iter / (dims[0] * dims[1] * dims[2])) % dims[3] );
            BOOST_CHECK( ci == ind.end() );
        }
        BOOST_CHECK_EQUAL( iter, total );
        State::const_iterator ci = ind.begin();
        BOOST_CHECK_EQUAL( (ci++)->first, vs[0] );
        BOOST_CHECK_EQUAL( (ci++)->first, vs[1] );
        BOOST_CHECK_EQUAL( (ci++)->first, vs[2] );
        BOOST_CHECK_EQUAL( (ci++)->first, vs[3] );
        BOOST_CHECK( ci == ind.end() );
    }
}


#ifndef HAMILTONIANS_XYZNNN_HPP
#define HAMILTONIANS_XYZNNN_HPP
#include <Eigen/Eigen>
#include <nlohmann/json.hpp>

class XYZNNN
{
private:
	int n_;
	double a_;
	double b_;
	constexpr static double J1 = -1.0;
	constexpr static double J2 = -1.0;
public:

	XYZNNN(int n, double a, double b)
		: n_(n), a_(a), b_(b)
	{
	}

	nlohmann::json params() const
	{
		return nlohmann::json
		{
			{"name", "XYZNNN"},
			{"n", n_},
			{"a", a_},
			{"b", b_}
		};
	}

	template<class State>
	typename State::Scalar operator()(const State& smp) const
	{
		typename State::Scalar s = 0.0;

		//Nearest-neighbor
		for(int i = 0; i < n_; i++)
		{
			double yysign = -smp.sigmaAt(i)*smp.sigmaAt((i+1)%n_);
			s += -J1*yysign; //zz
			s += J1*(a_+yysign*b_)*smp.ratio(i, (i+1)%n_); //xx+yy
		}
		//Next-nearest-neighbor
		for(int i = 0; i < n_; i++)
		{
			double yysign = -smp.sigmaAt(i)*smp.sigmaAt((i+2)%n_);
			s += -J2*yysign; //zz
			s += J2*(b_+yysign*a_)*smp.ratio(i, (i+2)%n_); //xx+yy
		}
		return s;
	}

	std::vector< std::array<int, 2> > flips() const
	{
		std::vector< std::array<int, 2> > res;
		for(int i = 0; i < n_; i++)
		{
			res.push_back(std::array<int, 2>{i,(i+1)%n_});
			res.push_back(std::array<int, 2>{i,(i+2)%n_});
		}
		return res;
	}

	std::map<uint32_t, double> operator()(uint32_t col) const
	{
		std::map<uint32_t, double> m;
		for(int i = 0; i < n_; i++)
		{
			int b1 = (col >> i) & 1;
			int b2 = (col >> ((i+1)%n_)) & 1;
			int sgn = (1-2*b1)*(1-2*b2);
			long long int x = (1 << i) | (1 << ((i+1)%(n_)));
			m[col ^ x] += J1*(a_ - sgn*b_);
			m[col] += J1*sgn;
		}
		for(int i = 0; i < n_; i++)
		{
			int b1 = (col >> i) & 1;
			int b2 = (col >> ((i+2)%n_)) & 1;
			int sgn = (1-2*b1)*(1-2*b2);
			long long int x = (1 << i) | (1 << ((i+2)%(n_)));
			m[col ^ x] += J2*(b_ - sgn*a_);
			m[col] += J2*sgn;
		}
		return m;
	}
};
#endif//HAMILTONIANS_XYZNNN_HPP


#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include "../jngen.h"

#include <algorithm>
#include <set>
#include <sstream>
#include <utility>

BOOST_AUTO_TEST_SUITE(tree)

void checkEquals(const jngen::Tree& t1, const jngen::Tree& t2) {
    BOOST_TEST(t1.n() == t2.n());
    for (int i = 0; i < t1.n(); ++i) {
        BOOST_TEST(t1.edges(i).sorted() == t2.edges(i).sorted());
    }
}

BOOST_AUTO_TEST_CASE(manual_construction) {
    setMod().reset();

    Tree t;

    BOOST_TEST(t.n() == 1);
    BOOST_TEST(t.m() == 0);
    BOOST_TEST(t.isConnected());

    t.addEdge(0, 1);
    t.addEdge(2, 3);
    BOOST_TEST(!t.isConnected());

    t.addEdge(1, 2);

    BOOST_TEST(t.n() == 4);
    BOOST_TEST(t.m() == 3);

    std::ostringstream ss;
    ss << t.printN().add1() << std::endl;

    BOOST_TEST(ss.str() == "4\n1 2\n3 4\n2 3\n");
}

void dfs(int v, int anc, const Tree& t, std::vector<int>& dist) {
    for (int to: t.edges(v)) {
        if (to == anc) {
            continue;
        }
        dist[to] = dist[v] + 1;
        dfs(to, v, t, dist);
    }
}

/*
 * Find the diameter of the given tree.
 *
 * Returns: the diameter of the tree, measured in number of edges.
 * center: one or two vertices -- the center of the tree.
 * dist: distance from the first of the centers to all nodes.
 */
int findDiameter(
        const Tree& t,
        std::vector<int>& centers,
        std::vector<int>& dist)
{
    BOOST_REQUIRE(t.isConnected());
    std::vector<int> dist1(t.n(), -1);
    std::vector<int> dist2(t.n(), -1);

    dist1[0] = 0;
    dfs(0, -1, t, dist1);

    int left = std::max_element(dist1.begin(), dist1.end()) - dist1.begin();
    dist1[left] = 0;
    dfs(left, -1, t, dist1);
    int right = std::max_element(dist1.begin(), dist1.end()) - dist1.begin();
    dist2[right] = 0;
    dfs(right, -1, t, dist2);

    BOOST_REQUIRE(dist1[right] == dist2[left]);

    int diam = dist1[right];

    centers.clear();
    for (int v = 0; v < t.n(); ++v) {
        if (dist1[v] + dist2[v] == diam && std::abs(dist1[v] - dist2[v]) <= 1) {
            centers.push_back(v);
        }
    }

    if (diam % 2 == 1) {
        BOOST_REQUIRE(centers.size() == 2);
    } else {
        BOOST_REQUIRE(centers.size() == 1);
    }

    dist1[centers[0]] = 0;
    dfs(centers[0], -1, t, dist1);
    dist = dist1;

    return diam;
}

/* Mostly performs sanity check on the generators: check some basic properties
 * of the resulting trees such as diameter.
 */
BOOST_AUTO_TEST_CASE(generators) {
    setMod().reset();
    rnd.seed(12345);

    std::vector<int> centers, dist;

    auto b = Tree::bamboo(10);
    BOOST_TEST(findDiameter(b, centers, dist) == 9);
    BOOST_TEST(centers[0] == 4);
    BOOST_TEST(centers[1] == 5);

    std::ostringstream ss;

    ss << b;
    std::string first = ss.str();
    ss.clear();

    b.shuffle();

    ss << b;
    std::string second = ss.str();
    ss.clear();

    BOOST_TEST(first != second);

    auto s = Tree::star(10);
    BOOST_TEST(findDiameter(s, centers, dist) == 2);
    BOOST_TEST(centers[0] == 0);

    // probability of failure < 1e-5
    auto c = Tree::caterpillar(100, 10);
    BOOST_TEST(findDiameter(c, centers, dist) == 11);

    // probability of failure < 1e-3
    c = Tree::caterpillar(8004, 8000);
    BOOST_TEST(findDiameter(c, centers, dist) == 7999);

    // probability of failure unknown, but very low
    auto t = Tree::randomPrim(150, 15000);
    BOOST_TEST(t == Tree::bamboo(150));
}

BOOST_AUTO_TEST_CASE(prufer_all_trees) {
    auto a = TArray<Tree>::randomfUnique(120, []() {
        return Tree::random(5);
    });
    BOOST_TEST(a.size() == 5*4*3*2*1);

    auto b = TArray<Tree>::randomfAll([]() {
        return Tree::random(5);
    });
    BOOST_TEST(b.size() == 5*5*5);
}

BOOST_AUTO_TEST_CASE(check_link) {
    /*        0   (4-2)    1
            1   4   +    2   4
          2    3 5      0 3   5
                    =
              0
            1      4
          2     3 5    8
                     6 9 7
                          10
                            11
     */
    Tree t1;
    for (std::pair<int, int> edge:
            Arrayp{{0, 1}, {1, 2}, {0, 4}, {4, 3}, {4, 5}}) {
        t1.addEdge(edge.first, edge.second);
    }

    Tree t2;
    for (std::pair<int, int> edge:
            Arrayp{{1, 2}, {2, 0}, {2, 3}, {1, 4}, {4, 5}}) {
        t2.addEdge(edge.first, edge.second);
    }

    Tree t;
    for (std::pair<int, int> edge: Arrayp{
        {0, 1}, {1, 2}, {0, 4}, {4, 3}, {4, 5}, {4, 8}, {8, 6}, {8, 9},
        {8, 7}, {7, 10}, {10, 11}})
    {
        t.addEdge(edge.first, edge.second);
    }

    Tree linked = t1.link(4, t2, 2);

    BOOST_TEST(t1.n() + t2.n() == linked.n());
    BOOST_TEST(t1.m() + t2.m() + 1 == linked.m());
    checkEquals(linked, t);
}

BOOST_AUTO_TEST_CASE(check_glue) {
    /*        0   (4-2)    1
            1   4   .    2   4
          2    3 5      0 3   5
                    =
              0
            1      4
          2     3 5 6 8 7
                         9
                          10
     */
    Tree t1;
    for (std::pair<int, int> edge:
            Arrayp{{0, 1}, {1, 2}, {0, 4}, {4, 3}, {4, 5}}) {
        t1.addEdge(edge.first, edge.second);
    }

    Tree t2;
    for (std::pair<int, int> edge:
            Arrayp{{1, 2}, {2, 0}, {2, 3}, {1, 4}, {4, 5}}) {
        t2.addEdge(edge.first, edge.second);
    }

    Tree t;
    for (std::pair<int, int> edge: Arrayp{
        {0, 1}, {1, 2}, {0, 4}, {4, 3}, {4, 5}, {4, 6}, {8, 4}, {4, 7},
        {9, 7}, {9, 10}})
    {
        t.addEdge(edge.first, edge.second);
    }

    Tree glued = t1.glue(4, t2, 2);

    BOOST_TEST(t1.n() + t2.n() - 1 == glued.n());
    BOOST_TEST(t1.m() + t2.m() == glued.m());
    checkEquals(glued, t);
}

BOOST_AUTO_TEST_CASE(print_parents) {
    rnd.seed(123);
    setMod().reset();

    std::ostringstream ss;

    const std::string res1 = "5\ngrt kzw bar pja oap\n5 1 3 3\n";

    Tree t = Tree::random(5);
    t.setVertexWeights(TArray<std::string>::random(t.n(), "[a-z]{%d}", 3));
    ss << t.add1().printN().printParents() << std::endl;

    BOOST_TEST(ss.str() == res1);

    t.setVertexWeights(WeightArray(t.n()));

    ss.str("");
    ss << t.printParents(0);
    BOOST_TEST(ss.str() == "-1 4 0 2 2");

    ss.str("");
    ss << t.printParents(1);
    BOOST_TEST(ss.str() == "2 -1 4 2 1");
}

// TODO: add tests to check random generators exactly

BOOST_AUTO_TEST_SUITE_END()


// Copyright Yamaha 2021
// MIT License
// https://github.com/yamaha-bps/cbr_control/blob/master/LICENSE

#ifndef CBR_CONTROL__RATE_LIMITER_HPP_
#define CBR_CONTROL__RATE_LIMITER_HPP_

#include <boost/hana/adapt_struct.hpp>

#include <cbr_utils/cyber_timer.hpp>

#include <memory>
#include <type_traits>
#include <utility>

namespace cbr
{

struct RateLimiterParams
{
  double rise_rate{1.};
  double fall_rate{-1.};

  void check_correctness() const
  {
    if (rise_rate < 0.) {
      throw std::invalid_argument("parameter 'rise_rate' must be >= 0");
    }
    if (fall_rate > 0.) {
      throw std::invalid_argument("parameter 'fall_rate' must be <= 0");
    }
  }
};

template<typename _clock_t = std::chrono::high_resolution_clock>
class RateLimiter
{
public:
  using clock_t = _clock_t;
  using timer_t = CyberTimerNoAvg<std::ratio<1>, double, clock_t>;

  // Constructors
  RateLimiter() = default;
  RateLimiter(const RateLimiter &) = default;
  RateLimiter(RateLimiter &) = default;
  RateLimiter(RateLimiter &&) = default;
  RateLimiter & operator=(const RateLimiter &) = default;
  RateLimiter & operator=(RateLimiter &) = default;
  RateLimiter & operator=(RateLimiter &&) = default;
  ~RateLimiter() = default;

  template<typename T>
  explicit RateLimiter(T && clock, const RateLimiterParams & prm = {})
  : timer_(std::forward<T>(clock)),
    prm_(prm)
  {
    prm_.check_correctness();
  }

  explicit RateLimiter(const RateLimiterParams & prm)
  : prm_(prm)
  {
    prm_.check_correctness();
  }

  template<typename T>
  void set_clock(T && clock)
  {
    timer_.set_clock(std::forward<T>(clock));
  }

  void set_params(const RateLimiterParams & prm)
  {
    prm.check_correctness();
    prm_ = prm;
  }

  const RateLimiterParams & get_params() const
  {
    return prm_;
  }

  const double & update(const double val, const typename timer_t::time_point tNow)
  {
    if (init_) {
      // Define dt
      const double dt = timer_.toctic(tNow);

      // Compute Rate (derivative)
      if (dt <= 0.) {
        return output_;
      }
      const double rate = (val - output_) / dt;

      // Assign Output
      if (rate > prm_.rise_rate) {
        return output_ += dt * prm_.rise_rate;
      } else if (rate < prm_.fall_rate) {
        return output_ += dt * prm_.fall_rate;
      } else {
        return output_ = val;
      }
    }

    init_ = true;
    timer_.tic(tNow);

    return output_ = val;
  }

  const double & update(const double val)
  {
    return update(val, timer_.now());
  }

  const double & operator()(const double val)
  {
    return update(val);
  }

  const double & getValue() const
  {
    return output_;
  }

  void reset()
  {
    init_ = false;
  }

  const double & reset(const double val, const typename timer_t::time_point tNow)
  {
    init_ = true;
    timer_.tic(tNow);
    return output_ = val;
  }

  const double & reset(const double val)
  {
    return reset(val, timer_.now());
  }

protected:
  timer_t timer_ = timer_t(clock_t{});
  RateLimiterParams prm_;
  double output_{0.};
  bool init_{false};
};

}    // namespace cbr

// cppcheck-suppress unknownMacro
BOOST_HANA_ADAPT_STRUCT(
  cbr::RateLimiterParams,
  rise_rate,
  fall_rate
);

#endif  // CBR_CONTROL__RATE_LIMITER_HPP_


// MIT License
//
// Copyright (c) 2021 Oliver Schick
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <mpo19/paillier_wrapper.hpp>
#include <cstring>

#define BOOST_TEST_MODULE paillier_wrapper_test
#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/data/monomorphic.hpp>

namespace bdata = boost::unit_test::data;
using namespace mpo19;

constexpr int m = 100;

constexpr key_id global = "Global";

bool equal(plaintext const& lhs, plaintext const& rhs)
{
    std::vector<char> dec_lhs = lhs;
    std::vector<char> dec_rhs = rhs;
    assert(!dec_lhs.empty() && !dec_rhs.empty());
    return strcmp(dec_lhs.data(), dec_rhs.data()) == 0;
}

bool equal(paillier<global> const& lhs, paillier<global> const& rhs)
{
    return equal(decrypt(lhs), decrypt(rhs));
}

BOOST_DATA_TEST_CASE(paillier_operation_test
                     , bdata::random(0, m) ^ bdata::random(0, m)
                     ^ bdata::xrange(10)
                     , s1, s2, idx)
{
    (void) idx;
    BOOST_TEST(paillier<global>::get_keys().has_public_key());
    BOOST_TEST(paillier<global>::get_keys().has_private_key());
    paillier<global>  p1 = paillier<global>::gen_random(40);
    paillier<global>  p2 = paillier<global>::gen_random(40);
    paillier<global>  p3 = paillier<global>::gen_random(40);

    //Associativity
    BOOST_TEST( equal( (p1 + p2) + p3, p1 + (p2 + p3) ) );

    BOOST_TEST( equal( (s1 * p1) * s2, s1 * (p1 * s2) ) );
    BOOST_TEST( equal(p1 * (s1 * s2), (p1 * s1) * s2) );

    //Commutativity
    BOOST_TEST( equal(p1 + p2, p2 + p1) );
    BOOST_TEST( equal(s1 * p1, p1 * s1) );

    //Neutral Element
    BOOST_TEST( equal(p1 + paillier<global>::encrypt_zero(), p1) );
    BOOST_TEST( equal(p1 * 1, p1) );

    //Distributivity
    BOOST_TEST( equal(s1 * (p1 + p2), s1 * p1 + s1 * p2) );

    //Plus is consistent
    BOOST_TEST( equal(p1 + p1, 2*p1) );
    BOOST_TEST( equal(p1 + p1 + p1, 3*p1) );

    //Consistency with +=, *=
    paillier<global>  enc_s1 = paillier<global>::encrypt(s1);
    paillier<global>  enc_s2 = paillier<global>::encrypt(s2);

    enc_s1 += enc_s2;
    BOOST_TEST( equal(enc_s1, paillier<global>::encrypt(s1+s2) ) );
    enc_s2 += enc_s1;
    BOOST_TEST( equal(enc_s2, paillier<global>::encrypt(s2+s1+s2) ) );
    enc_s1 += enc_s2;
    BOOST_TEST( equal(enc_s1, paillier<global>::encrypt(s1+s2+s2+s1+s2) ) );
    enc_s1 *= s2;
    BOOST_TEST( equal(enc_s1, paillier<global>::encrypt( (s1+s2+s2+s1+s2)*s2) ) );
    enc_s1 *= s1;
    BOOST_TEST( equal(enc_s1, paillier<global>::encrypt( (s1+s2+s2+s1+s2)*s2*s1) ) );
}

#include <iostream>
#include <fstream>

BOOST_DATA_TEST_CASE(paillier_serialization_test
                     , bdata::random(0, m) ^ bdata::xrange(10), s1, idx)
{
    (void) idx;
    paillier<global> p1{paillier<global>::gen_random(40)};
    paillier<global> p2{paillier<global>::gen_random(40)};

    std::ofstream ofs;
    ofs.exceptions(std::ios::failbit | std::ios::badbit);
    ofs.open("test.bin", std::ios::binary | std::ios::trunc | std::ios::out);

    ofs << plaintext{} << paillier<global>::get_keys().get_public() << " "
        << plaintext{} << p1 << p2 << s1 << " "
        << p1 + p2 << p2 * s1
        << decrypt(p1) << plaintext{};
    ofs.close();

    std::ifstream ifs;
    ifs.exceptions(std::ios::failbit | std::ios::badbit);
    ifs.open("test.bin", std::ios::binary | std::ios::in);
    paillier_keys::public_key pub;
    paillier<global>  sp1, sp2, sp1p2, sp2s1;
    plaintext dec_p1, inv_p1, inv_p2, inv_p3;
    int ss1;
    ifs >> inv_p1 >> pub;
    char skip = ifs.get();
    BOOST_TEST(' ' == skip);
    ifs >> inv_p2 >> sp1 >> sp2 >> ss1;
    skip = ifs.get();
    BOOST_TEST(' ' == skip);
    ifs >> sp1p2 >> sp2s1 >> dec_p1 >> inv_p3;
    ifs.close();

    BOOST_TEST(equal(p1, sp1));
    BOOST_TEST(equal(p2, sp2));
    BOOST_TEST(s1 == ss1);
    BOOST_TEST(equal(p1 + p2, sp1p2));
    BOOST_TEST(equal(p2 * s1, sp2s1));
    BOOST_TEST(equal(decrypt(p1), dec_p1));
    BOOST_TEST(!inv_p1.valid());
    BOOST_TEST(!inv_p2.valid());
    BOOST_TEST(!inv_p3.valid());
}


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

  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/function/scalar/ilog2.hpp>
#include <scalar_test.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>
#include <boost/simd/constant/three.hpp>
#include <boost/simd/constant/four.hpp>
#include <boost/simd/constant/pi.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/two.hpp>
#include <boost/simd/constant/valmax.hpp>

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

  // return type conformity test
  STF_EXPR_IS(ilog2(T()),  bd::as_integer_t<T>);

  // specific values tests
  STF_EQUAL(ilog2(bs::Two<T>()), 1);
  STF_EQUAL(ilog2(bs::Three<T>()), 1);
  STF_EQUAL(ilog2(bs::Four<T> ()), 2);
  STF_EQUAL(ilog2(bs::Pi<T> ()), 1);
  STF_EQUAL(ilog2(bs::One<T>()), 0);
} // end of test for real_

STF_CASE_TPL (" ilog2signed_int",  STF_SIGNED_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::ilog2;

  // return type conformity test
  STF_EXPR_IS(ilog2(T()),  bd::as_integer_t<T>);

  // specific values tests
  STF_EQUAL(ilog2(bs::One<T>()), 0);
  STF_EQUAL(ilog2(bs::Two<T>()), 1);
} // end of test for signed_int_

 STF_CASE_TPL (" ilog2unsigned_int",  STF_UNSIGNED_INTEGRAL_TYPES)
 {
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::ilog2;

  // return type conformity test
  STF_EXPR_IS(ilog2(T()),  bd::as_integer_t<T>);

  // specific values tests
  STF_EQUAL(ilog2(bs::One<T>()), 0u);
  STF_EQUAL(ilog2(bs::Two<T>()),1u);

  T j = 1;
  for(T i=2; i < bs::Valmax<T>()/2; i*= 2)
  {
    STF_EQUAL(ilog2(T(i)),j);
    STF_EQUAL(ilog2(T(i+1)),j);
    ++j;
  }
 } // end of test for unsigned_int_


//////////////////////////////////////////////////////////////////////////////
// data::set::levels_traits.hpp         									//
//                                                                          //
//                                                                          //
//  (C) Copyright 2010 Erwann Rogard                                        //
//  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_STATISTICS_DETAIL_DATA_SET_LEVEL_TRAITS_HPP_ER_2010
#define BOOST_STATISTICS_DETAIL_DATA_SET_LEVEL_TRAITS_HPP_ER_2010
#include <boost/statistics/detail/data/types/array/array_traits.hpp>

namespace boost{
namespace statistics{
namespace detail{
namespace data{

	// An often convenient and efficient way to represent K input levels is
    // as a array of fields of static size (K).
	template<int K, typename F = field::x>
    struct level_traits : array_traits<F,K>{};

}// data
}// detail
}// statistics
}// boost

#endif


//==============================================================================
//         Copyright 2015          J.T. Lapreste
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/arithmetic/include/functions/round.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/include/constants/one.hpp>
#include <boost/simd/include/constants/mone.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/constants/minf.hpp>
#include <boost/simd/include/constants/nan.hpp>
#include <boost/simd/include/constants/valmax.hpp>
#include <boost/simd/include/constants/valmin.hpp>
#include <boost/simd/include/constants/maxflint.hpp>
#include <boost/simd/include/constants/half.hpp>

#include <boost/simd/sdk/config.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/simd/include/functions/prev.hpp>
#include <boost/simd/include/functions/next.hpp>
#include <boost/simd/include/functions/splat.hpp>
#include <boost/simd/include/functions/multiplies.hpp>
#include <boost/simd/include/functions/plus.hpp>
#include <boost/simd/include/functions/splat.hpp>

NT2_TEST_CASE_TPL ( round_real, BOOST_SIMD_SIMD_REAL_TYPES)
{
  using boost::simd::round;
  using boost::simd::tag::round_;
  using boost::simd::next;
  using boost::simd::prev;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;
  typedef typename boost::dispatch::meta::call<round_(vT)>::type r_t;

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(round(boost::simd::Inf<vT>()), boost::simd::Inf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Minf<vT>()), boost::simd::Minf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Nan<vT>()), boost::simd::Nan<r_t>());
#endif
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.4)), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.5)), boost::simd::Two<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.6)), boost::simd::Two<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(2.5)), boost::simd::Three<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Half<vT>()), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Mhalf<vT>()), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Mone<vT>()), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::One<vT>()), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Zero<vT>()), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>()-boost::simd::Half<T>()),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>()),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(prev(prev(boost::simd::Half<vT>()))),  boost::simd::Zero<vT>());
  NT2_TEST_EQUAL(round(prev(boost::simd::Half<vT>())),  boost::simd::Zero<vT>());
  NT2_TEST_EQUAL(round(     boost::simd::Half<vT>()) ,  boost::simd::One <vT>());
  NT2_TEST_EQUAL(round(next(boost::simd::Half<vT>())),  boost::simd::One <vT>());
  vT z = boost::simd::Maxflint <vT>()*boost::simd::Half<vT>()+boost::simd::One<vT>();
  NT2_TEST_EQUAL(round(z), z);
} // end of test for floating_

NT2_TEST_CASE_TPL ( round_real2,  BOOST_SIMD_SIMD_REAL_TYPES)
{

  using boost::simd::round;
  using boost::simd::tag::round_;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;
  typedef typename boost::dispatch::meta::call<round_(vT)>::type r_t;

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(round(boost::simd::Inf<vT>(), 2), boost::simd::Inf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Minf<vT>(), 2), boost::simd::Minf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Nan<vT>(), 2), boost::simd::Nan<r_t>());
#endif
  NT2_TEST_EQUAL(round(boost::simd::Mhalf<vT>(), 2), boost::simd::Mhalf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Mone<vT>(), 2), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::One<vT>(), 2), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Zero<vT>(), 2), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>()-boost::simd::Half<vT>(), 2),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>(), 2),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.44), 1), boost::simd::splat<vT>(1.4));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.45), 1), boost::simd::splat<vT>(1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.46), 1), boost::simd::splat<vT>(1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(2.45), 1), boost::simd::splat<vT>(2.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.44), 1), boost::simd::splat<vT>(-1.4));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.45), 1), boost::simd::splat<vT>(-1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.46), 1), boost::simd::splat<vT>(-1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-2.45), 1), boost::simd::splat<vT>(-2.5));
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(145), -2), boost::simd::splat<vT>(100), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(150), -2), boost::simd::splat<vT>(200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(156), -2), boost::simd::splat<vT>(200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(250), -2), boost::simd::splat<vT>(300), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-145), -2), boost::simd::splat<vT>(-100), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-155), -2), boost::simd::splat<vT>(-200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-156), -2), boost::simd::splat<vT>(-200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-255), -2), boost::simd::splat<vT>(-300), 0.5);
} // end of test for floating_

NT2_TEST_CASE_TPL ( round_real2b,  BOOST_SIMD_SIMD_REAL_TYPES)
{

  using boost::simd::round;
  using boost::simd::tag::round_;
  using boost::simd::native;
  using boost::simd::splat;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;
  typedef typename boost::dispatch::meta::as_integer<vT>::type viT;
  typedef typename boost::dispatch::meta::call<round_(vT)>::type r_t;

  // specific values tests
#ifndef BOOST_SIMD_NO_INVALIDS
  NT2_TEST_EQUAL(round(boost::simd::Inf<vT>(), splat<viT>(2)), boost::simd::Inf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Minf<vT>(), splat<viT>(2)), boost::simd::Minf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Nan<vT>(), splat<viT>(2)), boost::simd::Nan<r_t>());
#endif
  NT2_TEST_EQUAL(round(boost::simd::Mhalf<vT>(), splat<viT>(2)), boost::simd::Mhalf<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Mone<vT>(), splat<viT>(2)), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::One<vT>(), splat<viT>(2)), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Zero<vT>(), splat<viT>(2)), boost::simd::Zero<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>()-boost::simd::Half<vT>(), splat<viT>(2)),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(boost::simd::Maxflint<vT>(), splat<viT>(2)),boost::simd::Maxflint<vT>());
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.44), splat<viT>(1)), boost::simd::splat<vT>(1.4));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.45), splat<viT>(1)), boost::simd::splat<vT>(1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(1.46), splat<viT>(1)), boost::simd::splat<vT>(1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(2.45), splat<viT>(1)), boost::simd::splat<vT>(2.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.44), splat<viT>(1)), boost::simd::splat<vT>(-1.4));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.45), splat<viT>(1)), boost::simd::splat<vT>(-1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-1.46), splat<viT>(1)), boost::simd::splat<vT>(-1.5));
  NT2_TEST_EQUAL(round(boost::simd::splat<vT>(-2.45), splat<viT>(1)), boost::simd::splat<vT>(-2.5));
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(145), splat<viT>(-2)), boost::simd::splat<vT>(100), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(150), splat<viT>(-2)), boost::simd::splat<vT>(200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(156), splat<viT>(-2)), boost::simd::splat<vT>(200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(250), splat<viT>(-2)), boost::simd::splat<vT>(300), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-145), splat<viT>(-2)), boost::simd::splat<vT>(-100), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-155), splat<viT>(-2)), boost::simd::splat<vT>(-200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-156), splat<viT>(-2)), boost::simd::splat<vT>(-200), 0.5);
  NT2_TEST_ULP_EQUAL(round(boost::simd::splat<vT>(-255), splat<viT>(-2)), boost::simd::splat<vT>(-300), 0.5);
} // end of test for floating_

NT2_TEST_CASE_TPL ( round_unsigned_int,  BOOST_SIMD_SIMD_UNSIGNED_TYPES)
{
  using boost::simd::round;
  using boost::simd::tag::round_;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;
  typedef typename boost::dispatch::meta::call<round_(vT)>::type r_t;

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

NT2_TEST_CASE_TPL ( round_signed_int,  BOOST_SIMD_SIMD_INTEGRAL_SIGNED_TYPES)
{
  using boost::simd::round;
  using boost::simd::tag::round_;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef native<T,ext_t>                  vT;
  typedef typename boost::dispatch::meta::call<round_(vT)>::type r_t;

  // specific values tests
  NT2_TEST_EQUAL(round(boost::simd::Mone<vT>()), boost::simd::Mone<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::One<vT>()), boost::simd::One<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Valmax<vT>()), boost::simd::Valmax<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Valmin<vT>()), boost::simd::Valmin<r_t>());
  NT2_TEST_EQUAL(round(boost::simd::Zero<vT>()), boost::simd::Zero<r_t>());
} // end of test for signed_int_


#include <Eigen/Core>
#include <Eigen/SVD>

#include <iostream>
#include <sstream>
#include <string>

#include "arraytools.h"
#include "oaoptions.h"
#include "printfheader.h"
#include "tools.h"
#include "version.h"

namespace nauty {
#include "nauty.h"
}

/// Information about compile time options
std::string compile_information () {
        std::stringstream ss;
        print_options (ss);

        return ss.str ();
}

/** Return version of program */
std::string version () {
        std::string v = __version__;
        return v;
}

/** @brief Print copyright notice
 */
void print_copyright () {
        myprintf ("Orthogonal Arrays %s\n", version ().c_str ());
        myprintf ("For more details see the files README.txt and LICENSE.txt\n");
}
/** @brief Print brief copyright notice
 */
void print_copyright_light () { myprintf ("Orthogonal Array package %s\n", version ().c_str ()); }

#include <Eigen/Core>
#include <Eigen/LU>
#include <Eigen/SVD>

// http://sourceforge.net/p/predef/wiki/Compilers/
#if defined(__GNUC__)
#if defined(__GNUC_PATCHLEVEL__)
#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
#endif
#else
#define __GNUC_VERSION__ "none"
#endif

#ifndef __INTEL_COMPILER
#define __INTEL_COMPILER "none"
#endif

/**
 * Print the compile-time options to a string.
 */
std::string print_options_string () {
        std::string tabsep = "  ";

        std::stringstream outx;

        outx << "Orthogonal Array Package " << version () << std::endl;

        outx << "Compile date: " << __DATE__ << " " << __TIME__ << std::endl;

        outx << tabsep << "void * type: sizeof(void *) " << sizeof (void *) << std::endl;
        outx << tabsep << "array_t type: sizeof(array_t) " << sizeof (array_t) << std::endl;
        outx << tabsep << "integer types: sizeof(short int) " << sizeof (short int) << std::endl;
        outx << tabsep << "integer types: sizeof(unsigned long int) " << sizeof (unsigned long int) << ","
             << " sizeof(int) " << sizeof (int) << std::endl;
        outx << tabsep << "integer types: sizeof(long long) " << sizeof (long long) << std::endl;
        outx << tabsep << "floating point type: sizeof(float) " << sizeof (float) << ", sizeof(double) "
             << sizeof (double) << ", sizeof(long double) " << sizeof (long double) << std::endl;
        outx << tabsep << "Eigen version: " << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "."
             << EIGEN_MINOR_VERSION << std::endl;

        Eigen::MatrixXd mymatrix (1, 1);
        Eigen::FullPivLU< Eigen::MatrixXd > lu_decomp (mymatrix);

        outx << tabsep << "eigen: JacobiSVD threshold " << lu_decomp.threshold () << std::endl;

// http://sourceforge.net/p/predef/wiki/Compilers/
#ifdef WIN32
#else
        outx << tabsep << "Compiler: __VERSION__ " << __VERSION__ << std::endl;
#endif
        outx << tabsep << "Compiler: __GNUC_VERSION__ " << __GNUC_VERSION__ << std::endl;
        outx << tabsep << "Compiler: __INTEL_COMPILER " << __INTEL_COMPILER << std::endl;

#ifdef __OPTIMIZE__
        outx << tabsep << "Optimization: __OPTIMIZE__" << std::endl;
#endif
        outx << tabsep << "Compile time options: "; // << std::endl;
        std::string sep = ", ";

#ifdef USEZLIB
        outx << "USEZLIB" << sep;
#endif

#ifdef OACHECK
        outx << "OACHECK" << sep;
#endif

#ifdef OADEBUG
        outx << "OADEBUG" << sep;
#endif

#ifdef OAOVERFLOW
        outx << "OAOVERFLOW" << sep;
#endif

#ifdef OAMEM
        outx << "OAMEM" << sep;
#endif

#ifdef SAFELPERM
        outx << "SAFELPERM" << sep;
#endif

#ifdef FREQELEM
        outx << "FREQELEM" << sep;
#endif

#ifdef USE_ROW_SYMMETRY
        outx << "USE_ROW_SYMMETRY" << sep;
#endif

#ifdef USE_SMALLSTEP
        outx << "USE_SMALLSTEP" << sep;
#endif

#ifdef TPLUSCOLUMN
        outx << "USE_TPLUSCOLUMN" << sep;
#endif

#ifdef SYMMBLOCKS
        outx << "SYMMBLOCKS" << sep;
#endif

#ifdef JCHECK
        outx << "JCHECK" << sep;
#endif
#ifdef OADEV
        outx << "OADEV" << sep;
#endif
#ifdef SWIGCODE
        outx << "SWIG" << sep;
#endif
        outx << std::endl;

        outx << tabsep << "columns sorting method: " << oacolSortName << std::endl;

        outx << tabsep << "nauty: NAUTYVERSION " << NAUTYVERSION << std::endl;
        outx << tabsep << "nauty: SIZEOF_LONG " << SIZEOF_LONG << std::endl;

        if (SIZEOF_LONG != sizeof (long)) {
                outx << tabsep << "!! ERROR: sizeof(long) does not correspond to compile time size of long"
                     << std::endl;
        }
        const std::string s = outx.str ();
        return s;
}

void print_options () {
        std::string s = print_options_string ();
        myprintf ("%s", s.c_str ());
}

int has_zlib(){
#ifdef USEZLIB
	return true;
#else
	return false;
#endif
}

/**
 * Print the compile-time options to output stream.
 * @param out
 */
void print_options (std::ostream &out) {
        std::string s = print_options_string ();
        out << s;
}

// kate: indent-mode cstyle; indent-width 4; replace-tabs off; tab-width 4;


#include "regularization.hpp"

#include <string>
#include <armadillo>
#include "yaml-cpp/yaml.h"
#include <iostream>

Regularization::Regularization(const std::string &filenm):
  fitness_(0.)
{
  YAML::Node config = YAML::LoadFile(filenm);

  ni_ = config["ni"].as<int>();
  nk_ = config["nk"].as<int>();
  nplus_ = config["nplus"].as<int>();
  nx_ = ni_ + nplus_*2;
  nz_ = nk_ + nplus_*2;

  ni1_ = nplus_;
  ni2_ = ni1_ + ni_ - 1;
  nk1_ = nplus_;
  nk2_ = nk1_ + nk_ - 1;

  file_umodel_ = config["file_umodel"].as<std::string>();
  file_rmodel_ = config["file_rmodel"].as<std::string>();

  umodel_.set_size(nx_, nz_);
  rmodel_.set_size(nx_, nz_);
  gradient_.set_size(nx_, nz_);
}

namespace
{
  void load_hdf5(arma::mat& data, std::string& filenm)
  {
    data.load(filenm);
  }
}

void Regularization::load()
{
  load_hdf5(umodel_, file_umodel_);
  load_hdf5(rmodel_, file_rmodel_);
}

void Regularization::save(std::string& filenm)
{
  gradient_.save(filenm, arma::hdf5_binary);
}

void Regularization::print_fitness(const std::string& s) const
{
  std::cout << "The fitness of the "
            << s
            << " is "
            << fitness_
            << std::endl;
}


/**
 *          Copyright Matthias Walter 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)
 **/

#ifndef PERMUTATION_HPP_
#define PERMUTATION_HPP_

#include <utility>
#include <iostream>
#include <vector>
#include <map>
#include <exception>
#include <cassert>
#include <boost/random/uniform_int.hpp>

namespace unimod
{

  /**
   * Exception to indicate that the size of a permutation could not be be reduced.
   */

  class permutation_shrink_exception: std::exception
  {
  public:
    permutation_shrink_exception()
    {

    }

    virtual ~permutation_shrink_exception() throw ()
    {

    }

    virtual const char* what() const throw ()
    {
      return "Cannot shrink permutation";
    }
  };

  /**
   * A permutation which maps integers from 0 to size-1 to the same range
   * in any possible way. This implementation stores the image of each
   * of the values in a vector.
   */

  class permutation
  {
  public:
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef size_t value_type;
    typedef std::vector <value_type> data_type;

  protected:
    data_type _data;

  public:

    /**
     * Constructs a permutation of a given size,
     * initializing to the identity.
     *
     * @param size Optional size of the permutation
     */

    permutation(size_type size = 0)
    {
      reset(size);
    }

    /**
     * Constructs a permutation of a given size,
     * initializing to a random permutation.
     *
     * @param size Optional size of the permutation
     * @param rng Random number generator.
     */

    template <typename RandomNumberGenerator>
    permutation(size_type size, RandomNumberGenerator& rng)
    {
      reset(size);
      shuffle(rng);
    }

    /**
     * Copy constructor
     *
     * @param other Another permutation
     */

    permutation(const permutation& other)
    {
      _data.resize(other.size());
      for (size_type i = 0; i < _data.size(); ++i)
        _data[i] = other._data[i];
    }

    /**
     * Destructor
     */

    virtual ~permutation()
    {

    }

    /**
     * Resizes the permutation and resets it to identity.
     *
     * @param new_size New size
     */

    void reset(size_t new_size)
    {
      _data.resize(new_size);
      for (size_type i = 0; i < new_size; ++i)
      {
        _data[i] = i;
      }
    }

    /**
     * Resets the permutation to identity.
     */

    inline void reset()
    {
      reset(_data.size());
    }

    /**
     * Shuffles a permutation.
     *
     * @param rng Random number generator.
     */

    template <typename RandomNumberGenerator>
    void shuffle(RandomNumberGenerator& rng)
    {
      for (size_t i = 0; i < _data.size(); ++i)
      {
        boost::uniform_int <int> dist(i, _data.size() - 1);
        size_t j = dist(rng);
        swap(i, j);
      }
    }

    /**
     * @return The current size of the permutation
     */

    inline size_type size() const
    {
      return _data.size();
    }

    /**
     * The image of a specific integer in range 0 .. size-1.
     *
     * @param index Given integer
     * @return The integers image
     */

    inline value_type operator()(value_type index) const
    {
      return get(index);
    }

    /**
     * The image of a specific integer in range 0 .. size-1.
     * @param index Given integer
     * @return The integers image
     */

    inline value_type get(value_type index) const
    {
      assert (index < _data.size());

      return _data[index];
    }

    /**
     * Swaps the images of two integers in range 0 .. size-1.
     *
     * @param a First integer
     * @param b Second integer
     */

    inline void swap(value_type a, value_type b)
    {
      std::swap(_data[a], _data[b]);
    }

    /**
     * Swaps the preimages of two integers in range 0 .. size-1.
     *
     * @param a First integer
     * @param b Second integer
     */

    void rswap(value_type a, value_type b)
    {
      value_type tmp, pa = a, pb = b;
      while ((tmp = get(pa)) != a)
        pa = tmp;
      while ((tmp = get(pb)) != b)
        pb = tmp;
      swap(pa, pb);
    }

    /**
     * Makes this permutation its own inverse.
     */

    void revert()
    {
      /// Create a temporary copy
      value_type* temp = new value_type[size()];
      for (size_type i = 0; i < size(); ++i)
        temp[i] = _data[i];

      for (size_type i = 0; i < size(); ++i)
        _data[temp[i]] = i;
      delete[] temp;
    }

    /**
     * @return The inverse permutation of this permutation
     */

    permutation reverse() const
    {
      permutation result(size());
      for (size_type i = 0; i < size(); ++i)
        result._data[get(i)] = i;
      return result;
    }

    /**
     * Assignment operator.
     *
     * @param other Another permutation
     * @return A reference to this permutation
     */

    permutation& operator=(const permutation& other)
    {
      _data.resize(other.size());
      for (size_type i = 0; i < _data.size(); ++i)
        _data[i] = other._data[i];
      return *this;
    }

    /**
     * Calculates the product of this and another permutation.
     * The result is equivalent to applying the second permutation
     * first and this one afterwards.
     *
     * @param rhs Right hand side permutation
     * @return The resulting permutation
     */

    permutation operator*(const permutation& rhs) const
    {
      assert (size() == rhs.size());

      permutation result(size());
      for (size_type i = 0; i < size(); ++i)
        result._set(i, _data[rhs(i)]);

      return result;
    }

    /**
     * Resizes the permutation, retaining the contents.
     * This may fail if it cannot be shrunken this way and
     * will throw a permutation_shrink_exception in that case.
     *
     * @param new_size New size of the permutation
     */

    void resize(size_type new_size)
    {
      size_type old_size = size();
      for (size_type i = new_size; i < old_size; ++i)
      {
        if (_data[i] < new_size)
          throw permutation_shrink_exception();
      }

      _data.resize(new_size);
      for (size_type i = old_size; i < new_size; i++)
        _data[i] = i;
    }

    /**
     * Grows the permutation by a given number of elements.
     *
     * @param by Number of elements to increase the size by
     */

    inline void grow(difference_type by)
    {
      resize(size() + by);
    }

    /**
     * Shrinks the permutation by a given number of elements.
     *
     * @param by Number of elements to decrease the size by
     */

    inline void shrink(difference_type by)
    {
      resize(size() - by);
    }

  protected:

    /// Class to enumerate permutations

    friend class permutation_enumerator;

    /// Class to setup a permutation which can be put before a vector.

    template <class Less>
    friend void sort(permutation& permutation, size_t first, size_t beyond, Less& less);

    /**
     * Sets a specific value without checking validity.
     *
     * @param index Index of the entry
     * @param value New value
     */

    void _set(value_type index, value_type value)
    {
      _data[index] = value;
    }

    /**
     * @return A reference to the data vector
     */

    inline data_type& get_data()
    {
      return _data;
    }

  };

  /**
   * Enumerates all permutations of a given size with
   * optional constraints. You must derive from it
   * and override the visitor() method.
   */

  class permutation_enumerator
  {
  public:
    typedef size_t size_type;
    typedef std::vector <permutation::value_type> memberlist_type;
    typedef std::pair <memberlist_type*, permutation*> groupinfo_type;
    typedef std::map <int, groupinfo_type> state_type;

  private:
    size_type _size;
    state_type _state;
    permutation _permutation;

  public:

    /**
     * Constructs an enumerator without constraints.
     * Has O(size!) running time.
     *
     * @param size Size of the permutations
     */

    permutation_enumerator(permutation::size_type size) :
      _permutation(size)
    {
      if (size)
      {
        memberlist_type* memberlist = new memberlist_type();
        memberlist->resize(size);
        for (permutation::size_type i = 0; i < size; i++)
          (*memberlist)[i] = i;
        permutation* perm = new permutation(size);
        _state[0] = groupinfo_type(memberlist, perm);
      }
    }

    /**
     * Constructs an enumerator with grouping constraints:
     * Only those permutations are enumerated where k and p(k) are
     * in the same group for all i.
     *
     * @param groups Vector of groups
     */

    permutation_enumerator(const std::vector <permutation::value_type>& groups) :
      _permutation(groups.size())
    {
      _size = groups.size();
      for (size_t i = 0; i < groups.size(); ++i)
      {
        state_type::iterator iter = _state.find(groups[i]);
        if (iter == _state.end())
        {
          _state[groups[i]] = groupinfo_type(new memberlist_type(), NULL);
          _state[groups[i]].first->push_back(i);
        }
        else
        {
          iter->second.first->push_back(i);
        }
      }
      for (state_type::iterator iter = _state.begin(); iter != _state.end(); ++iter)
      {
        groupinfo_type& info = iter->second;
        info.second = new permutation(info.first->size());
      }
    }

    /**
     * Destructor.
     */

    virtual ~permutation_enumerator()
    {
      for (state_type::iterator iter = _state.begin(); iter != _state.end(); ++iter)
      {
        delete iter->second.first;
        delete iter->second.second;
      }
    }

    /**
     * @return true if and only if the size of each permutation is zero
     */

    inline bool empty()
    {
      return _size == 0;
    }

    /**
     * Starts the enumeration which is aborted if any
     * visitor returns false.
     *
     * @return true if and only if all visitors returned true
     */

    virtual bool enumerate()
    {
      if (empty())
        return true;

      return enumerate_group(_state.begin(), 0);
    }

  protected:

    /**
     * Method which is called for each enumerated permutation.
     * Needs to be overridden.
     *
     * @param perm Current permutation
     * @return false to abort enumeration
     */

    virtual bool visitor(const permutation& perm) = 0;

  private:

    /**
     * Enumerates possible values at a given index in a given group.
     *
     * @param state Current state and group
     * @param index Current index to enumerate values
     * @return false to abort enumeration
     */

    bool enumerate_group(state_type::iterator state, permutation::size_type index)
    {
      /// Nothing to enumerate - just call the visitor.
      if (state == _state.end())
      {
        for (state = _state.begin(); state != _state.end(); ++state)
        {
          const memberlist_type& memberlist = *(state->second.first);
          const permutation& perm = *(state->second.second);
          for (permutation::size_type i = 0; i < perm.size(); i++)
          {
            _permutation._set(memberlist[i], memberlist[perm(i)]);
          }
        }

        return visitor(_permutation);
      }

      /// Jump to next group
      if (index >= state->second.first->size())
      {
        return enumerate_group(++state, 0);
      }

      /// Enumerate the current groups permutation.
      permutation& p = *(state->second.second);
      for (permutation::size_type i = 0; i < p.size(); i++)
      {
        bool found = false;
        for (permutation::size_type j = 0; j < index; j++)
        {
          if (p(j) == i)
          {
            found = true;
            break;
          }
        }
        if (!found)
        {
          p._set(index, i);
          if (!enumerate_group(state, index + 1))
            return false;
        }
      }

      return true;
    }
  };

  /**
   * Compares two permutations for equality.
   *
   * @param p First permutation
   * @param q Second permutation
   * @return true if and only if the permutations are the same
   */

  inline bool operator==(const permutation& p, const permutation& q)
  {
    if (p.size() != q.size())
      return false;

    for (size_t i = 0; i < p.size(); ++i)
    {
      if (p(i) != q(i))
        return false;
    }
    return true;
  }

  /**
   * Output operator for permutations.
   *
   * @param stream A given output stream
   * @param p A given permutation
   * @return The stream after writing the permutation
   */

  inline std::ostream& operator<<(std::ostream& stream, const permutation& p)
  {
    if (p.size() > 0)
    {
      stream << p(0);
      for (size_t i = 1; i < p.size(); i++)
        stream << ' ' << p(i);
    }
    return stream;
  }

  /**
   * Arranges part of a given permutation such that it can be used to
   * view a vector in a sorted way.
   *
   * @param permutation The given permutation to be changed
   * @param first First index of the part
   * @param beyond Beyond index of the part
   * @param less Functor to compare two elements
   */

  template <class Less>
  inline void sort(permutation& permutation, size_t first, size_t beyond, Less& less)
  {
    permutation::data_type& data = permutation.get_data();
    std::sort(data.begin() + first, data.begin() + beyond, less);
  }

  /**
   * Arranges a given permutation such that it can be used to
   * view a vector in a sorted way.
   *
   * @param permutation The given permutation to be changed
   * @param less Functor to compare two elements
   */

  template <class Less>
  inline void sort(permutation& permutation, Less& less)
  {
    sort(permutation, 0, permutation.size(), less);
  }

}

#endif /* PERMUTATION_HPP_ */


#include <iostream>
#include <string>
#include <sstream>
#include "LFSR.hpp"

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

// The initial test that was in this file.
BOOST_AUTO_TEST_CASE(fiveBitsTapAtTwo)
{
  LFSR l("00111", 2);
  BOOST_REQUIRE(l.step() == 1);
  BOOST_REQUIRE(l.step() == 1);
  BOOST_REQUIRE(l.step() == 0);
  BOOST_REQUIRE(l.step() == 0);
  BOOST_REQUIRE(l.step() == 0);
  BOOST_REQUIRE(l.step() == 1);
  BOOST_REQUIRE(l.step() == 1);
  BOOST_REQUIRE(l.step() == 0);

  LFSR l2("00111", 2);
  BOOST_REQUIRE(l2.generate(8) == 198);
}

// My first test. I just tested what Princeton's
// website gave as examples.
// In this case, they use 11 bit seeds with a tap of 8.
BOOST_AUTO_TEST_CASE(PrincetonExamples)
{
  // The simulate step test
  LFSR test("01101000010", 8);

  BOOST_REQUIRE(test.step() == 1);
  BOOST_REQUIRE(test.step() == 1);
  BOOST_REQUIRE(test.step() == 0);
  BOOST_REQUIRE(test.step() == 0);
  BOOST_REQUIRE(test.step() == 1);
  BOOST_REQUIRE(test.step() == 0);
  BOOST_REQUIRE(test.step() == 0);
  BOOST_REQUIRE(test.step() == 1);
  BOOST_REQUIRE(test.step() == 0);
  BOOST_REQUIRE(test.step() == 0);

  // The generate test from Princeton
  LFSR test2("01101000010", 8);
  BOOST_REQUIRE(test2.generate(5) == 25);
  BOOST_REQUIRE(test2.generate(5) == 4);
  BOOST_REQUIRE(test2.generate(5) == 30);
  BOOST_REQUIRE(test2.generate(5) == 27);
  BOOST_REQUIRE(test2.generate(5) == 18);
  BOOST_REQUIRE(test2.generate(5) == 26);
  BOOST_REQUIRE(test2.generate(5) == 28);
  BOOST_REQUIRE(test2.generate(5) == 24);
  BOOST_REQUIRE(test2.generate(5) == 23);
  BOOST_REQUIRE(test2.generate(5) == 29);
}

// A couple of tests making sure the constructor functions
// as intended. This also tests the << operator as well.
BOOST_AUTO_TEST_CASE(Constructor_Tests)
{
  LFSR test("001100", 5);
  std::stringstream buffer;
  buffer << test;

  // Make sure the constructor saves the seed correctly.
  BOOST_REQUIRE(buffer.str().compare("001100") == 0);

  // Try a much larger seed - 30 bits for example.
  LFSR test2("0000000111111111001010101011", 10);
  buffer.str("");   // Clear the stringstream object
  buffer.clear();
  buffer << test2;

  // Make sure the constructor saves the seed correctly.
  BOOST_REQUIRE(buffer.str().compare("0000000111111111001010101011") == 0);

  // Now try a very small seed - 1 bit for example.
  LFSR test3("1", 1);
  buffer.str("");   // Clear the stringstream object
  buffer.clear();
  buffer << test3;

  // Make sure the constructor saves the seed correctly.
  BOOST_REQUIRE(buffer.str().compare("1") == 0);
}