#include "kalmanfilter.h"
#include <Eigen/Cholesky>

const double KalmanFilter::chi2inv95[10] = {
    0,
    3.8415,
    5.9915,
    7.8147,
    9.4877,
    11.070,
    12.592,
    14.067,
    15.507,
    16.919
};
KalmanFilter::KalmanFilter()
{
    int ndim = 4;
    double dt = 1.;

    _motion_mat = Eigen::MatrixXf::Identity(8, 8);
    for(int i = 0; i < ndim; i++) {
        _motion_mat(i, ndim+i) = dt;
    }
    _update_mat = Eigen::MatrixXf::Identity(4, 8);

    this->_std_weight_position = 1. / 20;
    this->_std_weight_velocity = 1. / 160;
}

KAL_DATA KalmanFilter::initiate(const DETECTBOX &measurement)
{
    DETECTBOX mean_pos = measurement;
    DETECTBOX mean_vel;
    for(int i = 0; i < 4; i++) mean_vel(i) = 0;

    KAL_MEAN mean;
    for(int i = 0; i < 8; i++){
        if(i < 4) mean(i) = mean_pos(i);
        else mean(i) = mean_vel(i - 4);
    }

    KAL_MEAN std;
    std(0) = 2 * _std_weight_position * measurement[3];
    std(1) = 2 * _std_weight_position * measurement[3];
    std(2) = 1e-2;
    std(3) = 2 * _std_weight_position * measurement[3];
    std(4) = 10 * _std_weight_velocity * measurement[3];
    std(5) = 10 * _std_weight_velocity * measurement[3];
    std(6) = 1e-5;
    std(7) = 10 * _std_weight_velocity * measurement[3];

    KAL_MEAN tmp = std.array().square();
    KAL_COVA var = tmp.asDiagonal();
    return std::make_pair(mean, var);
}

void KalmanFilter::predict(KAL_MEAN &mean, KAL_COVA &covariance)
{
    //revise the data;
    DETECTBOX std_pos;
    std_pos << _std_weight_position * mean(3),
            _std_weight_position * mean(3),
            1e-2,
            _std_weight_position * mean(3);
    DETECTBOX std_vel;
    std_vel << _std_weight_velocity * mean(3),
            _std_weight_velocity * mean(3),
            1e-5,
            _std_weight_velocity * mean(3);
    KAL_MEAN tmp;
    tmp.block<1,4>(0,0) = std_pos;
    tmp.block<1,4>(0,4) = std_vel;
    tmp = tmp.array().square();
    KAL_COVA motion_cov = tmp.asDiagonal();
    KAL_MEAN mean1 = this->_motion_mat * mean.transpose();
    KAL_COVA covariance1 = this->_motion_mat * covariance *(_motion_mat.transpose());
    covariance1 += motion_cov;

    mean = mean1;
    covariance = covariance1;
}

KAL_HDATA KalmanFilter::project(const KAL_MEAN &mean, const KAL_COVA &covariance)
{
    DETECTBOX std;
    std << _std_weight_position * mean(3), _std_weight_position * mean(3),
            1e-1, _std_weight_position * mean(3);
    KAL_HMEAN mean1 = _update_mat * mean.transpose();
    KAL_HCOVA covariance1 = _update_mat * covariance * (_update_mat.transpose());
    Eigen::Matrix<float, 4, 4> diag = std.asDiagonal();
    diag = diag.array().square().matrix();
    covariance1 += diag;
//    covariance1.diagonal() << diag;
    return std::make_pair(mean1, covariance1);
}

KAL_DATA
KalmanFilter::update(
        const KAL_MEAN &mean,
        const KAL_COVA &covariance,
        const DETECTBOX &measurement)
{
    KAL_HDATA pa = project(mean, covariance);
    KAL_HMEAN projected_mean = pa.first;
    KAL_HCOVA projected_cov = pa.second;

    //chol_factor, lower =
    //scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
    //kalmain_gain =
    //scipy.linalg.cho_solve((cho_factor, lower),
    //np.dot(covariance, self._upadte_mat.T).T,
    //check_finite=False).T
    Eigen::Matrix<float, 4, 8> B = (covariance * (_update_mat.transpose())).transpose();
    Eigen::Matrix<float, 8, 4> kalman_gain = (projected_cov.llt().solve(B)).transpose(); // eg.8x4
    Eigen::Matrix<float, 1, 4> innovation = measurement - projected_mean; //eg.1x4
    auto tmp = innovation*(kalman_gain.transpose());
    KAL_MEAN new_mean = (mean.array() + tmp.array()).matrix();
    KAL_COVA new_covariance = covariance - kalman_gain*projected_cov*(kalman_gain.transpose());
    return std::make_pair(new_mean, new_covariance);
}

Eigen::Matrix<float, 1, -1>
KalmanFilter::gating_distance(
        const KAL_MEAN &mean,
        const KAL_COVA &covariance,
        const std::vector<DETECTBOX> &measurements,
        bool only_position)
{
    KAL_HDATA pa = this->project(mean, covariance);
    if(only_position) {
        printf("not implement!");
        exit(0);
    }
    KAL_HMEAN mean1 = pa.first;
    KAL_HCOVA covariance1 = pa.second;

//    Eigen::Matrix<float, -1, 4, Eigen::RowMajor> d(size, 4);
    DETECTBOXSS d(measurements.size(), 4);
    int pos = 0;
    for(DETECTBOX box:measurements) {
        d.row(pos++) = box - mean1;
    }
    Eigen::Matrix<float, -1, -1, Eigen::RowMajor> factor = covariance1.llt().matrixL();
    Eigen::Matrix<float, -1, -1> z = factor.triangularView<Eigen::Lower>().solve<Eigen::OnTheRight>(d).transpose();
    auto zz = ((z.array())*(z.array())).matrix();
    auto square_maha = zz.colwise().sum();
    return square_maha;
}


/*  This file is part of libDAI - http://www.libdai.org/
 *
 *  libDAI is licensed under the terms of the GNU General Public License version
 *  2, or (at your option) any later version. libDAI is distributed without any
 *  warranty. See the file COPYING for more details.
 *
 *  Copyright (C) 2010  Joris Mooij  [joris dot mooij at libdai dot org]
 */

#include <dai/alldai.h>
#include <fstream>
#include "dai/emrun.h"
#include <dai/util.h>
#include <string>
#include <sys/stat.h>
#include <time.h>
#include <iomanip>      // std::setprecision
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include<math.h>
#include <string>
#include <iostream>

#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/generator_iterator.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/bimap/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/config.hpp>
#include <boost/bimap.hpp>
#include <boost/optional.hpp>
#include <boost/none.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_inserter.hpp>
using namespace std;
using namespace dai;
using namespace boost;
// Define a random number generator and initialize it with a reproducible
// seed.
mt19937 generator(42);

// Define a uniform random number distribution which produces "double"
// values between 0 and 1 (0 inclusive, 1 exclusive).
boost::uniform_real<> uni_dist(0,1);
boost::variate_generator<mt19937&, boost::uniform_real<> > uni(generator, uni_dist);

boost::normal_distribution<> nd(0.0, 1.0);
boost::variate_generator<mt19937&, boost::normal_distribution<> > normal(generator, nd);

// GA - initialization
size_t max_gen = 5; // no. of generations
size_t population_size =4; // population size
Real pc;// = 0.8; // crossover probability - between 0.6 an 0.9
Real pm;// = 0.3; // mutation probability - between 1/pop.size and 1/chromosome_length
int population_no=0; // current population id

