//
// Copyright (c) 2016 CNRS
//

#include "pinocchio/multibody/joint/joint-composite.hpp"
#include "pinocchio/algorithm/joint-configuration.hpp"
#include "pinocchio/algorithm/kinematics.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/utility/binary.hpp>

using namespace pinocchio;
using namespace Eigen;

template<typename JointModel>
void test_joint_methods(const JointModelBase<JointModel> & jmodel, JointModelComposite & jmodel_composite);

template<typename JointModel>
void test_joint_methods(const JointModelBase<JointModel> & jmodel)
{
  JointModelComposite jmodel_composite(jmodel);
  test_joint_methods(jmodel,jmodel_composite);
}

template<typename JointModel>
void test_joint_methods(const JointModelBase<JointModel> & jmodel, JointModelComposite & jmodel_composite)
{
  typedef typename JointModelBase<JointModel>::JointDataDerived JointData;

  JointData jdata = jmodel.createData();
  JointDataComposite jdata_composite = jmodel_composite.createData();

  jmodel_composite.setIndexes(jmodel.id(), jmodel.idx_q(), jmodel.idx_v());

  typedef typename JointModel::ConfigVector_t ConfigVector_t;
  typedef typename JointModel::TangentVector_t TangentVector_t;
  typedef typename LieGroup<JointModel>::type LieGroupType;

  ConfigVector_t ql(ConfigVector_t::Constant(jmodel.nq(),-M_PI));
  ConfigVector_t qu(ConfigVector_t::Constant(jmodel.nq(),M_PI));
  ConfigVector_t q = LieGroupType().randomConfiguration(ql,qu);

  BOOST_CHECK(jmodel.nv() == jmodel_composite.nv());
  BOOST_CHECK(jmodel.nq() == jmodel_composite.nq());

  jmodel.calc(jdata,q);
  jmodel_composite.calc(jdata_composite,q);

  BOOST_CHECK(jdata_composite.M.isApprox((SE3)jdata.M));
  BOOST_CHECK(jdata_composite.S.matrix().isApprox(jdata.S.matrix()));

  q = LieGroupType().randomConfiguration(ql,qu);
  TangentVector_t v = TangentVector_t::Random(jmodel.nv());
  jmodel.calc(jdata,q,v);
  jmodel_composite.calc(jdata_composite,q,v);

  BOOST_CHECK(jdata_composite.M.isApprox((SE3)jdata.M));
  BOOST_CHECK(jdata_composite.S.matrix().isApprox(jdata.S.matrix()));
  BOOST_CHECK(jdata_composite.v.isApprox((Motion)jdata.v));
  BOOST_CHECK(jdata_composite.c.isApprox((Motion)jdata.c));

  // TODO: Not yet checked
//  {
//    VectorXd q1(jmodel.random());
//    jmodel.normalize(q1);
//    VectorXd q2(jmodel.random());
//    jmodel.normalize(q2);
//    VectorXd v(VectorXd::Random(jmodel.nv()));
//
//    BOOST_CHECK(jmodel_composite.integrate(q1,v).isApprox(jmodel.integrate(q1,v)));
//
//    TangentVector_t v1 = jmodel_composite.difference(q1,q2);
//    TangentVector_t v2 = jmodel.difference(q1,q2);
//
//    BOOST_CHECK(v1.isApprox(v2));
//
//    const double alpha = 0.2;
//    BOOST_CHECK(jmodel_composite.interpolate(q1,q2,alpha).isApprox(jmodel.interpolate(q1,q2,alpha)));
//    BOOST_CHECK(math::fabs(jmodel_composite.distance(q1,q2)-jmodel.distance(q1,q2))<= NumTraits<double>::dummy_precision());
//  }

  Inertia::Matrix6 I1(Inertia::Random().matrix());
  Inertia::Matrix6 I2 = I1;

  jmodel.calc_aba(jdata,I1,true);
  jmodel_composite.calc_aba(jdata_composite,I2,true);

  double prec = 1e-10; // higher tolerance to errors due to possible numerical imprecisions

  BOOST_CHECK(jdata.U.isApprox(jdata_composite.U,prec));
  BOOST_CHECK(jdata.Dinv.isApprox(jdata_composite.Dinv,prec));
  BOOST_CHECK(jdata.UDinv.isApprox(jdata_composite.UDinv,prec));

  // Checking the inertia was correctly updated
  // We use isApprox as usual, except for the freeflyer,
  // where the correct result is exacly zero and isApprox would fail.
  // Only for this single case, we use the infinity norm of the difference
  if(jmodel.shortname() == "JointModelFreeFlyer")
    BOOST_CHECK((I1-I2).lpNorm<Eigen::Infinity>() < prec);
  else
    BOOST_CHECK(I1.isApprox(I2,prec));
}

struct TestJointComposite{

  template <typename JointModel>
  void operator()(const JointModelBase<JointModel> &) const
  {
    JointModel jmodel;
    jmodel.setIndexes(0,0,0);

    test_joint_methods(jmodel);
  }

//  void operator()(const JointModelBase<JointModelComposite> &) const
//  {
//    JointModelComposite jmodel_composite;
//    jmodel_composite.addJoint(pinocchio::JointModelRX());
//    jmodel_composite.addJoint(pinocchio::JointModelRY());
//    jmodel_composite.setIndexes(0,0,0);
//
//    test_joint_methods(jmodel_composite);
//  }

  void operator()(const JointModelBase<JointModelRevoluteUnaligned> &) const
  {
    JointModelRevoluteUnaligned jmodel(1.5, 1., 0.);
    jmodel.setIndexes(0,0,0);

    test_joint_methods(jmodel);
  }

  void operator()(const JointModelBase<JointModelPrismaticUnaligned> &) const
  {
    JointModelPrismaticUnaligned jmodel(1.5, 1., 0.);
    jmodel.setIndexes(0,0,0);

    test_joint_methods(jmodel);
  }

};

BOOST_AUTO_TEST_SUITE ( BOOST_TEST_MODULE )

BOOST_AUTO_TEST_CASE(test_basic)
{
  typedef boost::variant< JointModelRX, JointModelRY, JointModelRZ, JointModelRevoluteUnaligned
  , JointModelSpherical, JointModelSphericalZYX
  , JointModelPX, JointModelPY, JointModelPZ
  , JointModelPrismaticUnaligned
  , JointModelFreeFlyer
  , JointModelPlanar
  , JointModelTranslation
  , JointModelRUBX, JointModelRUBY, JointModelRUBZ
  > Variant;

  boost::mpl::for_each<Variant::types>(TestJointComposite());
}

BOOST_AUTO_TEST_CASE(chain)
{
  JointModelComposite jmodel_composite;
  jmodel_composite.addJoint(JointModelRZ()).addJoint(JointModelRY(),SE3::Random()).addJoint(JointModelRX());
  BOOST_CHECK_MESSAGE( jmodel_composite.nq() == 3, "Chain did not work");
  BOOST_CHECK_MESSAGE( jmodel_composite.nv() == 3, "Chain did not work");
  BOOST_CHECK_MESSAGE( jmodel_composite.njoints == 3, "Chain did not work");
}

BOOST_AUTO_TEST_CASE(vsZYX)
{
  JointModelSphericalZYX jmodel_spherical;
  jmodel_spherical.setIndexes(0,0,0);

  JointModelComposite jmodel_composite((JointModelRZ()));
  jmodel_composite.addJoint(JointModelRY());
  jmodel_composite.addJoint(JointModelRX());

  test_joint_methods(jmodel_spherical, jmodel_composite);
}

BOOST_AUTO_TEST_CASE(vsTranslation)
{
  JointModelTranslation jmodel_translation;
  jmodel_translation.setIndexes(0,0,0);

  JointModelComposite jmodel_composite((JointModelPX()));
  jmodel_composite.addJoint(JointModelPY());
  jmodel_composite.addJoint(JointModelPZ());

  test_joint_methods(jmodel_translation, jmodel_composite);
}

BOOST_AUTO_TEST_CASE (test_recursive_variant)
{
  /// Create joint composite with two joints,
  JointModelComposite jmodel_composite_two_rx((JointModelRX()));
  jmodel_composite_two_rx.addJoint(JointModelRY());

  /// Create Joint composite with three joints, and add a composite in it, to test the recursive_wrapper
  JointModelComposite jmodel_composite_recursive((JointModelFreeFlyer()));
  jmodel_composite_recursive.addJoint(JointModelPlanar());
  jmodel_composite_recursive.addJoint(jmodel_composite_two_rx);
}

BOOST_AUTO_TEST_CASE(test_copy)
{
  JointModelComposite jmodel_composite_planar((JointModelPX()));
  jmodel_composite_planar.addJoint(JointModelPY());
  jmodel_composite_planar.addJoint(JointModelRZ());
  jmodel_composite_planar.setIndexes(0,0,0);

  JointDataComposite jdata_composite_planar = jmodel_composite_planar.createData();

  VectorXd q1(VectorXd::Random(3));
  VectorXd q1_dot(VectorXd::Random(3));

  JointModelComposite model_copy = jmodel_composite_planar;
  JointDataComposite data_copy = model_copy.createData();

  BOOST_CHECK_MESSAGE( model_copy.nq() == jmodel_composite_planar.nq(), "Test Copy Composite, nq are differents");
  BOOST_CHECK_MESSAGE( model_copy.nv() == jmodel_composite_planar.nv(), "Test Copy Composite, nv are differents");

  jmodel_composite_planar.calc(jdata_composite_planar,q1, q1_dot);
  model_copy.calc(data_copy,q1, q1_dot);

}

BOOST_AUTO_TEST_CASE(test_kinematics)
{
  Model model;
  JointModelComposite jmodel_composite;

  SE3 config=SE3::Random();
  JointIndex parent=0;

  for(int i=0; i<10; i++)
  {
    parent = model.addJoint(parent, JointModelRX(), config, "joint");
    jmodel_composite.addJoint(JointModelRX(),config);

    config.setRandom();
  }

  Data data(model);

  Model model_c;
  model_c.addJoint(0,jmodel_composite,SE3::Identity(),"joint");

  Data data_c(model_c);

  BOOST_CHECK(model.nv == model_c.nv);
  BOOST_CHECK(model.nq == model_c.nq);

  VectorXd q(VectorXd::Random(model.nv));
  forwardKinematics(model,data,q);
  forwardKinematics(model_c,data_c,q);

  BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back()));

  q.setRandom(model.nq);
  VectorXd v(VectorXd::Random(model.nv));
  forwardKinematics(model,data,q,v);
  forwardKinematics(model_c,data_c,q,v);

  BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back()));
  BOOST_CHECK(data.v.back().isApprox(data_c.v.back()));

  q.setRandom(model.nq);
  v.setRandom(model.nv);
  VectorXd a(VectorXd::Random(model.nv));
  forwardKinematics(model,data,q,v,a);
  forwardKinematics(model_c,data_c,q,v,a);

  BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back()));
  BOOST_CHECK(data.v.back().isApprox(data_c.v.back()));
  BOOST_CHECK(data.a.back().isApprox(data_c.a.back()));
}

BOOST_AUTO_TEST_SUITE_END ()


/*
Copyright 2009-2021 Nicolas Colombe

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.
*/

#pragma once

#include <math/mathexp.hpp>
#include <core/containers.hpp>
#include <math/vector2.hpp>
#include <math/segment.hpp>
#include <boost/container/flat_map.hpp>

namespace eXl
{
  struct PolyVertex
  {
    PolyVertex(Vector2i const& iPos, Vector2f const& iPosf)
      : position(iPos)
      , positionf(iPosf)
    {
    }

    Vector2f positionf;
    Vector2i position;
    int32_t firstEdge = -1;
  };

  struct PolyHalfEdge
  {
    uint32_t srcVtx;
    uint32_t dstVtx;
    uint32_t sibling;
    int32_t userId = -1;
    int32_t nextEdge = -1;
    Vector2f normDir;
    float length;
  };

  inline std::size_t hash_value(Vector2i const& iPt)
  {

    if (sizeof(Vector2i) == sizeof(std::size_t))
    {
      return reinterpret_cast<size_t const&>(iPt);
    }
    else
    {
      size_t seed = iPt.X();
      boost::hash_combine(seed, iPt.Y());

      return seed;
    }
  }

  struct EXL_MATH_API PolyMesh
  {
    Vector<PolyVertex> vertices;
    Vector<PolyHalfEdge> edges;

    // boost::container::flat_map<Vector2i, uint32_t, std::less<Vector2i>, eXl::Allocator<std::pair<Vector2i, uint32_t>>> pointMap;
    // Need a way to keep capacity.
    UnorderedMap<Vector2i, uint32_t> pointMap;

    // leftmost/bottom most point
    boost::optional<std::pair<Vector2i, uint32_t>> smallerPoint;

    void UpdateSmallerPoint(std::pair<Vector2i, uint32_t> const& iNewPoint);

