/*******************************************************/
/* oPoSSuM solver: network.hpp                         */
/* Concrete classes for the tree network and PSL prob. */
/* (c) Arnaud Malapert I3S (UNS-CNRS) 2012             */
/*******************************************************/

#ifndef NETWORK_HPP_
#define NETWORK_HPP_

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <queue>
#include <assert.h>
#include <cassert>
#include <boost/random/variate_generator.hpp>
#include <boost/generator_iterator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random.hpp>
#include <boost/random/uniform_01.hpp>
#include <boost/random/binomial_distribution.hpp>

#include "cudf_types.h"

//Define the seed of random
#define SEED 1000

extern bool showID;

using namespace boost::random;
using namespace std;

// class predeclarations
class ServerType;
class FacilityType;
class FacilityNode;
class NetworkLink;
class LinkIterator;
class NodeIterator;
class AncestorIterator;
class PathIterator;
class PSLProblem;

typedef vector<unsigned int> IntList;
typedef vector<unsigned int>::iterator IntListIterator;

typedef vector<CUDFcoefficient> CUDFcoefficientList;
typedef vector<CUDFcoefficient>::iterator CUDFcoefficientListIterator;

typedef vector<ServerType*> ServerTypeList;
typedef vector<ServerType*>::iterator ServerTypeListIterator;

typedef vector<FacilityType*> FacilityTypeList;
typedef vector<FacilityType*>::iterator FacilityTypeListIterator;

typedef vector<FacilityNode*> FacilityList;
typedef vector<FacilityNode*>::iterator FacilityListIterator;

typedef vector<NetworkLink*> LinkList;
typedef vector<NetworkLink*>::iterator LinkListIterator;

//Functors and templates

//Fonctor to delete an object in any type
struct FonctorDeletePtr {
	template<class T> void operator ()(T* p) const {
		delete p;
		p = NULL;
	}
};

template<typename T>
T& dereference(T* ptr) {
	return *ptr;
}

//----------------------------------------
//	ServerType Declaration
//----------------------------------------

class ServerType {
public:
	ServerType() : capacity(0) {}
	ServerType(unsigned int capacity) : capacity(capacity) {}

	virtual ~ServerType() {}

	inline CUDFcoefficient getMaxConnections() const {
		return capacity;
	}

	friend istream& operator>>(istream& in, ServerType& f);

private:
	CUDFcoefficient capacity;

};

//----------------------------------------
//	FacilityType Declaration
//----------------------------------------

class FacilityType {
public:
	FacilityType() : level(0), binornd(NULL), reliabilityProbability(1) {
		binornd = new variate_generator<mt19937&, binomial_distribution<> >(fake_binornd);
	}

	//Destructor of FacilityType
	//Delete the generator of binomial distribution
	//
	virtual ~FacilityType() {
		delete binornd;
	}

	static void setStaticSeed(const unsigned int seed);
	void setSeed(const unsigned int seed);
	void setBinomial(unsigned int n, double p);

	inline unsigned int getLevel() const {
		return level;
	}

	inline unsigned int binoN() const {
		return binornd->distribution().t();
	}

	inline double binoP() const {
		return binornd->distribution().p();
	}

	inline CUDFcoefficient getDemand(unsigned int stage) const {
		return demands[stage];
	}
	inline CUDFcoefficient getTotalDemand() {
		CUDFcoefficient sum = 0;
		for (CUDFcoefficientListIterator j = demands.begin(); j != demands.end(); ++j)
			sum += *j;
		return sum;
	}
	inline CUDFcoefficient getServerCapacity(const unsigned int stype) const {
		return serverCapacities[stype];
	}

	inline CUDFcoefficient getTotalCapacity() {
		CUDFcoefficient sum = 0;
		for (CUDFcoefficientListIterator j = serverCapacities.begin(); j != serverCapacities.end(); ++j)
			sum += *j;
		return sum;
	}

	unsigned int genRandomFacilities();
	unsigned int genRandomBandwidthIndex();
	unsigned int genRandomBandwidthIndex(unsigned int maxBandwidth);
	bool genRandomReliability();

	istream& read(istream& in, const PSLProblem& problem);
	friend ostream& operator<<(ostream& out, const FacilityType& f);

private:
	static mt19937 default_random_generator;
	static uniform_01< mt19937&, double > randd;
	static variate_generator<mt19937&, binomial_distribution<> > fake_binornd;

	unsigned int level;
	CUDFcoefficientList demands;
	CUDFcoefficientList serverCapacities;
	vector<double> bandwidthProbabilities;
	double reliabilityProbability;
	variate_generator<mt19937&, binomial_distribution<> >* binornd;

};

//----------------------------------------
//	FacilityNode Declaration
//----------------------------------------

class FacilityNode {
	friend class NetworkLink;

public:
	FacilityNode(unsigned int id, FacilityType* type) : id(id), type(type), father(NULL) {
	}

	//Destructor of FacilityNode
	//Do not delete type and father
	//Delete all children
	//
	~FacilityNode() {
		for_each(children.begin(), children.end(), FonctorDeletePtr());
	}

	//the keyword inline is used only on header file
	//
	inline unsigned int getID() const {
		return id;
	}
	inline FacilityType* getType() const {
		return type;
	}
	inline NetworkLink* toFather() const {
		return father;
	}
	FacilityNode* getFather() const;
	inline unsigned int getChildrenCount() const {
		return children.size();
	}
	inline NetworkLink* toChild(unsigned int i) const {
		return children[i];
	}
	FacilityNode* getChild(unsigned int i) const;

	inline bool isRoot() const {
		return father == NULL;
	}
	inline bool isInternalNode() const {
		return !isRoot() && !isLeaf();
	}
	inline bool isLeaf() const {
		return children.empty();
	}

	bool isReliableFromRoot();

	ostream& toDotty(ostream& out);

	void print(ostream& out);

	//For LinkListIterator
	LinkListIterator cbegin() {
		return children.begin();
	}

	LinkListIterator cend() {
		return children.end();
	}

	//For NodeIterator
	NodeIterator nbegin();
	NodeIterator nend();

	//For LinkIterator
	LinkIterator lbegin();
	LinkIterator lend();

	//For AncestorIterator
	AncestorIterator abegin();
	AncestorIterator aend();

	//For PathIterator
	PathIterator pbegin();
	PathIterator pend();

private:
	unsigned int id;
	FacilityType* type;
	NetworkLink* father;
	LinkList children;
};

//----------------------------------------
//	NetworkLink Declaration
//----------------------------------------

class NetworkLink {
public:

	NetworkLink(unsigned int id, FacilityNode* father, FacilityNode* child,
			PSLProblem& problem, bool hierarchic);

	//Destructor of NetworkLink
	//Do not delete origin and destination
	//because these nodes are deleted in the destructor of PSLProblem
	//
	~NetworkLink() {}

	inline unsigned int getID() const {
		return id;
	}
	inline FacilityNode* getOrigin() const {
		return origin;
	}
	inline FacilityNode* getDestination() const {
		return destination;
	}
	inline bool isReliable() const {
		return reliable;
	}
	inline unsigned int getBandwidth() const {
		return bandwidth;
	}
	//void forEachPath(void(*ptr)(FacilityNode* n1, FacilityNode* n2)) const;
	template <typename FuncType>
	void forEachPath(FuncType functor) const;

	ostream& toDotty(ostream& out);

private:
	unsigned int id;
	FacilityNode *origin;
	FacilityNode *destination;
	unsigned int bandwidth;
	bool reliable;
};

//----------------------------------------
//	LinkIterator Declaration
//----------------------------------------

class LinkIterator : public std::iterator<std::forward_iterator_tag, FacilityNode> {
public:
	LinkIterator(FacilityNode* p);

	//Destructor of LinkIterator
	//Do not delete pointers of iterator
	//
	~LinkIterator() {}

	LinkIterator(const LinkIterator& other) : current(other.current), end(other.end), queue(other.queue)  {}

	// The assignment and relational operators are straightforward
	LinkIterator& operator=(const LinkIterator& other) {
		if(*this != other) {
			current = other.current;
			end = other.end;
			queue = other.queue;
		}
		return *this;
	}

	bool operator==(const LinkIterator& other) {
		return current == other.current;
	}

	bool operator!=(const LinkIterator& other) {
		//cout << *current << "!= " << (other.current) << endl;
		return current != other.current;
	}

	LinkIterator& operator++();

	LinkIterator& operator++(int) {
		++(*this);
		return *this;
	}

	NetworkLink* operator*() {
		return *current;
	}

	NetworkLink* operator->() {
		return *current;
	}

private:
	LinkListIterator current;
	LinkListIterator end;
	deque<FacilityNode*> queue;
};

//----------------------------------------
//	NodeIterator Declaration
//----------------------------------------

class NodeIterator : public std::iterator<std::forward_iterator_tag, FacilityNode> {
public:
	NodeIterator(FacilityNode* p) : node(p), clink(NULL), elink(NULL) {}

	//Destructor of NodeIterator
	//Do not delete pointers of iterator
	//
	~NodeIterator() {}

	NodeIterator(const NodeIterator& other) : node(other.node), clink(other.clink), elink(other.elink) {}

	// The assignment and relational operators are straightforward
	NodeIterator& operator=(const NodeIterator& other) {
		if(*this != other) {
			node = other.node;
			clink = other.clink;
			elink = other.elink;
		}
		return *this;
	}

	bool operator==(const NodeIterator& other) {
		return (node == other.node);
	}

	bool operator!=(const NodeIterator& other) {
		return (node != other.node);
	}

	NodeIterator& operator++();

	NodeIterator& operator++(int) {
		++(*this);
		return *this;
	}

	FacilityNode* operator*() {
		return node;
	}

	FacilityNode* operator->() {
		return node;
	}

private:
	FacilityNode* node;
	LinkIterator clink;
	LinkIterator elink;

};

//----------------------------------------
//	AncestorIterator Declaration
//----------------------------------------

class AncestorIterator : public std::iterator<std::forward_iterator_tag, FacilityNode> {
public:
	AncestorIterator(FacilityNode* p) : node( p) {
		++(*this);
	}

	//Destructor of AncestorIterator
	//Do not delete pointers of iterator
	//
	~AncestorIterator() {}

	AncestorIterator(const AncestorIterator& other) : node(other.node) {}

	// The assignment and relational operators are straightforward
	AncestorIterator& operator=(const AncestorIterator& other) {
		if(*this != other) {
			node = other.node;
		}
		return *this;
	}

	bool operator==(const AncestorIterator& other) {
		return (node == other.node);
	}

	bool operator!=(const AncestorIterator& other) {
		return (node != other.node);
	}

	AncestorIterator& operator++();

	AncestorIterator& operator++(int) {
		++(*this);
		return *this;
	}

	FacilityNode* operator*() {
		return node;
	}