// 1. Creating initial population of EM runs
string alarmfgloc;
char* gibbsfile;// = "/home/priya/libDAI-0.3.1/alarm/500/5.tab";
char* networkname ; //= "alarm";
size_t maxIters =1000; // maximum number of iterations
char* emfile;
ofstream out;
EMRun* runname;
vector <EMRun*> layer;
vector <EMRun*> layer_curr;
vector <EMRun*> layer_prev;
vector <EMRun*> layer_parent;
dai::hash_map<int, FactorGraph> hashmap;
int *arrval;
//
// Generate a random number between 0 and 1
// return a uniform number in [0,1].
double unifRand()
{
    return rand()/double(RAND_MAX);
}
void initializeEM()
{
    size_t i =0,j=0;
	cout<<"Initial start EM"<<endl;
	while(i<population_size)
	{
        string number;
        stringstream num;
        num << i;
        number = num.str();
        string dirname;
        stringstream p_id;
        p_id << population_no;
        dirname = p_id.str();
        string fgfileloc =  alarmfgloc+"/"+networkname+"_"+number+".fg";
        const char* fgfile = &fgfileloc[0];
        FactorGraph fg;
        fg.ReadFromFile(fgfile);
        runname = new EMRun(networkname, i, fg, gibbsfile,emfile);
        // 2. Run EM
        boost::thread threadid(boost::bind(&EMRun::startEM, boost::ref(runname), maxIters));
        layer.push_back(runname);
        sleep(1);
        // 4. Next individual
        cout<<" run "<<i<<" started"<<endl;
        i=i+1;
    }
}
void printFactors()
{
    vector<EMRun*>::iterator it1;
    for (int i=0;i<population_size;i++)
    {
       FactorGraph fg = hashmap[i];
    cout<<"------ Printing ------"<<i<<endl;
    for( size_t I = 0; I < fg.nrFactors(); I++ )
    {
        Factor P = fg.factor( I );
        dai::TProb<double> myvector = P.p();
        for (dai::TProb<double>::iterator it = myvector.begin();it != myvector.end(); ++it)
            std::cout << ' ' << *it;
        std::cout << '\n';
    }
    }
}
void startEM()
{
   // printFactors();
    for (int i=0;i<population_size;i++)
    {
        FactorGraph fg = hashmap[i];
        double runid = i;
        cout<<"Starting EM "<<runid<<endl;
        runname = new EMRun(networkname, i, fg, gibbsfile,emfile);
        // 2. Run EM
        boost::thread threadid(boost::bind(&EMRun::startEM, boost::ref(runname), maxIters));
        layer.push_back(runname);
        sleep(1);
	}

}
std::vector<EMRun*>::iterator compareRuns(std::vector<EMRun*>::iterator *it)
{
    if(layer_prev.size() !=0 )
      {
        cout<<" iters = "<<(**it)->getIters()<<endl;
        double iters = (**it)->getIters();
        double val = (**it)->getRun();
        cout<<" em run stopped "<<val<<endl;
        double ll = (**it)->getLL();
        vector<EMRun*>::iterator itprev;
        std::vector<Real> llTraceprev;
        // get the pervious run

        for (itprev=layer_prev.begin(); itprev != layer_prev.end(); ++itprev)
        {
            double runid = (*itprev)->getRun();
            if(val==runid)
            {
                //out1<<runid<<" "<<iters<<" ";

                llTraceprev = (*itprev)->lastlog();
                cout<<val<<" "<<"runid = "<<(*itprev)->getRun()<<"  "<<" "<<(*itprev)->getIters()<<endl;
                break;
            }
        }
        //check if current EM run's LL is greater or equal to prev EM run's LL

        double llprev;
        cout<<" size = "<<llTraceprev.size()<<endl;
        if((llTraceprev.size()-1)>iters)
            llprev = llTraceprev.at(iters);
        else
            llprev = llTraceprev.at(llTraceprev.size()-1);
       // cout<<" LL for prev run = "<<llprev<<endl;
        if(ll>=llprev)
        {
            cout<<" current LL "<<ll<<" is good"<<endl;
            boost::thread thread7(boost::bind(&EMRun::resumeEM, boost::ref(**it)));
            cout<<" em run resumed"<<val<<endl;
        }
        else
        {
            cout<<" current LL "<<ll<<" is not good"<<endl;
            **it = *itprev;
            (*itprev)->forceStopped();
            cout<<" em run not resumed"<<val<<endl;
        }

    }
    return *it;
    ////////////
}
void checkEMforTermination()
{
    layer_prev.assign(layer_curr.begin(), layer_curr.end());
	layer_curr.clear();
    int i=0;
	while (true){
	    //cout<<"in while loop "<<layer.size()<<endl;
        i++;
	    vector<EMRun*>::iterator it;
	    for (it=layer.begin(); it != layer.end(); ++it){
//            if((*it)->getIters() > 2*i)
//            it = compareRuns(&it);
//            cout<<" iters = "<<(*it)->getIters()<<endl;
//
	      //cout<<"layer size "<<layer.size()<<endl;
	      if((*it)->hasTerminated()) { //if it has terminated, set the run aside

              double ll = (*it)->getLL();
              double iters = (*it)->getIters();
              double runid = (*it)->getRun();
              //cout<<"em run "<<runid<<" terminated "<<iters<<endl;
              std::vector<Real> llTrace = (*it)->lastlog();
              cout<<"Run number "<<runid<<" ll = "<<ll<<" iters = "<<iters<<endl;
              InfAlg* inf1 = (*it)->getInf();
              FactorGraph fg1 = inf1->fg();
              //cout<<fg1<<endl;
              sleep(1);
              out<<pc<<" "<<pm<<" "<<gibbsfile<<" "<<runid<<" "<<iters<<" "<<ll<<" "<<endl;
              layer_curr.push_back(*it);
              layer.erase(it);
              if (layer.size() == 0){break;}
              else { it = layer.begin(); }
          }
            //we stop the run
        else if(((*it)->getIters()) == maxIters){
            double ll = (*it)->getLL();
            double iters = (*it)->getIters();
            double runid = (*it)->getRun();
            sleep(1);
            //cout<<"Run number "<<number<<" has reached maximum iterations so stopped"<<endl;
            //out<<pc<<" "<<pm<<" "<<gibbsfile<<" "<<runid<<" "<<iters<<" "<<ll<<" "<<endl;
		    layer_curr.push_back(*it);
            if(!(*it)->isForceStop())
            {
                boost::thread thread5(boost::bind(&EMRun::stopEM, boost::ref(*it)));

            }
            layer.erase(it);
            //	if (layer.size() == 0){break;}
            //	else { it = layer.begin(); }
	      }

	 }
	 if (layer.size() == 0){ //cout<<"breaking while"<<endl;
		break; }
	 else { //cout<<"iterating"<<endl;
		}
	  sleep(1);
	}
    layer_parent.assign(layer_curr.begin(), layer_curr.end());
}

void doMutation() // open each child file and apply mutation if required
{
    //cout<<"Mutation Begins"<<endl;
    double pmut=0;
    vector<EMRun*>::iterator it_C;
    //printFactors();
    for (it_C=layer_parent.begin(); it_C != layer_parent.end(); ++it_C){
        double runid = (*it_C)->getRun();
        InfAlg* inf = (*it_C)->getInf();
        FactorGraph fg = hashmap[runid];//inf->fg();
        std::vector<int> mutateFactors;
        mutateFactors.clear();
        mutateFactors = (*it_C)->getmutateFactors();
        int noMutations =0;
        //cout<<" Run id "<<runid;
        //cout<<"______"<<mutateFactors.size()<<endl;
        cout<<"Mutation at ";
        for( size_t I = 0; I < fg.nrFactors(); I++ )
            {
//                std::vector<int>::iterator it;
//                it = find (mutateFactors.begin(), mutateFactors.end(), I);
//                if (it != mutateFactors.end())
//                {
//                    //std::cout << "Element found in myvector: " << *it << '\n';
//                    pmut=1;
//                }
//                else
//                {
//                    //  std::cout << "Element not found in myvector\n";
//                    pmut=0;
//                }
                pmut = uni(); // generates random a value between 0 and 1 for child1
                //cout<<pmut<<" "<<endl;
                int no_states = fg.factor( I ).nrStates();// total no. of states
                int no_arr_arrset =0; // factor_states
                int arr_size =1; //states of parents before factor_pos
                int arr_set =0; //states of parents after factor_pos
                int arr_set_states =0; // no. of states till factor_pos

                //cout<<fg.factor( I ).nrStates()<<endl;
                Factor P = fg.factor( I );
                VarSet vs = P.vars();
//                cout<<"vars = "<<vs<<endl;
//                cout << "{";
                for( VarSet::const_iterator v = vs.begin(); v != vs.end(); v++ )
                {
                   // cout << (v != vs.begin() ? ", " : "") << *v;
                    if(v->label()<I)
                        arr_size = arr_size * v->states();
                    if(v->label() == I)
                    {
                       // cout<<" states = "<<v->states()<<endl;
                        no_arr_arrset = v->states();
                        arr_set_states = arr_size * v->states();
                        break;
                    }
                }
                //cout << "}"<<endl;
                arr_set = no_states/arr_set_states;
                //cout<<"no. of states "<<no_states<<"\t"<<"array set "<<arr_set<<"\t"<<"arr_set_states "<<arr_set_states<<"\t"<<"no_arr_arrset "<<no_arr_arrset<<"\t"<<"array size "<<arr_size<<endl;

                if(pmut>pm) //do mutation handling the constraint that the states of the random variable sum to 1.
                {
                noMutations++;
                cout<<" "<<I;
                int k=0;
                while(k<arr_set)
                {
                    //Random values are generated---~----~----
                    std::vector< double * > Arrays1;
                    for(int l=0; l<no_arr_arrset; l++)
                    {
                        Arrays1.push_back( new double[arr_size]);
                    }
                    vector<double*>::iterator it;
                    for(int m=0; m<arr_size; m++)
                    {
                        it=Arrays1.begin();
                        std::vector<double> vec;
                        for(int i=0; i<no_arr_arrset; i++)
                        {
                            vec.push_back(uni());
                        }
                        const double total = std::accumulate(vec.begin(), vec.end(), 0.0);
                        for (double& value: vec)
                        {
                            double* arr = *it;
                            value /= total;
                            arr[m] = value;
                            ++it;
                           // cout<<value <<endl;
                        }
                        // cout<<endl;
                        vec.clear();
                    }
                    //Random values are generated---x----x----
                    //Random or actual values will be updated -----~------~
                    vector<double*>::iterator it11;
                    it11=Arrays1.begin();
                    int stat=0;
                    for(int l=0; l<no_arr_arrset; l++)
                    {
                        double* arr = *it11;
                        for(int m=0; m<arr_size; m++)
                        {
                            stringstream v;
                            v << fixed << setprecision(12) << arr[m];
                            //c1<<stat<<"   "<<v.str()<<endl;
                            //cout<< "replaced"<<v.str()<<endl;
                            P.set(stat,arr[m]);
                            stat++;
                        }
                        ++it11;
                    }
                    //Random values are updated ------x------x--------
                    k++;
                } // end of while
                } // end of if
                fg.setFactor(I,P);
            } // end of factors
        cout<<" Total mutations "<<noMutations<<" runid "<<runid<<endl;
        hashmap[runid]=fg;
    } // end of factorgraphs
     //printFactors();
    //cout<<"Mutation Done"<<endl;
}

void doCrossover()
{
    //cout<<"Crossover Begins"<<endl;
	// compute crossover probability
    double pcross = uni(); // generates random a value between 0 and 1
	//cout<<"Crossover probability "<<pcross <<endl;
	// 4. Select 2 parents randomly
	const int LOW = 0;
	const int HIGH = population_size-1;
    set<int> myset;
	set<int>::iterator it;
	size_t p=0;
	arrval = new int[population_size];
    /*Declare variable to hold seconds on clock.*/
	time_t seconds;
	/*Get value from system clock and place in seconds variable.*/
	time(&seconds);
	/*Convert seconds to a unsigned integer.*/
	srand(time(0));

    for (int n=0;n<population_size;n++)
    {
        int val = rand() % (HIGH - LOW + 1) + LOW;
        it=myset.find(val);
        arrval[n] = val;
        if(it==myset.end()) // if the value is not in the set
        {
            myset.insert(val);
            p++;
            if(p == 2)
            {
               // cout <<" Random value is"<<arrval[n]<<" and "<< arrval[n-1];
                EMRun* r1 = layer_parent.at(n);
                EMRun* r2 = layer_parent.at(n-1);
                double runid = (r1)->getRun();
                InfAlg* inf = (r1)->getInf();
                FactorGraph fg = inf->fg();
                double runid1 = (r2)->getRun();
                InfAlg* inf1 = (r2)->getInf();
                FactorGraph fg1 = inf1->fg();
                // randomly select a crossover point
                int cr_pt = (rand() % fg.nrVars());
               // cout<<" Crossover point is "<< cr_pt<<endl;
                p=0;
                if(pcross>pc)
                {
                for( size_t I = cr_pt; I < fg.nrFactors(); I++ )
                {
                    Factor P = fg.factor( I );
                    dai::TProb<double> myvector = P.p();
                    Factor P1 = fg1.factor( I );
                    dai::TProb<double> myvector1 = P1.p();
                    dai::TProb<double>::iterator it1 = myvector1.begin();
                    dai::TProb<double>::iterator it = myvector.begin();
                    for (int state=0;state<myvector.size();state++)
                    {
                        P.set(state,*it1);
                        P1.set(state,*it);
                        ++it1;++it;
                    }
                    fg.setFactor(I,P);
                    fg1.setFactor(I,P1);
                }
                }
                int val = arrval[n];int val1 = arrval[n-1];
                hashmap[val]=fg;
                hashmap[val1]=fg1;
            }
        }
        else
        {
            n=n-1;
            continue;
        }
    }
    //cout<<"Crossover Done"<<endl;
    //printFactors();

}