    PolyHalfEdge const* GetNextIncomingEdge(uint32_t curVtx, PolyHalfEdge const* curEdge) const;

    bool FindInsertionPoint(uint32_t srcVtx, uint32_t dstVtx, uint32_t firstEdge, Vector2f const& iOutgoingDir, int32_t& prevInsertPt, int32_t& nextInsertPt) const;

    boost::optional<uint32_t> InsertEdge(Segmenti const& iSeg, Segmentf const& iFltSeg, int32_t edgeId = -1);

    void Clear();
  };
}


/*
Copyright 2008 Intel Corporation

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).
*/
#include <boost/polygon/polygon.hpp>
#include <cassert>
#include <list>
namespace gtl = boost::polygon;
using namespace boost::polygon::operators;

//first lets turn our polygon usage code into a generic
//function parameterized by polygon type
template <typename Polygon>
void test_polygon() {
  //lets construct a 10x10 rectangle shaped polygon
  typedef typename gtl::polygon_traits<Polygon>::point_type Point;
  Point pts[] = {gtl::construct<Point>(0, 0),
		 gtl::construct<Point>(10, 0),
		 gtl::construct<Point>(10, 10),
		 gtl::construct<Point>(0, 10) };
  Polygon poly;
  gtl::set_points(poly, pts, pts+4);

  //now lets see what we can do with this polygon
  assert(gtl::area(poly) == 100.0f);
  assert(gtl::contains(poly, gtl::construct<Point>(5, 5)));
  assert(!gtl::contains(poly, gtl::construct<Point>(15, 5)));
  gtl::rectangle_data<int> rect;
  assert(gtl::extents(rect, poly)); //get bounding box of poly
  assert(gtl::equivalence(rect, poly)); //hey, that's slick
  assert(gtl::winding(poly) == gtl::COUNTERCLOCKWISE);
  assert(gtl::perimeter(poly) == 40.0f);

  //add 5 to all coords of poly
  gtl::convolve(poly, gtl::construct<Point>(5, 5));
  //multiply all coords of poly by 2
  gtl::scale_up(poly, 2);
  gtl::set_points(rect, gtl::point_data<int>(10, 10),
		  gtl::point_data<int>(30, 30));
  assert(gtl::equivalence(poly, rect));
}

//Now lets declare our own polygon class
//Oops, we need a point class to support our polygon, lets borrow
//the CPoint example
struct CPoint {
  int x;
  int y;
};

//we have to get CPoint working with boost polygon to make our polygon
//that uses CPoint working with boost polygon
namespace boost { namespace polygon {
    template <>
    struct geometry_concept<CPoint> { typedef point_concept type; };
    template <>
    struct point_traits<CPoint> {
      typedef int coordinate_type;

      static inline coordinate_type get(const CPoint& point,
					orientation_2d orient) {
	if(orient == HORIZONTAL)
	  return point.x;
	return point.y;
      }
    };

    template <>
    struct point_mutable_traits<CPoint> {
      typedef int coordinate_type;

      static inline void set(CPoint& point, orientation_2d orient, int value) {
	if(orient == HORIZONTAL)
	  point.x = value;
	else
	  point.y = value;
      }
      static inline CPoint construct(int x_value, int y_value) {
	CPoint retval;
	retval.x = x_value;
	retval.y = y_value;
	return retval;
      }
    };
  } }

//I'm lazy and use the stl everywhere to avoid writing my own classes
//my toy polygon is a std::list<CPoint>
typedef std::list<CPoint> CPolygon;

//we need to specialize our polygon concept mapping in boost polygon
namespace boost { namespace polygon {
    //first register CPolygon as a polygon_concept type
    template <>
    struct geometry_concept<CPolygon>{ typedef polygon_concept type; };

    template <>
    struct polygon_traits<CPolygon> {
      typedef int coordinate_type;
      typedef CPolygon::const_iterator iterator_type;
      typedef CPoint point_type;

      // Get the begin iterator
      static inline iterator_type begin_points(const CPolygon& t) {
	return t.begin();
      }

      // Get the end iterator
      static inline iterator_type end_points(const CPolygon& t) {
	return t.end();
      }

      // Get the number of sides of the polygon
      static inline std::size_t size(const CPolygon& t) {
	return t.size();
      }

      // Get the winding direction of the polygon
      static inline winding_direction winding(const CPolygon& t) {
	return unknown_winding;
      }
    };

    template <>
    struct polygon_mutable_traits<CPolygon> {
      //expects stl style iterators
      template <typename iT>
      static inline CPolygon& set_points(CPolygon& t,
					 iT input_begin, iT input_end) {
	t.clear();
	t.insert(t.end(), input_begin, input_end);
	return t;
      }

    };
  } }

//now there's nothing left to do but test that our polygon
//works with library interfaces
int main() {
  test_polygon<CPolygon>(); //woot!
  return 0;
}


/**
 * @file main.cpp
 * @author Markose Jacob
 * @version 1.0
 * @section DISCRIPTION
 * This program is used to find the path inside a maze which is predefined
 */
#include <iostream>
#include <vector>
#include <boost/lexical_cast.hpp>// for converting float to string
#include <string>

using namespace std;
/**
 * @brief Function checks if the coordinates are going out of the maze
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns ture if x or y goes outside the Maze
 */
bool IsOutsideMaze (int x,int y);
/**
 * @brief Function checks if the goal coordinate has reached or not
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @param goalx Coordinate of goal along x axis
 * @param goaly Coordinate of goal along x axis
 * @return Returns true if goal position has reached else false
 */
bool IsGoal (int x,int y, int goalx, int goaly);
/**
 * @brief Function checks if the coordinate has an obstacle
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns true if there is an obstacle in that location
 */
bool Isobstacle (int x, int y);
/**
 * @brief Recursive function to find a valid path from start to goal.
 * The function first checks if the current position is out side the maze.
 * It then checks if the current position is goal or not
 * It then checks if the current position is an obstacle
 * Then function tries to find a path in north direction, then in East Direction, then in South direction, and finally in West direction.
 * If any of these are possible then the move is saved in a vector and returns true
 * If no moves are possible then the function marks that location  with a 'X' and backtracks.
 * When the goal is reached, it returns a true.
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns true if a path is found
 */
bool FindPath (int x, int y);
/**
 * @brief Function makes a move in North direction
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns a vector with new coordinates
 */
vector<int> GoNorth (int x,int y);
/**
 * @brief Function makes a move in East direction
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns a vector with new coordinates
 */
vector<int> GoEast (int x,int y);
/**
 * @brief Function makes a move in South direction
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns a vector with new coordinates
 */
vector<int> GoSouth (int x,int y);
/**
 * @brief Function makes a move in West direction
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns a vector with new coordinates
 */
vector<int> GoWest (int x,int y);
/**
 * @brief Function checks if the coordinate entered by the user is an obstacle or not
 * @param x Current position along x axis
 * @param y Current position along y axis
 * @return Returns false if there is an obstacle in that location
 */
bool CheckEntryIsobstacle(int x, int y);
/**
 * Function Displays the maze
 */
void DisplayMaze();

vector<vector<int>> Path; // Vector to store the path
int SizeOfPath;  // Variable to store the size of path
vector<string> Movements; // Vector to store movements made
int goalx{}; // To store x coordinate of goal
int goaly{}; // To store y coordinate of goal
vector<vector <char> > maze{ {'.','#','#','#','#','#'},  // To store the maze
                              {'.','.','.','#','.','#'},
                              {'#','.','#','#','.','#'},
                              {'#','.','#','#','.','#'},
                              {'#','.','#','.','.','.'},
                              {'#','.','.','.','#','#'},
                              } ;

int main(){
    float a,b,c,d;
    int w,x,t,s,y,z; // int variables to store coordinates
    string g = "."; // to check if there is a decimal number
    bool con1,con2 = true; // bool variables to terminate while loops
    bool con3, con4, con6,con7 = false; // bool variables to terminate while loops
    char Answer; // Char Variable to terminate while loop
    cout << "Maze is : ";
    DisplayMaze(); //Displays the maze
    while((Answer != 'y') || (Answer != 'Y'))
    {
            do {
                do {
                    do {
                        cout << "\n\nEnter the coordinates for start position : " << endl;
                        cin >> a >> b; //Takes input from user
                        std::string a1 = boost::lexical_cast<std::string>(a);
                        std::string a2 = boost::lexical_cast<std::string>(b);
                        if ((a1.find(g) != string::npos) || (a2.find(g) != string::npos)) { //Checks if the entry has decimal value
                            cout << "Please enter a int value and not float!!";
                            con6 = true;
                        } else {
                            con6 = false;
                        }
                    }while(con6==true);
                    if (((a >= 6) || (a < 0)) || ((b >= 6) || (b < 0))) //checks if the the input is inside the maze
                    {
                        con3 = true;
                        cout << "The value is outside maze" << endl;
                        DisplayMaze();
                    } else {
                        con3 = false;
                    }
                } while (con3 == true);
                cout << endl;
                w = 5 - b; //Changing the coordinates to match that of vector
                x = a; //Changing the coordinates to match that of vector
                if (CheckEntryIsobstacle(w, x)) //Checks if the location has an obstacle
                {
                    con1 = true;
                }
                else
                    {
                    cout << "The entered coordinate is an obstacle. Please re-enter!! " << endl; //checks if there is an obstacle in the entered coordinate.
                    con1 = false;
                }
            }while(con1 == false);
            do {
                do {
                    do{

                        DisplayMaze();
                        cout << "\nEnter the coordinates for goal position : " << endl;
                        cin >> c >> d; //goal input from user
                        std::string a3 = boost::lexical_cast<std::string>(c);
                        std::string a4 = boost::lexical_cast<std::string>(d);
                        if ((a3.find(g) != string::npos) || (a4.find(g) != string::npos)) {
                            cout << "Please enter a int value and not float!!";
                            con7 = true;
                        }
                        else{
                        con7 = false;
                        }
                    }while(con7==true);
                    if (((c>=6)||(c<0))||((d>=6)||(d<0))) //checks if the the input is inside the maze
                    {
                        con4 = true;
                        cout << "The value is outside maze" << endl;

                    } else
                    {
                        con4 = false;
                    }
                }while (con4==true);
                cout << endl;
                t = 5 - d;//Changing the coordinates to match that of vector
                s = c;//Changing the coordinates to match that of vector
                if (CheckEntryIsobstacle(t, s)) //Checks if the location has an obstacle
                {
                    con2 = true;
                }
                else
                    {
                    cout << "The entered coordinate is an obstacle. Please re-enter!! " << endl;
                    con2 = false;
                }
            }while(con2 == false);
    cout << endl;
    maze.at(w).at(x) = 'S';
    maze.at(t).at(s) = 'G';
    DisplayMaze();
    cout << "\n\nIs this the start and goal location you want? (y/n) " << endl; //Asks if the user wants to change the goal and start location
    cin >> Answer;
    if((Answer=='y') || (Answer == 'Y'))
    {
        break;
    }
        maze.at(w).at(x) = '.';
        maze.at(t).at(s) = '.';
    }

    goalx = t;
    goaly = s;
    DisplayMaze();
    maze.at(w).at(x) = '.';
    FindPath(w,x); // Runs recursive function to solve maze
    if(maze[w][x]=='+') {

        maze[w][x]='S';
        cout << "\nThe maze solution path looks like this: " << endl;
        cout << "\nStarting Position: " << "[" << a << "," << b << "]\n"; //outputs the starting location
        for (int i=SizeOfPath-1 ; i > -1 ; --i)
        {
            cout << Movements[i] << ": "; // Outputs all the movements made to reach goal
            y = Path[i][1];//Changing the coordinates to match that of vector
            z = 5-Path[i][0];//Changing the coordinates to match that of vector
            cout << "[" << y << "," << z << "]" << endl;
        }
        cout << "\n\nReached Goal Node!!!\n" << endl;
        DisplayMaze();
    }
    else
        cout << " No path can be found!! \n" << endl;
    return 0;
}

bool CheckEntryIsobstacle(int x,int y)
{
    if(maze[x][y]=='#' || maze[x][y]=='+')
    {
        return false;
    }
    else
    {
        return true;
    }
}
void DisplayMaze()
{

    cout << endl;
    for(int i =0; i<6; i++)
    {
        cout << 5-i << " ";
        for(int j=0; j<6; j++)
        {
            cout << maze.at(i).at(j) << " ";
        }
        cout << endl;
    }
    cout << "  ";
    for(int g = 0; g<6; g++)
    {
        cout << g << " ";
    }
}

bool IsOutsideMaze(int x,int y)
{
    if(x>=6 || x<0)
    {
        return true;
    }
    else if(y>=6 || y<0)
    {
        return true;
    }
    else
    {
        return false;
    }

}