	FacilityNode* operator->() {
		return node;
	}

private:
	FacilityNode* node;

};

//----------------------------------------
//	PathIterator Declaration
//----------------------------------------

class PathIterator : public std::iterator<std::forward_iterator_tag, pair<FacilityNode*, FacilityNode*> > {
public:
	PathIterator(FacilityNode* p) : cnode(p->nbegin()), enode(p->nend()), cdest(p->nbegin()), edest(p->nend()) {
		cdest++;
	}

	//Destructor of PathIterator
	//Do not delete pointers of iterator
	//
	~PathIterator() {}

	PathIterator(const PathIterator& other) : cnode(other.cnode), enode(other.enode), cdest(other.cdest), edest(other.edest) {}

	// The assignment and relational operators are straightforward
	PathIterator& operator=(const PathIterator& other) {
		if(*this != other) {
			cnode= other.cnode;
			enode= other.enode;
			cdest = other.cdest;
			edest = other.edest;
		}
		return *this;
	}

	bool operator==(const PathIterator& other) {
		return (cnode == other.cnode) && (cdest== other.cdest);
	}

	bool operator!=(const PathIterator& other) {
		return (cnode != other.cnode) || (cdest!= other.cdest);
	}

	PathIterator& operator++();

	PathIterator& operator++(int) {
		++(*this);
		return *this;
	}

	pair<FacilityNode*, FacilityNode*> operator*() {
		return pair<FacilityNode*, FacilityNode*>(*cnode, *cdest);
	}

	pair<FacilityNode*, FacilityNode*> operator->() {
		return *(*this);
	}

private:
	NodeIterator cnode;
	NodeIterator enode;
	NodeIterator cdest;
	NodeIterator edest;

};
//----------------------------------------
//	PSLProblem Declaration
//----------------------------------------

class PSLProblem {
public:
	PSLProblem() : _groupCount(0), root(NULL), _nodeCount(0) {}

	//Destructor of PSLProblem
	//Delete all nodes of the tree
	//Delete all servers
	//Delete all facilities
	//
	~PSLProblem() {
		deleteTree(root);
		for_each(servers.begin(), servers.end(), FonctorDeletePtr());
		for_each(facilities.begin(), facilities.end(), FonctorDeletePtr());
	}

	inline unsigned int getBandwidth(unsigned int idx) const {
		return bandwidths[idx];
	}
	inline unsigned int bandwidthCount() const {
		return bandwidths.size();
	}
	inline ServerType* getServer(int idx) {
		return servers[idx];
	}
	inline unsigned int serverTypeCount() const {
		return servers.size();
	}

	inline unsigned int groupCount() const {
		return _groupCount;
	}

	inline unsigned int facilityTypeCount() const {
		return facilities.size();
	}

	inline unsigned int levelTypeCount() const {
		return facilities[facilities.size()-1]->getLevel() + 1;
	}

	inline unsigned int levelCount() const {
		return levelNodeCounts.size();
	}

	void setSeed(const unsigned int seed);

	ostream& print_generator(ostream& out);

	FacilityNode* generateNetwork();
	//generate Breadth-First Numbered Tree
	FacilityNode* generateNetwork(bool hierarchic);

	bool checkNetwork();
	bool checkNetworkHierarchy();
	inline FacilityNode* getRoot() const {
		return root;
	}

	inline unsigned int nodeCount() const {
		return _nodeCount;
	}

	inline unsigned int linkCount() const {
		return _nodeCount - 1;
	}

	inline unsigned int pathCount() const {
		return lengthCumulPathCounts.back();
	}

	inline unsigned int stageCount() const {
		return _groupCount + 1;
	}

	inline unsigned int rankCount() const {
		return endBij();
	}

	inline IntList getLevelNodeCounts() {
		return levelNodeCounts;
	}
	//For NodeIterator
	inline NodeIterator nbegin() { return root->nbegin();}
	NodeIterator nend() { return root->nend();}

	//For LinkIterator
	LinkIterator lbegin() { return root->lbegin();}
	LinkIterator lend() { return root->lend();}

	ostream& toRanks(ostream& out);
	ostream& toDotty(ostream& out);

	friend ostream& operator<<(ostream& out, const PSLProblem& f);
	friend istream& operator>>(istream& in, PSLProblem& problem);

	//----------------------------------------
	//	Rank Mapper (associates each variable to an unique index)
	//----------------------------------------
	int rankX(FacilityNode *node) const {
		return node->getID();
	}
	int rankX(FacilityNode *node, unsigned int stype) const {
		assert(stype >= 0 && stype < serverTypeCount());
		return endX() + node->getID() * serverTypeCount() + stype;
	}

	int rankY(FacilityNode *node, unsigned int stage) const {
		assert(stage >= 0 && stage < stageCount());
		return endXk() + node->getID() * stageCount() + stage;
	}

	int rankZ(FacilityNode *node, unsigned int stage) const {
		assert(stage >= 0 && stage < stageCount());
		return endYi() + node->getID() * stageCount() + stage;
	}

	int rankY(NetworkLink *link, unsigned int stage) const {
		assert(stage >= 0 && stage < stageCount());
		return endZi() + link->getID() * stageCount() + stage;
	}

	int rankZ(FacilityNode *source, FacilityNode *destination, unsigned int stage) const {
		return endYij() + rank(source, destination, stage);
	}

	int rankB(FacilityNode *source, FacilityNode *destination, unsigned int stage) const {
		return endZij() + rank(source, destination, stage);
	}

	int rankZ(pair<FacilityNode*, FacilityNode* > const &path, unsigned int stage) const {
		return rankZ(path.first, path.second, stage);
	}

	int rankB(pair<FacilityNode*, FacilityNode* > const &path, unsigned int stage) const {
		return rankB(path.first, path.second, stage);
	}
private:

	inline int endX() const {
		return _nodeCount;
	}

	inline int endXk() const {
		return endX() + _nodeCount * serverTypeCount();
	}

	inline int endYi() const {
		return endXk() + _nodeCount * stageCount();
	}

	inline int endZi() const {
		return endYi() + _nodeCount * stageCount();
	}

	inline int endYij() const {
		return endZi() +  linkCount() * stageCount();
	}

	inline int endZij() const {
		return endYij() + pathCount() * stageCount();
	}

	inline int endBij() const {
		return endZij() + pathCount() * stageCount();
	}

	inline int rank(FacilityNode* source, FacilityNode* destination) const {
		int length = destination->getType()->getLevel() - source->getType()->getLevel();
		//path are ranked by length and their index using the bread-first numbered tree.
		return lengthCumulPathCounts[length-1] + (destination->getID() - levelCumulNodeCounts[length]);
	}

	inline int rank(FacilityNode* source, FacilityNode* destination, unsigned int stage) const {
		assert(stage >= 0 && stage < stageCount());
		return rank(source, destination) * stageCount() + stage;
	}

	//Delete tree from root node
	void deleteTree(FacilityNode* node) {
		levelNodeCounts.clear();
		levelCumulNodeCounts.clear();
		lengthCumulPathCounts.clear();
		_nodeCount = 0;
		if(node != NULL) {
			for ( size_t i = 0; i < node->getChildrenCount(); ++i ) {
				deleteTree(node->toChild(i)->getDestination());
			}
			delete node;
			node = NULL;
		}
	}

	IntList bandwidths;
	ServerTypeList servers;
	FacilityTypeList facilities;
	unsigned int _groupCount;
	FacilityNode* root;
	unsigned int _nodeCount;
	IntList levelNodeCounts;
	//number of nodes of level lower or equal than l;
	IntList levelCumulNodeCounts;
	//number of path of length lower or equal than l
	IntList lengthCumulPathCounts;

};

//----------------------------------------
//	ostream and istream Declaration
//----------------------------------------

ostream& operator<<(ostream& out, const PSLProblem& f);
istream& operator>>(istream& in, PSLProblem& s);

ostream& operator<<(ostream& out, const ServerType& s);
istream& operator>>(istream& in, ServerType& s);

ostream& operator<<(ostream& out, const FacilityType& f);

ostream& operator<<(ostream& out, const FacilityNode& n);
ostream& operator<<(ostream& out, const NetworkLink& l);

//----------------------------------------
//	template definition (must not be placed into cpp)
//----------------------------------------
template <typename FuncType>
inline void NetworkLink::forEachPath(FuncType func) const {
	//void NetworkLink::forEachPath(
	//void(*ptr)(FacilityNode *n1, FacilityNode *n2)) const {
	FacilityNode* ancestor = getDestination();
	FacilityList successors;
	do {
		ancestor = ancestor->getFather();
		successors.push_back(getDestination());
		while (!successors.empty()) {
			FacilityNode* successor = successors.back();
			successors.pop_back();
			func(ancestor, successor);
			if (!successor->isLeaf()) {
				for (unsigned int i = 0; i < successor->getChildrenCount();
						++i) {
					successors.push_back(successor->getChild(i));
				}
			}
		}
	} while (!ancestor->isRoot());
}

inline bool isReliablePath(const FacilityNode* origin, FacilityNode* destination) {
	while(destination) {
		if(destination == origin) return true;
		else if(destination->toFather()->isReliable()) {
			destination = destination->getFather();
		} else destination = NULL;
	}
	return false;
}

#endif /* NETWORK_HPP_ */