void replacementStrategy()
{
 //cout<<"In replacement strategy"<<endl;
 double ll, ll1;
 string ssiters,ssiters1,ssll1,ssll,ssrunid, ssrunid1;
 layer_parent.clear();
 for( size_t n = 0; n < population_size; n++ )
 {
	int val = arrval[n];
	//cout<<"val = "<<val<<endl;
	vector<EMRun*>::iterator it, it1;
	int i=0;
	for (it=layer_prev.begin(); it != layer_prev.end(); ++it)
    {
	      ll = (*it)->getLL();
	      double iters = (*it)->getIters();
	      double runid = (*it)->getRun();
	      stringstream sll;
	      stringstream siters;
              stringstream srunid;
	      sll<<ll; ssll = sll.str();
	      siters <<iters; ssiters = siters.str();
	      srunid <<runid; ssrunid = srunid.str();
	     // cout<<"runid = "<<ssrunid<<"  "<<ssll<<" "<<ssiters<<endl;
	      if(val==runid)
	      {
              //out1<<runid<<" "<<iters<<" ";
            //  cout<<val<<" "<<"runid = "<<ssrunid<<"  "<<ssll<<" "<<ssiters<<endl;
              break;
	      }
	}
    for (it1=layer_curr.begin(); it1 != layer_curr.end(); ++it1)
    {
	      ll1 = (*it1)->getLL();
	      double iters1 = (*it1)->getIters();
	      double runid1 = (*it1)->getRun();
              stringstream sll1;
              stringstream siters1;
              stringstream srunid1;
	      sll1<<ll1; ssll1 = sll1.str();
	      siters1 <<iters1; ssiters1 = siters1.str();
	      srunid1 <<runid1; ssrunid1 = srunid1.str();
	     // cout<<"runid = "<<ssrunid1<<"  "<<ssll1<<" "<<ssiters1<<endl;
	      if(val==runid1)
	      {
             // out1<<runid1<<" "<<iters1<<" ";
             // cout<<val<<" "<<"runid = "<<ssrunid1<<"  "<<ssll1<<" "<<ssiters1<<endl;
              break;
	      }
	      i++;
	}
	if(ll<=ll1)
	{
		//cout<<"Child  has a better LL so leave the child as it is."<<endl;
        out<<population_no<<"  "<<ssrunid1<<"  "<<ssll1<<" "<<ssiters1<<endl;
	}
	else
	{
       // cout<<"Replace child with parent."<<endl;
        out<<population_no<<"  "<<ssrunid<<"  "<<ssll<<" "<<ssiters<<endl;
		*it1=*it; //replacing the object in the layer_curr vector

	}
  }
  layer_parent.assign(layer_curr.begin(), layer_curr.end());

}

int main(int argc, char *argv[]) {
    generator.seed(static_cast<unsigned int>(std::time(0)));

    gibbsfile = argv[1];
    stringstream ss2(argv[2]);
    alarmfgloc = ss2.str();
    istringstream ss( argv[3] );
    ss >> pm;
    stringstream ss1( argv[4] );
    ss1 >> pc;
    const char* fname =argv[5];
    networkname = argv[6];
    emfile = argv[7];
    out.open(fname);

    time_t timer1, timer2;
    time(&timer1);
    clock_t tStart = clock();

    initializeEM();

    cout<<"population no"<<population_no<<endl;
    while(population_no<max_gen)
    {
          checkEMforTermination();
         if(population_no>0)
            replacementStrategy();
          doCrossover();
          doMutation();
          startEM();
          population_no=population_no+1;
          cout<<"population no"<<population_no<<endl;
   }

    time(&timer2);
    double t = difftime(timer2,timer1);
    double t_c = (clock() - tStart)/CLOCKS_PER_SEC;
    out<<"Time taken: "<<t<<"s"<<endl;
    out<<" Processor Time taken: "<<t_c<<"s"<<endl;
    out.close();
    return 0;
}


#include "Quaca.h"
#include "catch.hpp"
#include <armadillo>
#include <complex>

TEST_CASE("Construction of Green's tensor plate vacuum works properly",
          "[GreensTensorPlateVacuum]") {

  SECTION("Construction with direct input") {

    double omega_p = 9;
    double gamma = 0.1;
    auto perm = std::make_shared<PermittivityDrude>(omega_p, gamma);
    auto refl = std::make_shared<ReflectionCoefficientsLocBulk>(perm);

    double v = 1E-5;
    double za = 0.1;
    double beta = 1E4;
    double delta_cut = 20;
    vec::fixed<2> rel_err = {1E-8, 1E-6};

    GreensTensorPlateVacuum Greens(v, beta, za, refl, delta_cut, rel_err);

    REQUIRE(Greens.get_v() == v);
    REQUIRE(Greens.get_beta() == beta);
    REQUIRE(Greens.get_za() == za);
    REQUIRE(Greens.get_delta_cut() == delta_cut);
    REQUIRE(Greens.get_rel_err_0() == rel_err(0));
    REQUIRE(Greens.get_rel_err_1() == rel_err(1));

    REQUIRE(Greens.get_vacuums_greens_tensor()->get_v() == v);
    REQUIRE(Greens.get_vacuums_greens_tensor()->get_beta() == beta);
  }
}

TEST_CASE("GreensTensorPlateVacuum calculate_tensor function returns the sum "
          "of plate and vacuum Green's tensor",
          "[GreensTensorPlateVacuum]") {

  double omega_p = 9;
  double gamma = 0.1;
  auto perm = std::make_shared<PermittivityDrude>(omega_p, gamma);
  auto refl = std::make_shared<ReflectionCoefficientsLocBulk>(perm);

  double v = 1E-8;
  double za = 0.1;
  double beta = 0.01;
  double delta_cut = 20;
  vec::fixed<2> rel_err = {1E-8, 1E-6};

  GreensTensorPlateVacuum GTPlateVacuum(v, beta, za, refl, delta_cut, rel_err);
  GreensTensorPlate GTPlate(v, beta, za, refl, delta_cut, rel_err);
  GreensTensorVacuum GTVacuum(v, beta, rel_err(0));

  auto k_x = GENERATE(-12.42,0.124);
  auto k_y = GENERATE(-6.543,34.123);
  auto omega = GENERATE(-1.1, 5.3);
  //Only for \omega^2 - k^2 >= 0 GreensTensorVacuum returns non-trivial results
  omega *= sqrt(pow(k_x,2) + pow(k_y,2));

  cx_mat::fixed<3, 3> TensorPlateVacuum(fill::zeros);
  GTPlateVacuum.calculate_tensor(omega, {-k_x, -k_y}, TensorPlateVacuum);

  cx_mat::fixed<3, 3> TensorVacuum(fill::zeros);
  GTVacuum.calculate_tensor(omega, {-k_x, -k_y}, TensorVacuum);

  cx_mat::fixed<3, 3> TensorPlate(fill::zeros);
  GTPlate.calculate_tensor(omega, {-k_x, -k_y}, TensorPlate);

  //Ensure non-trivial results
  REQUIRE(!TensorPlateVacuum.is_zero());
  REQUIRE(!TensorVacuum.is_zero());
  REQUIRE(!TensorPlate.is_zero());
}

TEST_CASE("GreensTensorPlateVacuum integrate_k function returns the sum "
          "of plate and vacuum Green's tensor",
          "[GreensTensorPlateVacuum]") {

  double omega_p = 9;
  double gamma = 0.1;
  auto perm = std::make_shared<PermittivityDrude>(omega_p, gamma);
  auto refl = std::make_shared<ReflectionCoefficientsLocBulk>(perm);

  double v = 1E-5;
  double za = 0.1;
  double beta = 1E4;
  double delta_cut = 20;
  vec::fixed<2> rel_err = {1E-8, 1E-6};

  GreensTensorPlateVacuum GTPlateVacuum(v, beta, za, refl, delta_cut, rel_err);
  GreensTensorPlate GTPlate(v, beta, za, refl, delta_cut, rel_err);
  GreensTensorVacuum GTVacuum(v, beta, rel_err(0));

  auto k_x = GENERATE(-10.32,2.43);
  auto k_y = GENERATE(-6.53,32.43);
  auto omega = GENERATE(3.2);
  //Only for \omega^2 - k^2 >= 0 GreensTensorVacuum returns non-trivial results
  omega *= sqrt(pow(k_x,2) + pow(k_y,2));

  cx_mat::fixed<3, 3> TensorPlateVacuum(fill::zeros);
  GTPlateVacuum.integrate_k(omega, TensorPlateVacuum, IM, UNIT);

  cx_mat::fixed<3, 3> TensorVacuum(fill::zeros);
  GTVacuum.integrate_k(omega, TensorVacuum, IM, UNIT);

  cx_mat::fixed<3, 3> TensorPlate(fill::zeros);
  GTPlate.integrate_k(omega, TensorPlate, IM, UNIT);

  //Ensure non-trivial results
  REQUIRE(!TensorPlateVacuum.is_zero());
  REQUIRE(!TensorVacuum.is_zero());
  REQUIRE(!TensorPlate.is_zero());

  REQUIRE(approx_equal(TensorPlateVacuum,TensorVacuum + TensorPlate, "reldiff", 1e-10));

}


/*

 Copyright (c) 2014 University of Edinburgh, Imperial College, University of Manchester.
 Developed in the PAMELA project, EPSRC Programme Grant EP/K008730/1

 This code is licensed under the MIT License.

 */
#include <supereight/denseslam/DenseSLAMSystem.h>
#include <default_parameters.h>
#include <interface.h>
#include <stdint.h>
#include <tick.h>
#include <vector>
#include <sstream>
#include <string>
#include <cstring>

#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <iomanip>
#include <getopt.h>
#include <supereight/shared/perfstats.h>
#include <PowerMonitor.h>

#include <Eigen/Dense>

#include <chrono>

#ifndef __QT__

#include <draw.h>
#endif