bool IsGoal(int x,int y, int goalx, int goaly)
{
    if(x == goalx && y == goaly)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool Isobstacle(int x,int y)
{
    if(maze[x][y]=='#' || maze[x][y]=='+')
    {
        return true;
    }
    else
    {
        return false;
    }
}
vector<int> GoNorth(int x,int y)
{
    x = x-1;
    y = y;
    vector<int> North{x,y};
    return North;
}
vector<int> GoEast(int x,int y)
{
    x = x;
    y = y+1;
    vector<int> East{x,y};
    return East;
}
vector<int> GoSouth(int x,int y)
{
    x = x+1;
    y = y;
    vector<int> South{x,y};
    return South;
}
vector<int> GoWest(int x,int y)
{
    x = x;
    y = y-1;
    vector<int> West{x,y};
    return West;
}

bool FindPath (int x, int y) // Recursive function to find path
{
    if(IsOutsideMaze(x, y))
    {
        return false;
    }
    if(IsGoal(x, y,goalx,goaly))
    {
        return true;
    }
    if(Isobstacle(x, y))
    {
        return false;
    }
    vector<int> PosibleMoves;
    maze[x][y] = '+';
    if(FindPath(GoNorth(x,y)[0],GoNorth(x,y)[1]))
    {
        PosibleMoves = GoNorth(x,y); // Storing the coordinates of north move
        Path.push_back(PosibleMoves); // updating with new coordinates
        SizeOfPath = Path.size(); // Updating the size of path
        Movements.push_back("Moved North"); //Updating Movement with the Moved North
        return true;

    }
    if(FindPath(GoEast(x,y)[0],GoEast(x,y)[1]))
    {
        PosibleMoves = GoEast(x,y);
        Path.push_back(PosibleMoves);
        SizeOfPath = Path.size();
        Movements.push_back("Moved East ");
        return true;

    }
    if(FindPath(GoSouth(x,y)[0],GoSouth(x,y)[1]))
    {
        PosibleMoves = GoSouth(x,y);
        Path.push_back(PosibleMoves);
        SizeOfPath = Path.size();
        Movements.push_back("Moved South");
        return true;

    }
    if(FindPath(GoWest(x,y)[0],GoWest(x,y)[1]))
    {
        PosibleMoves = GoWest(x,y);
        Path.push_back(PosibleMoves);
        SizeOfPath = Path.size();
        Movements.push_back("Moved West ");
        return true;

    }
    maze[x][y] = 'X';
    return false;
}


//////////////////////////////////////////////////////////////////////////////
// cross_validation::data::input_output_generator.hpp                       //
//                                                                          //
//  (C) Copyright 2009 Erwann Rogard                                        //
//  Use, modification and distribution are subject to the                   //
//  Boost Software License, Version 1.0. (See accompanying file             //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)        //
//////////////////////////////////////////////////////////////////////////////
#ifndef  BOOST_STATISTICS_DETAIL_CROSS_VALIDATION_DATA_INPUT_OUTPUT_GENERATOR_HPP_ER_2009
#define  BOOST_STATISTICS_DETAIL_CROSS_VALIDATION_DATA_INPUT_OUTPUT_GENERATOR_HPP_ER_2009

#include <boost/statistics/detail/cross_validation/data/input_output.hpp>

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

    // Maps x to a data-type representing (x,f(x))
    //
    // Note: the library does not require a specific data-type; this one is
    // provided as a convenience
    //
    // private inheritance of F was abandonned after compilor error with
    // F = function<R(A)>
    template<
        typename X,typename F,
        typename Kx = mpl::int_<1>,
        typename Ky = mpl::int_<2>
    >
    class input_output_generator {
        typedef meta_input_output<X,F,Kx,Ky> meta_;

        public:

        typedef meta_ meta_input_output;

        typedef typename meta_::type result_type;

        input_output_generator(){}

        input_output_generator(const F& f):f_(f){}
        input_output_generator(const input_output_generator& that)
            :f_(that.f_){}
        input_output_generator&
        operator=(const input_output_generator& that)
        {
            if(&that!=this){
                this->f_ = that.f_;
            }
            return (*this);
        }

        template<typename X1>
        result_type operator()(const X1& x)const{
            return meta_::make(x,this->f_);
        }

        protected:
        mutable F f_;

    };

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

#endif


// -*- C++ -*-
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//                                   Jiao Lin
//                      California Institute of Technology
//                         (C) 2007 All Rights Reserved
//
// {LicenseText}
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

#include <boost/python.hpp>
#include "wrap_vector.h"
#include "mccomposite/geometry/RotationMatrix.h"

namespace wrap_mccomponents {

  void wrap_basic_containers()
  {
    using namespace boost::python;

    wrap_vector<int>( "int" );
    wrap_vector<unsigned int>( "uint" );
    wrap_vector<double>( "double" );

    wrap_vector2<mccomposite::geometry::RotationMatrix>("rotmat");
  }
}

// version
// $Id$

// End of file


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
/*!
 * \file
**/
#ifndef BOOST_SIMD_OPERATOR_FUNCTIONS_IS_GREATER_EQUAL_HPP_INCLUDED
#define BOOST_SIMD_OPERATOR_FUNCTIONS_IS_GREATER_EQUAL_HPP_INCLUDED
#include <boost/simd/include/functor.hpp>
#include <boost/dispatch/include/functor.hpp>

/*!
 * \ingroup boost_simd_operator
 * \defgroup boost_simd_operator_is_greater_equal is_greater_equal
 *
 * \par Description
 * Returns True<result_type>() or False<result_type>() according a0 is greater or equal to a1 or not.
 *
 * \par Header file
 *
 * \code
 * #include <nt2/include/functions/is_greater_equal.hpp>
 * \endcode
 *
 * \par Alias
 * \arg ge
 *
 * \synopsis
 *
 * \code
 * namespace boost::simd
 * {
 *   template <class A0>
 *     meta::call<tag::is_greater_equal_(A0,A0)>::type
 *     is_greater_equal(const A0 & a0,const A0 & a1);
 * }
 * \endcode
 *
 * \param a0 the first parameter of is_greater_equal
 * \param a1 the second parameter of is_greater_equal
 *
 * \return an integer value
 *
 * \par Notes
 * In SIMD mode, this function acts elementwise on the inputs vectors elements
 * \par
 * This is a predicate operation. Such operations return bool in scalar mode,
 * but not in SIMD mode.
 * \par
 * The return type in SIMD mode is the common type of the parameters and is
 * a 'signed boolean' type. This means that in this case True has all its bits
 * sets to one. This is to facilitate masking operations. You are invited to
 * consult the rationale.
 *
**/

namespace boost { namespace simd
{
  namespace tag
  {
    /*!
     * \brief Define the tag is_greater_equal_ of functor is_greater_equal
     *        in namespace boost::simd::tag for toolbox boost.simd.operator
    **/
    struct is_greater_equal_ : ext::elementwise_<is_greater_equal_> { typedef ext::elementwise_<is_greater_equal_> parent; };
  }

  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::is_greater_equal_, is_greater_equal , 2 )
  BOOST_DISPATCH_FUNCTION_IMPLEMENTATION(tag::is_greater_equal_, ge               , 2 )
} }

namespace boost { namespace dispatch { namespace meta
{
  template<>
  struct hierarchy_of<boost::proto::tag::greater_equal>
  {
    typedef boost::simd::tag::is_greater_equal_ type;
  };
  template<>
  struct proto_tag<boost::simd::tag::is_greater_equal_>
  {
    typedef boost::proto::tag::greater_equal type;
  };
} } }

#include <boost/simd/operator/specific/common.hpp>

#endif


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE geo_vec
#include <boost/test/unit_test.hpp>
#include "geo_vec.hpp"
#include <functional>

BOOST_AUTO_TEST_CASE( geo_vec_constructs_is_empty )
{
  geo_vec<int> v;
  BOOST_CHECK(v.empty());
}

BOOST_AUTO_TEST_CASE( geo_vec_constructs_with_args )
{
  geo_vec<int> v(4,2);
  BOOST_CHECK(!v.empty());
}

struct fixture {

  std::vector<int> fix_v;

  //setup
  fixture():
    fix_v(14,42){}

  //teardown
  ~fixture(){}

};

BOOST_FIXTURE_TEST_SUITE( suite_w_given_vector, fixture)

BOOST_AUTO_TEST_CASE( fixture_works )
{
  BOOST_CHECK(fix_v.size());
}

BOOST_AUTO_TEST_CASE( copy_construct_std_vec )
{
  geo_vec<int> v(fix_v);

  BOOST_CHECK(!v.empty());
  BOOST_CHECK(v.norm());
  BOOST_CHECK_EQUAL(v.norm(), 14*42);
}

BOOST_AUTO_TEST_CASE( use_custom_norm )
{
  geo_vec<int> v(fix_v);
  BOOST_CHECK_EQUAL(v.norm(std::plus<int>()), v.norm());
}

struct add_squared
{
  template <typename T>
  T operator()(const T& _first, const T& _second){
    return _first + _second*_second;
  }
};

BOOST_AUTO_TEST_CASE( use_squared_norm )
{
  geo_vec<int, add_squared> v(fix_v);
  geo_vec<int> def(fix_v);

  BOOST_CHECK_EQUAL(def.norm(), 14*42*42);
}

BOOST_AUTO_TEST_SUITE_END()


// Copyright (c) 2009, Object Computing, Inc.
// All rights reserved.
// See the file license.txt for licensing information.
#include <Common/QuickFASTPch.h>
#include "Decimal.h"
#include <Common/Exceptions.h>
#include <Common/WorkingBuffer.h>
#include <boost/algorithm/string/trim.hpp>

using namespace ::QuickFAST;

Decimal::Decimal(
    mantissa_t mantissa,
    exponent_t exponent,
    bool autoNormalize)
: mantissa_(mantissa)
, exponent_(exponent)
, autoNormalize_(autoNormalize)
{
}

Decimal::Decimal(const Decimal & rhs)
: mantissa_(rhs.mantissa_)
, exponent_(rhs.exponent_)
, autoNormalize_(rhs.autoNormalize_)
{
}

Decimal::~Decimal()
{
}

void
Decimal::parse(const std::string & value)
{
  std::string str = value;
  boost::algorithm::trim(str);
  size_t dotPos = str.find(".");
  std::string wholeString = str.substr(0,dotPos);
  std::string fracString;
  if(dotPos != std::string::npos)
  {
    fracString = str.substr(dotPos+1);
  }
  std::string mantissaString = wholeString+fracString;
  exponent_ = -exponent_t(fracString.size());

  bool overflow = false;

  // VC8 stringstream is truncating a large string instead of throwing
  // the exception, so we'll always fall back on the overflow code.
#if defined _MSC_VER && _MSC_VER < 1500
  overflow = true;
#else
  try {
    mantissa_ = boost::lexical_cast<mantissa_t>(mantissaString);
  }
  catch (std::exception &)
  {
    overflow = true;
  }
#endif

  if (overflow && autoNormalize_)
  {
    size_t pos = mantissaString.find_last_not_of ("0");
    exponent_ += exponent_t(mantissaString.length () - pos - 1);
    mantissaString = mantissaString.substr (0, pos + 1);
    mantissa_ = boost::lexical_cast<mantissa_t>(mantissaString);
  }

  if(autoNormalize_)
  {
    normalize();
  }
}

void
Decimal::setAutoNormalize(bool autoNormalize)
{
  autoNormalize_ = autoNormalize;
  if(autoNormalize_)
  {
    normalize();
  }
}

void
Decimal::setMantissa(mantissa_t mantissa)
{
  mantissa_ = mantissa;
}

void
Decimal::setExponent(exponent_t exponent)
{
  exponent_ = exponent;
}

mantissa_t
Decimal::getMantissa() const
{
  return mantissa_;
}

exponent_t
Decimal::getExponent() const
{
  return exponent_;
}

void
Decimal::toString(std::string & value)const
{
#if 0
  value = boost::lexical_cast<std::string>(double(*this));
#elif 1
  std::stringstream str;
  str << double(*this);
  value = str.str();
#else
  WorkingBuffer buffer;
  buffer.clear(true, 20);
  bool negative = false;
  int64 m = mantissa_;
  if(m < 0)
  {
    negative = true;
    m = -m;
  }
  short e = exponent_;
  if(e >= 0)
  {
    // No trailing decimal point
    // buffer.push((unsigned char)'.');
    while(e > 0)
    {
      buffer.push((unsigned char)'0');
      e -= 1;
    }
  }
  bool none = true;
  while(m != 0 || e < 0 || none)
  {
    none = false;
    char c = (m % 10) + '0';
    m /= 10;
    buffer.push((unsigned char)c);
    if(e < 0)
    {
      e += 1;
      if(e == 0)
      {
        buffer.push((unsigned char)'.');
        // insure at least one character to the left of the decimal point
        if(m == 0)
        {
          buffer.push((unsigned char)'0');
        }
      }
    }
  }
  if(negative)
  {
    buffer.push((unsigned char)'-');
  }
  value.assign((const char *)buffer.begin(), buffer.end()-buffer.begin());
#endif
}