/*!
 * @file
 * Defines the @ref Field typeclass.
 *
 *
 * @copyright Louis Dionne 2014
 * Distributed under the Boost Software License, Version 1.0.
 *         (See accompanying file LICENSE.md or copy at
 *             http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_MPL11_FIELD_HPP
#define BOOST_MPL11_FIELD_HPP

#include <boost/mpl11/fwd/field.hpp>

#include <boost/mpl11/bool.hpp>
#include <boost/mpl11/core.hpp>
#include <boost/mpl11/fwd/ring.hpp>

namespace boost { namespace mpl11 {
    template <typename Left, typename Right, typename>
    struct Field : false_ { };

    template <>
    struct instantiate<Field> {
        template <typename Left, typename Right = Left>
        struct with;

        template <typename Datatype>
        struct with<Datatype> : true_ {
            template <typename x, typename y>
            using quot_impl = mult<box<x>, recip<box<y>>>;

            template <typename x>
            using recip_impl = quot<one<Datatype>, box<x>>;
        };
    };

    template <typename x, typename y>
    struct quot :
        Field<
            typename datatype<typename x::type>::type,
            typename datatype<typename y::type>::type
        >::template quot_impl<typename x::type, typename y::type>
    { };

    template <typename x>
    struct recip :
        Field<typename datatype<typename x::type>::type>::
        template recip_impl<typename x::type>
    { };
}} // end namespace boost::mpl11

#endif // !BOOST_MPL11_FIELD_HPP


//=======================================================================
// Copyright (c)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
#include "test_utils/sample_graph.hpp"

#include "paal/data_structures/facility_location/facility_location_solution.hpp"
#include "paal/data_structures/voronoi/voronoi.hpp"
#include "paal/local_search/facility_location/facility_location_solution_adapter.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/algorithm/sort.hpp>

using namespace paal::data_structures;
using namespace paal::local_search;

BOOST_AUTO_TEST_CASE(facility_location_solution_adapterTest) {
    typedef sample_graphs_metrics SGM;
    auto gm = SGM::get_graph_metric_small();
    std::vector<int> fcosts{ 7, 8 };
    auto cost = [&](int i) { return fcosts[i]; };

    typedef voronoi<decltype(gm)> VorType;
    typedef typename VorType::GeneratorsSet FSet;
    VorType voronoi(FSet{}, FSet{ SGM::A, SGM::B, SGM::C, SGM::D, SGM::E }, gm);

    typedef facility_location_solution<decltype(cost), VorType> Sol;

    Sol sol(std::move(voronoi), FSet{ SGM::A, SGM::B }, cost);

    facility_location_solution_adapter<Sol> sa(sol);
    std::vector<int> saSorted;

    BOOST_CHECK_EQUAL(boost::distance(sa.getChosenCopy()), 0);

    boost::copy(sa.getUnchosenCopy(), std::back_inserter(saSorted));
    boost::sort(saSorted);
    auto b = saSorted.begin();
    auto e = saSorted.end();
    auto A = *b;
    BOOST_CHECK_EQUAL(*b, SGM::A);
    BOOST_CHECK(b != e);
    BOOST_CHECK_EQUAL(*(++b), SGM::B);
    auto B = *b;
    BOOST_CHECK(b != e);
    BOOST_CHECK(++b == e);

    sa.add_facility(A);
    BOOST_CHECK_EQUAL(boost::distance(sa.getChosenCopy()), 1);
    BOOST_CHECK_EQUAL(boost::distance(sa.getUnchosenCopy()), 1);
    BOOST_CHECK_EQUAL(*std::begin(sa.getChosenCopy()), A);
    BOOST_CHECK_EQUAL(*std::begin(sa.getUnchosenCopy()), B);
}


#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <random>
#include <sstream>
#include <fftw3.h>
#include "parameter.hpp"
#include "utilities.hpp"
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

void dir_manage(const std::string exist_dir, const std::string new_dir )
{

    //Path of the existing data directory
    const fs::path existpath("../" + exist_dir );

    //Tries to remove all files in there. If it fails, it throws an error.
    try {
        fs::remove_all(existpath);
    }
    catch (fs::filesystem_error& ex) {
        std::cout << ex.what() << std::endl;
        throw;
    }

    //Path of the newly set directory
    const fs::path newpath("../" + new_dir );

    //Tries to create a directory. If it fails, it throws an error.
    boost::system::error_code error;
    const bool result = fs::create_directory(newpath, error);
    if (!result || error) {
        std::cout << "failed to create directory" << std::endl;
    }

}

void file_manage(const std::string exist_file)
{
    //Path of the existing status file
    const fs::path statuspath("../" + exist_file);

    //Tries to remove the file. If it fails, it throws an error.
    try {
        fs::remove(statuspath);
    }
    catch (fs::filesystem_error& ex) {
        std::cout << ex.what() << std::endl;
        throw;
    }

}

double rand_uniform(void)
{
    std::random_device rnd;
    std::mt19937 mt( rnd() );
    std::uniform_real_distribution<> rand( 0, 1 );
 //   std::cout << rand(mt) << "\n";
    return (rand(mt));
}

void set_mode(double p2, double m2, double *field, double *deriv, int real)
{
    double phase,phase2, amplitude, rms_amplitude, omega;
    double re_f_left, im_f_left, re_f_right, im_f_right;
#if  dim==1
    static double norm = m*pow(L/(dx*dx),.5)/sqrt(4*M_PI);
#elif  dim==2
    static double norm =  m*pow(L/(dx*dx),1)/(sqrt(2*M_PI));
#elif  dim==3
    static double norm =  m*pow(L/(dx*dx),1.5)/sqrt(2);
#endif
    static int tachyonic = 0; //Avoid printing the same error repeatedly

    if(p2+m2>0)
        omega=sqrt(p2+m2);
    else
    {
        if(tachyonic==0)
            std::cout <<"Warning: Tachyonic mode(s) may be initialized inaccurately"<< std::endl;
        omega=sqrt(p2);
        tachyonic=1;
    }

    if(omega>0.)
        rms_amplitude=norm/sqrt(omega)*pow(p2,.75-(double)dim/4.);
    else
        rms_amplitude=0.;

        //Amplitude = RMS amplitude x Rayleigh distributed random number
        // The same amplitude is used for left and right moving waves to generate standing waves. The extra 1/sqrt(2) normalizes the initial occupation number correctly.

    amplitude = rms_amplitude/sqrt(2.)*sqrt(log(1./rand_uniform()));
    phase = 2*M_PI*rand_uniform();
  // std::cout << "phase1 " << phase/(2*M_PI) << std::endl;
        //Left moving component
        re_f_left = amplitude * cos( phase );
        im_f_left = amplitude * sin( phase );
        //Right moving component
    phase2 = 2*M_PI*rand_uniform();
  //  std::cout << "phase2 " << phase/(2*M_PI) << std::endl;
        re_f_right = amplitude * cos( phase2 );
        im_f_right = amplitude * sin( phase2 );

    field[0] = re_f_left + re_f_right;
    field[1] = im_f_left + im_f_right;
    deriv[0] = omega*(im_f_left - im_f_right);
    deriv[1] = -omega*(re_f_left - re_f_right);
    if(real==1)
    {
        field[1]=0;
        deriv[1]=0;
    }
    return;
   }

void DFT_c2rD1( double* f)
{
    fftw_plan p;
    double* out;
    fftw_complex *in;
    size_t in_size;

    in_size = sizeof(fftw_complex) * (N/2+1);
    in  = (fftw_complex*)fftw_malloc( in_size );
    out = new double [N]();
    p = fftw_plan_dft_c2r_1d( N, in, out, FFTW_ESTIMATE );

        for( int j = 0; j < N/2+1; ++j ){
            int idx = j;
            if(idx==0)
            {
                in[idx][0] = f[idx]  ;
                in[idx][1] = 0  ;

            }else if(idx==N/2){
                in[idx][0] = f[1]  ;
                in[idx][1] = 0  ;
            }else{
                in[idx][0] = f[2*idx]  ;
                in[idx][1] = f[2*idx+1]  ;
            }

        }

    fftw_execute(p);

    // Set output data
    for( int j = 0; j < N; ++j ){
        int idx = j;
        f[idx] = out[idx]/N;
    }

    if( p ) fftw_destroy_plan(p);
    if( in ) fftw_free(in);
    delete[] out;
}
/*
void DFT_c2rD2d( double* df,double* fdnyquist )
{
    fftw_plan p;
    double* out;
    fftw_complex *in;
    size_t in_size;

    in_size = sizeof(fftw_complex) * N * (N/2+1);
    in  = (fftw_complex*)fftw_malloc( in_size );
    out = new double [N*N]();
    p = fftw_plan_dft_c2r_2d( N, N, in, out, FFTW_ESTIMATE );

    for( int j = 0; j < N; ++j ){
        //#pragma omp parallel for schedule( static ) num_threads( num_threads )
        for( int k = 0; k < N/2+1; ++k ){
            int idx = (N/2+1)*j + k;
            // int idx = j*N + k;
            if(k == N/2){
                in[idx][0] = (double)fdnyquist[2*j] ;
                in[idx][1] = (double)fdnyquist[2*j+1] ;
               // std::cout << "in[" << idx << "][0] = " << in[idx][0] << std::endl;
               // std::cout << "in[" << idx << "][1] = " << in[idx][1] << std::endl;
            }else {
                in[idx][0] =  (double)df[j*N + 2*k] ;
                in[idx][1] = (double)df[j*N + 2*k+1] ;
               // std::cout << "in[" << idx << "][0] = " << in[idx][0] << std::endl;
               // std::cout << "in[" << idx << "][1] = " << in[idx][1] << std::endl;
            }
        }
    }
    fftw_execute(p);

    // Set output data

    for( int j = 0; j < N; ++j ){
        //#pragma omp parallel for schedule( static ) num_threads( num_threads )
        for( int k = 0; k < N; ++k ){
            int idx = j*N + k;
            std::cout << "out[" << idx << "] = " << out[idx] << std::endl;
            df[idx] = out[idx]/(N*N);
        }
    }

    if( p ) fftw_destroy_plan(p);
    if( in ) fftw_free(in);
    delete[] out;
}
*/
void DFT_c2rD2( double* f,double* fnyquist )
{
    fftw_plan p;
    double* out;
    fftw_complex *in;
    size_t in_size;

    in_size = sizeof(fftw_complex) * N * (N/2+1);
    in  = (fftw_complex*)fftw_malloc( in_size );
    out = new double [N*N]();
    p = fftw_plan_dft_c2r_2d( N, N, in, out, FFTW_ESTIMATE );

        for( int j = 0; j < N; ++j ){
            for( int k = 0; k < N/2+1; ++k ){
                int idx = (N/2+1)*j + k;
              //  int idx = j*N + k;
                if(k == N/2){
                    in[idx][0] =  fnyquist[2*j] ;
                    in[idx][1] =  fnyquist[2*j+1] ;
                }else {
                    in[idx][0] =  f[j*N + 2*k];
                    in[idx][1] =  f[j*N + 2*k+1] ;
                }
            }
        }
        fftw_execute(p);

        // Set output data

     for( int j = 0; j < N; ++j ){
        for( int k = 0; k < N; ++k ){
            int idx = j*N + k;
            f[idx] = out[idx]/(N*N);
        }
     }

    if( p ) fftw_destroy_plan(p);
    if( in ) fftw_free(in);
    delete[] out;
}

void DFT_c2rD3( double* f,double** fnyquist )
{
    fftw_plan p;
    double* out;
    fftw_complex *in;
    size_t in_size;

    in_size = sizeof(fftw_complex) * N * N * (N/2+1);
    in  = (fftw_complex*)fftw_malloc( in_size );
    out = new double [N*N*N]();
    p = fftw_plan_dft_c2r_3d( N, N, N, in, out, FFTW_ESTIMATE );

//#pragma omp parallel for simd collapse(3) schedule( static ) num_threads( num_threads )
        for( int j = 0; j < N; ++j ){
            for( int k = 0; k < N; ++k ){
                for( int l = 0; l < N/2+1; ++l ){
                    int idx = (j*N + k)*(N/2+1) + l;
                    if(l == N/2){
                        in[idx][0] = fnyquist[j][2*k] ;
                        in[idx][1] = fnyquist[j][2*k+1] ;
                    }
                    else{
                        in[idx][0] =  f[(j*N + k)*N + 2*l] ;
                        in[idx][1] =  f[(j*N + k)*N + 2*l+1] ;
                    }
                }
            }
        }
        fftw_execute(p);

        // Set output data

         for( int j = 0; j < N; ++j ){
        for( int k = 0; k < N; ++k ){
            for( int l = 0; l < N; ++l ){
                int idx = (j*N + k)*N + l;
                f[idx] = out[idx]/(N*N*N);
            }
        }
    }

    if( p ) fftw_destroy_plan(p);
    if( in ) fftw_free(in);
    delete[] out;
}