PerfStats Stats;
PowerMonitor *powerMonitor = NULL;
uint16_t * inputDepth = NULL;
static uchar3 * inputRGB = NULL;
static uchar4 * depthRender = NULL;
static uchar4 * trackRender = NULL;
static uchar4 * volumeRender = NULL;
static DepthReader *reader = NULL;
static DenseSLAMSystem *pipeline = NULL;

static Eigen::Vector3f init_pose;
static std::ostream* logstream = &std::cout;
static std::ofstream logfilestream;
/*
 int          compute_size_ratio = default_compute_size_ratio;
 std::string  input_file         = "";
 std::string  log_file           = "" ;
 std::string  dump_volume_file   = "" ;
 float3       init_poseFactors   = default_initial_pos_factor;
 int          integration_rate   = default_integration_rate;
 float3       volume_size        = default_volume_size;
 uint3        volume_resolution  = default_volume_resolution;
 */
DepthReader *createReader(Configuration *config, std::string filename = "");
int processAll(DepthReader *reader, bool processFrame, bool renderImages,
		Configuration *config, bool reset = false);

void qtLinkKinectQt(int argc, char *argv[], DenseSLAMSystem **_pipeline,
		DepthReader **_depthReader, Configuration *config, void *depthRender,
		void *trackRender, void *volumeModel, void *inputRGB);

void storeStats(int frame,
    std::chrono::time_point<std::chrono::steady_clock> *timings,
    float3 pos, bool tracked,
		bool integrated) {
	Stats.sample("frame", frame, PerfStats::FRAME);
	Stats.sample("acquisition",  std::chrono::duration<double>(timings[1] - timings[0]).count(), PerfStats::TIME);
	Stats.sample("preprocessing",std::chrono::duration<double>(timings[2] - timings[1]).count(), PerfStats::TIME);
	Stats.sample("tracking",     std::chrono::duration<double>(timings[3] - timings[2]).count(), PerfStats::TIME);
	Stats.sample("integration",  std::chrono::duration<double>(timings[4] - timings[3]).count(), PerfStats::TIME);
	Stats.sample("raycasting",   std::chrono::duration<double>(timings[5] - timings[4]).count(), PerfStats::TIME);
	Stats.sample("rendering",    std::chrono::duration<double>(timings[6] - timings[5]).count(), PerfStats::TIME);
	Stats.sample("computation",  std::chrono::duration<double>(timings[5] - timings[1]).count(), PerfStats::TIME);
	Stats.sample("total",        std::chrono::duration<double>(timings[6] - timings[0]).count(), PerfStats::TIME);
	Stats.sample("X", pos.x, PerfStats::DISTANCE);
	Stats.sample("Y", pos.y, PerfStats::DISTANCE);
	Stats.sample("Z", pos.z, PerfStats::DISTANCE);
	Stats.sample("tracked", tracked, PerfStats::INT);
	Stats.sample("integrated", integrated, PerfStats::INT);
}

/***
 * This program loop over a scene recording
 */

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

	Configuration config = parseArgs(argc, argv);
	powerMonitor = new PowerMonitor();

	// ========= READER INITIALIZATION  =========
	reader = createReader(&config);

	//  =========  BASIC PARAMETERS  (input size / computation size )  =========
	uint2 inputSize =
			(reader != NULL) ? reader->getinputSize() : make_uint2(640, 480);
	const uint2 computationSize = make_uint2(
			inputSize.x / config.compute_size_ratio,
			inputSize.y / config.compute_size_ratio);

	//  =========  BASIC BUFFERS  (input / output )  =========

	// Construction Scene reader and input buffer
	//we could allocate a more appropriate amount of memory (less) but this makes life hard if we switch up resolution later;
	inputDepth =
        (uint16_t*) malloc(sizeof(uint16_t) * inputSize.x*inputSize.y);
	inputRGB =
        (uchar3*) malloc(sizeof(uchar3) * inputSize.x*inputSize.y);
	depthRender =
        (uchar4*) malloc(sizeof(uchar4) * computationSize.x*computationSize.y);
	trackRender =
        (uchar4*) malloc(sizeof(uchar4) * computationSize.x*computationSize.y);
	volumeRender =
        (uchar4*) malloc(sizeof(uchar4) * computationSize.x*computationSize.y);

	init_pose = config.initial_pos_factor.cwiseProduct(config.volume_size);
	pipeline = new DenseSLAMSystem(
      Eigen::Vector2i(computationSize.x, computationSize.y),
      Eigen::Vector3i::Constant(static_cast<int>(config.volume_resolution.x())),
			Eigen::Vector3f::Constant(config.volume_size.x()),
      init_pose,
      config.pyramid, config);

	if (config.log_file != "") {
		logfilestream.open(config.log_file.c_str());
		logstream = &logfilestream;
	}

	logstream->setf(std::ios::fixed, std::ios::floatfield);

	//temporary fix to test rendering fullsize
	config.render_volume_fullsize = false;

	//The following runs the process loop for processing all the frames, if QT is specified use that, else use GLUT
	//We can opt to not run the gui which would be faster
	if (!config.no_gui) {
#ifdef __QT__
		qtLinkKinectQt(argc,argv, &pipeline, &reader, &config, depthRender, trackRender, volumeRender, inputRGB);
#else
		if ((reader == NULL) || (reader->cameraActive == false)) {
			std::cerr << "No valid input file specified\n";
			exit(1);
		}
		while (processAll(reader, true, true, &config, false) == 0) {
			drawthem(inputRGB, depthRender, trackRender, volumeRender,
					trackRender, inputSize, computationSize,
                    computationSize, computationSize);
		}
#endif
	} else {
		if ((reader == NULL) || (reader->cameraActive == false)) {
			std::cerr << "No valid input file specified\n";
			exit(1);
		}
		while (processAll(reader, true, true, &config, false) == 0) {
		}
		std::cout << __LINE__ << std::endl;
	}
	// ==========     DUMP VOLUME      =========

	if (config.dump_volume_file != "") {
    auto start = std::chrono::steady_clock::now();
		pipeline->dump_mesh(config.dump_volume_file.c_str());
    auto end = std::chrono::steady_clock::now();
	  Stats.sample("meshing",
        std::chrono::duration<double>(end - start).count(),
        PerfStats::TIME);
	}

	//if (config.log_file != "") {
	//	std::ofstream logStream(config.log_file.c_str());
	//	Stats.print_all_data(logStream);
	//	logStream.close();
	//}
  //
	if (powerMonitor && powerMonitor->isActive()) {
		std::ofstream powerStream("power.rpt");
		powerMonitor->powerStats.print_all_data(powerStream);
		powerStream.close();
	}
	std::cout << "{";
	//powerMonitor->powerStats.print_all_data(std::cout, false);
	//std::cout << ",";
	Stats.print_all_data(std::cout, false);
	std::cout << "}" << std::endl;

	//  =========  FREE BASIC BUFFERS  =========

	free(inputDepth);
	free(depthRender);
	free(trackRender);
	free(volumeRender);

}

int processAll(DepthReader *reader, bool processFrame, bool renderImages,
		Configuration *config, bool reset) {
	static int frameOffset = 0;
	static bool firstFrame = true;
	bool tracked = false, integrated = false;
	std::chrono::time_point<std::chrono::steady_clock> timings[7];
	float3 pos;
	int frame = 0;
	const uint2 inputSize =
			(reader != NULL) ? reader->getinputSize() : make_uint2(640, 480);
  Eigen::Vector4f camera =
			(reader != NULL) ? reader->getK() : Eigen::Vector4f::Constant(0.0f);
  camera /= config->compute_size_ratio;

	if (config->camera_overrided)
		camera = config->camera / config->compute_size_ratio;

	if (reset) {
		frameOffset = reader->getFrameNumber();
	}

	if (processFrame) {
		Stats.start();
	}
    Eigen::Matrix4f pose;
	Eigen::Matrix4f gt_pose;
	timings[0] = std::chrono::steady_clock::now();
	if (processFrame) {

		// Read frames and ground truth data if set
		bool read_ok;
		if (config->groundtruth_file == "") {
			read_ok = reader->readNextDepthFrame(inputRGB, inputDepth);
		} else {
			read_ok = reader->readNextData(inputRGB, inputDepth, gt_pose);
		}

		// Finish processing if the next frame could not be read
		if (!read_ok) {
			timings[0] = std::chrono::steady_clock::now();
			return true;
		}

		// Process read frames
		frame = reader->getFrameNumber() - frameOffset;
		if (powerMonitor != NULL && !firstFrame)
			powerMonitor->start();

		timings[1] = std::chrono::steady_clock::now();

		pipeline->preprocessing(inputDepth,
			Eigen::Vector2i(inputSize.x, inputSize.y),
			config->bilateralFilter);

		timings[2] = std::chrono::steady_clock::now();

		if (config->groundtruth_file == "") {
			// No ground truth used, call tracking.
			tracked = pipeline->tracking(camera, config->icp_threshold,
					config->tracking_rate, frame);
		} else {
			// Set the pose to the ground truth.
			pipeline->setPose(gt_pose);
			tracked = true;
		}

		Eigen::Vector3f tmp = pipeline->getPosition();
		pos = make_float3(tmp.x(), tmp.y(), tmp.z());
		pose = pipeline->getPose();

		timings[3] = std::chrono::steady_clock::now();

		// Integrate only if tracking was successful or it is one of the
		// first 4 frames.
		if (tracked || (frame <= 3)) {
			integrated = pipeline->integration(camera,
					config->integration_rate, config->mu, frame);
		} else {
			integrated = false;
		}

		timings[4] = std::chrono::steady_clock::now();

		pipeline->raycasting(camera, config->mu, frame);

		timings[5] = std::chrono::steady_clock::now();
	}
	if (renderImages) {
		pipeline->renderDepth((unsigned char*)depthRender, pipeline->getComputationResolution());
		pipeline->renderTrack((unsigned char*)trackRender, pipeline->getComputationResolution());
		pipeline->renderVolume((unsigned char*)volumeRender, pipeline->getComputationResolution(),
				(processFrame ? reader->getFrameNumber() - frameOffset : 0),
				config->rendering_rate, camera, 0.75 * config->mu);
		timings[6] = std::chrono::steady_clock::now();
	}

	if (powerMonitor != NULL && !firstFrame)
		powerMonitor->sample();

	float xt = pose(0, 3) - init_pose.x();
	float yt = pose(1, 3) - init_pose.y();
	float zt = pose(2, 3) - init_pose.z();
	storeStats(frame, timings, pos, tracked, integrated);
	if(config->log_file != "") {
		*logstream << reader->getFrameNumber() << "\t" << xt << "\t" << yt << "\t" << zt << "\t" << std::endl;
	}

	//if (config->no_gui && (config->log_file == ""))
	//	Stats.print();
	firstFrame = false;

	return false;
}