Decimal &
Decimal::operator = (const Decimal & rhs)
{
  Decimal temp(rhs);
  swap(temp);
  return *this;
}

void
Decimal::swap(Decimal & rhs)
{
  exponent_t texp = exponent_;
  exponent_ = rhs.exponent_;
  rhs.exponent_ = texp;
  mantissa_t tman = mantissa_;
  mantissa_ = rhs.mantissa_;
  rhs.mantissa_ = tman;
}

void
Decimal::normalize(bool strict /*= true*/)
{
  while(mantissa_ != 0 && mantissa_ % 10 == 0 && exponent_ < 64)
  {
    mantissa_ /= 10;
    exponent_ += 1;
  }
  if(exponent_ > 64)
  {
    if(strict)
    {
      throw OverflowError("[ERR R1]Decimal Exponent overflow.");
    }
    while(exponent_ > 64)
    {
      mantissa_ *= 10;
      exponent_ -= 1;
    }
  }
  if(exponent_ < -64)
  {
    if(strict)
    {
      throw OverflowError("[ERR R1]Decimal Exponent undeflow.");
    }
    while(exponent_ < -64)
    {
      mantissa_ /= 10;
      exponent_ += 1;
    }
  }
}

void
Decimal::denormalize(exponent_t exponent)
{
  while(exponent_ > exponent && mantissa_ < (LLONG_MAX/10))
  {
    exponent_ -= 1;
    mantissa_ *= 10;
    // todo check mantissa overflow
  }
}
void
Decimal::maximizeMantissa()
{
  // this could be considerably faster!
  while(exponent_ > SCHAR_MIN && mantissa_ < (LLONG_MAX/10))
  {
    exponent_ -= 1;
    mantissa_ *= 10;
  }
}

bool
Decimal::operator<(const Decimal & rhs) const
{
  if(exponent_ == rhs.exponent_)
  {
    return mantissa_ < rhs.mantissa_;
  }

  if(rhs.exponent_ < exponent_)
  {
    Decimal temp(*this);
    temp.denormalize(rhs.exponent_);
    return temp.mantissa_ < rhs.mantissa_;
  }
  else
  {
    Decimal temp(rhs);
    temp.denormalize(exponent_);
    return mantissa_ < temp.mantissa_;
  }
//  // at this point comparison is iffy, converting to double doesn't
//  // hurt
//  return (double) *this < (double)rhs;

}

bool
Decimal::operator==(const Decimal & rhs) const
{
  if(exponent_ == rhs.exponent_)
  {
    return mantissa_ == rhs.mantissa_;
  }

  if(rhs.exponent_ < exponent_)
  {
    Decimal temp(*this);
    temp.denormalize(rhs.exponent_);
    return temp.mantissa_ == rhs.mantissa_;
  }
  else
  {
    Decimal temp(rhs);
    temp.denormalize(exponent_);
    return mantissa_== temp.mantissa_;
  }
}

Decimal::operator double()const
{
  // faster than the pow function or repeated multiply/divides
  static double powerTable[] =
  {
      1.0e-63, 1.0e-62, 1.0e-61, 1.0e-60, 1.0e-59, 1.0e-58, 1.0e-57, 1.0e-56,
      1.0e-55, 1.0e-54, 1.0e-53, 1.0e-52, 1.0e-51, 1.0e-50, 1.0e-49, 1.0e-48,
      1.0e-47, 1.0e-46, 1.0e-45, 1.0e-44, 1.0e-43, 1.0e-42, 1.0e-41, 1.0e-40,
      1.0e-39, 1.0e-38, 1.0e-37, 1.0e-36, 1.0e-35, 1.0e-34, 1.0e-33, 1.0e-32,
      1.0e-31, 1.0e-30, 1.0e-29, 1.0e-28, 1.0e-27, 1.0e-26, 1.0e-25, 1.0e-24,
      1.0e-23, 1.0e-22, 1.0e-21, 1.0e-20, 1.0e-19, 1.0e-18, 1.0e-17, 1.0e-16,
      1.0e-15, 1.0e-14, 1.0e-13, 1.0e-12, 1.0e-11, 1.0e-10, 1.0e-9 , 1.0e-8 ,
      1.0e-7 , 1.0e-6 , 1.0e-5 , 1.0e-4 , 1.0e-3 , 1.0e-2 , 1.0e-1 , 1.0e0  ,
      1.0e1  , 1.0e2  , 1.0e3  , 1.0e4  , 1.0e5  , 1.0e6  , 1.0e7  , 1.0e8  ,
      1.0e9  , 1.0e10 , 1.0e11 , 1.0e12 , 1.0e13 , 1.0e14 , 1.0e15 , 1.0e16 ,
      1.0e17 , 1.0e18 , 1.0e19 , 1.0e20 , 1.0e21 , 1.0e22 , 1.0e23 , 1.0e24 ,
      1.0e25 , 1.0e26 , 1.0e27 , 1.0e28 , 1.0e29 , 1.0e30 , 1.0e31 , 1.0e32 ,
      1.0e33 , 1.0e34 , 1.0e35 , 1.0e36 , 1.0e37 , 1.0e38 , 1.0e39 , 1.0e40 ,
      1.0e41 , 1.0e42 , 1.0e43 , 1.0e44 , 1.0e45 , 1.0e46 , 1.0e47 , 1.0e48 ,
      1.0e49 , 1.0e50 , 1.0e51 , 1.0e52 , 1.0e53 , 1.0e54 , 1.0e55 , 1.0e56 ,
      1.0e57 , 1.0e58 , 1.0e59 , 1.0e60 , 1.0e61 , 1.0e62 , 1.0e63
  };
  if(exponent_ >= -63 && exponent_ <= 63)
  {
    return (double)mantissa_ * powerTable[exponent_ + 63];
  }
  // note it is a FAST reportable error if abs(exponent) > 63, but for now we'll just fake it here.
  return double(double(mantissa_) * pow(10.0L, exponent_));
}

Decimal &
Decimal::operator+=(const Decimal & rhs)
{
  if(rhs.exponent_ < exponent_)
  {
    Decimal temp(*this);
    temp.denormalize(rhs.exponent_);
    temp.mantissa_ += rhs.mantissa_;
    temp.normalize();
    swap(temp);
  }
  else
  {
    Decimal temp(rhs);
    temp.denormalize(exponent_);
    temp.mantissa_ += mantissa_;
    temp.normalize();
    swap(temp);
  }
  return *this;
}

Decimal &
Decimal::operator-=(const Decimal & rhs)
{
  if(rhs.exponent_ < exponent_)
  {
    Decimal temp(*this);
    temp.denormalize(rhs.exponent_);
    temp.mantissa_ -= rhs.mantissa_;
    temp.normalize();
    swap(temp);
  }
  else
  {
    Decimal temp(rhs);
    temp.denormalize(exponent_);
    temp.mantissa_ = mantissa_ - temp.mantissa_;
    temp.normalize();
    swap(temp);
  }
  return *this;
}

Decimal &
Decimal::operator*=(const Decimal & rhs)
{
  Decimal temp(*this);
  temp.exponent_ += rhs.exponent_;
  temp.mantissa_ *= rhs.mantissa_;
  temp.normalize();
  swap(temp);
  return *this;
}

Decimal&
Decimal::operator/=(const Decimal & rhs)
{
  Decimal temp(*this);
  temp.maximizeMantissa();
  temp.exponent_ -= rhs.exponent_;
  temp.mantissa_ /= rhs.mantissa_;
  temp.normalize(false);
  swap(temp);
  return *this;
}


//==================================================================================================
/**
  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#include <boost/simd/function/shuffle.hpp>
#include <boost/simd/function/deinterleave_first.hpp>
#include <boost/simd/function/deinterleave_second.hpp>
#include <boost/simd/constant/valmin.hpp>
#include <boost/simd/constant/valmax.hpp>
#include <boost/simd/pack.hpp>
#include <simd_test.hpp>

namespace bs = boost::simd;

STF_CASE_TPL( "deinterleave shuffle with back 0s", STF_NUMERIC_TYPES)
{
  // cardinal 2
  {
    bs::pack<T,2> a{ bs::Valmax<T>(), T(42) };
    bs::pack<T,2> b{ T(13), bs::Valmin<T>() };
    bs::pack<T,2> z(0);

    STF_ALL_EQUAL( (bs::shuffle<0,-1>(a,b)), (bs::deinterleave_first (a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<1,-1>(a,b)), (bs::deinterleave_second(a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<2,-1>(a,b)), (bs::deinterleave_first (b,z)) );
    STF_ALL_EQUAL( (bs::shuffle<3,-1>(a,b)), (bs::deinterleave_second(b,z)) );
  }

  // cardinal 4
  {
    bs::pack<T,4> a{ bs::Valmax<T>(), T(42), T(69), bs::Valmin<T>() };
    bs::pack<T,4> b{ T(13), bs::Valmin<T>(), T(37), bs::Valmax<T>() };
    bs::pack<T,4> z(0);

    STF_ALL_EQUAL( (bs::shuffle<0,2,-1,-1>(a,b))    , (bs::deinterleave_first (a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<1,3,-1,-1>(a,b))    , (bs::deinterleave_second (a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<4,6,-1,-1>(a,b)) , (bs::deinterleave_first(b,z)) );
    STF_ALL_EQUAL( (bs::shuffle<5,7,-1,-1>(a,b)) , (bs::deinterleave_second(b,z)) );
  }

  // cardinal 8
  {
    bs::pack<T,8> a { bs::Valmax<T>(),T(66),T(99),T(55), T(-1),T(77), T(23), bs::Valmin<T>()};
    bs::pack<T,8> b{ T(13), bs::Valmin<T>(), T(37), bs::Valmax<T>(), T(54),T(13),T(37),T(69) };
    bs::pack<T,8> z(0);

    STF_ALL_EQUAL( (bs::shuffle<0,2,4,6,-1,-1,-1,-1>(a,b))    , (bs::deinterleave_first (a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<1,3,5,7,-1,-1,-1,-1>(a,b))    , (bs::deinterleave_second (a,z)) );
    STF_ALL_EQUAL( (bs::shuffle<8,10,12,14,-1,-1,-1,-1>(a,b)) , (bs::deinterleave_first(b,z)) );
    STF_ALL_EQUAL( (bs::shuffle<9,11,13,15,-1,-1,-1,-1>(a,b)) , (bs::deinterleave_second(b,z)) );
  }
}


/****************************************************************************
 *  hipipe library
 *  Copyright (c) 2017, Cognexa Solutions s.r.o.
 *  Copyright (c) 2018, Iterait a.s.
 *  Author(s) Filip Matzner
 *
 *  This file is distributed under the MIT License.
 *  See the accompanying file LICENSE.txt for the complete license agreement.
 ****************************************************************************/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE run_graph_test

#include "../core/common.hpp"

#include <hipipe/tensorflow/load_graph.hpp>
#include <hipipe/tensorflow/run_graph.hpp>

#include <boost/test/unit_test.hpp>

namespace htf = hipipe::tensorflow;

BOOST_AUTO_TEST_CASE(test_simple_run)
{
    auto sess = load_graph("transpose_add_one_2_3_net.pb");
    // prepare inputs
    std::vector<std::string>       input_names  = {"input"};
    std::tuple<std::vector<float>> input_data   = {{0, 1, 2, 3, 4, 5}};
    std::vector<std::vector<long>> input_shapes = {{2, 3}};
    std::vector<std::string>       output_names = {"output"};

    // prepare outputs
    std::tuple<std::vector<float>> output_data;
    std::vector<std::vector<long>> output_shapes;

    // run graph
    std::tie(output_data, output_shapes) =
      htf::run_graph<float>(*sess, input_names, input_data, input_shapes, output_names);

    // test output shape
    BOOST_TEST(output_shapes.size() == 1);
    BOOST_TEST(output_shapes[0][0] == 3);
    BOOST_TEST(output_shapes[0][1] == 2);

    // test output data
    test_ranges_equal(std::get<0>(output_data), std::vector<float>{1, 4, 2, 5, 3, 6});
}


//==================================================================================================
/**
  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
**/
//==================================================================================================
#include <boost/config.hpp>
#include <simd_test.hpp>
#include <boost/simd/function/insert.hpp>
#include <boost/simd/detail/unroll.hpp>
#ifndef BOOST_NO_CXX11_USER_DEFINED_LITERALS
#include <boost/simd/literal.hpp>
#endif
#include <boost/simd/pack.hpp>
#include <simd_test.hpp>
#include <array>

namespace bs = boost::simd;
namespace bd = boost::dispatch;

template<typename A, typename P, typename... N>
void f( nsm::list<N...> const&, A& a, P& p)
{
  using T = typename P::value_type;
  BOOST_SIMD_LOCAL_UNROLL( a[N::value] = T(N::value+1) );
  BOOST_SIMD_LOCAL_UNROLL( (bs::insert(p, N{}, T(N::value+1))) );
}