/*
void DFT_c2r( double** f,double* fnyquist )
{
	  fftw_plan p;
		double* out;
    fftw_complex *in;
		size_t in_size;

		switch( dim )
		{
			case 1:
				in_size = sizeof(fftw_complex) * (N/2+1);
				in  = (fftw_complex*)fftw_malloc( in_size );
				out = new double [N]();
				p = fftw_plan_dft_c2r_1d( N, in, out, FFTW_ESTIMATE );
				break;
			case 2:
				in_size = sizeof(fftw_complex) * N * (N/2+1);
				in  = (fftw_complex*)fftw_malloc( in_size );
				out = new double [N*N]();
				p = fftw_plan_dft_c2r_2d( N, N, in, out, FFTW_ESTIMATE );
				break;
			case 3:
				in_size = sizeof(fftw_complex) * N * N * (N/2+1);
				in  = (fftw_complex*)fftw_malloc( in_size );
				out = new double [N*N*N]();
				p = fftw_plan_dft_c2r_3d( N, N, N, in, out, FFTW_ESTIMATE );
				break;
		}

		for( int i = 0; i < num_fields; ++i )
		{

				// Create input data
				switch( dim ){
					case 1:
						#pragma omp parallel for schedule( static ) num_threads( num_threads )
						for( int j = 0; j < N/2+1; ++j ){
							int idx = j;
							if(idx==0)
                            {
                                in[idx][0] = f[i][idx]  ;
                                in[idx][1] = 0  ;

                            }else if(idx==N/2){
                                in[idx][0] = f[i][1]  ;
                                in[idx][1] = 0  ;
                            }else{
                                in[idx][0] = f[i][2*idx]  ;
                                in[idx][1] = f[i][2*idx+1]  ;
                            }

						}
						break;
					case 2:
						#pragma omp parallel for schedule( static ) num_threads( num_threads )
						for( int j = 0; j < N; ++j ){
							for( int k = 0; k < N/2+1; k=k+2 ){
									int idx = j*N + k;
                                if(k == N/2){
                                    in[idx][0] = fnyquist[2*j] ;
                                    in[idx][1] = fnyquist[2*j+1] ;
                                }else {
                                    in[idx][0] =  f[i][idx] ;
                                    in[idx][1] =  f[i][idx+1] ;
                                }
							}
						}
						break;
					case 3:
						#pragma omp parallel for schedule( static ) num_threads( num_threads )
						for( int j = 0; j < N; ++j ){
							for( int k = 0; k < N; ++k ){
									for( int l = 0; l < N/2+1; l=l+2 ){
											int idx = (j*N + k)*N + l;
                                        if(l == N/2){
                                        in[idx][0] = fnyquist[j][2*k] ;
                                        in[idx][1] = fnyquist[j][2*k+1] ;
                                        }
                                        else{
                                            in[idx][0] =  f[i][idx] ;
                                            in[idx][1] =  f[i][idx+1] ;
                                        }
                                        }
							}
						}
						break;
				}

				fftw_execute(p);

				// Set output data
        #pragma omp parallel for schedule( static ) num_threads( num_threads )
        for( int j = 0; j < N; ++j ){
            switch( dim ){
							case 1:
                int idx = j;
                f[i][idx] = out[idx]/N;
								break;
            	case 2:
                for( int k = 0; k < N; ++k ){
                    int idx = j*N + k;
                    f[i][idx] = out[idx]/(N*N);
                }
								break;
            	case 3:
                for( int k = 0; k < N; ++k ){
                    for( int l = 0; l < N; ++l ){
                        int idx = (j*N + k)*N + l;
                        f[i][idx] = out[idx]/(N*N*N);
                    }
                }
								break;
						}
        }
    }

		if( p ) fftw_destroy_plan(p);
		if( in ) fftw_free(in);
		delete[] out;
}
*/

void write_VTK_f( const std::string dir_f, double* f, std::string str, int loop )
{
   // double a = leapfrog->a();
	unsigned int size;
	std::stringstream ss;
	std::ofstream fout;

	if( dim == 1 ){
		ss << "../" << dir_f << "/" << str << "." << std::setw(4) << std::setfill('0') << loop+1 <<".txt";
    	fout.open( ss.str().c_str() );

    	for( int j = 0; j < N; j++ ){
			int idx = j;
			fout << idx*dx << " " << f[idx] << std::endl;
		}
    }else{
    	ss << "../" << dir_f << "/" << str << "." << std::setw(4) << std::setfill('0') << loop+1 <<".vti";
    	fout.open( ss.str().c_str() );

  	  	fout << "<?xml version=\"1.0\"?>" << std::endl;
  		fout << "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt32\">" << std::endl <<std::endl;
    	switch( dim ){
    		case 2:
				size = sizeof(double) * pow(N, 2);//8byte*pow(N,2)
				fout << "<ImageData WholeExtent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << " 0 " << "\" Origin=\"0 0 0\" Spacing=\"" << dx << " " << dx << " " << dx << "\">" << std::endl;
				fout << "<Piece Extent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << " 0 " << "\">" << std::endl;
    			break;
			case 3:
				size = sizeof(double) * pow(N, 3);
				fout << "<ImageData WholeExtent=\"0 " << N-1 << " 0 " << N-1 <<" 0 " << N-1 << "\" Origin=\"0 0 0\" Spacing=\"" << dx << " " << dx << " " << dx << "\">" << std::endl;
				fout << "<Piece Extent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << N-1 << "\">" << std::endl;
				break;
    	}
    	fout << "<PointData Scalars=\"field\">" << std::endl;
    	fout << "<DataArray type=\"Float64\" Name=\"field\" format=\"appended\" offset=\"0\" />" << std::endl;
    	fout << "</PointData>" << std::endl;
	    fout << "<CellData>" << std::endl;
	    fout << "</CellData>" << std::endl;
	    fout << "</Piece>" << std::endl << std::endl;

	    fout << "</ImageData>" << std::endl << std::endl;
	    fout << "<AppendedData encoding=\"raw\">" << std::endl;
	    fout << "_" ;
	    fout.close();

	    fout.open( ss.str().c_str(), std::ios::binary | std::ios::app);
	    fout.write( (char*) &size, sizeof(unsigned int) );//4byte

           fout.write( (char*) f, size );
	    fout.close();
	    fout.open( ss.str().c_str(), std::ios::app);
	    fout << std::endl << "</AppendedData>" << std::endl;
		fout << "</VTKFile>" ;
	}
	fout.close();
}

void write_VTK_ed( const std::string dir_ed, double* f, std::string str, int loop )
{
  //  double a = leapfrog->a();
   // std::cout << "aaa = " <<  a << std::endl;
    unsigned int size;
    std::stringstream ss;
    std::ofstream fout;

    if( dim == 1 ){
        ss << "../" << dir_ed << "/" << str << "." << std::setw(4) << std::setfill('0') << loop+1 <<".txt";
        fout.open( ss.str().c_str() );

        for( int j = 0; j < N; j++ ){
            int idx = j;
            fout << idx*dx << " " << f[idx] << std::endl;
        }
    }else{
        ss << "../" << dir_ed << "/" << str << "." << std::setw(4) << std::setfill('0') << loop+1 <<".vti";
        fout.open( ss.str().c_str() );

        fout << "<?xml version=\"1.0\"?>" << std::endl;
        fout << "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt32\">" << std::endl <<std::endl;
        switch( dim ){
            case 2:
                size = sizeof(double) * pow(N, 2);//8byte*pow(N,2)
                fout << "<ImageData WholeExtent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << " 0 " << "\" Origin=\"0 0 0\" Spacing=\"" << dx << " " << dx << " " << dx << "\">" << std::endl;
                fout << "<Piece Extent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << " 0 " << "\">" << std::endl;
                break;
            case 3:
                size = sizeof(double) * pow(N, 3);
                fout << "<ImageData WholeExtent=\"0 " << N-1 << " 0 " << N-1 <<" 0 " << N-1 << "\" Origin=\"0 0 0\" Spacing=\"" << dx << " " << dx << " " << dx << "\">" << std::endl;
                fout << "<Piece Extent=\"0 " << N-1 << " 0 " << N-1 << " 0 " << N-1 << "\">" << std::endl;
                break;
        }
        fout << "<PointData Scalars=\"energy\">" << std::endl;
        fout << "<DataArray type=\"Float64\" Name=\"energy density\" format=\"appended\" offset=\"0\" />" << std::endl;
        fout << "</PointData>" << std::endl;
        fout << "<CellData>" << std::endl;
        fout << "</CellData>" << std::endl;
        fout << "</Piece>" << std::endl << std::endl;

        fout << "</ImageData>" << std::endl << std::endl;
        fout << "<AppendedData encoding=\"raw\">" << std::endl;
        fout << "_" ;
        fout.close();

        fout.open( ss.str().c_str(), std::ios::binary | std::ios::app);
        fout.write( (char*) &size, sizeof(unsigned int) );//4byte

            fout.write( (char*) f, size );

        fout.close();
        fout.open( ss.str().c_str(), std::ios::app);
        fout << std::endl << "</AppendedData>" << std::endl;
        fout << "</VTKFile>" ;
    }
    fout.close();
}