// Copyright Abel Sinkovics (abel@sinkovics.hu) 2013.
// 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 "min.hpp"

#include <mpllibs/metamonad/tmp_tag.hpp>
#include <mpllibs/metamonad/tmp_value.hpp>

#include <boost/mpl/int.hpp>
#include <boost/mpl/equal_to.hpp>

#include <iostream>

using mpllibs::metamonad::tmp_tag;
using mpllibs::metamonad::tmp_value;

namespace
{
  struct test_class_tag : tmp_tag<test_class_tag> {};
  struct test_class : tmp_value<test_class, test_class_tag> {};
}

int main()
{
  using mpllibs::metamonad::exception;

  using boost::mpl::int_;
  using boost::mpl::equal_to;

  std::cout
    << "min<11, 13> = " << min<int_<11>, int_<13> >::type::value
    << std::endl
    << "equal_to<exception, min<test_class, test_class>> = "
    <<
      (equal_to<
        exception<non_comparable>,
        min<test_class, test_class>::type
      >::type::value ? "yes" : "no")
    << std::endl;
}


#ifndef GROUPABLE_TIME_SERIES_SET_H
#define GROUPABLE_TIME_SERIES_SET_H

#include <vector>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>

#include "distance/Distance.hpp"
#include "group/GlobalGroupSpace.hpp"
#include "TimeSeriesSet.hpp"

#define GROUP_FILE_VERSION 1

namespace genex {

/**
 *  @brief a GroupableTimeSeriesSet object is a TimeSeriesSet with grouping capability
 */
class GroupableTimeSeriesSet : public TimeSeriesSet
{
public:

  /**
   *  @brief Destructor
   */
  virtual ~GroupableTimeSeriesSet();

  /**
   *  @brief groups the datset into similarity groups
   *
   *  @param distanceName the distance to use for comparing similarity
   *  @param threshold to use for determing the bound of similarity
   *  @param numThreads number of thread to perform grouping
   *  @param wholeSeriesOnly if set to true group the largest length only
   *
   *  @return the number of groups created
   */
  int groupAllLengths(const std::string& distanceName,
                      data_t threshold,
                      int numThreads,
                      bool wholeSeriesOnly);

  /**
   *  @brief deletes and clears the groups
   */
  void reset();

  /**
   *  @brief check if the dataset is grouped
   */
  bool isGrouped() const;

  /**
   *  @brief returns name of the distance used for grouping
   */
  int getTotalNumberOfGroups() const;
  string getDistanceName() const;
  data_t getThreshold() const;

  void saveGroupsOld(const std::string& path, bool groupSizeOnly) const;
  int loadGroupsOld(const std::string& path);

  /**
   * @brief Finds the best matching subsequence in the dataset
   *
   * @param other the timeseries to find the match for
   *
   * @return a struct containing the closest TimeSeries and the distance between them
   * @throws exception if dataset is not grouped
   */
  candidate_time_series_t getBestMatch(const TimeSeries& other) const;

  /**
   * @brief Finds k similar timeseries.
   *
   * @param data the timeseries to find the matches for
   * @param k the number of time series to look for.
   * @param h the number of time series to examine.
   *
   * @return a vector of struct containing the closest TimeSeries and the distance between them
   * @throws exception if dataset is not grouped
   */
  std::vector<candidate_time_series_t> getKBestMatches(const TimeSeries& data, int k, int h);

private:
  GlobalGroupSpace* groupsAllLengthSet = nullptr;

  /*************************
   *  Start serialization
   *************************/
  friend class boost::serialization::access;
  template<class A>
  void save(A & ar, unsigned) const
  {
    if (!this->isGrouped()) {
      throw GenexException("No group found");
    }

    ar << this->getItemCount()
       << this->getMaxLength();

    ar << *(this->groupsAllLengthSet);
  }

  template<class A>
  void load(A & ar, unsigned)
  {
    int grpItemCount, grpItemLength;
    ar >> grpItemCount >> grpItemLength;
    if (grpItemCount != this->getItemCount())
    {
      throw GenexException("Incompatible item count");
    }
    if (grpItemLength != this->getMaxLength())
    {
      throw GenexException("Incompatible item length");
    }
    reset();
    this->groupsAllLengthSet = new GlobalGroupSpace(*this);
    ar >> *(this->groupsAllLengthSet);
  }

  BOOST_SERIALIZATION_SPLIT_MEMBER()

  /*************************
   *  End serialization
   *************************/
};

} // namespace genex

#endif // GROUPABLE_TIME_SERIES_SET_H


//  Copyright John Maddock 2012.
//  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)

//
// This tests that cpp_dec_float_50 meets our
// conceptual requirements when used with Boost.Math.
//
#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#pragma warning(disable : 4800)
#pragma warning(disable : 4512)
#pragma warning(disable : 4127)
#pragma warning(disable : 4512)
#pragma warning(disable : 4503)    // decorated name length exceeded, name was truncated
#endif

#include <boost/container_hash/hash.hpp>
#include <libs/math/test/compile_test/poison.hpp>

#if !defined(TEST_MPF_50) && !defined(TEST_BACKEND) && !defined(TEST_MPZ) && !defined(TEST_CPP_DEC_FLOAT) && \
    !defined(TEST_MPFR_50) && !defined(TEST_MPFR_6) && !defined(TEST_MPFR_15) && !defined(TEST_MPFR_17) &&   \
    !defined(TEST_MPFR_30) && !defined(TEST_CPP_DEC_FLOAT_NO_ET) && !defined(TEST_LOGGED_ADAPTER) &&         \
    !defined(TEST_CPP_BIN_FLOAT)
#define TEST_MPF_50
#define TEST_BACKEND
#define TEST_MPZ
#define TEST_MPFR_50
#define TEST_MPFR_6
#define TEST_MPFR_15
#define TEST_MPFR_17
#define TEST_MPFR_30
#define TEST_CPP_DEC_FLOAT
#define TEST_CPP_DEC_FLOAT_NO_ET
#define TEST_LOGGED_ADAPTER
#define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50) || defined(TEST_MPZ)
#include <nil/crypto3/multiprecision/gmp.hpp>
#endif
#ifdef TEST_BACKEND
#include <nil/crypto3/multiprecision/concepts/mp_number_archetypes.hpp>
#endif
#if defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_DEC_FLOAT_NO_ET) || defined(TEST_LOGGED_ADAPTER)
#include <nil/crypto3/multiprecision/cpp_dec_float.hpp>
#endif
#if defined(TEST_CPP_BIN_FLOAT)
#include <nil/crypto3/multiprecision/cpp_bin_float.hpp>
#endif
#if defined(TEST_MPFR_50) || defined(TEST_MPFR_6) || defined(TEST_MPFR_15) || defined(TEST_MPFR_17) || \
    defined(TEST_MPFR_30)
#include <nil/crypto3/multiprecision/mpfr.hpp>
#endif
#ifdef TEST_LOGGED_ADAPTER
#include <nil/crypto3/multiprecision/logged_adaptor.hpp>
#endif

#include <boost/math/special_functions.hpp>

template<class T>
void test_extra(T) {
    T v1, v2, v3;
    int i;
    (boost::math::fpclassify)(v1);
    (boost::math::isfinite)(v1);
    (boost::math::isnormal)(v1);
    (boost::math::isnan)(v1);
    (boost::math::isinf)(v1);
    (boost::math::signbit)(v1);
    (boost::math::copysign)(v1, v2);
    (boost::math::changesign)(v1);
    (boost::math::sign)(v1);
    boost::math::log1p(v1);
    boost::math::expm1(v1);
    boost::math::cbrt(v1);
    boost::math::sqrt1pm1(v1);
    boost::math::powm1(v1, v2);
    boost::math::hypot(v1, v2);
    boost::math::sinc_pi(v1);
    boost::math::sinhc_pi(v1);
    boost::math::asinh(v1);
    boost::math::acosh(v1);
    boost::math::atanh(v1);
    boost::math::sin_pi(v1);
    boost::math::cos_pi(v1);
    boost::math::trunc(v1);
    boost::math::itrunc(v1);
    boost::math::ltrunc(v1);
    boost::math::round(v1);
    boost::math::iround(v1);
    boost::math::lround(v1);
    boost::math::modf(v1, &v1);
    boost::math::modf(v1, &i);
    long l;
    boost::math::modf(v1, &l);
#ifdef BOOST_HAS_LONG_LONG
    boost::math::lltrunc(v1);
    boost::math::llround(v1);
    boost::long_long_type ll;
    boost::math::modf(v1, &ll);
#endif
    boost::math::pow<2>(v1);
    boost::math::nextafter(v1, v1);
    boost::math::float_next(v1);
    boost::math::float_prior(v1);
    boost::math::float_distance(v1, v1);
    // Misc functions that don't fit elsewhere:
    boost::math::expint(v1);
    boost::math::expint(i);
    boost::math::expint(i, v2);
    boost::math::expint(i, i);
    boost::math::zeta(v1);
    boost::math::zeta(i);
    boost::math::owens_t(v1, v2);
}

void foo() {
#ifdef TEST_BACKEND
    test_extra(nil::crypto3::multiprecision::concepts::mp_number_float_architype());
#endif
#ifdef TEST_MPF_50
    test_extra(nil::crypto3::multiprecision::mpf_float_50());
#endif
#ifdef TEST_MPFR_50
    test_extra(nil::crypto3::multiprecision::mpfr_float_50());
#endif
#ifdef TEST_MPFR_6
    test_extra(nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::mpfr_float_backend<6>>());
#endif
#ifdef TEST_MPFR_15
    test_extra(nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::mpfr_float_backend<15>>());
#endif
#ifdef TEST_MPFR_17
    test_extra(nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::mpfr_float_backend<17>>());
#endif
#ifdef TEST_MPFR_30
    test_extra(nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::mpfr_float_backend<30>>());
#endif
#ifdef TEST_CPP_DEC_FLOAT
    test_extra(nil::crypto3::multiprecision::cpp_dec_float_50());
#endif
#ifdef TEST_CPP_BIN_FLOAT
    test_extra(nil::crypto3::multiprecision::cpp_bin_float_50());
#endif
#ifdef TEST_CPP_DEC_FLOAT_NO_ET
    test_extra(nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<100>,
                                                    nil::crypto3::multiprecision::et_off>());
#endif
#ifdef TEST_LOGGED_ADAPTER
    typedef nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::logged_adaptor<nil::crypto3::multiprecision::cpp_dec_float<50>>>
        num_t;
    test_extra(num_t());
#endif
}