template <typename T, std::size_t N, typename Env>
void test_st(Env& runtime)
{
  bs::pack<T, N>  p;
  std::array<T,N> a;

  f( nsm::range<std::size_t, 0, N>(),a,p);

  bs::pack<T, N> ref(&a[0], &a[0] + N);
  STF_EQUAL(ref, p);
}

STF_CASE_TPL("Check static insert on pack" , STF_NUMERIC_TYPES)
{
  static const std::size_t N = boost::simd::pack<T>::static_size;

  test_st<T, N>(runtime);
  test_st<T, N/2>(runtime);
  test_st<T, N*2>(runtime);
}

#ifndef BOOST_NO_CXX11_USER_DEFINED_LITERALS

using namespace bs::literal;

template <typename T, std::size_t N, typename Env>
void test_lt(Env& runtime)
{
  bs::pack<T, N>  p;
  std::array<T,N> a;

  for(std::size_t i=0;i<N;++i)
    a[i] = p[i] = T(0);

  a[0] = T(1);
  insert(p,0_c, 1);

  if(N>1) { a[1] = T(2); insert(p,1_c, 2); }
  if(N>3) { a[3] = T(4); insert(p,3_c, 4); }
  if(N>7) { a[7] = T(8); insert(p,7_c, 8); }

  bs::pack<T, N> ref(&a[0], &a[0] + N);
  STF_EQUAL(ref, p);
}

STF_CASE_TPL("Check static insert on pack using literals" , STF_NUMERIC_TYPES)
{
  static const std::size_t N = boost::simd::pack<T>::static_size;

  test_lt<T, N>(runtime);
  test_lt<T, N/2>(runtime);
  test_lt<T, N*2>(runtime);
}

#endif // !BOOST_NO_CXX11_USER_DEFINED_LITERALS


#include "graphalgos.hpp"

#include "../manager/errors.hpp"   // for InconsistentDataError
#include "../util/fault_codes.hpp" // for FAULT_CRITICAL_PATH_INFEASIBLE
#include "datastructures/fast_reset_vector.hpp"
#include "instance/instance.hpp" // for Instance
#include "instance/job.hpp"      // for Job
#include "instance/laggraph.hpp" // for LagGraph, LagGraph::(anonymous)

#include <algorithm>           // for move, max, reverse
#include <assert.h>            // for assert
#include <bits/std_function.h> // for function
#include <boost/range/adaptor/reversed.hpp>
#include <ext/alloc_traits.h> // for __alloc_traits<>::value_type
#include <functional>         // for function
#include <numeric>
#include <string> // for string
#include <unordered_set>

NecessaryOrderComputer::NecessaryOrderComputer(const Instance & instance_in)
    : predecessor_count(instance_in.job_count(), 0),
      successor_count(instance_in.job_count(), 0), instance(instance_in)
{
	CriticalPathComputer cp(this->instance);
	this->earliest_starts = cp.get_forward();
	this->latest_finishs = cp.get_reverse();
	this->compute();
}

void
NecessaryOrderComputer::compute()
{
	std::vector<unsigned int> by_es(this->instance.job_count());
	std::vector<unsigned int> by_lf(this->instance.job_count());

	std::iota(by_es.begin(), by_es.end(), 0);
	std::iota(by_lf.begin(), by_lf.end(), 0);

	std::sort(by_es.begin(), by_es.end(),
	          [&](unsigned int lhs, unsigned int rhs) {
		          return this->earliest_starts[lhs] < this->earliest_starts[rhs];
	          });
	std::sort(by_lf.begin(), by_lf.end(),
	          [&](unsigned int lhs, unsigned int rhs) {
		          return this->latest_finishs[lhs] < this->latest_finishs[rhs];
	          });

	size_t finished = 0;
	for (const auto & v : by_es) {
		while (this->latest_finishs[by_lf[finished]] <= this->earliest_starts[v]) {
			finished++;
		}
		this->predecessor_count[v] = finished;
	}

	size_t started = 0;
	auto start_it = by_es.rbegin();
	for (auto it = by_lf.rbegin(); it != by_lf.rend(); it++) {
		while (this->earliest_starts[*start_it] >= this->latest_finishs[*it]) {
			started++;
			start_it++;
		}

		this->successor_count[*it] = started;
	}
}

const std::vector<size_t> &
NecessaryOrderComputer::get_successor_count() const noexcept
{
	return this->successor_count;
}

const std::vector<size_t> &
NecessaryOrderComputer::get_predecessor_count() const noexcept
{
	return this->predecessor_count;
}

TopologicalSort::TopologicalSort(const LagGraph & graph_in) : graph(graph_in) {}

std::vector<LagGraph::vertex>
TopologicalSort::get()
{
	using vertex = LagGraph::vertex;

	std::vector<unsigned int> indices(this->graph.vertex_count(), 0);

	unsigned int index = (unsigned int)(this->graph.vertex_count() - 1);

	std::function<bool(vertex, vertex)> visit = [&](vertex v, vertex from) {
		(void)from;
		(void)v;
		return true;
	};
	std::function<void(vertex, vertex, int)> traverse = [&](vertex from,
	                                                        vertex to, int lag) {
		(void)from;
		(void)to;
		(void)lag;
	};
	std::function<void(vertex)> backtrack = [&](unsigned int v) {
		if (indices[v] <= index) {
			indices[v] = index;
			index--;
		}
	};

#ifdef ASSERTIONS
	bool finished = false;
#endif

	std::vector<bool> visited;

	for (vertex v = 0; v < this->graph.vertex_count(); ++v) {
		if (this->graph.reverse_neighbor_count(v) > 0) {
			continue; // Only select vertices without incoming edges as roots
		}
		assert(indices[v] == 0);
		DFS<decltype(visit), decltype(backtrack), decltype(traverse)>(
		    this->graph, v, visit, backtrack, traverse);

#ifdef ASSERTIONS
		if (index == ((unsigned int)0 - 1)) {
			finished = true;
		}
#endif
	}

#ifdef ASSERTIONS
	assert(finished);
#endif

	std::vector<vertex> ordered(this->graph.vertex_count());
	for (vertex v = 0; v < this->graph.vertex_count(); ++v) {
		ordered[indices[v]] = v;
	}

	return ordered;
}

CriticalPathComputer::CriticalPathComputer(const Instance & instance_in)
    : l("CritPath"), instance(instance_in)
{}

std::vector<unsigned int>
CriticalPathComputer::get_forward()
{
	using vertex = LagGraph::vertex;
	const LagGraph & graph = this->instance.get_laggraph();

	std::vector<vertex> topological_order = TopologicalSort(graph).get();
	std::vector<unsigned int> earliest_start(graph.vertex_count());

	for (auto v : topological_order) {
		earliest_start[v] = this->instance.get_job(v).get_release();
	}

	for (auto v : topological_order) {
		const auto ec = graph.neighbors(v);
		for (auto edge = ec.cbegin(); edge != ec.cend(); ++edge) {
			unsigned int new_start;
			if (edge->lag < -1 * (int)earliest_start[v]) {
				new_start = 0;
			} else {
				new_start = (unsigned int)((int)earliest_start[v] + edge->lag);
			}

			earliest_start[edge->t] = std::max(earliest_start[edge->t], new_start);
		}
	}

	return earliest_start;
}

std::vector<unsigned int>
CriticalPathComputer::get_reverse()
{
	using vertex = LagGraph::vertex;
	const LagGraph & graph = this->instance.get_laggraph();

	std::vector<vertex> topological_order = TopologicalSort(graph).get();
	std::reverse(topological_order.begin(), topological_order.end());

	std::vector<unsigned int> latest_finish(graph.vertex_count());

	for (auto v : topological_order) {
		latest_finish[v] = this->instance.get_job(v).get_deadline();
	}

	for (auto v : topological_order) {
		for (auto edge : graph.reverse_neighbors(v)) {
			assert(edge.s == v);
			auto t = edge.t;
			const Job & t_job = this->instance.get_job(t);
			const Job & s_job = this->instance.get_job(v);

			int new_finish = (int)latest_finish[v] - (int)s_job.get_duration() +
			                 (int)t_job.get_duration() - (int)edge.lag;

			if (new_finish < 0) {
				BOOST_LOG(l.e()) << "Negative latest finish time detected.";
				BOOST_LOG(l.d()) << "LF-Times computed so far:";
				for (auto w : topological_order) {
					BOOST_LOG(l.d()) << "-> " << w << ": " << latest_finish[w];
					if (w == v) {
						BOOST_LOG(l.d()) << "--> Results in " << new_finish << " for " << t;
						break;
					}
				}

				throw InconsistentDataError(this->instance, -1,
				                            FAULT_CRITICAL_PATH_INFEASIBLE,
				                            "Negative latest finish time");
			}

			if ((unsigned int)new_finish < latest_finish[t]) {
				latest_finish[t] = (unsigned int)new_finish;
			}
		}
	}

	return latest_finish;
}

APLPComputer::APLPComputer(const Instance & instance_in) : instance(instance_in)
{}

std::vector<std::vector<int>>
APLPComputer::get()
{
	this->result.clear();
	this->result.resize(this->instance.job_count(),
	                    std::vector<int>(this->instance.job_count(), -1));

	this->topological_order =
	    TopologicalSort(this->instance.get_laggraph()).get();

	for (unsigned int jid = 0; jid < this->instance.job_count(); ++jid) {
		this->compute_SSLP(jid);
	}

	// TODO this is unsafe! But fast…
	return std::move(this->result);
}

// TODO this can be sped up.
// TODO make this fail if there are negative edges / cycles
void
APLPComputer::compute_SSLP(unsigned int start_job)
{
	const LagGraph & graph = this->instance.get_laggraph();

	this->result[start_job][start_job] = 0;

	auto it = this->topological_order.begin();

	// skip forward to job A
	while (*it != start_job) {
		it++;
	}

	// relax edges
	while (it != topological_order.end()) {
		const unsigned int v = *it;
		it++;

		if (this->result[start_job][v] == -1) { // no path here
			continue;
		}

		for (const auto & edge : graph.neighbors(v)) {
			int relaxed_dist = this->result[start_job][v] + edge.lag;
			assert(relaxed_dist >= 0); // negative paths break things for now

			this->result[start_job][edge.t] =
			    std::max(this->result[start_job][edge.t], relaxed_dist);
		}
	}
}


///

#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <map>
#include <iterator>
// BGL includes
// #include <boost/graph/adjacency_list.hpp>

// // BGL graph definitions
// // =====================
// // Graph Type with nested interior edge properties for Flow Algorithms
// // =====================
// // Graph Type, OutEdgeList Type, VertexList Type, (un)directedS
// typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS     // Use vecS for the VertexList! Choosing setS for the OutEdgeList disallows parallel edges.
//     >          graph;
// typedef boost::graph_traits<graph>::vertex_descriptor    vertex_desc;    // Vertex Descriptor: with vecS vertex list, this is really just an int in the range [0, num_vertices(G)).
// typedef boost::graph_traits<graph>::edge_iterator    edge_it;    // to iterate over all edges
// typedef  boost::graph_traits<graph>::out_edge_iterator      out_edge_it;
// // Custom Edge Adder Class, that holds the references
// // to the graph, capacity map and reverse edge map
// // ===================================================

std::vector<int> age;
std::vector<int> solution;
std::vector<std::pair<int,int>> curr_path;

struct second_greater {
  bool operator() (const std::pair<int, int>& t0, const std::pair<int,int>& t1) {
    return t0.second > t1.second;
  }
};

void solve_for(int idx, std::vector<std::vector<int>> &children,
  std::vector<std::vector<std::pair<int,int>>> &queries) {

  curr_path.push_back({idx, age[idx]});
  std::vector<std::pair<int,int>> queries_for_idx = queries[idx];
  for(auto p : queries_for_idx) {
    int sol_idx = p.first;
    int b = p.second;
    auto j = std::lower_bound(curr_path.begin(), curr_path.end(), std::make_pair(0, b), second_greater());
    solution[sol_idx] = j->first;
  }
  for(const int i : children[idx]) {
    solve_for(i, children, queries);
  }

  curr_path.pop_back();

}