void write_status( const std::string status_file, Field* field, LeapFrog* leapfrog, Energy* energy, double** f, double t )
{
	double a = leapfrog->a();
	std::ofstream ofs;

	if( t == t0 )
	{
		ofs.open( "../" + status_file, std::ios::trunc );

		ofs << std::setw(3) << std::right << "  t ";
		if( expansion ) ofs << "  a ";
		for( int i = 0; i < num_fields; ++i ) ofs << "field_ave["  << i << "] ";
		for( int i = 0; i < num_fields; ++i ) ofs << "field_var["  << i << "] ";
        for( int i = 0; i < num_fields; ++i ) ofs << "field_deriv_ave["  << i << "] ";
        for( int i = 0; i < num_fields; ++i ) ofs << "field_deriv_var["  << i << "] ";
		for( int i = 0; i < num_fields; ++i ) ofs << "energy_ave[" << i << "] ";
        for( int i = 0; i < num_fields; ++i ) ofs << "energy_var[" << i << "] ";
        ofs << "total_energy_ave ";
         ofs << "time_deriv_ave ";
         ofs << "gradient_ave ";
        ofs << "potential_ave ";
        ofs << "hubble ";
        ofs << "adotdot ";
        ofs << "energy_max" << std::endl;
	}
	else ofs.open( "../" + status_file, std::ios::app );

	ofs << std::setw(3) << std::right << t << " ";
	if( expansion )
	{
		ofs << std::setw(3) << std::right << a << " ";
		for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->f_average(f[i], i)/a << " "; //Reduced Plank units
		for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->f_variance(f[i], i)/a << " ";//Reduced Plank units
        for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->df_average(f[i], i) << " ";//Programming variable
        for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->df_variance(f[i], i) << " ";//Programming variable
	}
	else
	{
		for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->f_average(f[i], i) << " ";//Reduced Plank units
		for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->f_variance(f[i], i) << " ";//Reduced Plank units
        for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->df_average(f[i], i) << " ";//Programming variable
        for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << field->df_variance(f[i], i) << " ";//Programming variable
	}
	for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << energy->average(i) << " ";
    for( int i = 0; i < num_fields; ++i ) ofs << std::showpos << std::scientific << std::setprecision(4) << energy->variance(i) << " ";
	ofs << std::showpos << std::scientific << std::setprecision(4) << energy->total_average() << " ";
    ofs << std::showpos << std::scientific << std::setprecision(4) << energy->timederiv_average () << " ";
     ofs << std::showpos << std::scientific << std::setprecision(4) << energy->grad_average ()  << " ";
    ofs << std::showpos << std::scientific << std::setprecision(4) << energy->potential_average () << " ";
    ofs << std::showpos << std::scientific << std::setprecision(4) << leapfrog->hubble() << " ";
    ofs << std::showpos << std::scientific << std::setprecision(4) << leapfrog->adotdot() << " ";
    ofs << std::showpos << std::scientific << std::setprecision(4) << energy->energy_max() << std::endl;

}


/* naive_bayes_generator.cc
   Jeremy Barnes, 15 March 2006
   Copyright (c) 2006 Jeremy Barnes  All rights reserved.
   $Source$

   Generator for glz_classifiers.
*/

#include "naive_bayes_generator.h"
#include "registry.h"
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#include "training_index.h"
#include "weighted_training.h"
#include "stump_training.h"
#include "stump_training_core.h"
#include "jml/stats/distribution_ops.h"
#include "jml/utils/smart_ptr_utils.h"

using namespace std;

namespace ML {

/*****************************************************************************/
/* NAIVE_BAYES_GENERATOR                                                     */
/*****************************************************************************/

Naive_Bayes_Generator::
Naive_Bayes_Generator()
{
    defaults();
}

Naive_Bayes_Generator::~Naive_Bayes_Generator()
{
}

void
Naive_Bayes_Generator::
configure(const Configuration & config)
{
    Classifier_Generator::configure(config);

    config.find(trace,        "trace");
    config.find(feature_prop, "feature_prop");
}

void
Naive_Bayes_Generator::
defaults()
{
    Classifier_Generator::defaults();
    trace = 0;
    feature_prop = 1.0;
}

Config_Options
Naive_Bayes_Generator::
options() const
{
    Config_Options result = Classifier_Generator::options();
    result
        .add("trace", trace, "0-",
             "trace execution of training in a very fine-grained fashion")
        .add("feature_prop", feature_prop, "0.0<N<=1.0",
             "which proportion of features do we look at");

    return result;
}

void
Naive_Bayes_Generator::
init(std::shared_ptr<const Feature_Space> fs, Feature predicted)
{
    Classifier_Generator::init(fs, predicted);
    model = Naive_Bayes(fs, predicted);
}

std::shared_ptr<Classifier_Impl>
Naive_Bayes_Generator::
generate(Thread_Context & context,
         const Training_Data & training_set,
         const Training_Data & validation_set,
         const distribution<float> & training_ex_weights,
         const distribution<float> & validate_ex_weights,
         const std::vector<Feature> & features, int) const
{
    boost::timer timer;

    Feature predicted = model.predicted();

    boost::multi_array<float, 2> weights
        = expand_weights(training_set, training_ex_weights, predicted);

    Naive_Bayes current
        = train_weighted(context, training_set, weights, features);

    if (verbosity > 2) {
        cerr << endl << "Learned Bayes classifier function: " << endl;
        int nl = current.label_count();
        cerr << "feature                       split";
        if (nl == 2 && false)
            cerr << "       label1";
        else
            for (unsigned l = 0;  l < nl;  ++l)
                cerr << format("    label%-4d", l);
        cerr << endl;

        for (unsigned i = 0;  i < current.features.size();  ++i) {
            string feat
                = current.feature_space()
                ->print(current.features[i].feature);

            string spaces = feat;
            std::fill(spaces.begin(), spaces.end(), ' ');

            for (unsigned j = 0;  j < 3;  ++j) {
                if (j == 2) {
                    float sum_missing = 0.0;

                    for (unsigned l = 0;  l < nl;  ++l)
                        sum_missing += current.probs[i][j][l];

                    if (sum_missing == 0.0) continue;
                }
                if (j == 0) cerr << format("%-30s", feat.c_str());
                else cerr << format("%-30s", spaces.c_str());

                if (j == 0) cerr << format(" <  %13f", current.features[i].arg);
                else if (j == 1)
                    cerr << format(" >= %13f", current.features[i].arg);
                else cerr << " MISSING         ";

                if (nl == 2 && false)
                    cerr << format("%9.4f", current.probs[i][j][1]);
                else
                    for (unsigned l = 0;  l < nl;  ++l)
                        cerr << format("%9.4f", current.probs[i][j][l]);
                cerr << endl;
            }
            cerr << endl;
        }
    }

    return make_sp(current.make_copy());
}

namespace {

/*****************************************************************************/
/* NAIVE_BAYES_ACCUM                                                         */
/*****************************************************************************/

template<class W, class Z, class Tracer = No_Trace>
struct Naive_Bayes_Accum {

    Naive_Bayes_Accum(const Feature_Space & fs, size_t nl, float epsilon,
                      Tracer tracer = Tracer())
        : tracer(tracer), w(2), arg(0.5), z(1.0), fs(fs), nl(nl),
          epsilon(epsilon)
    {
    }

    Tracer tracer;
    Z calc_z;

    W w;
    float arg;
    float z;
    Feature feature;

    const Feature_Space & fs;
    size_t nl;
    float epsilon;

    /* Results go in here. */
    vector<Naive_Bayes::Bayes_Feature> features;
    vector<distribution<float> > dist_true;
    vector<distribution<float> > dist_false;
    vector<distribution<float> > dist_missing;

    /** Method that gets called when we start a new feature.  We use it to
        pre-cache part of the work from the Z calculation, as we are
        assured that the MISSING buckets of W will never change after this
        method is called.
    */
    bool start(const Feature & feature, const W & w, double & missing)
    {
        bool optional = fs.info(feature).optional();
        missing = calc_z.missing(w, optional);
        return true;  // Yes, we can continue...
    }

    /** Method that gets called when we have found a potential split point. */
    float add(const Feature & feature, const W & w, float arg, float z,
              double missing)
    {
        if (tracer)
            tracer("naive bayes accum", 3)
                << "  accum: feature " << feature << " arg " << arg
                << "  z " << z << "  " << fs.print(feature) << endl;

        if (z < this->z || this->z == 1.0) {
            // A better one.  This replaces whatever we had accumulated so
            // far.
            this->z = z;
            this->w = w;
            this->arg = arg;
            this->feature = feature;
        }

        return z;
    }

    /** Method that gets called when we have found a potential split point. */
    float add(const Feature & feature, const W & w, float arg,
              double missing)
    {
        float z = calc_z.non_missing(w, missing);
        return add(feature, w, arg, z, missing);
    }

    /** Method that gets called when we have found a potential split point. */
    float add_presence(const Feature & feature, const W & w, float arg,
                       double missing)
    {
        float z = calc_z.non_missing_presence(w, missing);
        return add(feature, w, arg, z, missing);
    }

    /** Called once we have tried all split points for a feature.  We know
        where that split point is and the W matrix.  From this, we can
        calculate the probabilities.
    */
    void finish(const Feature & feature)
    {
        Naive_Bayes::Bayes_Feature bayes_feature;
        bayes_feature.feature = feature;
        bayes_feature.arg = arg;

        features.push_back(bayes_feature);

        distribution<float> d_true(nl), d_false(nl), d_missing(nl);

        for (unsigned l = 0; l < nl;  ++l) {
            float w_false   = w(l, false,   true);
            float w_true    = w(l, true,    true);
            float w_missing = w(l, MISSING, true);

            float total = (w_false + w_true + w_missing) * epsilon;

            d_true[l]    = log(std::max(1.0F, w_true    / total));
            d_false[l]   = log(std::max(1.0F, w_false   / total));
            if (!fs.info(feature).optional())
                d_missing[l] = log(std::max(1.0F, w_missing / total));
        }

        dist_true.push_back(d_true);
        dist_false.push_back(d_false);
        dist_missing.push_back(d_missing);

        if (tracer)
            tracer("naive bayes accum", 3)
                << "  finish: feature " << feature << " arg " << arg
                << "  z " << z << "  " << fs.print(feature) << endl
                << "  w: " << w.print() << endl
                << "  epsilon: " << epsilon << endl
                << "  dist_true: " << d_true << endl
                << "  dist_false: " << d_false << endl
                << "  dist_missing: " << d_missing << endl;

        /* Set up for the next go around... */
        z = 1.0;
        arg = 0.5;
    }