int main() {
    foo();
}


/*!
  \file gpp_test_utils_test.cpp
  \rst
  This file contains functions for testing the functions and classes in gpp_test_utils.hpp. These
  tests are generally pretty simple since these functions implicitly work; e.g., if
  CheckDoubleWithinRelative() were wrong, other tests wouldn't make any sense.

  TODO(GH-122): implement the rest of the unit tests for gpp_test_utils
\endrst*/

#include "gpp_test_utils_test.hpp"

#include <algorithm>
#include <limits>
#include <vector>

#include <boost/random/uniform_real.hpp>  // NOLINT(build/include_order)

#include "gpp_common.hpp"
#include "gpp_covariance.hpp"
#include "gpp_geometry.hpp"
#include "gpp_logging.hpp"
#include "gpp_math.hpp"
#include "gpp_random.hpp"
#include "gpp_test_utils.hpp"

namespace optimal_learning {

namespace {

/*!\rst
  Assumes CheckDoubleWithin() is already verified.
\endrst*/
OL_WARN_UNUSED_RESULT int FillRandomCovarianceHyperparametersTest() {
  int total_errors = 0;
  const int kDim = 5;

  UniformRandomGenerator uniform_generator(314);
  UniformRandomGenerator uniform_generator_original(uniform_generator);

  boost::uniform_real<double> uniform_double(0.32, 4.7);

  SquareExponential covariance(kDim, 1.0, 1.0);
  int num_hyperparameters = covariance.GetNumberOfHyperparameters();

  std::vector<double> hyperparameters(num_hyperparameters);
  std::vector<double> hyperparameters_covariance(num_hyperparameters);

  FillRandomCovarianceHyperparameters(uniform_double, &uniform_generator, &hyperparameters, &covariance);

  // Verify that hyperparameters output and hyperparameters of covariance are the same
  covariance.GetHyperparameters(hyperparameters_covariance.data());
  if (!CheckIntEquals(hyperparameters.size(), hyperparameters_covariance.size())) {
    ++total_errors;
  }
  if (!std::equal(hyperparameters.begin(), hyperparameters.end(), hyperparameters_covariance.begin())) {
    ++total_errors;
  }

  // Verify that hyperparameters fall within the [min, max] range of the uniform_real interval
  ClosedInterval interval = {uniform_double.a(), uniform_double.b()};
  for (const auto hyperparameter : hyperparameters) {
    if (!interval.IsInside(hyperparameter)) {
      ++total_errors;
    }
  }

  // Verify that uniform_generator changed
  if (uniform_generator == uniform_generator_original) {
    ++total_errors;
  }

  // Verify that the uniform_generator was called hyperparameters.size() times
  uniform_generator_original.engine.discard(num_hyperparameters);
  if (uniform_generator != uniform_generator_original) {
    ++total_errors;
  }

  return total_errors;
}

/*!\rst
  Assumes CheckDoubleWithin() is already verified.
\endrst*/
OL_WARN_UNUSED_RESULT int FillRandomDomainBoundsTest() {
  int total_errors = 0;
  const int kDim = 5;

  UniformRandomGenerator uniform_generator(314);
  UniformRandomGenerator uniform_generator_original(uniform_generator);
  boost::uniform_real<double> uniform_double_lower_bound(-2.0, 0.5);
  boost::uniform_real<double> uniform_double_upper_bound(2.0, 3.5);

  std::vector<ClosedInterval> domain_bounds(kDim);

  FillRandomDomainBounds(uniform_double_lower_bound, uniform_double_upper_bound, &uniform_generator, &domain_bounds);

  // Verify that uniform_generator changed
  if (uniform_generator == uniform_generator_original) {
    ++total_errors;
  }

  // Verify that the uniform_generator was called 2*kDim times
  uniform_generator_original.engine.discard(2*kDim);
  if (uniform_generator != uniform_generator_original) {
    ++total_errors;
  }

  // Verify that the ClosedIntervals' min, max values fall within the specified
  // bounds of the uniform_real input
  ClosedInterval lower_interval = {uniform_double_lower_bound.a(), uniform_double_lower_bound.b()};
  ClosedInterval upper_interval = {uniform_double_upper_bound.a(), uniform_double_upper_bound.b()};
  for (const auto domain_interval : domain_bounds) {
    if (!lower_interval.IsInside(domain_interval.min)) {
      ++total_errors;
    }
    if (!upper_interval.IsInside(domain_interval.max)) {
      ++total_errors;
    }
  }

  return total_errors;
}

/*!\rst
  Assumes FillRandomCovarianceHyperparameters(), FillRandomDomainBounds(), and CheckDoubleWithin()
  are already verified.
\endrst*/
OL_WARN_UNUSED_RESULT int FillRandomGaussianProcess() {
  int total_errors = 0;
  const int kDim = 5;
  const int kNumSampled = 2;
  const int kNumToDraw = 3;
  const int kNumPoints = kNumSampled + kNumToDraw;

  UniformRandomGenerator uniform_generator(314);
  SquareExponential covariance(kDim, 0.4, 0.9);

  std::vector<double> points_sampled(kNumPoints*kDim, std::numeric_limits<double>::quiet_NaN());
  std::vector<double> points_sampled_value(kNumPoints, std::numeric_limits<double>::quiet_NaN());
  std::vector<double> noise_variance(kNumPoints, std::numeric_limits<double>::quiet_NaN());

  boost::uniform_real<double> uniform_double_lower_bound(-2.0, 0.5);
  boost::uniform_real<double> uniform_double_upper_bound(2.0, 3.5);
  std::vector<ClosedInterval> domain_bounds(kDim);
  FillRandomDomainBounds(uniform_double_lower_bound, uniform_double_upper_bound, &uniform_generator, &domain_bounds);
  TensorProductDomain domain(domain_bounds.data(), kDim);
  domain.GenerateUniformPointsInDomain(kNumSampled, &uniform_generator, points_sampled.data());

  boost::uniform_real<double> uniform_double_value(-0.7, 0.5);
  std::generate(points_sampled_value.begin(), points_sampled_value.begin() + kNumSampled, [&]() {
    return uniform_double_value(uniform_generator.engine);
  });

  boost::uniform_real<double> uniform_double_noise(0.01, 0.1);
  std::generate(noise_variance.begin(), noise_variance.begin() + kNumSampled, [&]() {
    return uniform_double_noise(uniform_generator.engine);
  });

  GaussianProcess gaussian_process(covariance, points_sampled.data(), points_sampled_value.data(), noise_variance.data(), kDim, 0);

  // add in kNumSampled points
  FillRandomGaussianProcess(points_sampled.data(), noise_variance.data(), kDim, kNumSampled, points_sampled_value.data(), &gaussian_process);

  // Verify that the GP's num_sampled value is correct
  if (!CheckIntEquals(kNumSampled, gaussian_process.num_sampled())) {
    ++total_errors;
  }

  // Verify that the points_sampled, points_sampled_value, and noise_variance match
  // between the direct output and the GaussianProcess
  if (!std::equal(gaussian_process.points_sampled().begin(), gaussian_process.points_sampled().end(), points_sampled.begin())) {
    ++total_errors;
  }

  if (!std::equal(gaussian_process.points_sampled_value().begin(), gaussian_process.points_sampled_value().end(), points_sampled_value.begin())) {
    ++total_errors;
  }

  if (!std::equal(gaussian_process.noise_variance().begin(), gaussian_process.noise_variance().end(), noise_variance.begin())) {
    ++total_errors;
  }

  // now add in kNumtoDraw points and re-verify
  domain.GenerateUniformPointsInDomain(kNumToDraw, &uniform_generator, points_sampled.data() + kDim*kNumSampled);

  std::generate(points_sampled_value.begin() + kNumSampled, points_sampled_value.begin() + kNumPoints, [&]() {
    return uniform_double_value(uniform_generator.engine);
  });

  std::generate(noise_variance.begin() + kNumSampled, noise_variance.begin() + kNumPoints, [&]() {
    return uniform_double_noise(uniform_generator.engine);
  });

  // add in kNumToDraw points
  FillRandomGaussianProcess(points_sampled.data() + kDim*kNumSampled, noise_variance.data() + kNumSampled, kDim, kNumToDraw, points_sampled_value.data() + kNumSampled, &gaussian_process);

  // Verify that the GP's num_sampled value is correct
  if (!CheckIntEquals(kNumPoints, gaussian_process.num_sampled())) {
    ++total_errors;
  }

  // Verify that the points_sampled, points_sampled_value, and noise_variance match
  // between the direct output and the GaussianProcess
  if (!std::equal(points_sampled.begin(), points_sampled.end(), gaussian_process.points_sampled().begin())) {
    ++total_errors;
  }

  if (!std::equal(points_sampled_value.begin(), points_sampled_value.end(), gaussian_process.points_sampled_value().begin())) {
    ++total_errors;
  }

  if (!std::equal(noise_variance.begin(), noise_variance.end(), gaussian_process.noise_variance().begin())) {
    ++total_errors;
  }

  return total_errors;
}

}  // end unnamed namespace

int TestUtilsTests() {
  int total_errors = 0;
  int current_errors = 0;

  current_errors = FillRandomCovarianceHyperparametersTest();
  if (current_errors != 0) {
    OL_PARTIAL_FAILURE_PRINTF("FillRandomCovarianceHyperparameters failed with %d errors\n", current_errors);
  } else {
    OL_PARTIAL_SUCCESS_PRINTF("FillRandomCovarianceHyperparameters passed\n");
  }
  total_errors += current_errors;

  current_errors = FillRandomDomainBoundsTest();
  if (current_errors != 0) {
    OL_PARTIAL_FAILURE_PRINTF("FillRandomDomainBounds failed with %d errors\n", current_errors);
  } else {
    OL_PARTIAL_SUCCESS_PRINTF("FillRandomDomainBounds passed\n");
  }
  total_errors += current_errors;

  current_errors = FillRandomGaussianProcess();
  if (current_errors != 0) {
    OL_PARTIAL_FAILURE_PRINTF("FillRandomGaussianProcess failed with %d errors\n", current_errors);
  } else {
    OL_PARTIAL_SUCCESS_PRINTF("FillRandomGaussianProcess passed\n");
  }
  total_errors += current_errors;

  return total_errors;
}

}  // end namespace optimal_learning