// Main
void testcase() {
  // build graph
  int n, q;
  std::cin >> n >> q;

  std::unordered_map<std::string, int> name_to_ind;
  name_to_ind.clear();

  std::vector<std::vector<int>> children(n);

  age.clear();
  age.reserve(n);

  solution.clear();
  solution = std::vector<int>(q);

  curr_path.clear();

  std::vector<std::string> ind_to_name;
  ind_to_name.reserve(n);

  int root = -1;
  int max_age =  std::numeric_limits<int>::min();

  for(int i = 0; i < n; i++) {
    std::string s; int a;
    std::cin >> s; std::cin >> a;
    name_to_ind.insert({s, i});
    ind_to_name.push_back(s);
    age.push_back(a);
    if(a > max_age) {
      root = i; max_age = a;
    }
  }

  for(int i = 0; i < n - 1; i++) {
    std::string s, p;
    std::cin >> s; std::cin >> p;
    children[name_to_ind.at(p)].push_back(name_to_ind.at(s));
  }

  std::vector<std::vector<std::pair<int,int>>> queries(n);

  for(int k = 0; k < q; k++) {
    std::string s; int b;
    std::cin >> s; std::cin >> b;
    int idx = name_to_ind.at(s);
    queries[idx].push_back({k, b});
  }

  solve_for(root, children, queries);

  for(int k = 0; k < q; k++) {
    std::cout << ind_to_name[solution[k]] << " ";
  }
  std::cout << std::endl;
}

int main() {
  std::ios_base::sync_with_stdio(false);
  std::size_t t;
  for (std::cin >> t; t > 0; --t) testcase();
  return 0;
}


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include <boost/test/unit_test.hpp>
#include "armnnTfParser/ITfParser.hpp"
#include "ParserPrototxtFixture.hpp"

BOOST_AUTO_TEST_SUITE(TensorflowParser)

struct UnsupportedMaximumFixture
    : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
{
    UnsupportedMaximumFixture()
    {
        m_Prototext = R"(
            node {
                name: "graphInput"
                op: "Placeholder"
                attr {
                    key: "dtype"
                    value {
                        type: DT_FLOAT
                    }
                }
                attr {
                    key: "shape"
                    value {
                        shape {
                        }
                    }
                }
            }
            node {
                name: "Maximum"
                op: "Maximum"
                input: "graphInput"
                attr {
                    key: "dtype"
                    value {
                        type: DT_FLOAT
                    }
                }
            }
        )";
    }
};

BOOST_FIXTURE_TEST_CASE(UnsupportedMaximum, UnsupportedMaximumFixture)
{
    BOOST_CHECK_THROW(
        SetupSingleInputSingleOutput({ 1, 1 }, "graphInput", "Maximum"),
        armnn::ParseException);
}

struct SupportedMaximumFixture
    : public armnnUtils::ParserPrototxtFixture<armnnTfParser::ITfParser>
{
    SupportedMaximumFixture(const std::string & maxInput0,
                            const std::string & maxInput1,
                            const std::string & mulInput0,
                            const std::string & mulInput1)
    {
        m_Prototext = R"(
            node {
                name: "graphInput"
                op: "Placeholder"
                attr {
                    key: "dtype"
                    value { type: DT_FLOAT }
                }
                attr {
                    key: "shape"
                    value { shape { } }
                }
            }
            node {
                name: "Alpha"
                op: "Const"
                attr {
                    key: "dtype"
                    value { type: DT_FLOAT }
                }
                attr {
                    key: "value"
                    value {
                        tensor {
                            dtype: DT_FLOAT
                            tensor_shape {
                                dim { size: 1 }
                            }
                            float_val: 0.1
                        }
                    }
                }
            }
            node {
                name: "Mul"
                op: "Mul"
                input: ")" + mulInput0 + R"("
                input: ")" + mulInput1 + R"("
                attr {
                    key: "T"
                    value { type: DT_FLOAT }
                }
            }
            node {
                name: "Maximum"
                op: "Maximum"
                input: ")" + maxInput0 + R"("
                input: ")" + maxInput1 + R"("
                attr {
                    key: "T"
                    value { type: DT_FLOAT }
                }
            }
        )";
        SetupSingleInputSingleOutput({ 1, 2 }, "graphInput", "Maximum");
    }
};

struct LeakyRelu_Max_MulAT_T_Fixture : public SupportedMaximumFixture
{
    LeakyRelu_Max_MulAT_T_Fixture()
    : SupportedMaximumFixture("Mul","graphInput","Alpha","graphInput") {}
};

BOOST_FIXTURE_TEST_CASE(LeakyRelu_Max_MulAT_T, LeakyRelu_Max_MulAT_T_Fixture)
{
    RunTest<2>(std::vector<float>({-5.0, 3.0}), {-0.5, 3.0});
}

struct LeakyRelu_Max_T_MulAT_Fixture : public SupportedMaximumFixture
{
    LeakyRelu_Max_T_MulAT_Fixture()
    : SupportedMaximumFixture("graphInput","Mul","Alpha","graphInput") {}
};

BOOST_FIXTURE_TEST_CASE(LeakyRelu_Max_T_MulAT, LeakyRelu_Max_T_MulAT_Fixture)
{
    RunTest<2>(std::vector<float>({-10.0, 3.0}), {-1.0, 3.0});
}

struct LeakyRelu_Max_MulTA_T_Fixture : public SupportedMaximumFixture
{
    LeakyRelu_Max_MulTA_T_Fixture()
    : SupportedMaximumFixture("Mul", "graphInput","graphInput","Alpha") {}
};

BOOST_FIXTURE_TEST_CASE(LeakyRelu_Max_MulTA_T, LeakyRelu_Max_MulTA_T_Fixture)
{
    RunTest<2>(std::vector<float>({-5.0, 3.0}), {-0.5, 3.0});
}

struct LeakyRelu_Max_T_MulTA_Fixture : public SupportedMaximumFixture
{
    LeakyRelu_Max_T_MulTA_Fixture()
    : SupportedMaximumFixture("graphInput", "Mul", "graphInput", "Alpha") {}
};

BOOST_FIXTURE_TEST_CASE(LeakyRelu_Max_T_MulTA, LeakyRelu_Max_T_MulTA_Fixture)
{
    RunTest<2>(std::vector<float>({-10.0, 13.0}), {-1.0, 13.0});
}

BOOST_AUTO_TEST_SUITE_END()


// Boost.Maral library (Molecular Archiving, Retrieval & Algorithm Library)
//
// Copyright (C) 2014 Armin Madadkar Sobhani
//
// Distributed under the Boost Software License Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// $Id$

#ifndef MARAL_UNITS_HPP
#define MARAL_UNITS_HPP

#include <boost/units/systems/si/plane_angle.hpp>
#include <boost/units/systems/angle/degrees.hpp>
#include <boost/units/systems/angle/gradians.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/base_units/metric/angstrom.hpp>
#include <boost/units/systems/si/io.hpp>

namespace boost { namespace units
{
    typedef metric::angstrom_base_unit::unit_type angstrom_unit;
    BOOST_UNITS_STATIC_CONSTANT(angstrom, angstrom_unit);
    BOOST_UNITS_STATIC_CONSTANT(angstroms, angstrom_unit);

    typedef scaled_base_unit<si::meter_base_unit,
            scale<10, static_rational<-9> > > nanometer_base_unit;
    typedef nanometer_base_unit::unit_type nanometer_unit;
    BOOST_UNITS_STATIC_CONSTANT(nanometer, nanometer_unit);
    BOOST_UNITS_STATIC_CONSTANT(nanometers, nanometer_unit);

}}  // namespace boost::units