    void results(Naive_Bayes & output) const
    {
        vector<pair<Naive_Bayes::Bayes_Feature, int> > sorted;
        sorted.reserve(features.size());
        for (unsigned i = 0;  i < features.size();  ++i)
            sorted.push_back(make_pair(features[i], i));
        sort_on_first_ascending(sorted);

        boost::multi_array<float, 3> probs(boost::extents[features.size()][3][nl]);
        distribution<double> missing(nl);
        output.features
            = vector<Naive_Bayes::Bayes_Feature>
                (first_extractor(sorted.begin()),
                 first_extractor(sorted.end()));

        for (unsigned f = 0;  f < features.size();  ++f) {
            for (unsigned l = 0;  l < nl;  ++l) {
                int f2 = sorted[f].second;
                probs[f][false][l]   = dist_false[f2][l];
                probs[f][true][l]    = dist_true[f2][l];
                probs[f][MISSING][l] = dist_missing[f2][l];
                missing[l]          += dist_missing[f2][l];
            }
        }

        swap_multi_arrays(output.probs, probs);
        output.missing_total
            = distribution<float>(missing.begin(), missing.end());
    }
};

} // file scope

Naive_Bayes
Naive_Bayes_Generator::
train_weighted(Thread_Context & context,
               const Training_Data & data,
               const boost::multi_array<float, 2> & weights,
               const std::vector<Feature> & features_) const
{
    Naive_Bayes result = model;

    vector<Feature> features = features_;

    for (int i = 0;  i < features.size();  ++i) {
        if (features[i] == model.predicted()) {
            std::swap(features[i], features.back());
            features.pop_back();
        }
    }

    /* Test the given proportion of possible features, and return the best. */
    if (feature_prop < 1.0)
        std::random_shuffle(features.begin(), features.end());

    /* Choose the top proportion of them. */
    size_t nf = (size_t)((float)features.size() * feature_prop);
    size_t nl = result.label_count();
    size_t nx = data.example_count();

    if (nf == 0)
        throw Exception("Naive_Bayes::train_weighted: attempt to train with "
                        "no features (or feature_prop too low)");

    if (result.features.size() < 100) nf = result.features.size();

    const vector<Label> & labels = data.index().labels(model.predicted());

    /* Work out the label priors.  These are smoothed as well. */
    distribution<double> class_weights(nl);
    for (unsigned x = 0;  x < nx;  ++x) {
        float total_weight = 0.0;
        if (weights.shape()[1] == 1)
            total_weight = nl * weights[x][0];
        else
            for (unsigned l = 0;  l < nl;  ++l)
                total_weight += weights[x][l];
        class_weights[labels[x]] += total_weight;
    }

    for (unsigned l = 0;  l < nl;  ++l)
        class_weights[l] = std::max(class_weights[l], 1.0 / (nx * nl));

    class_weights.normalize();

    //cerr << "class_weights = " << class_weights << endl;

    result.label_priors
        = distribution<float>(class_weights.begin(), class_weights.end());

    {
        typedef W_normal W;
        typedef Z_normal Z;

        typedef Naive_Bayes_Accum<W, Z, Stream_Tracer> Accum;
        typedef Stump_Trainer<W, Z, Stream_Tracer> Trainer;

        float epsilon = 1.0 / (nx * nl);

        Accum accum(*model.feature_space(), nl, epsilon, trace);
        Trainer trainer(trace);

        trainer.test_all(features, data, model.predicted(), LW_Array<const float>(weights),
                         accum);

        accum.results(result);
    }

    return result;
}

/*****************************************************************************/
/* REGISTRATION                                                              */
/*****************************************************************************/

namespace {

Register_Factory<Classifier_Generator, Naive_Bayes_Generator>
    NAIVE_BAYES_REGISTER("naive_bayes");

} // file scope

} // namespace ML


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_HPP
#define BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_HPP

// Buffer strategies

#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

#include <boost/geometry/extensions/strategies/buffer_side.hpp>

namespace boost { namespace geometry
{

namespace strategy { namespace buffer
{

/*

   A Buffer-join strategy gets 4 input points.
   On the two consecutive segments s1 and s2 (joining at vertex v):

   The lines from parallel at s1, s2 (at buffer-distance) end/start
   in two points perpendicular to the segments: p1 and p2.
   These parallel lines interesct in point ip

             (s2)
              |
              |
              ^
              |
        (p2)  |(v)
        *     +----<--- (s1)

        x(ip) *(p1)

    So, in clockwise order:
        v : vertex point
        p1: perpendicular on left side of segment1<1> (perp1)
        ip: intersection point
        p2: perpendicular on left side of segment2<0> (perp2)
*/

// TODO: merge join_miter with join_round, lot of duplicate code

template
<
    typename PointIn,
    typename PointOut
>
struct join_miter
{
    typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
    typedef typename coordinate_type<PointIn>::type coordinate_type;

    template <typename RangeOut>
    inline void apply(PointIn const& ip, PointIn const& vertex,
                PointIn const& perp1, PointIn const& perp2,
                coordinate_type const& buffer_distance,
                RangeOut& range_out) const
    {
        coordinate_type zero = 0;
        int signum = buffer_distance > zero ? 1
                   : buffer_distance < zero ? -1
                   : 0;

        if (side::apply(perp1, ip, perp2) == signum)
        {
        }
        else
        {
            PointIn p = ip;

            // Normalize it and give it X*dist.
            coordinate_type dx = get<0>(ip) - get<0>(vertex);
            coordinate_type dy = get<1>(ip) - get<1>(vertex);

            coordinate_type length = sqrt(dx * dx + dy * dy);

            // TODO: make max-mitre-limit flexible
            coordinate_type ten = 10.0;
            coordinate_type zero_seven = 0.7;

            coordinate_type max = ten * geometry::math::abs(buffer_distance);

            if (length > max)
            {

                coordinate_type prop = zero_seven * buffer_distance;
                prop /= length;
                set<0>(p, get<0>(vertex) + dx * prop);
                set<1>(p, get<1>(vertex) + dy * prop);

#ifdef BOOST_GEOMETRY_DEBUG_BUFFER
                std::cout << length << std::endl;
#endif
            }

            range_out.push_back(perp1);
            range_out.push_back(p);
            range_out.push_back(perp2);
        }

    }
};

template
<
    typename PointIn,
    typename PointOut
>
struct join_bevel
{
    typedef typename coordinate_type<PointIn>::type coordinate_type;

    template <typename RangeOut>
    inline void apply(PointIn const& ip, PointIn const& vertex,
                PointIn const& perp1, PointIn const& perp2,
                coordinate_type const& buffer_distance,
                RangeOut& range_out) const
    {
    }
};

template
<
    typename PointIn,
    typename PointOut
>
struct join_round
{
    inline join_round(int max_level = 4)
        : m_max_level(max_level)
    {}

    typedef typename strategy::side::services::default_strategy<typename cs_tag<PointIn>::type>::type side;
    typedef typename coordinate_type<PointOut>::type coordinate_type;

    typedef typename geometry::select_most_precise
        <
            typename geometry::select_most_precise
                <
                    typename geometry::coordinate_type<PointIn>::type,
                    typename geometry::coordinate_type<PointOut>::type
                >::type,
            double
        >::type promoted_type;

    int m_max_level;

#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
    template <typename RangeOut>
    inline void mid_points(PointIn const& vertex,
                PointIn const& p1, PointIn const& p2,
                coordinate_type const& buffer_distance,
                RangeOut& range_out,
                int level = 1) const
    {
        // Generate 'vectors'
        coordinate_type vp1_x = get<0>(p1) - get<0>(vertex);
        coordinate_type vp1_y = get<1>(p1) - get<1>(vertex);

        coordinate_type vp2_x = (get<0>(p2) - get<0>(vertex));
        coordinate_type vp2_y = (get<1>(p2) - get<1>(vertex));

        // Average them to generate vector in between
        coordinate_type two = 2;
        coordinate_type v_x = (vp1_x + vp2_x) / two;
        coordinate_type v_y = (vp1_y + vp2_y) / two;

        coordinate_type length2 = sqrt(v_x * v_x + v_y * v_y);

        coordinate_type prop = buffer_distance / length2;

        PointIn mid_point;
        set<0>(mid_point, get<0>(vertex) + v_x * prop);
        set<1>(mid_point, get<1>(vertex) + v_y * prop);

        if (level < m_max_level)
        {
            mid_points(vertex, p1, mid_point, buffer_distance, range_out, level + 1);
        }
        range_out.push_back(mid_point);
        if (level < m_max_level)
        {
            mid_points(vertex, mid_point, p2, buffer_distance, range_out, level + 1);
        }
    }
#endif

    template <typename RangeOut>
    inline void generate_points(PointIn const& vertex,
                PointIn const& perp1, PointIn const& perp2,
                promoted_type const& buffer_distance,
                RangeOut& range_out) const
    {
        promoted_type dx1 = get<0>(perp1) - get<0>(vertex);
        promoted_type dy1 = get<1>(perp1) - get<1>(vertex);
        promoted_type dx2 = get<0>(perp2) - get<0>(vertex);
        promoted_type dy2 = get<1>(perp2) - get<1>(vertex);

        dx1 /= buffer_distance;
        dy1 /= buffer_distance;
        dx2 /= buffer_distance;
        dy2 /= buffer_distance;

        promoted_type angle_diff = acos(dx1 * dx2 + dy1 * dy2);

        // Default might be 100 steps for a full circle (2 pi)
        promoted_type const steps_per_circle = 100.0;
		promoted_type two = 2.0;
        int n = boost::numeric_cast<int>(steps_per_circle * angle_diff
                    / (two * geometry::math::pi<promoted_type>()));

		if (n > 1000)
		{
			std::cout << dx1 << ", " << dy1 << " .. " << dx2 << ", " << dy2 << std::endl;
			std::cout << angle_diff << " -> " << n << std::endl;
			n = 1000;
		}
		else if (n <= 1)
		{
			return;
		}

        promoted_type const angle1 = atan2(dy1, dx1);
        promoted_type diff = angle_diff / promoted_type(n);
        promoted_type a = angle1 - diff;

        for (int i = 0; i < n - 1; i++, a -= diff)
        {
            PointIn p;
            set<0>(p, get<0>(vertex) + buffer_distance * cos(a));
            set<1>(p, get<1>(vertex) + buffer_distance * sin(a));
            range_out.push_back(p);
        }
    }

    template <typename RangeOut>
    inline void apply(PointIn const& ip, PointIn const& vertex,
                PointIn const& perp1, PointIn const& perp2,
                coordinate_type const& buffer_distance,
                RangeOut& range_out) const
    {
		if (geometry::equals(perp1, perp2))
		{
			//std::cout << "Corner for equal points " << geometry::wkt(ip) << " " << geometry::wkt(perp1) << std::endl;
			return;
		}

        coordinate_type zero = 0;
        int signum = buffer_distance > zero ? 1
                   : buffer_distance < zero ? -1
                   : 0;

        if (side::apply(perp1, ip, perp2) == signum)
        {
        }
        else
        {
            // Generate 'vectors'
            coordinate_type vix = (get<0>(ip) - get<0>(vertex));
            coordinate_type viy = (get<1>(ip) - get<1>(vertex));

            coordinate_type length_i = sqrt(vix * vix + viy * viy);

            coordinate_type const bd = geometry::math::abs(buffer_distance);
            coordinate_type prop = bd / length_i;

            PointIn bp;
            set<0>(bp, get<0>(vertex) + vix * prop);
            set<1>(bp, get<1>(vertex) + viy * prop);

            range_out.push_back(perp1);

#ifdef BOOST_GEOMETRY_BUFFER_USE_MIDPOINTS
            if (m_max_level <= 1)
            {
                if (m_max_level == 1)
                {
                    range_out.push_back(bp);
                }
            }
            else
            {
                mid_points(vertex, perp1, bp, bd, range_out);
                range_out.push_back(bp);
                mid_points(vertex, bp, perp2, bd, range_out);
            }
#else
            generate_points(vertex, perp1, perp2, bd, range_out);
#endif

            range_out.push_back(perp2);
        }
    }
};

template
<
    typename CoordinateType
>
class distance_assymetric
{
public :
    distance_assymetric(CoordinateType const& left,
                CoordinateType const& right)
        : m_left(left)
        , m_right(right)
    {}