#include <boost/python.hpp>
#include "easykf.h"

using namespace boost::python;

namespace easykf {

  namespace bindings {

  }
}

BOOST_PYTHON_MODULE(libpyeasykf)
{
  ////////////////
  // ekf_types.h

  class_<ekf::EvolutionAnneal>("ekf_EvolutionAnneal", init<double, double, double>())
    .def("updateEvolutionNoise", &ekf::EvolutionAnneal::updateEvolutionNoise, "")
    ;

  // Bindings for ekf.h
  // struct ekf::ekf_param, ekf::ekf_state
  class_<ekf::ekf_param>("ekf_param", init<>())
    .def_readwrite("evolution_noise", &ekf::ekf_param::evolution_noise)
    .def_readwrite("observation_noise", &ekf::ekf_param::observation_noise)
    .def_readwrite("n", &ekf::ekf_param::n)
    .def_readwrite("no", &ekf::ekf_param::no)
    .def_readwrite("observation_gradient_is_diagonal", &ekf::ekf_param::observation_gradient_is_diagonal)
    ;

  class_<ekf::ekf_state>("ekf_state", init<>())
    .def_readwrite("xk", &ekf::ekf_state::xk)
    .def_readwrite("xkm", &ekf::ekf_state::xkm)
    .def_readwrite("Pxk", &ekf::ekf_state::Pxk)

    ;

  // def("ekf_param", ekf::ekf_param);
  // def("ekf_state", ekf::ekf_state);

  def("ekf_init", ekf::ekf_init);
  def("ekf_free", ekf::ekf_free);
  //def("ekf_iterate", ekf::ekf_iterate);

  def("ukf_math_min", ukf::math::min);
  def("ukf_math_choleskyUpdate", ukf::math::choleskyUpdate);

}


//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_FormFactor.hpp
//! \author Alex Robinson
//! \brief  The form factor declaration
//!
//---------------------------------------------------------------------------//

#ifndef MONTE_CARLO_FORM_FACTOR_HPP
#define MONTE_CARLO_FORM_FACTOR_HPP

// Boost Includes
#include <boost/units/quantity.hpp>

// FRENSIE Includes
#include "Utility_InverseCentimeterUnit.hpp"

namespace MonteCarlo{

//! The form factor class
class FormFactor
{

public:

  //! The form factor independent quantity type
  typedef boost::units::quantity<Utility::Units::InverseCentimeter> ArgumentQuantity;

  //! Default constructor
  FormFactor()
  { /* ... */ }

  //! Destructor
  virtual ~FormFactor()
  { /* ... */ }

  //! Evaluate the form factor
  virtual double evaluate( const ArgumentQuantity argument ) const = 0;

  //! Return the max form factor value
  virtual double getMaxValue() const = 0;

  //! Return the min form factor value
  virtual double getMinValue() const = 0;

  //! Return the lower bound of the argument
  virtual ArgumentQuantity getLowerBoundOfArgument() const = 0;

  //! Return the upper bound of the argument
  virtual ArgumentQuantity getUpperBoundOfArgument() const = 0;
};

} // end MonteCarlo namespace

#endif // end MONTE_CARLO_FORM_FACTOR_HPP

//---------------------------------------------------------------------------//
// end MonteCarlo_FormFactor.hpp
//---------------------------------------------------------------------------//


//---------------------------------------------------------------------------//

// Copyright (c) 2019-2020 Mikhail Komarov <nemo@nil.foundation>
//
// MIT License
//
// 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.
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_BLOCK_MODE_CIPHER_BLOCK_CHAINING_HPP
#define CRYPTO3_BLOCK_MODE_CIPHER_BLOCK_CHAINING_HPP

#include <boost/integer.hpp>

#include <nil/crypto3/modes/mode.hpp>
#include <nil/crypto3/modes/cts.hpp>
#include <nil/crypto3/modes/padding.hpp>

#include <nil/crypto3/codec/algorithm/encode.hpp>

//#include <nil/crypto3/codec/logic.hpp>

namespace nil {
    namespace crypto3 {
        namespace block {
            namespace modes {
                namespace detail {
                    template<typename Cipher, typename Padding, template<typename> class Allocator = std::allocator>
                    struct cbc_policy {
                        typedef std::size_t size_type;

                        typedef Cipher cipher_type;
                        typedef Padding padding_type;

                        constexpr static const size_type block_bits = cipher_type::block_bits;
                        constexpr static const size_type block_words = cipher_type::block_words;
                        typedef typename cipher_type::block_type block_type;

                        typedef std::vector<boost::uint_t<CHAR_BIT>, Allocator<boost::uint_t<CHAR_BIT>>> iv_type;
                    };

                    template<typename Cipher, typename Padding, typename CiphertextStealingMode>
                    struct cbc_encryption_policy : public cbc_policy<Cipher, Padding> {};

                    template<typename Cipher, typename Padding>
                    struct cbc_encryption_policy<Cipher, Padding, cts<0, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const size_type block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const size_type block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, iv,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, previous,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const block_type &previous = block_type(),
                                                             const iv_type &iv = iv_type()) {
                            block_type result = {0};
                            std::array<uint8_t, block_bits / CHAR_BIT> byte_array = {0};

                            pack(plaintext, byte_array);

                            size_type rem = std::count(byte_array.begin(), byte_array.end(), block_type::value_type()) %
                                            (block_bits / CHAR_BIT);
                            if (rem || padding_type::always_pad) {
                                block_type padbuffer = padding_type::pad(plaintext, rem), block;
                                //                            codec::encode<codec::encoder::logic_xor>(!iv.empty() ? iv
                                //                            : previous, padbuffer, block .begin());
                                result = cipher.encrypt(block);
                            }

                            return result;
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_encryption_policy<Cipher, Padding, cts<1, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const size_type block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const size_type block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, iv,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, previous,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const block_type &previous = block_type(),
                                                             const iv_type &iv = iv_type()) {
                            block_type result = {0};
                            std::array<uint8_t, block_bits / CHAR_BIT> byte_array = {0};

                            pack(plaintext, byte_array);

                            size_type rem = std::count(byte_array.begin(), byte_array.end(), block_type::value_type()) %
                                            (block_bits / CHAR_BIT);
                            if (rem || padding_type::always_pad) {
                                block_type padbuffer = padding_type::pad(plaintext, rem), block;
                                //                            codec::encode<codec::encoder::logic_xor>(!iv.empty() ? iv
                                //                            : previous, padbuffer, block .begin());
                                result = cipher.encrypt(block);
                            }

                            return result;
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_encryption_policy<Cipher, Padding, cts<2, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const size_type block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const size_type block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, iv,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, previous,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const block_type &previous = block_type(),
                                                             const iv_type &iv = iv_type()) {
                            block_type result = {0};
                            std::array<uint8_t, block_bits / CHAR_BIT> byte_array = {0};

                            pack(plaintext, byte_array);

                            size_type rem = std::count(byte_array.begin(), byte_array.end(), block_type::value_type()) %
                                            (block_bits / CHAR_BIT);
                            if (rem || padding_type::always_pad) {
                                block_type padbuffer = padding_type::pad(plaintext, rem), block;
                                //                            codec::encode<codec::encoder::logic_xor>(!iv.empty() ? iv
                                //                            : previous, padbuffer, block .begin());
                                result = cipher.encrypt(block);
                            }

                            return result;
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_encryption_policy<Cipher, Padding, cts<3, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const size_type block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const size_type block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, iv,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type block = {0};

                            //                        codec::encode<codec::encoder::logic_xor>(plaintext, previous,
                            //                        block.begin());

                            return cipher.encrypt(block);
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const block_type &previous = block_type(),
                                                             const iv_type &iv = iv_type()) {
                            BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
                            uint8_t *buf = buffer.data() + offset;
                            const size_t sz = buffer.size() - offset;

                            const size_t BS = block_size();

                            if (sz < BS + 1) {
                                throw encoding_error(name() + ": insufficient data to encipher");
                            }

                            if (sz % BS == 0) {
                                update(buffer, offset);

                                // swap last two blocks
                                for (size_t i = 0; i != BS; ++i) {
                                    std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
                                }
                            } else {
                                const size_t full_blocks = ((sz / BS) - 1) * BS;
                                const size_t final_bytes = sz - full_blocks;
                                BOOST_ASSERT_MSG(final_bytes > BS && final_bytes < 2 * BS,
                                                 "Left over size in expected range");

                                secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
                                buffer.resize(full_blocks + offset);
                                update(buffer, offset);

                                xor_buf(last.data(), state_ptr(), BS);
                                cipher().encrypt(last.data());

                                for (size_t i = 0; i != final_bytes - BS; ++i) {
                                    last[i] ^= last[i + BS];
                                    last[i + BS] ^= last[i];
                                }

                                cipher().encrypt(last.data());

                                buffer += last;
                            }
                        }
                    };

                    template<typename Cipher, typename Padding, typename CiphertextStealingMode>
                    struct cbc_decryption_policy : public cbc_policy<Cipher, Padding> {};

                    template<typename Cipher, typename Padding>
                    struct cbc_decryption_policy<Cipher, Padding, cts<0, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const std::size_t block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const std::size_t block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(block, iv);

                            return block;
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            const size_t BS = block_size();

                            BOOST_ASSERT_MSG(sz % BS == 0, "Input is full blocks");
                            size_t blocks = sz / BS;

                            while (blocks) {
                                const size_t to_proc = std::min(BS * blocks, m_tempbuf.size());

                                cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS);

                                xor_buf(m_tempbuf.data(), state_ptr(), BS);
                                xor_buf(&m_tempbuf[BS], buf, to_proc - BS);
                                copy_mem(state_ptr(), buf + (to_proc - BS), BS);

                                copy_mem(buf, m_tempbuf.data(), to_proc);

                                buf += to_proc;
                                blocks -= to_proc / BS;
                            }