namespace maral {

////////////////////////////////////////////////////////////////////////////////
/// \brief Namespace for units, quantities and unit system support.
///
/// Namespace for supporting units, quantities, unit system and dimensional
/// analysis. It is based on Boost.Units. Some terminology from Boost.Units:
///
/// \li \b Unit: A set of base units raised to rational exponents, e.g. m^1,
/// kg^1, m^1/s^2.
/// \li \b Quantity: A quantity represents a concrete amount of a unit. Thus,
/// while the meter is the base unit of length in the SI system, 5.5 meters is a
/// quantity of length in that system.
/// \li \b System: A unit system is a collection of base units representing all
/// the measurable entities of interest for a specific problem.
///
/// Maral uses SI unit system by default.

namespace units {

////////////////////////////////////////////////////////////////////////////////
// Units for Angle

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing angles in
/// radians.
///
/// \param Type Value type of the angle (e.g. int, float, double, ...).
/// \remarks
/// \par
/// A partial specialization of boost::units::quantity for storing angle values
/// in radians.
/// \see radians, to_radians

template <typename Type>
using angle_in_radians =
    boost::units::quantity<boost::units::si::plane_angle, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing angles in
/// degrees.
///
/// \param Type Value type of the angle (e.g. int, float, double, ...).
/// \remarks
/// \par
/// A partial specialization of boost::units::quantity for storing angle values
/// in degrees.
/// \see degrees, to_degrees

template <typename Type>
using angle_in_degrees =
    boost::units::quantity<boost::units::degree::plane_angle, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing angles in
/// gradians.
///
/// \param Type Value type of the angle (e.g. int, float, double, ...).
/// \remarks
/// \par
/// A partial specialization of boost::units::quantity for storing angle values
/// in gradians.
/// \see degrees, to_degrees

template <typename Type>
using angle_in_gradians =
    boost::units::quantity<boost::units::gradian::plane_angle, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \return Created angle in raidans as a boost::units::quantity object.
/// \param rad Angle value in radians.
/// \remarks
/// Type-safe factory method for creating an angle in radians from a value
/// specified.
/// \see to_radians

template <typename Type>
inline
angle_in_radians<Type> radians(Type rad)
{
    return angle_in_radians<Type>(rad * boost::units::si::radians);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Created angle in degrees as a boost::units::quantity object.
/// \param deg Angle value in degrees.
/// \remarks
/// Type-safe factory method for creating an angle in degrees from a value
/// specified.
/// \see to_degrees

template <typename Type>
inline
angle_in_degrees<Type> degrees(Type deg)
{
    return angle_in_degrees<Type>(deg * boost::units::degree::degrees);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Created angle in gradians as a boost::units::quantity object.
/// \param grd Angle value in gradians.
/// \remarks
/// Type-safe factory method for creating an angle in gradians from a value
/// specified.
/// \see to_gradians

template <typename Type>
inline
angle_in_gradians<Type> gradians(Type grd)
{
    return angle_in_degrees<Type>(grd * boost::units::gradian::gradians);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Angle in radians.
/// \param ang Reference to an angle quantity object.
/// \remarks
/// Conversion method for getting angle quantity in radians.
/// \see radians

template <typename Unit, typename Type>
inline
angle_in_radians<Type> to_radians(
    const boost::units::quantity<Unit, Type>& ang)
{
    return static_cast< angle_in_radians<Type> > (ang);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Angle in degrees.
/// \param ang Reference to an angle quantity object.
/// \remarks
/// Conversion method for getting angle quantity in degrees.
/// \see degrees

template <typename Unit, typename Type>
inline
angle_in_degrees<Type> to_degrees(
    const boost::units::quantity<Unit, Type>& ang)
{
    return static_cast< angle_in_degrees<Type> > (ang);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Angle in gradians.
/// \param ang Reference to an angle quantity object.
/// \remarks
/// Conversion method for getting angle quantity in gradians.
/// \see gradians

template <typename Unit, typename Type>
inline
angle_in_gradians<Type> to_gradians(
    const boost::units::quantity<Unit, Type>& ang)
{
    return static_cast< angle_in_gradians<Type> > (ang);
}

////////////////////////////////////////////////////////////////////////////////
// Units for Length

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing length in
/// Angstroms.
///
/// \param Type Value type of the length (e.g. int, float, double, ...).
/// \remarks
/// \par
/// An alias of boost::units::quantity for storing length values in Angstroms.
/// \see angstroms, to_angstroms

template <typename Type>
using length_in_angstroms =
    boost::units::quantity<boost::units::angstrom_unit, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing length in
/// nanometers.
///
/// \param Type Value type of the length (e.g. int, float, double, ...).
/// \remarks
/// \par
/// An alias of boost::units::quantity for storing length values in nanometers.
/// \see nanometers, to_nanometers

template <typename Type>
using length_in_nanometers =
    boost::units::quantity<boost::units::nanometer_unit, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \brief Specialization of boost::units::quantity for storing angles in
/// gradians.
///
/// \param Type Value type of the angle (e.g. int, float, double, ...).
/// \remarks
/// \par
/// A partial specialization of boost::units::quantity for storing angle values
/// in gradians.
/// \see degrees, to_degrees

//template <typename Type>
//using angle_in_gradians =
//    boost::units::quantity<boost::units::gradian::plane_angle, Type>;

////////////////////////////////////////////////////////////////////////////////
/// \return Created length in Angstroms as a boost::units::quantity object.
/// \param ang Length value in Angstroms.
/// \remarks
/// Type-safe factory method for creating a length in Angstroms from a value
/// specified.
/// \see to_angstroms

template <typename Type>
inline
length_in_angstroms<Type> angstroms(Type ang)
{
    return length_in_angstroms<Type>(ang * boost::units::angstroms);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Created length in nanometers as a boost::units::quantity object.
/// \param len Length value in nanometers.
/// \remarks
/// Type-safe factory method for creating a length in nanometers from a value
/// specified.
/// \see to_nanometers

template <typename Type>
inline
length_in_nanometers<Type> nanometers(Type len)
{
    return length_in_nanometers<Type>(len * boost::units::nanometers);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Created angle in gradians as a boost::units::quantity object.
/// \param grd Angle value in gradians.
/// \remarks
/// Type-safe factory method for creating an angle in gradians from a value
/// specified.
/// \see to_gradians

//template <typename Type>
//inline
//angle_in_gradians<Type> gradians(Type grd)
//{
//    return angle_in_degrees<Type>(grd * boost::units::gradian::gradians);
//}

////////////////////////////////////////////////////////////////////////////////
/// \return Length in Angstroms.
/// \param len Reference to a length quantity object.
/// \remarks
/// Conversion method for getting length quantity in Angstroms.
/// \see angstroms

template <typename Unit, typename Type>
inline
length_in_angstroms<Type> to_angstroms(
    const boost::units::quantity<Unit, Type>& len)
{
    return static_cast< length_in_angstroms<Type> > (len);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Length in nanometers.
/// \param len Reference to a length value.
/// \remarks
/// Conversion method for getting a length quantity in nanometers.
/// \see nanometers

template <typename Unit, typename Type>
inline
length_in_nanometers<Type> to_nanometers(
    const boost::units::quantity<Unit, Type>& len)
{
    return static_cast< length_in_nanometers<Type> > (len);
}

////////////////////////////////////////////////////////////////////////////////
/// \return Angle in gradians.
/// \param ang Reference to an angle quantity object.
/// \remarks
/// Conversion method for getting angle quantity in gradians.
/// \see gradians

//template <typename Unit, typename Type>
//inline
//angle_in_gradians<Type> to_gradians(
//    const boost::units::quantity<Unit, Type>& ang)
//{
//    return static_cast< angle_in_gradians<Type> > (ang);
//}

}}    // namespace maral::units

#endif    // MARAL_UNITS_HPP


/***************************************************************************
 * Copyright 1998-2020 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxCoreRender.                                   *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#include <stdexcept>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

#include "slg/film/film.h"
#include "slg/film/imagepipeline/plugins/colorlut.h"
#include "slg/utils/filenameresolver.h"

using namespace std;
using namespace luxrays;
using namespace slg;

//------------------------------------------------------------------------------
// ColorLUT filter plugin
//------------------------------------------------------------------------------

BOOST_CLASS_EXPORT_IMPLEMENT(slg::ColorLUTPlugin)

ColorLUTPlugin::ColorLUTPlugin(const string &filmName, const float str) {
	const string resolvedFileName = SLG_FileNameResolver.ResolveFile(filmName);

	lut = octoon::image::detail::basic_lut<float>::parse(resolvedFileName);
	strength = str;
}

ColorLUTPlugin::~ColorLUTPlugin() {
}

ColorLUTPlugin::ColorLUTPlugin() {
}

ImagePipelinePlugin *ColorLUTPlugin::Copy() const {
	ColorLUTPlugin *clp = new ColorLUTPlugin();

	const string dump = lut.dump();
	istringstream is(dump);
	clp->lut.create(is);

	return clp;
}

//------------------------------------------------------------------------------
// CPU version
//------------------------------------------------------------------------------

void ColorLUTPlugin::Apply(Film &film, const u_int index) {
	Spectrum *pixels = (Spectrum *)film.channel_IMAGEPIPELINEs[index]->GetPixels();
	const u_int pixelCount = film.GetWidth() * film.GetHeight();

	const bool hasPN = film.HasChannel(Film::RADIANCE_PER_PIXEL_NORMALIZED);
	const bool hasSN = film.HasChannel(Film::RADIANCE_PER_SCREEN_NORMALIZED);

	#pragma omp parallel for
	for (
		// Visual C++ 2013 supports only OpenMP 2.5
#if _OPENMP >= 200805
		unsigned
#endif
		int i = 0; i < pixelCount; ++i) {
		if (film.HasSamples(hasPN, hasSN, i)) {
			Spectrum color = pixels[i].Clamp(0.f, 1.f);
			auto transformedColor = lut.lookup(color.c[0], color.c[1], color.c[2]);
			pixels[i].c[0] = Lerp(strength, color.c[0], transformedColor[0]);
			pixels[i].c[1] = Lerp(strength, color.c[1], transformedColor[1]);
			pixels[i].c[2] = Lerp(strength, color.c[2], transformedColor[2]);
		}
	}
}


// Copyright (c) 2018 The Xaya developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chain.h>
#include <chainparams.h>
#include <consensus/params.h>
#include <pow.h>
#include <powdata.h>

#include <test/test_bitcoin.h>

#include <boost/test/unit_test.hpp>

/* No space between BOOST_FIXTURE_TEST_SUITE and '(', so that extraction of
   the test-suite name works with grep as done in the Makefile.  */
BOOST_FIXTURE_TEST_SUITE(dualalgo_tests, TestingSetup)

/* ************************************************************************** */

namespace
{

/* Original DGW difficulty formula that does not take algo into account except
   for the PoW limit.  We use that as golden truth after separating the blocks
   of each difficulty into individual chains to test our per-algo difficulty
   retargeting function.  */
unsigned int
OriginalDGW(const PowAlgo algo, const CBlockIndex* pindexLast, const Consensus::Params& params) {
    /* current difficulty formula, dash - DarkGravity v3, written by Evan Duffield - evan@dash.org */
    const arith_uint256 bnPowLimit
        = UintToArith256(powLimitForAlgo(algo, params));
    constexpr int64_t nPastBlocks = 24;

    // make sure we have at least (nPastBlocks + 1) blocks, otherwise just return powLimit
    if (!pindexLast || pindexLast->nHeight < nPastBlocks) {
        return bnPowLimit.GetCompact();
    }

    const CBlockIndex *pindex = pindexLast;
    arith_uint256 bnPastTargetAvg;

    for (unsigned int nCountBlocks = 1; nCountBlocks <= nPastBlocks; nCountBlocks++) {
        const arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits);
        if (nCountBlocks == 1) {
            bnPastTargetAvg = bnTarget;
        } else {
            // NOTE: that's not an average really...
            bnPastTargetAvg = (bnPastTargetAvg * nCountBlocks + bnTarget) / (nCountBlocks + 1);
        }

        if(nCountBlocks != nPastBlocks) {
            assert(pindex->pprev); // should never fail
            pindex = pindex->pprev;
        }
    }

    arith_uint256 bnNew(bnPastTargetAvg);

    const int nextHeight = pindexLast->nHeight + 1;
    int64_t nActualTimespan = pindexLast->GetBlockTime() - pindex->GetBlockTime();
    // NOTE: is this accurate? nActualTimespan counts it for (nPastBlocks - 1) blocks only...
    int64_t nTargetTimespan
        = nPastBlocks * params.rules->GetTargetSpacing(algo, nextHeight);

    if (nActualTimespan < nTargetTimespan/3)
        nActualTimespan = nTargetTimespan/3;
    if (nActualTimespan > nTargetTimespan*3)
        nActualTimespan = nTargetTimespan*3;

    // Retarget
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > bnPowLimit) {
        bnNew = bnPowLimit;
    }

    return bnNew.GetCompact();
}

class TestChain
{

private:

  std::vector<std::unique_ptr<CBlockIndex>> blocks;

public:

  CBlockIndex*
  tip () const
  {
    if (blocks.empty ())
      return nullptr;
    return blocks.back ().get ();
  }

  unsigned
  height () const
  {
    const CBlockIndex* pindex = tip ();
    return pindex == nullptr ? 0 : pindex->nHeight;
  }

  void
  attach (const CBlockIndex& indexNew)
  {
    std::unique_ptr<CBlockIndex> modified(new CBlockIndex (indexNew));
    modified->pprev = tip ();
    modified->nHeight = blocks.size ();
    blocks.push_back (std::move (modified));
  }

};

} // anonymous namespace

BOOST_AUTO_TEST_CASE (difficulty_retargeting)
{
  /* The test for our dual-algo difficulty retargeting works as follows:
     We construct a chain of blocks with randomly chosen algorithms and
     block times (nBits of each block is set according to GetNextWorkRequired,
     although that does not really matter).  We also attach the same blocks
     to two separate chains that contain only blocks of each algo.  We then
     verify that our GetNextWorkRequired function returns the same result as
     the original DGW function does for the single-algo chain.  */

  const Consensus::Params& params = Params ().GetConsensus ();
  BOOST_CHECK (!params.fPowNoRetargeting);

  for (unsigned trials = 0; trials < 5; ++trials)
    {
      TestChain mixedChain;
      std::map<PowAlgo, TestChain> perAlgoChains;

      uint32_t lastTime = 1000000000;

      for (unsigned len = 0; len < 500; ++len)
        {
          for (const PowAlgo algo : {PowAlgo::SHA256D, PowAlgo::NEOSCRYPT})
            {
              const uint32_t nextWork
                  = GetNextWorkRequired (algo, mixedChain.tip (), params);
              const uint32_t golden
                  = OriginalDGW (algo, perAlgoChains[algo].tip (), params);
              BOOST_CHECK_EQUAL (nextWork, golden);
            }

          CBlockIndex indexNew;
          if (InsecureRandBool ())
            indexNew.algo = PowAlgo::SHA256D;
          else
            indexNew.algo = PowAlgo::NEOSCRYPT;
          indexNew.nBits = GetNextWorkRequired (indexNew.algo,
                                                mixedChain.tip (), params);

          /* Increment the time typically, but allow also decrements.  Average
             time increase should be AvgTargetSpacing,
             so choosing randomly in [-10, target spacing - 10] seems
             like a good enough approximation.  Since these values are actually
             then a bit faster than expected, we increase the difficulty away
             from the minimum, which is also good for the test.  */
          const int64_t targetSpacing
              = AvgTargetSpacing (params, mixedChain.height () + 1);
          indexNew.nTime = lastTime
                            + InsecureRandRange (targetSpacing)
                            - 10;
          lastTime = indexNew.nTime;

          mixedChain.attach (indexNew);
          perAlgoChains[indexNew.algo].attach (indexNew);
        }

      /* Verify that we have actually increased the difficulty and not just
         stuck to the minimum (which would make the test somewhat trivial).  */
      for (const auto& entry : perAlgoChains)
        BOOST_CHECK (entry.second.tip ()->nBits
                      != GetNextWorkRequired (entry.first, nullptr, params));
    }
}

/* ************************************************************************** */

namespace
{

constexpr unsigned BEFORE_FORK = 200;
constexpr unsigned AFTER_FORK = 800;

class PostIcoForkSetup : public TestingSetup
{
public:

  const Consensus::Params* params = nullptr;

  PostIcoForkSetup ()
  {
    SelectParams (CBaseChainParams::REGTEST);
    params = &Params ().GetConsensus ();

    BOOST_CHECK (!params->rules->ForkInEffect (Consensus::Fork::POST_ICO,
                                               BEFORE_FORK));
    BOOST_CHECK (params->rules->ForkInEffect (Consensus::Fork::POST_ICO,
                                              AFTER_FORK));
  }

};

} // anonymous namespace

BOOST_FIXTURE_TEST_CASE (avg_target_spacing, PostIcoForkSetup)
{
  BOOST_CHECK_EQUAL (AvgTargetSpacing (*params, BEFORE_FORK), 30);
  BOOST_CHECK_EQUAL (AvgTargetSpacing (*params, AFTER_FORK), 30);
}

namespace
{

class BlockProofEquivalentTimeSetup : public PostIcoForkSetup
{
public:

  TestChain chain;

  BlockProofEquivalentTimeSetup ()
  {
    /* Turn off "no retargeting" rule.  We won't need to mine valid blocks
       anyway, and this messes with the "relative difficulty" between
       the algorithms as it disables rescaling of the minimum difficulty.  */
    const_cast<Consensus::Params*> (params)->fPowNoRetargeting = false;
  }

  /**
   * Attaches a block with minimum difficulty and the given algorithm
   * to the test chain.
   */
  void
  AttachBlock (const PowAlgo algo)
  {
    CBlockIndex indexNew;
    indexNew.algo = algo;

    const uint256 bnPowLimit = powLimitForAlgo (indexNew.algo, *params);
    indexNew.nBits = UintToArith256 (bnPowLimit).GetCompact ();

    arith_uint256 previousWork;
    if (chain.tip () != nullptr)
      previousWork = chain.tip ()->nChainWork;
    indexNew.nChainWork = previousWork + GetBlockProof (indexNew);

    chain.attach (indexNew);
  }

  /**
   * Computes the proof-equivalent-time from tip-n to tip.
   */
  int64_t
  GetEquivalentTime (const unsigned n) const
  {
    const CBlockIndex* beforeTip = chain.tip ();
    for (unsigned i = 0; i < n; ++i)
      beforeTip = beforeTip->pprev;

    return GetBlockProofEquivalentTime (*chain.tip (), *beforeTip,
                                        *chain.tip (), *params);
  }

};

} // anonymous namespace

BOOST_FIXTURE_TEST_CASE (eqv_time_before_fork, BlockProofEquivalentTimeSetup)
{
  for (unsigned i = 0; i <= BEFORE_FORK; ++i)
    AttachBlock (i % 2 == 0 ? PowAlgo::SHA256D : PowAlgo::NEOSCRYPT);
  BOOST_CHECK_EQUAL (chain.height (), BEFORE_FORK);

  BOOST_CHECK_EQUAL (GetEquivalentTime (2), 60);
}

BOOST_FIXTURE_TEST_CASE (eqv_time_after_fork, BlockProofEquivalentTimeSetup)
{
  /* After the fork, attach one SHA-256d block for every three Neoscrypt
     blocks, as that corresponds to the ratio afterwards.  We expect four
     of those blocks to be equivalent to two minutes' time.  */

  for (unsigned i = 0; i <= AFTER_FORK; ++i)
    AttachBlock (i % 4 == 0 ? PowAlgo::SHA256D : PowAlgo::NEOSCRYPT);
  BOOST_CHECK_EQUAL (chain.height (), AFTER_FORK);

  BOOST_CHECK_EQUAL (GetEquivalentTime (4), 120);
}

/* ************************************************************************** */

BOOST_AUTO_TEST_SUITE_END ()


/**
 * @author Andre Anjos <andre.anjos@idiap.ch>
 * @date Sun 27 Oct 09:02:32 2013
 *
 * @brief Gamma distributions (with integers or floating point numbers)
 */

#define BOB_CORE_RANDOM_MODULE
#include <bob.core/random_api.h>
#include <bob.blitz/cppapi.h>
#include <bob.blitz/cleanup.h>
#include <bob.extension/documentation.h>
#include <boost/make_shared.hpp>

#include <bob.core/random.h>
#include <boost/random.hpp>

static auto gamma_doc = bob::extension::ClassDoc(
  BOB_EXT_MODULE_PREFIX ".gamma",
  "Models a random gamma distribution",
  "This distribution produces random numbers :math:`x` distributed with the probability density function\n\n"
  ".. math::\n\n   p(x) = x^{\\alpha-1}\\frac{e^{-x}}{\\Gamma(\\alpha)}\n\n"
  "where ``alpha`` (:math:`\\alpha`) is a parameter of this distribution class."
)
.add_constructor(bob::extension::FunctionDoc(
  "gamma",
  "Constructs a new gamma distribution object"
)
.add_prototype("dtype, [alpha]", "")
.add_parameter("dtype", ":py:class:`numpy.dtype` or anything that converts to a dtype", "The data type to get the distribution for; only real-valued types are supported")
.add_parameter("alpha", "dtype", "[Default: 1.] The mean :math:`\\alpha` of the gamma distibution")
);

/* How to create a new PyBoostGammaObject */
static PyObject* PyBoostGamma_New(PyTypeObject* type, PyObject*, PyObject*) {
  /* Allocates the python object itself */
  PyBoostGammaObject* self = (PyBoostGammaObject*)type->tp_alloc(type, 0);
  self->type_num = NPY_NOTYPE;
  self->distro.reset();

  return Py_BuildValue("N", self);
}

/* How to delete a PyBoostGammaObject */
static void PyBoostGamma_Delete (PyBoostGammaObject* o) {
  o->distro.reset();
  Py_TYPE(o)->tp_free((PyObject*)o);
}

template <typename T>
boost::shared_ptr<void> make_gamma(PyObject* alpha) {
  T calpha = 1.;
  if (alpha) calpha = PyBlitzArrayCxx_AsCScalar<T>(alpha);
  return boost::make_shared<bob::core::random::gamma_distribution<T>>(calpha);
}

PyObject* PyBoostGamma_SimpleNew (int type_num, PyObject* alpha) {
BOB_TRY
  PyBoostGammaObject* retval = (PyBoostGammaObject*)PyBoostGamma_New(&PyBoostGamma_Type, 0, 0);
  if (!retval) return 0;
  auto retval_ = make_safe(retval);

  retval->type_num = type_num;

  switch(type_num) {
    case NPY_FLOAT32:
      retval->distro = make_gamma<float>(alpha);
      break;
    case NPY_FLOAT64:
      retval->distro = make_gamma<double>(alpha);
      break;
    default:
      PyErr_Format(PyExc_NotImplementedError, "cannot create %s(T) with T having an unsupported numpy type number of %d (it only supports numpy.float32 or numpy.float64)", Py_TYPE(retval)->tp_name, retval->type_num);
      return 0;
  }

  if (!retval->distro) { // a problem occurred
    return 0;
  }

  return Py_BuildValue("O", retval);
BOB_CATCH_FUNCTION("SimpleNew", 0)
}

/* Implements the __init__(self) function */
static int PyBoostGamma_Init(PyBoostGammaObject* self, PyObject *args, PyObject* kwds) {
BOB_TRY
  static char** kwlist = gamma_doc.kwlist();

  PyObject* alpha = 0;

  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O", kwlist, &PyBlitzArray_TypenumConverter, &self->type_num, &alpha)) return -1; ///< FAILURE

  switch(self->type_num) {
    case NPY_FLOAT32:
      self->distro = make_gamma<float>(alpha);
      break;
    case NPY_FLOAT64:
      self->distro = make_gamma<double>(alpha);
      break;
    default:
      PyErr_Format(PyExc_NotImplementedError, "cannot create %s(T) with T having an unsupported numpy type number of %d (it only supports numpy.float32 or numpy.float64)", Py_TYPE(self)->tp_name, self->type_num);
      return -1;
  }

  if (!self->distro) { // a problem occurred
    return -1;
  }

  return 0; ///< SUCCESS
BOB_CATCH_MEMBER("constructor", -1)
}

int PyBoostGamma_Check(PyObject* o) {
  if (!o) return 0;
  return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBoostGamma_Type));
}

int PyBoostGamma_Converter(PyObject* o, PyBoostGammaObject** a) {
  if (!PyBoostGamma_Check(o)) return 0;
  Py_INCREF(o);
  (*a) = reinterpret_cast<PyBoostGammaObject*>(o);
  return 1;
}

static auto alpha_doc = bob::extension::VariableDoc(
  "alpha",
  "dtype",
  "The alpha parameter that the distribution currently has"
);
template <typename T> PyObject* get_alpha(PyBoostGammaObject* self) {
  return PyBlitzArrayCxx_FromCScalar(boost::static_pointer_cast<bob::core::random::gamma_distribution<T>>(self->distro)->alpha());
}

static PyObject* PyBoostGamma_GetAlpha(PyBoostGammaObject* self) {
BOB_TRY
  switch (self->type_num) {
    case NPY_FLOAT32:
      return get_alpha<float>(self);
    case NPY_FLOAT64:
      return get_alpha<double>(self);
    default:
      PyErr_Format(PyExc_NotImplementedError, "cannot get alpha parameter of %s(T) with T having an unsupported numpy type number of %d (DEBUG ME)", Py_TYPE(self)->tp_name, self->type_num);
      return 0;
  }
BOB_CATCH_MEMBER("alpha", 0)
}

static auto dtype_doc = bob::extension::VariableDoc(
  "dtype",
  ":py:class:`numpy.dtype`",
  "The type of scalars produced by this normal distribution"
);
static PyObject* PyBoostGamma_GetDtype(PyBoostGammaObject* self) {
BOB_TRY
  return reinterpret_cast<PyObject*>(PyArray_DescrFromType(self->type_num));
BOB_CATCH_MEMBER("dtype", 0)
}

static PyGetSetDef PyBoostGamma_getseters[] = {
    {
      dtype_doc.name(),
      (getter)PyBoostGamma_GetDtype,
      0,
      dtype_doc.doc(),
      0,
    },
    {
      alpha_doc.name(),
      (getter)PyBoostGamma_GetAlpha,
      0,
      alpha_doc.doc(),
      0,
    },
    {0}  /* Sentinel */
};

static auto reset_doc = bob::extension::FunctionDoc(
  "reset",
  "Resets this distribution",
  "After calling this method, subsequent uses of the distribution do not depend on values produced by any random number generator prior to invoking reset",
  true
)
.add_prototype("")
;
template <typename T> PyObject* reset(PyBoostGammaObject* self) {
  boost::static_pointer_cast<bob::core::random::gamma_distribution<T>>(self->distro)->reset();
  Py_RETURN_NONE;
}

static PyObject* PyBoostGamma_Reset(PyBoostGammaObject* self) {
BOB_TRY
  switch (self->type_num) {
    case NPY_FLOAT32:
      return reset<float>(self);
    case NPY_FLOAT64:
      return reset<double>(self);
    default:
      PyErr_Format(PyExc_NotImplementedError, "cannot reset %s(T) with T having an unsupported numpy type number of %d (DEBUG ME)", Py_TYPE(self)->tp_name, self->type_num);
      return 0;
  }
BOB_CATCH_MEMBER("reset", 0)
}

static auto call_doc = bob::extension::FunctionDoc(
  "draw",
  "Draws one random number from this distribution using the given ``rng``",
  ".. note:: The :py:meth:`__call__` function is a synonym for this ``draw``.",
  true
)
.add_prototype("rng", "value")
.add_parameter("rng", ":py:class:`mt19937`", "The random number generator to use")
.add_return("value", "dtype", "A random value that follows the gamma distribution")
;
template <typename T> PyObject* call(PyBoostGammaObject* self, PyBoostMt19937Object* rng) {
  typedef bob::core::random::gamma_distribution<T> distro_t;
  return PyBlitzArrayCxx_FromCScalar((*boost::static_pointer_cast<distro_t>(self->distro))(*rng->rng));
}

/**
 * Calling a PyBoostGammaObject to generate a random number
 */
static PyObject* PyBoostGamma_Call(PyBoostGammaObject* self, PyObject *args, PyObject* kwds) {
BOB_TRY
  char** kwlist = call_doc.kwlist();

  PyBoostMt19937Object* rng;

  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &PyBoostMt19937_Type, &rng)) return 0; ///< FAILURE

  switch(self->type_num) {
    case NPY_FLOAT32:
      return call<float>(self, rng);
      break;
    case NPY_FLOAT64:
      return call<double>(self, rng);
      break;
    default:
      PyErr_Format(PyExc_NotImplementedError, "cannot call %s(T) with T having an unsupported numpy type number of %d (DEBUG ME)", Py_TYPE(self)->tp_name, self->type_num);
  }

  return 0; ///< FAILURE
BOB_CATCH_MEMBER("call", 0)
}

static PyMethodDef PyBoostGamma_methods[] = {
    {
      call_doc.name(),
      (PyCFunction)PyBoostGamma_Call,
      METH_VARARGS|METH_KEYWORDS,
      call_doc.doc(),
    },
    {
      reset_doc.name(),
      (PyCFunction)PyBoostGamma_Reset,
      METH_NOARGS,
      reset_doc.doc(),
    },
    {0}  /* Sentinel */
};

extern PyObject* scalar_to_bytes(PyObject* s);

/**
 * String representation and print out
 */
static PyObject* PyBoostGamma_Repr(PyBoostGammaObject* self) {

  PyObject* salpha = scalar_to_bytes(PyBoostGamma_GetAlpha(self));
  if (!salpha) return 0;
  auto salpha_ = make_safe(salpha);

  return
    PyString_FromFormat
      (
       "%s(dtype='%s', alpha=%s)",
       Py_TYPE(self)->tp_name, PyBlitzArray_TypenumAsString(self->type_num),
       PyString_AS_STRING(salpha)
       );
}

PyTypeObject PyBoostGamma_Type = {
  PyVarObject_HEAD_INIT(0,0)
  0
};

bool init_BoostGamma(PyObject* module)
{
  // initialize the type struct
  PyBoostGamma_Type.tp_name = gamma_doc.name();
  PyBoostGamma_Type.tp_basicsize = sizeof(PyBoostGammaObject);
  PyBoostGamma_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  PyBoostGamma_Type.tp_doc = gamma_doc.doc();
  PyBoostGamma_Type.tp_str = reinterpret_cast<reprfunc>(PyBoostGamma_Repr);
  PyBoostGamma_Type.tp_repr = reinterpret_cast<reprfunc>(PyBoostGamma_Repr);

  // set the functions
  PyBoostGamma_Type.tp_new = PyBoostGamma_New;
  PyBoostGamma_Type.tp_init = reinterpret_cast<initproc>(PyBoostGamma_Init);
  PyBoostGamma_Type.tp_dealloc = reinterpret_cast<destructor>(PyBoostGamma_Delete);
  PyBoostGamma_Type.tp_methods = PyBoostGamma_methods;
  PyBoostGamma_Type.tp_getset = PyBoostGamma_getseters;
  PyBoostGamma_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBoostGamma_Call);

  // check that everything is fine
  if (PyType_Ready(&PyBoostGamma_Type) < 0) return false;

  // add the type to the module
  return PyModule_AddObject(module, "gamma", Py_BuildValue("O", &PyBoostGamma_Type)) >= 0;
}