    template <typename Point>
    inline CoordinateType apply(Point const& , Point const& ,
                buffer_side_selector side)  const
    {
        return side == buffer_side_left ? m_left : m_right;
    }

    inline int factor() const
    {
        return m_left < 0 ? -1 : 1;
    }

private :
    CoordinateType m_left;
    CoordinateType m_right;
};

}} // namespace strategy::buffer

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_STRATEGIES_BUFFER_HPP


#ifndef PYTHONIC_INCLUDE_NUMPY_RADIANS_HPP
#define PYTHONIC_INCLUDE_NUMPY_RADIANS_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"
#include <boost/simd/function/inrad.hpp>

namespace pythonic
{

  namespace numpy
  {
#define NUMPY_NARY_FUNC_NAME radians
#define NUMPY_NARY_FUNC_SYM boost::simd::inrad
#include "pythonic/include/types/numpy_nary_expr.hpp"
  }
}

#endif


/*
@copyright Louis Dionne 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_TEST_LAWS_ORDERABLE_HPP
#define BOOST_HANA_TEST_LAWS_ORDERABLE_HPP

#include <boost/hana/assert.hpp>
#include <boost/hana/bool.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/lazy.hpp>
#include <boost/hana/concept/orderable.hpp>

#include <laws/base.hpp>

namespace boost { namespace hana { namespace test {
    template <typename T, typename = when<true>>
    struct TestOrderable : TestOrderable<T, laws> {
        using TestOrderable<T, laws>::TestOrderable;
    };

    template <typename T>
    struct TestOrderable<T, laws> {
        template <typename Xs>
        TestOrderable(Xs xs) {
            hana::for_each(xs, [](auto x) {
                static_assert(Orderable<decltype(x)>::value, "");
            });

            foreach2(xs, [](auto a, auto b) {

                // antisymmetry
                BOOST_HANA_CHECK(
                    hana::and_(hana::less_equal(a, b), hana::less_equal(b, a))
                        ^implies^ hana::equal(a, b)
                );

                // totality
                BOOST_HANA_CHECK(
                    hana::or_(hana::less_equal(a, b), hana::less_equal(b, a))
                );

                // other methods in terms of `less_equal`
                BOOST_HANA_CHECK(
                    hana::less(a, b) ^iff^ hana::not_(hana::less_equal(b, a))
                );

                BOOST_HANA_CHECK(
                    hana::greater(a, b) ^iff^ hana::less(b, a)
                );

                BOOST_HANA_CHECK(
                    hana::greater_equal(a, b) ^iff^ hana::not_(hana::less(a, b))
                );

                // less.than & al.
                BOOST_HANA_CHECK(less.than(a)(b) ^iff^ hana::less(b, a));
                BOOST_HANA_CHECK(greater.than(a)(b) ^iff^ hana::greater(b, a));
                BOOST_HANA_CHECK(less_equal.than(a)(b) ^iff^ hana::less_equal(b, a));
                BOOST_HANA_CHECK(greater_equal.than(a)(b) ^iff^ hana::greater_equal(b, a));

                // ordering
                _injection<0> f{}; // test::_injection is also monotonic
                BOOST_HANA_CHECK(
                    hana::ordering(f)(a, b) ^iff^ hana::less(f(a), f(b))
                );
            });

            // transitivity
            foreach3(xs, [](auto a, auto b, auto c) {
                BOOST_HANA_CHECK(
                    hana::and_(hana::less_equal(a, b), hana::less_equal(b, c))
                        ^implies^ hana::less_equal(a, c)
                );
            });
        }
    };

    template <typename C>
    struct TestOrderable<C, when<Constant<C>::value>>
        : TestOrderable<C, laws>
    {
        template <typename Xs>
        TestOrderable(Xs xs) : TestOrderable<C, laws>{xs} {
            foreach2(xs, [](auto a, auto b) {

                BOOST_HANA_CHECK(
                    hana::value(hana::less(a, b)) ^iff^
                        hana::less(hana::value(a), hana::value(b))
                );

            });
        }
    };

    template <typename P>
    struct TestOrderable<P, when<Product<P>::value>>
        : TestOrderable<P, laws>
    {
        template <typename Products>
        TestOrderable(Products products)
            : TestOrderable<P, laws>{products}
        {
            foreach2(products, [](auto x, auto y) {
                BOOST_HANA_CHECK(
                    hana::less(x, y) ^iff^
                    hana::or_(
                        hana::less(hana::first(x), hana::first(y)),
                        hana::and_(
                            hana::equal(hana::first(x), hana::first(y)),
                            hana::less(hana::second(x), hana::second(y))
                        )
                    )
                );
            });
        }
    };

    template <typename S>
    struct TestOrderable<S, when<Sequence<S>::value>>
        : TestOrderable<S, laws>
    {
        struct invalid { };

        template <typename Xs>
        TestOrderable(Xs xs) : TestOrderable<S, laws>{xs} {
            constexpr auto list = make<S>;

            //////////////////////////////////////////////////////////////////
            // less
            //////////////////////////////////////////////////////////////////
            BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::less(
                list(),
                list()
            )));

            BOOST_HANA_CONSTANT_CHECK(hana::less(
                list(),
                list(invalid{})
            ));
            BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::less(
                list(invalid{}),
                list()
            )));
            BOOST_HANA_CONSTANT_CHECK(hana::less(
                list(ct_ord<0>{}),
                list(ct_ord<7>{})
            ));
            BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::less(
                list(ct_ord<1>{}),
                list(ct_ord<0>{})
            )));

            BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::less(
                list(ct_ord<0>{}, ct_ord<1>{}, ct_ord<8>{}),
                list(ct_ord<0>{}, ct_ord<1>{})
            )));

            BOOST_HANA_CONSTANT_CHECK(hana::less(
                list(ct_ord<0>{}, ct_ord<0>{}, ct_ord<8>{}),
                list(ct_ord<0>{}, ct_ord<1>{})
            ));
        }
    };
}}} // end namespace boost::hana::test

#endif // !BOOST_HANA_TEST_LAWS_ORDERABLE_HPP


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

    @copyright 2016 NumScale SAS

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

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

  /*!
    @ingroup group-predicates

    This function object returns @ref True if x is not less or equal to @ref Zero else returns @ref False.

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

    @par Note

     Using `is_nlez(x)` is similar to: `!(x <= 0)`

    @par Example:

      @snippet is_nlez.cpp is_nlez

    @par Possible output:

      @snippet is_nlez.txt is_nlez

  **/
  as_logical_t<Value> is_nlez(Value const& x);
} }
#endif

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

#endif


// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#include "stdafx.h"

#include <boost/test/unit_test.hpp>
#include "Common/boost-taef.h"

namespace ReplicationUnitTest
{
    using namespace Common;
    using namespace std;
    using namespace Reliability::ReplicationComponent;

    static StringLiteral const PublicTestSource("TESTDecayAverage");

    class TestDecayAverage
    {
    protected:
        TestDecayAverage() { BOOST_REQUIRE(Setup()); }
        TEST_CLASS_SETUP(Setup)
    };

    BOOST_FIXTURE_TEST_SUITE(TestDecayAverageSuite, TestDecayAverage)

        BOOST_AUTO_TEST_CASE(NoDecay_Basic)
    {
        DecayAverage avg(0.0, TimeSpan::FromTicks(1));
        avg.Update(TimeSpan::FromSeconds(10.0));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromSeconds(10));
        avg.Update(TimeSpan::FromSeconds(20.0));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromSeconds(20));
    }

    BOOST_AUTO_TEST_CASE(NoDecay_Overflow)
    {
        DecayAverage avg(0.0, TimeSpan::FromTicks(1));
        avg.Update(TimeSpan::FromMinutes(numeric_limits<double>::max()));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromMilliseconds(std::numeric_limits<uint>::max()));
        avg.Update(TimeSpan::FromMinutes(numeric_limits<double>::max()));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromMilliseconds(std::numeric_limits<uint>::max()));
    }

    BOOST_AUTO_TEST_CASE(SimpleAverage)
    {
        DecayAverage avg(1.0, TimeSpan::FromTicks(9999));
        avg.Update(TimeSpan::FromSeconds(10));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromSeconds(10));
        avg.Update(TimeSpan::FromSeconds(1));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromSeconds(5.5));
        avg.Update(TimeSpan::FromSeconds(100));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromSeconds(37));
    }

    BOOST_AUTO_TEST_CASE(SimpleAverageOverflow)
    {
        DecayAverage avg(1.0, TimeSpan::FromTicks(1));
        Sleep(1000);
        avg.Update(TimeSpan::FromMinutes(numeric_limits<double>::max()));
        VERIFY_ARE_EQUAL2(avg.Value, TimeSpan::FromMilliseconds(std::numeric_limits<uint>::max()));
    }

    BOOST_AUTO_TEST_CASE(SimpleStandardDeviation)
    {
        StandardDeviation sd;
        sd.Add(TimeSpan::FromSeconds(60));
        sd.Add(TimeSpan::FromSeconds(60));
        sd.Add(TimeSpan::FromSeconds(60));

        VERIFY_ARE_EQUAL2(sd.Average, TimeSpan::FromSeconds(60));
        VERIFY_ARE_EQUAL2(sd.StdDev, TimeSpan::FromSeconds(0));

        sd.Clear();
        VERIFY_ARE_EQUAL2(sd.Average, TimeSpan::Zero);
        VERIFY_ARE_EQUAL2(sd.StdDev, TimeSpan::FromSeconds(0));

        sd.Add(TimeSpan::FromSeconds(4));
        sd.Add(TimeSpan::FromSeconds(4));
        sd.Add(TimeSpan::FromSeconds(9));
        sd.Add(TimeSpan::FromSeconds(9));
        VERIFY_ARE_EQUAL2(sd.Average, TimeSpan::FromSeconds(6.5));
        VERIFY_ARE_EQUAL2(sd.StdDev, TimeSpan::FromSeconds(2.5));
    }

    BOOST_AUTO_TEST_CASE(OverflowStandardDeviation)
    {
        StandardDeviation sd;
        // NOTE - Currently the max TimeSpan value does not exceed max value accepted by the Add() method and hence this test case is moot
        // Keeping in the test in case that ever changes and we fail this variation that time
        sd.Add(TimeSpan::MaxValue);
        sd.Add(TimeSpan::MaxValue);
        sd.Add(TimeSpan::Zero);
        sd.Add(TimeSpan::Zero);
        VERIFY_ARE_EQUAL2(sd.Average.TotalMilliseconds(), (TimeSpan::MaxValue/2).TotalMilliseconds());
        VERIFY_ARE_EQUAL2(sd.StdDev > TimeSpan::Zero, true);
    }

    BOOST_AUTO_TEST_SUITE_END()

    bool TestDecayAverage::Setup()
    {
        return true;
    }
}