                            return sz;
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const iv_type &iv = iv_type()) {
                            BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
                            const size_t sz = buffer.size() - offset;

                            const size_t BS = block_size();

                            if (sz == 0 || sz % BS) {
                                throw decoding_error(name() + ": Ciphertext not a multiple of block size");
                            }

                            update(buffer, offset);

                            const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size() - BS], BS);
                            buffer.resize(buffer.size() - pad_bytes); // remove padding
                            if (pad_bytes == 0 && padding().name() != "NoPadding") {
                                throw decoding_error(name());
                            }
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_decryption_policy<Cipher, Padding, cts<1, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const std::size_t block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const std::size_t block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(block, iv);

                            return block;
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type result = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(result, previous);

                            return result;
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const iv_type &iv = iv_type()) {
                            block_type result = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(result, iv);

                            return result;
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_decryption_policy<Cipher, Padding, cts<2, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const std::size_t block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const std::size_t block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(block, iv);

                            return block;
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type result = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(result, previous);

                            return result;
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const iv_type &iv = iv_type()) {
                            block_type result = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(result, iv);

                            return result;
                        }
                    };

                    template<typename Cipher, typename Padding>
                    struct cbc_decryption_policy<Cipher, Padding, cts<3, Cipher, Padding>>
                        : public cbc_policy<Cipher, Padding> {
                        typedef typename cbc_policy<Cipher, Padding>::size_type size_type;

                        typedef typename cbc_policy<Cipher, Padding>::cipher_type cipher_type;
                        typedef typename cbc_policy<Cipher, Padding>::padding_type padding_type;

                        constexpr static const std::size_t block_bits = cbc_policy<Cipher, Padding>::block_bits;
                        constexpr static const std::size_t block_words = cbc_policy<Cipher, Padding>::block_words;
                        typedef typename cbc_policy<Cipher, Padding>::block_type block_type;

                        typedef typename cbc_policy<Cipher, Padding>::iv_type iv_type;

                        inline static block_type begin_message(const cipher_type &cipher, const block_type &plaintext,
                                                               const iv_type &iv = iv_type()) {
                            block_type block = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(block, iv);

                            return block;
                        }

                        inline static block_type process_block(const cipher_type &cipher, const block_type &plaintext,
                                                               const block_type &previous = block_type()) {
                            block_type result = cipher.decrypt(plaintext);

                            //                        codec::encode<codec::encoder::logic_xor>(result, previous);

                            return result;
                        }

                        inline static block_type end_message(const cipher_type &cipher, const block_type &plaintext,
                                                             const iv_type &iv = iv_type()) {
                            BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
                            const size_t sz = buffer.size() - offset;
                            uint8_t *buf = buffer.data() + offset;

                            const size_t BS = block_size();

                            if (sz < BS + 1) {
                                throw encoding_error(name() + ": insufficient data to isomorphic_decryption_mode");
                            }

                            if (sz % BS == 0) {
                                // swap last two blocks

                                for (size_t i = 0; i != BS; ++i) {
                                    std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
                                }

                                update(buffer, offset);
                            } else {
                                const size_t full_blocks = ((sz / BS) - 1) * BS;
                                const size_t final_bytes = sz - full_blocks;
                                BOOST_ASSERT_MSG(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");

                                secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
                                buffer.resize(full_blocks + offset);
                                update(buffer, offset);

                                cipher().decrypt(last.data());

                                xor_buf(last.data(), &last[BS], final_bytes - BS);

                                for (size_t i = 0; i != final_bytes - BS; ++i) {
                                    std::swap(last[i], last[i + BS]);
                                }

                                cipher().decrypt(last.data());
                                xor_buf(last.data(), state_ptr(), BS);

                                buffer += last;
                            }
                        }
                    };

                    template<typename Policy>
                    class cipher_block_chaining {
                        typedef Policy policy_type;

                    public:
                        typedef typename policy_type::cipher_type cipher_type;
                        typedef typename policy_type::padding_type padding_type;

                        typedef typename policy_type::size_type size_type;

                        typedef typename cipher_type::key_type key_type;
                        typedef typename policy_type::iv_type iv_type;

                        constexpr static const size_type block_bits = policy_type::block_bits;
                        constexpr static const size_type block_words = policy_type::block_words;
                        typedef typename cipher_type::block_type block_type;

                        cipher_block_chaining(const cipher_type &cipher) : cipher(cipher) {
                        }

                        block_type begin_message(const block_type &plaintext, const iv_type &iv = iv_type()) {
                            previous = policy_type::begin_message(cipher, plaintext, iv);
                            return previous;
                        }

                        block_type process_block(const block_type &plaintext) {
                            previous = policy_type::process_block(cipher, plaintext, previous);
                            return previous;
                        }

                        block_type end_message(const block_type &plaintext, const iv_type &iv = iv_type()) {
                            return policy_type::end_message(cipher, plaintext, iv);
                        }

                        inline static size_type required_output_size(size_type inputlen) {
                            return padding_type::required_output_size(inputlen);
                        }

                    protected:
                        block_type previous;
                        cipher_type cipher;
                    };
                }    // namespace detail

                /*!
                 * @brief Cipher Block Chaining Mode (CBC). Xors previous cipher
                 * text with current plaintext before encryption
                 * @tparam Cipher
                 * @tparam Padding
                 *
                 * @ingroup block_modes
                 */
                template<typename Cipher, template<typename> class Padding,
                         template<typename, template<typename> class> class CiphertextStealingMode = cts0>
                struct cipher_block_chaining {
                    typedef Cipher cipher_type;
                    typedef Padding<Cipher> padding_type;
                    typedef CiphertextStealingMode<Cipher, Padding> ciphertext_stealing_type;

                    typedef detail::cbc_encryption_policy<cipher_type, padding_type, ciphertext_stealing_type>
                        encryption_policy;
                    typedef detail::cbc_decryption_policy<cipher_type, padding_type, ciphertext_stealing_type>
                        decryption_policy;

                    template<template<typename, typename> class Policy>
                    struct bind {
                        typedef detail::cipher_block_chaining<Policy<cipher_type, padding_type>> type;
                    };
                };

                /*!
                 * @brief
                 * @tparam Cipher
                 * @tparam Padding
                 * @tparam CiphertextStealingMode
                 *
                 * @ingroup block_modes
                 */
                template<typename Cipher, template<typename> class Padding,
                         template<typename, template<typename> class> class CiphertextStealingMode>
                using cbc = cipher_block_chaining<Cipher, Padding, CiphertextStealingMode>;
            }    // namespace modes
        }        // namespace block
    }    // namespace crypto3
}    // namespace nil

#endif


/*
LICENSE: see isogeometric_application/LICENSE.txt
*/

//
//   Project Name:        Kratos
//   Last modified by:    $Author: hbui $
//   Date:                $Date: 2013-08-18 $
//   Revision:            $Revision: 1.1 $
//
//

// System includes

#if defined(KRATOS_PYTHON)
// External includes
#include <boost/python.hpp>

#include "custom_python/add_utilities_to_python.h"
#include "custom_python/add_control_point_to_python.h"
#include "custom_python/add_control_grids_to_python.h"
#include "custom_python/add_transformation_to_python.h"
#include "custom_python/add_nurbs_to_python.h"
#include "custom_python/add_pbbsplines_to_python.h"
#include "custom_python/add_hbsplines_to_python.h"
#include "custom_python/add_tsplines_to_python.h"
#include "custom_python/add_fespace_to_python.hpp"
#include "custom_python/add_grid_functions_to_python.hpp"
#include "custom_python/add_patches_to_python.h"
#include "custom_python/add_mesh_and_model_part_to_python.h"
#include "custom_python/add_processes_to_python.h"
#include "custom_python/add_io_to_python.h"
#include "custom_python/add_strategies_to_python.h"

////utilities

// Project includes
#include "includes/define.h"
#include "isogeometric_application.h"

namespace Kratos
{

namespace Python
{

BOOST_PYTHON_MODULE(KratosIsogeometricApplication)
{

    using namespace boost::python;

    class_<KratosIsogeometricApplication,
           KratosIsogeometricApplication::Pointer,
           bases<KratosApplication>, boost::noncopyable > ("KratosIsogeometricApplication")
           ;

    IsogeometricApplication_AddBackendUtilitiesToPython();
    IsogeometricApplication_AddFrontendUtilitiesToPython();
    IsogeometricApplication_AddControlPointToPython();
    IsogeometricApplication_AddControlGridsToPython();
    IsogeometricApplication_AddTransformationToPython();
    IsogeometricApplication_AddFESpacesToPython<1>();
    IsogeometricApplication_AddFESpacesToPython<2>();
    IsogeometricApplication_AddFESpacesToPython<3>();
    IsogeometricApplication_AddGridFunctionsToPython<1>();
    IsogeometricApplication_AddGridFunctionsToPython<2>();
    IsogeometricApplication_AddGridFunctionsToPython<3>();
    IsogeometricApplication_AddPatchesToPython();
    IsogeometricApplication_AddNURBSToPython();
    IsogeometricApplication_AddPBBSplinesToPython();
    IsogeometricApplication_AddHBSplinesToPython();
    IsogeometricApplication_AddTSplinesToPython();
    IsogeometricApplication_AddMeshAndModelPartToPython();
    IsogeometricApplication_AddProcessesToPython();
    IsogeometricApplication_AddIOToPython();
    IsogeometricApplication_AddStrategiesToPython();

    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NURBS_WEIGHT )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NURBS_WEIGHTS )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NUM_DIVISION_1 )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NUM_DIVISION_2 )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NUM_DIVISION_3 )
    KRATOS_REGISTER_IN_PYTHON_3D_VARIABLE_WITH_COMPONENTS( LOCAL_COORDINATES )
    KRATOS_REGISTER_IN_PYTHON_3D_VARIABLE_WITH_COMPONENTS( CONTROL_POINT_COORDINATES )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( NUM_IGA_INTEGRATION_METHOD )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( CONTROL_POINT )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_LEFT )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_RIGHT )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_TOP )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_BOTTOM )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_FRONT )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( KNOT_BACK )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( PATCH_INDEX )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( HIERARCHICAL_LEVEL )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( BASIS_FUNCTION_INDEX )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( EQUATION_INDEX )
    KRATOS_REGISTER_IN_PYTHON_VARIABLE( CELL_INDEX )

}

} // namespace Python.

} // namespace Kratos.

#endif // KRATOS_PYTHON defined


#include <boost/move/algo/adaptive_sort.hpp>


#ifndef HITTABLE_HPP
#define	HITTABLE_HPP
#include <armadillo>

using namespace arma;
using namespace std;

class Hittable{

public:
    virtual vec getMin()=0;
    virtual vec getMax()=0;
    virtual vec getCentro()=0;

};

#endif	/* HITTABLE_HPP */