#if __GNUG__ > 6
#pragma GCC diagnostic ignored "-Wint-in-bool-context"
#endif

#include "loguru.hpp"

#include <iostream>
#include <boost/test/included/unit_test.hpp>

#include "operators.h"

using namespace boost::unit_test;

#define BOOST_TEST_MODULE op_module

BOOST_AUTO_TEST_SUITE( op_add )
BOOST_AUTO_TEST_CASE( test_add_1 )
{
    LOG_F(INFO, "- test_add_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1,9,10,3,2,3,11,0,99,30,40,50};

    op.add(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 4);
    BOOST_CHECK(p[3] == 70);
}

BOOST_AUTO_TEST_CASE( test_add_2 )
{
    LOG_F(INFO, "- test_add_2 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1001,9,10,3,2,3,11,0,99,30,40,50};

    op.add(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 4);
    BOOST_CHECK(p[3] == 40);
}

BOOST_AUTO_TEST_CASE( test_add_3 )
{
    LOG_F(INFO, "- test_add_3 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{101,9,10,3,2,3,11,0,99,30,40,50};

    op.add(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 4);
    BOOST_CHECK(p[3] == 49);
}

BOOST_AUTO_TEST_CASE( test_add_4 )
{
    LOG_F(INFO, "- test_add_4 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1101,9,10,3,2,3,11,0,99,30,40,50};

    op.add(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 4);
    BOOST_CHECK(p[3] == 19);
}

BOOST_AUTO_TEST_CASE( test_add_5 )
{
    LOG_F(INFO, "- test_add_5 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 1;
    vector_big_int p{201,9,10,3,2,3,11,0,99,30,40,50};

    op.add(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 4);
    BOOST_CHECK(p[3] == 80);
}
BOOST_AUTO_TEST_SUITE_END() // op_add

BOOST_AUTO_TEST_SUITE( op_mul )
BOOST_AUTO_TEST_CASE( test_mul_1 )
{
    LOG_F(INFO, "- test_mul_1 ---------------------------");
    Operators op;
    int pc = 4;
    int relativeBase = 0;
    vector_big_int p{1,9,10,70,2,3,11,0,99,30,40,50};

    op.mul(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 8);
    BOOST_CHECK(p[0] == 3500);
}

BOOST_AUTO_TEST_CASE( test_mul_2 )
{
    LOG_F(INFO, "- test_mul_2 ---------------------------");
    Operators op;
    int pc = 4;
    int relativeBase = 0;
    vector_big_int p{1,9,10,70,102,3,11,0,99,30,40,50};

    op.mul(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d, relativeBase = %d", pc, relativeBase);
    LOG_F(INFO, "p[0] = %d, p[3] = %d", p[0], p[3]);

    BOOST_CHECK(pc == 8);
    BOOST_CHECK(p[0] == 150);
}
BOOST_AUTO_TEST_SUITE_END() // op_mul

BOOST_AUTO_TEST_SUITE( op_inp )
BOOST_AUTO_TEST_CASE( test_inp_1 )
{
    LOG_F(INFO, "- test_mul_3 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{3,3,99,-1};

    op.inp(p, pc, relativeBase,
        [](std::string s) -> int {
            return 8;
        }
    );

    BOOST_CHECK(p[3] == 8);
}
BOOST_AUTO_TEST_SUITE_END() // op_inp

BOOST_AUTO_TEST_SUITE( op_prt )
BOOST_AUTO_TEST_CASE( test_prt_1 )
{
    LOG_F(INFO, "- test_prt_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{4,3,99,42};

    op.prt(p, pc, relativeBase,
        [](int x) -> void {
            BOOST_CHECK(x == 42);
        }
    );
}
BOOST_AUTO_TEST_SUITE_END() // op_prt

BOOST_AUTO_TEST_SUITE( op_jmp )
BOOST_AUTO_TEST_CASE( test_jmp_1 )
{
    LOG_F(INFO, "- test_jmp_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1105,1,33};

    op.jmp(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d", pc);

    BOOST_CHECK(pc == 33);
}

BOOST_AUTO_TEST_CASE( test_jmp_2 )
{
    LOG_F(INFO, "- test_jmp_2 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1105,0,33};

    op.jmp(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d", pc);

    BOOST_CHECK(pc == 3);
}
BOOST_AUTO_TEST_SUITE_END() // op_jmp

BOOST_AUTO_TEST_SUITE( op_jmf )
BOOST_AUTO_TEST_CASE( test_jmf_1 )
{
    LOG_F(INFO, "- test_jmf_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1106,1,33};

    op.jmf(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d", pc);

    BOOST_CHECK(pc == 3);
}

BOOST_AUTO_TEST_CASE( test_jmf_2 )
{
    LOG_F(INFO, "- test_jmf_2 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{1106,0,33};

    op.jmf(p, pc, relativeBase);

    LOG_F(INFO, "pc = %d", pc);

    BOOST_CHECK(pc == 33);
}
BOOST_AUTO_TEST_SUITE_END() // op_jmf

BOOST_AUTO_TEST_SUITE( op_ltn )
BOOST_AUTO_TEST_CASE( test_ltn_1 )
{
    LOG_F(INFO, "- test_ltn_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{7,5,6,7,99,1,2,0};

    op.ltn(p, pc, relativeBase);

    BOOST_CHECK(p[7] == 1);
}

BOOST_AUTO_TEST_CASE( test_ltn_2 )
{
    LOG_F(INFO, "- test_ltn_2 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{7,5,6,7,99,2,1,0};

    op.ltn(p, pc, relativeBase);

    BOOST_CHECK(p[7] == 0);
}
BOOST_AUTO_TEST_SUITE_END() // op_ltn

BOOST_AUTO_TEST_SUITE( op_eql )
BOOST_AUTO_TEST_CASE( test_eql_1 )
{
    LOG_F(INFO, "- test_eql_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{8,5,6,7,99,1,2,0};

    op.eql(p, pc, relativeBase);

    BOOST_CHECK(p[7] == 0);
}

BOOST_AUTO_TEST_CASE( test_eql_2 )
{
    LOG_F(INFO, "- test_eql_2 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{8,5,6,7,99,1,1,0};

    op.eql(p, pc, relativeBase);

    BOOST_CHECK(p[7] == 1);
}
BOOST_AUTO_TEST_SUITE_END() // op_eql
BOOST_AUTO_TEST_SUITE( op_rel )
BOOST_AUTO_TEST_CASE( test_rel_1 )
{
    LOG_F(INFO, "- test_rel_1 ---------------------------");
    Operators op;
    int pc = 0;
    int relativeBase = 0;
    vector_big_int p{109,5,99};

    op.rel(p, pc, relativeBase);
    LOG_F(INFO, "relativeBase = %d", relativeBase);

    BOOST_CHECK(relativeBase == 5);
}
BOOST_AUTO_TEST_SUITE_END() // op_rel

//____________________________________________________________________________//

test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
    #ifdef UNIT_TEST_VERBOSITY
        loguru::g_stderr_verbosity = UNIT_TEST_VERBOSITY;
    #else
        loguru::g_stderr_verbosity = loguru::Verbosity_9;
    #endif

    loguru::set_thread_name("Test Op");

    return 0;
}

//____________________________________________________________________________//


//---------------------------------------------------------------------------//
// Copyright (c) 2013 Muhammad Junaid Muzammil <mjunaidmuzammil@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://kylelutz.github.com/compute for more information.
//---------------------------------------------------------------------------//

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

#include <boost/compute/random/threefry_engine.hpp>
#include <boost/compute/container/vector.hpp>

#include "check_macros.hpp"
#include "context_setup.hpp"

BOOST_AUTO_TEST_CASE(generate_uint)
{

    using boost::compute::uint_;

    boost::compute::threefry_engine<> rng(queue);

    boost::compute::vector<uint_> vector_ctr(20, context);

    uint32_t ctr[20];
    for(int i = 0; i < 10; i++) {
        ctr[i*2] = i;
        ctr[i*2+1] = 0;
    }

    boost::compute::copy(ctr, ctr+20, vector_ctr.begin(), queue);

    rng.generate(vector_ctr.begin(), vector_ctr.end(), queue);
    CHECK_RANGE_EQUAL(
        uint_, 20, vector_ctr,
        (uint_(0x6b200159),
         uint_(0x99ba4efe),
         uint_(0x508efb2c),
         uint_(0xc0de3f32),
         uint_(0x64a626ec),
         uint_(0xfc15e573),
         uint_(0xb8abc4d1),
         uint_(0x537eb86),
         uint_(0xac6dc2bb),
         uint_(0xa7adb3c3),
         uint_(0x5641e094),
         uint_(0xe4ab4fd),
         uint_(0xa53c1ce9),
         uint_(0xabcf1dba),
         uint_(0x2677a25a),
         uint_(0x76cf5efc),
         uint_(0x2d08247f),
         uint_(0x815480f1),
         uint_(0x2d1fa53a),
         uint_(0xdfe8514c))
    );
}

BOOST_AUTO_TEST_SUITE_END()


#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>

#include <boost/format.hpp>
#include "path_optimization.h"

using namespace planner;
using namespace std;

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

  NonHolonomicPath::State lc_start(0.0, 0.0, 0.0, 0.0);
  NonHolonomicPath::State lc_end(50.0, 3.7, 0.0, 0.0);

  NonHolonomicPath path;
  const bool success = path.optimizePath(lc_start, lc_end);

  if (!success) {
    boost::format state_format("%1% %2% %3% %4%\n");
    std::string error_msg("Path optimization failed.\n");
    error_msg += "lc start state (x y theta kappa): " + (
        state_format % lc_start.x
                     % lc_start.y
                     % lc_start.theta
                     % lc_start.kappa).str();
    error_msg += "lc end state (x y theta kappa): " + (
        state_format % lc_end.x
                     % lc_end.y
                     % lc_end.theta
                     % lc_end.kappa).str();
    throw std::runtime_error(error_msg);
    return -1;
  }

  boost::format waypoint_format("%1% %2% %3% %4% %5%\n");
  std::string path_msg;
  for (double s = 0.0; s <= path.sf; s+=0.05) {
    NonHolonomicPath::State state = path.evaluate(lc_start, s);
    path_msg += (waypoint_format % s
                                 % state.x
                                 % state.y
                                 % state.theta
                                 % state.kappa).str();
  }

  ofstream fout;
  fout.open("left_lane_change_path");
  fout << path_msg;
  fout.close();

  return 0;
}