//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012 - 2014 MetaScale SAS
//
//          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
//==============================================================================
#ifndef BOOST_SIMD_ARITHMETIC_FUNCTIONS_SIMD_COMMON_FLOOR_HPP_INCLUDED
#define BOOST_SIMD_ARITHMETIC_FUNCTIONS_SIMD_COMMON_FLOOR_HPP_INCLUDED

#include <boost/simd/arithmetic/functions/floor.hpp>
#include <boost/simd/include/functions/simd/round2even.hpp>
#include <boost/simd/include/functions/simd/selsub.hpp>
#include <boost/simd/include/functions/simd/is_greater.hpp>
#include <boost/simd/include/constants/one.hpp>
#include <boost/dispatch/attributes.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT          ( floor_, tag::cpu_
                                    , (A0)(X)
                                    , ((simd_<floating_<A0>,X>))
                                    )
  {
    typedef A0 result_type;
    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL(1)
    {
      const A0 d0 = round2even(a0);
      return selsub(gt(d0,a0),d0,One<A0>());
    }
  };
} } }

#endif


#include "VoronoiParametrization.hh"

#include <cmath>
#include <OpenMesh/Core/Utils/PropertyManager.hh>

#include <Eigen/Dense>

namespace betri
{

void VoronoiParametrization::prepare()
{
	if(!m_mesh.get_property_handle(m_vweight, vweightName))
		m_mesh.add_property(m_vweight, vweightName);

	if (!m_mesh.get_property_handle(m_eweight, eweightName))
		m_mesh.add_property(m_eweight, eweightName);

	if(!m_mesh.get_property_handle(m_sysid, sysidName))
		m_mesh.add_property(m_sysid, sysidName);

	// calculate cotangent edge weights (only needs to be done once)

	Scalar w;
	HalfedgeHandle    h0, h1, h2;
	VertexHandle      v0, v1;
	Point             p0, p1, p2, d0, d1;

	if (m_mode == WeightMode::cotangent) {

		for (auto e_it = m_mesh.edges_begin(), e_e = m_mesh.edges_end();
			e_it != e_e; ++e_it
		) {
			w = 0.0;

			// Compute cotangent edge weights

			h0 = m_mesh.halfedge_handle(*e_it, 0);
			v0 = m_mesh.to_vertex_handle(h0);
			p0 = m_mesh.point(v0);

			h1 = m_mesh.halfedge_handle(*e_it, 1);
			v1 = m_mesh.to_vertex_handle(h1);
			p1 = m_mesh.point(v1);

			h2 = m_mesh.next_halfedge_handle(h0);
			p2 = m_mesh.point(m_mesh.to_vertex_handle(h2));
			d0 = (p0 - p2).normalize();
			d1 = (p1 - p2).normalize();
			w += 1.0 / tan(acos(d0 | d1));

			h2 = m_mesh.next_halfedge_handle(h1);
			p2 = m_mesh.point(m_mesh.to_vertex_handle(h2));
			d0 = (p0 - p2).normalize();
			d1 = (p1 - p2).normalize();
			w += 1.0 / tan(acos(d0 | d1));

			weight(*e_it) = w;
		}
	} else {
		for (auto e_it = m_mesh.edges_begin(), e_e = m_mesh.edges_end();
			e_it != e_e; ++e_it
		) {
			weight(*e_it) = 1.0;
		}
	}
}

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

void VoronoiParametrization::cleanup()
{
	if (m_mesh.get_property_handle(m_vweight,  vweightName))
		m_mesh.remove_property(m_vweight);

	if (m_mesh.get_property_handle(m_sysid, sysidName))
		m_mesh.remove_property(m_sysid);
}

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

void VoronoiParametrization::calcWeights(
	BezierTMesh &mesh,
	WeightMode &mode,
	OpenMesh::VPropHandleT<Scalar> &vweight,
	OpenMesh::PropertyManager<OpenMesh::VPropHandleT<bool>, BezierTMesh> &inFace
) {
	Scalar area;

	if (mode == WeightMode::cotangent) {

		for (auto v_it = mesh.vertices_begin(), v_e = mesh.vertices_end();
			v_it != v_e; ++v_it
		) {
			area = 0.0;

			auto vf_end = mesh.vf_end(*v_it);
			for (auto vf_it = mesh.vf_begin(*v_it); vf_it != vf_end; ++vf_it) {

				auto fv_it = mesh.fv_begin(*vf_it);

				bool relevant = inFace[*fv_it];

				const Point& P = mesh.point(*fv_it);  ++fv_it;
				relevant = relevant || inFace[*fv_it];
				const Point& Q = mesh.point(*fv_it);  ++fv_it;
				relevant = relevant || inFace[*fv_it];
				const Point& R = mesh.point(*fv_it);

				if (relevant) {
					area += ((Q - P) % (R - P)).norm() * 0.5 * 0.3333;
				}
			}

			mesh.property(vweight, *v_it) = 1.0 / (2.0 * area);
		}
	} else {

		const auto valence = [&](VertexHandle vh) {

			int val = 0;
			for (auto vv_it = mesh.cvv_begin(vh), v_e = mesh.cvv_end(vh); vv_it != v_e; ++vv_it) {
				if (inFace[*vv_it]) {
					val++;
				}
			}
			return val;
		};

		for (auto v_it = mesh.vertices_begin(), v_e = mesh.vertices_end();
			v_it != v_e; ++v_it
		) {
			mesh.property(vweight, *v_it) = 1.0 / valence(*v_it);
		}
	}
}

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

void VoronoiParametrization::calcWeights(const FaceHandle face)
{
	auto inFace = OpenMesh::makeTemporaryProperty<VertexHandle, bool>(m_mesh);
	// mark all inner vertices as belonging to this face
	for (VertexHandle vh : *m_inner) {
		inFace[vh] = true;
	}
	// mark all border vertices as belonging to this face
	const ShortestPath &ab = ShortestPath::path(ttv(face)[0], ttv(face)[1]);
	for (VertexHandle vh : ab.list()) {
		inFace[vh] = true;
	}
	const ShortestPath &bc = ShortestPath::path(ttv(face)[1], ttv(face)[2]);
	for (VertexHandle vh : bc.list()) {
		inFace[vh] = true;
	}
	const ShortestPath &ca = ShortestPath::path(ttv(face)[2], ttv(face)[0]);
	for (VertexHandle vh : ca.list()) {
		inFace[vh] = true;
	}

	calcWeights(m_mesh, m_mode, m_vweight, inFace);
}

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

void VoronoiParametrization::initCoords(const FaceHandle face)
{
	// map boundary vertices onto triangle in texture space
	// (preserve edge length ratio)

	size_t innerIdx = 0;
	// reset all (interior) coordinates to triangle midpoint (also circle midpoint)
	for (auto vh : *m_inner) {
		hmap(vh) = m_mapper.middle();
		sysid(vh) = innerIdx++;
	}

	const ShortestPath &ab = ShortestPath::path(ttv(face)[0], ttv(face)[1]);
	const ShortestPath &bc = ShortestPath::path(ttv(face)[1], ttv(face)[2]);
	const ShortestPath &ca = ShortestPath::path(ttv(face)[2], ttv(face)[0]);

	std::vector<BoundaryMapper<VertexToTri>::Path*> paths;

	auto &listA = ab.list(ttv(face)[0]);
	auto &listB = bc.list(ttv(face)[1]);
	auto &listC = ca.list(ttv(face)[2]);

	paths.push_back(&listA);
	paths.push_back(&listB);
	paths.push_back(&listC);

	// map boundary
	m_mapper.map(paths);
}

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

bool VoronoiParametrization::solveLocal(const FaceHandle face)
{
	m_inner = &ttv(face).inner;
	nv_inner_ = m_inner->size();
	assert(nv_inner_ > 0);

	calcWeights(face);

	// calculate coordinates
	initCoords(face);

	// system matrix
	EigenSpMatT A(nv_inner_, nv_inner_);

	// right hand sides for u and v coordinates
	EigenVectorT rhsu(nv_inner_);
	rhsu.setZero();
	EigenVectorT rhsv(nv_inner_);
	rhsv.setZero();

	std::vector<EigenTripletT> triplets;

	// for all inner vertices, setup the corresponding row of the linear systems (u and v)
	// call add_row_to_system for all inner vertices
	// smooth parameterization using Laplacian relaxation.
	for (VertexHandle v : *m_inner) {
		addRow(triplets, rhsu, rhsv, v, face);
	}

	// now we have all triplets to setup the matrix A
	A.setFromTriplets(triplets.begin(), triplets.end());

	/**
	 * vertexweight the matrix is not symmetric!  Hence, we cannot use an ordinary conjugate
	 * gradient or cholesky decomposition. For solving this non-symmetric system we use a
	 * Biconjugate gradient stabilized method. You can experiment with different solvers
	 * (see http://eigen.tuxfamily.org/dox/TutorialSparse.html#TutorialSparseDirectSolvers) but
	 * first you need to make the system SPD (symmetric positive definite) try e.g. setting
	 * the vertexweight in add_row_to_system to 1. (this should NOT change the result)
	 */
	Eigen::BiCGSTAB<EigenSpMatT> bicg(A); // performs a Biconjugate gradient stabilized method

	bool error = false;

	auto resultU = bicg.solve(rhsu);
	if (bicg.info() != Eigen::Success) {
		error = true;
		std::cerr << "solve failed!" << std::endl;
	}

	auto resultV = bicg.solve(rhsv);
	if (bicg.info() != Eigen::Success) {
		error = true;
		std::cerr << "solve failed!" << std::endl;
	}

	if (!error) {
		std::cerr << "\tcalculated uv for " << m_inner->size() << " vertices\n";
		// write back to hmap
		for (VertexHandle v : *m_inner) {
			//assert(std::isgreaterequal(resultU[sysid(v)], 0.0));
			//assert(std::isgreaterequal(resultV[sysid(v)], 0.0));
			//assert(std::islessequal(resultU[sysid(v)], 1.0));
			//assert(std::islessequal(resultV[sysid(v)], 1.0));
			hmap(v) = Vec2(
				std::min(1.0, std::max(resultU[sysid(v)], 0.0)),
				std::min(1.0, std::max(resultV[sysid(v)], 0.0))
			);
		}
	}

	return !error;
}

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

bool VoronoiParametrization::solve()
{
	for (FaceHandle face : m_ctrl.faces()) {
		if (!solveLocal(face)) return false;
	}
	return true;
}

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

void VoronoiParametrization::addRow(
	std::vector<EigenTripletT>& _triplets,
	EigenVectorT& _rhsu,
	EigenVectorT& _rhsv,
	VertexHandle _origvh,
	FaceHandle face
) {
	// if vertex is boundary do nothing
	if (m_mesh.is_boundary(_origvh))
		return;

	Scalar weightsum(0.);
	Scalar vertexweight(weight(_origvh));

	for (auto h_it = m_mesh.cvoh_begin(_origvh); h_it != m_mesh.cvoh_end(_origvh); ++h_it) {

		EdgeHandle eh = m_mesh.edge_handle(*h_it);
		VertexHandle vert = m_mesh.to_vertex_handle(*h_it);
		Scalar w = weight(eh) * vertexweight;

		if (vtt(vert).isBorderOf(ttv(face))) {

			weightsum += w;

			// update rhs (u,v)
			_rhsu[sysid(_origvh)] -= w*hmap(vert)[0];
			_rhsv[sysid(_origvh)] -= w*hmap(vert)[1];
		} else if (vtt(vert).face == face) {
			weightsum += w;
			// update matrix (only vertices that are part of the local face)
			_triplets.push_back(EigenTripletT(sysid(_origvh), sysid(vert), w));
		}
	}
	_triplets.push_back(EigenTripletT(sysid(_origvh), sysid(_origvh), -weightsum));
}

} // namespace betri


#ifndef PYTHONIC_INCLUDE_NUMPY_SQRT_HPP
#define PYTHONIC_INCLUDE_NUMPY_SQRT_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"

#include <boost/simd/function/sqrt.hpp>

namespace pythonic
{

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

#endif


#ifndef CONNECT_FOUR_BOARD_HPP
#define CONNECT_FOUR_BOARD_HPP

#include <boost/serialization/bitset.hpp>
#include "Decl.hpp"

#if 0
struct Board{
        explicit Board(unsigned width, unsigned height)
                :width_{width}, height_{height}, rep_(Width() * Height(), ' ')
        {}
        char& operator()(unsigned x, unsigned y){
                return rep_[map_(x,y)];
        }
        char operator()(unsigned x, unsigned y)const{
                return rep_[map_(x,y)];
        }
        unsigned Width()const{ return width_; }
        unsigned Height()const{ return height_; }
        void Display()const{
                for(unsigned y=Height();y!=0;){
                        --y;
                        for(unsigned x=0;x!=Width();++x){
                                std::cout << '|' << (*this)(x,y);
                        }
                        std::cout << "|\n";
                }
                std::cout << "\n";
        }
        std::string Hash()const{
                #if 1
                std::string alt;
                for(unsigned y=0;y!=Height();++y){
                        for(unsigned x=Width();x!=0;){
                                --x;
                                alt += (*this)(x,y);
                        }
                }
                if( alt < rep_)
                        return std::move(alt);
                return rep_;
                #endif
                return rep_;
        }
        char Full(unsigned idx)const{
                return (*this)(idx, Height()-1) != ' ';
        }
private:
        unsigned map_(unsigned x, unsigned y)const{
                return y * width_ + x;
        }
        unsigned width_;
        unsigned height_;
        std::string rep_;
};
#endif

namespace Detail{
        template<size_t Width, size_t Height>
        struct BoardImpl{
                using HashType = std::tuple<unsigned long long, unsigned long long>;
                void Set(size_t x, size_t y, Tile t){
                        auto m = Map_(x,y);
                        switch(t){
                        case Tile_Hero:
                                mask_.set(m);
                                value_.set(m);
                                break;
                        case Tile_Villian:
                                mask_.set(m);
                                value_.reset(m);
                                break;
                        case Tile_Empty:
                                mask_.reset(m);
                                value_.reset(m);
                                break;
                        default:
                                break;
                        }
                        //Debug();

                }
                Tile Get(size_t x, size_t y)const{
                        auto m = Map_(x,y);
                        if( ! mask_.test(m) )
                                return Tile_Empty;
                        if( value_.test(m) )
                                return Tile_Hero;
                        return Tile_Villian;
                }
                HashType Hash()const{
                        return std::make_tuple( mask_.to_ullong(), value_.to_ullong() );
                }
                void Debug()const{
                        PRINT( mask_.to_string() );
                        PRINT( value_.to_string() );
                }
        private:
                friend class boost::serialization::access;

                template <typename Archive>
                void serialize(Archive &ar, const unsigned int version){
                        ar & mask_;
                        ar & value_;
                }
        private:
                static constexpr size_t BitSize(){
                        return Width * Height;
                }
                static constexpr size_t Map_(size_t x, size_t y){
                        return y * Width + x;
                }
                std::bitset< BitSize() > mask_;
                std::bitset< BitSize() > value_;
        };
}

template<size_t Width_, size_t Height_>
struct GenericBoard{
        using HashType = std::tuple<unsigned long long, unsigned long long>;
        void Set(size_t x, size_t y, Tile t){
                left_.Set(x,y,t);
                //right_.Set(Width_ - x - 1, y, t);
        }
        Tile Get(size_t x, size_t y)const{
                return left_.Get(x,y);
        }
        HashType Hash()const{
                Detail::BoardImpl<Width_, Height_> mirror;
                for(size_t x=0;x!=Width_;++x){
                        for(size_t y=0;y!=Height_;++y){
                                mirror.Set(Width_ -1 - x,y, left_.Get(x,y));
                        }
                }
                return std::min(left_.Hash(), mirror.Hash() );
                //return left_.Hash();
        }
        static auto Width(){ return Width_; }
        static auto Height(){ return Height_; }

        friend bool operator<(GenericBoard const& left, GenericBoard const& right){
                return left.Hash() < right.Hash();
        }
        friend bool operator<(HashType left, GenericBoard const& right){
                return left < right.Hash();
        }
        friend bool operator<(GenericBoard const& left, HashType right){
                return left.Hash() < right;
        }
private:
        friend class boost::serialization::access;

        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version){
                ar & left_;
        }

private:
        Detail::BoardImpl<Width_, Height_> left_;
        //Detail::BoardImpl<Width_, Height_> right_;
};

using Board = GenericBoard<5,5>;

template<class BoardType>
unsigned Level(BoardType const& board, unsigned idx){
        unsigned y=0;
        for(;y!=board.Height();++y){
                if( board.Get(idx, y) == Tile_Empty)
                        break;
        }
        return y;
}

// returns number of tiles different from Empty
inline
unsigned PopCount(Board const& board){
        unsigned ret=0;
        for(size_t x=0;x!=board.Width();++x){
                for(size_t y=0;y!=board.Height();++y){
                        ret += ( board.Get(x,y) == Tile_Empty ? 0 : 1 );
                }
        }
        return ret;
}

#endif // CONNECT_FOUR_BOARD_HPP


#include "gl/GraphLayout.hpp"

#include "Util/Util.hpp"

#include <unordered_map>
#include <utility>

#include <boost/graph/copy.hpp>

/**
 * derived from Springy JS
 *
 * copyright notice below
 */
/**
 * Springy v2.7.1
 *
 * Copyright (c) 2010-2013 Dennis Hotson
 *
 * 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.
 */

namespace pyramid_scheme_simulator {

void GraphLayout::Layout::mutatePoints(
        std::function<Point(const Point&)> f)
{
    Graph::vertex_iterator i, iEnd;
    std::tie(i, iEnd) = boost::vertices(*graph);

    for(; i != iEnd; ++i)
    {
        //replace each point with the result of calling
        //the function
        (*graph)[*i].setPoint(f((*graph)[*i].getPoint()));
    }
}

//like the above but without the ability to change the graph
void GraphLayout::Layout::forEachPoint(
        std::function<void(const Point&)> f)
{
    Graph::vertex_iterator i, iEnd;
    std::tie(i, iEnd) = boost::vertices(*graph);

    for(; i != iEnd; ++i)
    {
        f((*graph)[*i].getPoint());
    }
}

void GraphLayout::Layout::mutatePointPairs(std::function<
        std::pair<Point, Point>(const Point&, const Point&)> f)
{
    Graph::vertex_iterator i, iEnd;
    std::tie(i, iEnd) = boost::vertices(*graph);

    for(; i != iEnd; ++i)
    {
        Graph::vertex_iterator j, jEnd;
        std::tie(j, jEnd) = boost::vertices(*graph);

        for(; j != jEnd; ++j)
        {
            std::pair<Point, Point> res =
                f((*graph)[*i].getPoint(), (*graph)[*j].getPoint());

            (*graph)[*i].setPoint(res.first);
            (*graph)[*j].setPoint(res.second);
        }
    }
}

void GraphLayout::Layout::forEachSpring(
        std::function<void(Node&, Node&,
                    double, double)> f) const
{
    Graph::edge_iterator ei, eiEnd;
    std::tie(ei, eiEnd) = boost::edges(*graph);

    for(; ei != eiEnd; ++ei)
    {
        Graph::edge_descriptor ed = *ei;

        f((*graph)[boost::source(ed, *graph)],
          (*graph)[boost::target(ed, *graph)],
          (*graph)[ed].length,
          (*graph)[ed].springConstant);
    }
}

void GraphLayout::Layout::applyCoulombsLaw()
{
    const double _repulsion = repulsion;
    mutatePointPairs(
    [_repulsion](const Point& firstPoint,
        const Point& secondPoint)
    {
        if(firstPoint != secondPoint)
        {
            const Position d =
                firstPoint.position.subtract(
                        secondPoint.position);

            //add 0.1 to "avoid massive forces at small distances (and divide by zero)"
            const double distance =
                d.magnitude() + 0.1;

            const Vector direction = d.normalise();

            const Vector repulse =
                    direction.multiply(_repulsion);
            const double distanceSqr = distance * distance;

            //apply forces to each point and replace the
            //points in the graph with the new positions
            return std::make_pair(
            firstPoint
                .applyForce(
                    repulse
                        .divide(distanceSqr * 0.5)),
            secondPoint
                .applyForce(
                    repulse
                        .divide(distanceSqr * (-0.5))));
        }
        //if they're the same return them unchanged
        else
        {
            return std::make_pair(firstPoint, secondPoint);
        }
    });
}

void GraphLayout::Layout::applyHookesLaw()
{
    forEachSpring(
    [](Node& firstNode, Node& secondNode,
        double length, double springConstant) -> void
    {
        const Position d =
            secondNode.getPoint().position.subtract(
                    firstNode.getPoint().position);

        const double displacement = length - d.magnitude();
        const Vector direction = d.normalise();

        const auto newFirstPoint =
            firstNode.getPoint().applyForce(
                    direction.multiply(
                        springConstant * displacement * -0.5));

        const auto newSecondPoint =
            secondNode.getPoint().applyForce(
                    direction.multiply(
                        springConstant * displacement * 0.5));

        firstNode.setPoint(newFirstPoint);
        secondNode.setPoint(newSecondPoint);
    });
}

void GraphLayout::Layout::updateVelocity(GraphLayoutTick tick)
{
    const double _maxSpeed = maxSpeed,
          _damping = damping;

    mutatePoints(
    [tick, _damping, _maxSpeed](const Point& point)
    {
        std::unique_ptr<Vector> newVelocity =
            make_unique<Vector>(point.velocity.add(
                point.acceleration.multiply(tick))
            .multiply(_damping));

        if(newVelocity->magnitude() > _maxSpeed)
        {
            newVelocity = make_unique<Vector>(
                    newVelocity->normalise().multiply(_maxSpeed));
        }

        const Vector newAcceleration = Vector(0, 0);

        return Point(
                point.position,
                point.mass,
                *newVelocity,
                newAcceleration);
    });
}

void GraphLayout::Layout::updatePosition(GraphLayoutTick tick)
{
    mutatePoints(
    [tick](const Point& point)
    {
        const Position newPosition =
            point.position.add(point.velocity.multiply(tick));

        return Point(
                newPosition,
                point.mass,
                point.velocity,
                point.acceleration);
    });
}

std::pair<GraphLayout::Position, GraphLayout::Position>
    GraphLayout::Layout::getBoundingBox()
{
    double bottomLeftX = -2, bottomLeftY = -2,
           topRightX = 2, topRightY = 2;

    forEachPoint(
    [&](const Point& point)
    {
        if(point.position.x < bottomLeftX)
        {
            bottomLeftX = point.position.x;
        }
        if(point.position.y < bottomLeftY)
        {
            bottomLeftY = point.position.y;
        }
        if(point.position.x > topRightX)
        {
            topRightX = point.position.x;
        }
        if(point.position.y > topRightY)
        {
            topRightY = point.position.y;
        }
    });

    return std::make_pair(Vector(bottomLeftX, bottomLeftY),
            Vector(topRightX, topRightY));
}

void GraphLayout::Layout::attractToCenter()
{
    const double _repulsion = repulsion;
    mutatePoints(
    [_repulsion](const Point& point)
    {
        const auto direction = point.position.multiply(-1.0);
        return
            point.applyForce(direction.multiply(
                        _repulsion / 50.0));
    });
}

void GraphLayout::Layout::tick(GraphLayoutTick tick)
{
    applyCoulombsLaw();
    applyHookesLaw();
    attractToCenter();
    updateVelocity(tick);
    updatePosition(tick);
}

double GraphLayout::Layout::totalEnergy() const
{
    double energy = 0.0;

    forEachPoint(
    [&energy](const Point& point)
    {
        const double speed = point.velocity.magnitude();
        energy += 0.5 * point.mass * speed * speed;
    });

    return energy;
}

GraphLayout::SpringProperties GraphLayout::Layout::newSpring() const
{
    SpringProperties p;
    p.length = 1.0;
    p.springConstant = stiffness;

    return p;
}

void GraphLayout::Layout::makeGraph(Graph& to, const PopulationGraph& populationGraph)
{
    std::unordered_map<Unique, Graph::vertex_descriptor> vdMap;

    //add the vertices from the population graph,
    //creating new points for each unique
    for(const auto& p : populationGraph.vertices())
    {
        const Node newNode = Node(p->id);
        const Graph::vertex_descriptor newVd = boost::add_vertex(newNode, to);

        vdMap.emplace(std::make_pair(newNode.getUnique(), newVd));
    }

    PopulationGraph::Pop left, right;
    for(const auto e : populationGraph.edges())
    {
        std::tie(left, right) = e;

        const Graph::vertex_descriptor leftVd = vdMap.at(left->id),
              rightVd = vdMap.at(right->id);

        boost::add_edge(leftVd, rightVd, newSpring(), to);
    }
}

std::unique_ptr<GraphLayout::Graph>
    GraphLayout::Layout::copyGraph(const Graph& source)
{
    std::unique_ptr<Graph> newGraph = make_unique<Graph>();

    boost::copy_graph(source, *newGraph,
            boost::vertex_copy(Node::getNodeCopier(source, *newGraph)));

    //this is probably unnecessary since the internal unique_ptr<Point> in Node
    //should only be changed by setting it to a new Point (i.e. not modifying the data
    //its pointing to), but just to be really sure...
    Graph::vertex_iterator vi, viEnd;
    std::tie(vi, viEnd) = boost::vertices(*newGraph);
    for(; vi != viEnd; ++vi)
    {
        (*newGraph)[*vi].setPoint((*newGraph)[*vi].getPoint());
    }

    return newGraph;
}

//calls the static version with the member graph
std::unique_ptr<GraphLayout::Graph>
    GraphLayout::Layout::copyGraph() const
{
    return copyGraph(*graph);
}

std::unique_ptr<GraphLayout::Graph> GraphLayout::Layout::runSimulation(
        GraphLayoutTick* maxTicksPtr)
{
    std::function<bool()> condition;
    GraphLayoutTick currentTick = 0;

    const std::function<bool()> energyThresholdCondition =
        [this]() { return this->totalEnergy() < this->minEnergyThreshold; };

    //no maximum if the passed pointer is null
    if(maxTicksPtr == nullptr)
    {
        condition = energyThresholdCondition;
    }
    else
    {
        //otherwise make sure we haven't exceeded the max number of ticks
        const GraphLayoutTick maxTicks = *maxTicksPtr;
        condition = [energyThresholdCondition, maxTicks, &currentTick]()
        {
            return energyThresholdCondition() && currentTick < maxTicks;
        };
    }

    while(condition())
    {
        tick(currentTick);
        currentTick++;
    }

    return copyGraph();
}

std::unique_ptr<GraphLayout::Graph> GraphLayout::Layout::runSimulation()
{
    return runSimulation(nullptr);
}

std::unique_ptr<GraphLayout::Graph> GraphLayout::Layout::runSimulation(GraphLayoutTick maxTicks)
{
    return runSimulation(&maxTicks);
}

void GraphLayout::printGraphLayout(std::ostream& os, Graph& g)
{
    Graph::edge_iterator ei, eiEnd;
    std::tie(ei, eiEnd) = boost::edges(g);

    for(; ei != eiEnd; ++ei)
    {
        const Node &lhs = g[boost::source(*ei, g)].getUnique(),
              &rhs = g[boost::target(*ei, g)].getUnique();
        //TODO: should we use Unique::print?
        //it might be confusing...
        os << lhs.print() << " ---> " << rhs.print() << std::endl;
    }

    //print vertices that don't have any edges
    Graph::vertex_iterator vi, viEnd;
    std::tie(vi, viEnd) = boost::vertices(g);
    for(; vi != viEnd; ++vi)
    {
        Graph::out_edge_iterator oei, oeiEnd;
        std::tie(oei, oeiEnd) = boost::out_edges(*vi, g);

        if(oei == oeiEnd)
        {
            const Node& n = g[*vi];
            //this one has no edges (out and in edges are the same on an undirected graph)
            os << n.print() << std::endl;
        }
    }
}

}


// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// 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)

/**
\file

\brief quantity.cpp

\detailed
Test quantity algebra.

Output:
@verbatim

//[quantity_output_double
L                                 = 2 m
L+L                               = 4 m
L-L                               = 0 m
L*L                               = 4 m^2
L/L                               = 1 dimensionless
L*meter                           = 2 m^2
kilograms*(L/seconds)*(L/seconds) = 4 m^2 kg s^-2
kilograms*(L/seconds)^2           = 4 m^2 kg s^-2
L^3                               = 8 m^3
L^(3/2)                           = 2.82843 m^(3/2)
2vL                               = 1.41421 m^(1/2)
(3/2)vL                           = 1.5874 m^(2/3)
//]

//[quantity_output_complex
L                                 = (3,4) m
L+L                               = (6,8) m
L-L                               = (0,0) m
L*L                               = (-7,24) m^2
L/L                               = (1,0) dimensionless
L*meter                           = (3,4) m^2
kilograms*(L/seconds)*(L/seconds) = (-7,24) m^2 kg s^-2
kilograms*(L/seconds)^2           = (-7,24) m^2 kg s^-2
L^3                               = (-117,44) m^3
L^(3/2)                           = (2,11) m^(3/2)
2vL                               = (2,1) m^(1/2)
(3/2)vL                           = (2.38285,1.69466) m^(2/3)
//]

@endverbatim
**/

#include <complex>
#include <iostream>

#include <boost/mpl/list.hpp>

#include <boost/typeof/std/complex.hpp>

#include <boost/units/pow.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/io.hpp>

#include "test_system.hpp"

int main(void)
{
    using namespace boost::units;
    using namespace boost::units::test;

    {
    //[quantity_snippet_1
    quantity<length> L = 2.0*meters;                     // quantity of length
    quantity<energy> E = kilograms*pow<2>(L/seconds);    // quantity of energy
    //]

    std::cout << "L                                 = " << L << std::endl
              << "L+L                               = " << L+L << std::endl
              << "L-L                               = " << L-L << std::endl
              << "L*L                               = " << L*L << std::endl
              << "L/L                               = " << L/L << std::endl
              << "L*meter                           = " << L*meter << std::endl
              << "kilograms*(L/seconds)*(L/seconds) = "
              << kilograms*(L/seconds)*(L/seconds) << std::endl
              << "kilograms*(L/seconds)^2           = "
              << kilograms*pow<2>(L/seconds) << std::endl
              << "L^3                               = "
              << pow<3>(L) << std::endl
              << "L^(3/2)                           = "
              << pow<static_rational<3,2> >(L) << std::endl
              << "2vL                               = "
              << root<2>(L) << std::endl
              << "(3/2)vL                           = "
              << root<static_rational<3,2> >(L) << std::endl
              << std::endl;
    }

    {
    //[quantity_snippet_2
    quantity<length,std::complex<double> > L(std::complex<double>(3.0,4.0)*meters);
    quantity<energy,std::complex<double> > E(kilograms*pow<2>(L/seconds));
    //]

    std::cout << "L                                 = " << L << std::endl
              << "L+L                               = " << L+L << std::endl
              << "L-L                               = " << L-L << std::endl
              << "L*L                               = " << L*L << std::endl
              << "L/L                               = " << L/L << std::endl
              << "L*meter                           = " << L*meter << std::endl
              << "kilograms*(L/seconds)*(L/seconds) = "
              << kilograms*(L/seconds)*(L/seconds) << std::endl
              << "kilograms*(L/seconds)^2           = "
              << kilograms*pow<2>(L/seconds) << std::endl
              << "L^3                               = "
              << pow<3>(L) << std::endl
              << "L^(3/2)                           = "
              << pow<static_rational<3,2> >(L) << std::endl
              << "2vL                               = "
              << root<2>(L) << std::endl
              << "(3/2)vL                           = "
              << root<static_rational<3,2> >(L) << std::endl
              << std::endl;
    }

    return 0;
}


/**
* @file src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp
* @brief x87 FPU analysis - replace fpu stack operations with FPU registers.
* @copyright (c) 2020 Avast Software, licensed under the MIT license
*/

#include <llvm/IR/CFG.h>
#include <llvm/IR/InstIterator.h>
#include <llvm/IR/Operator.h>

#include <Eigen/Core>
#include <Eigen/QR>

#include "retdec/utils/io/log.h"
#include "retdec/bin2llvmir/optimizations/x87_fpu/x87_fpu.h"
#include "retdec/utils/string.h"
#include "retdec/bin2llvmir/providers/asm_instruction.h"
#include "retdec/bin2llvmir/utils/debug.h"
#define debug_enabled false

#include "retdec/bin2llvmir/utils/ir_modifier.h"
#include "retdec/bin2llvmir/utils/llvm.h"
#include "retdec/capstone2llvmir/x86/x86.h"

using namespace llvm;
using namespace retdec::bin2llvmir::llvm_utils;
using namespace retdec::utils::io;

namespace retdec {
namespace bin2llvmir {

int augmentedRank(Eigen::MatrixXd &A, Eigen::MatrixXd &B)
{
	A.conservativeResize(Eigen::NoChange, A.cols()+1);
	A.col(A.cols()-1) = B;

	int rankAugmentedA = A.colPivHouseholderQr().rank();

	A.conservativeResize(Eigen::NoChange, A.cols()-1);

	return rankAugmentedA;
}

class FunctionAnalyzeMetadata
{
	public:

		bool analyzeSuccess = true;
		enum IndexType {
			inIndex, outIndex
		};

		llvm::Function& function;
		std::map<llvm::BasicBlock*, std::map<IndexType,unsigned >> indexes;

		std::list<llvm::BasicBlock*> terminatingBasicBlocks;
		// A * x = B
		Eigen::MatrixXd A;
		Eigen::MatrixXd B;
		Eigen::MatrixXd x;

		int numberOfEquations = 0;

		// 1. index to register, 2.pseudo instruction
		std::list<std::pair<uint32_t ,llvm::Instruction*>> pseudoCalls;
		std::map<llvm::Value*, int> topVals;

		int expectedTop = 0;
		bool expectedTopAnalyzed = false;
		std::set<llvm::Function*> calledFunctions;

	void initSystem();
	void addEquation(const std::list<std::tuple<llvm::BasicBlock&,int,IndexType >>& vars, int result);
	FunctionAnalyzeMetadata(llvm::Function &function1) : function(function1) {};

};

char X87FpuAnalysis::ID = 0;

static RegisterPass<X87FpuAnalysis> X(
		"retdec-x87-fpu",
		"x87 fpu register analysis",
		false, // Only looks at CFG
		false // Analysis Pass
);

X87FpuAnalysis::X87FpuAnalysis() :
		ModulePass(ID)
{

}

bool X87FpuAnalysis::runOnModule(llvm::Module& m)
{
	_module = &m;
	_config = ConfigProvider::getConfig(_module);
	_abi = AbiProvider::getAbi(_module);
	return run();
}

bool X87FpuAnalysis::runOnModuleCustom(
		llvm::Module& m,
		Config* c,
		Abi* a)
{
	_module = &m;
	_config = c;
	_abi = a;
	return run();
}

std::list<FunctionAnalyzeMetadata> getFunctions2Analyze(llvm::GlobalVariable* top)
{
	std::list<Function*> functions;
	for (Value::use_iterator k = top->use_begin(); k != top->use_end(); ++k)
	{
		if (Instruction *ins= dyn_cast<Instruction>(k->getUser()))
		{
			functions.push_back(ins->getParent()->getParent());
		}
	}
	functions.sort();
	functions.unique();

	std::list<FunctionAnalyzeMetadata> functionsMetadata;
	for (auto &f : functions)
	{
		unsigned index = 0;
		FunctionAnalyzeMetadata metadata(*f);
		for (Function::iterator it = f->begin(), end = f->end(); it != end; ++it)
		{
			BasicBlock* bb = it.operator->();
			Instruction& endInst = bb->getInstList().back();
			if (dyn_cast<ReturnInst>(&endInst)) //it is terminating block
			{
				metadata.terminatingBasicBlocks.push_back(bb);
			}
			metadata.indexes[bb][FunctionAnalyzeMetadata::inIndex] = index;
			metadata.indexes[bb][FunctionAnalyzeMetadata::outIndex] = index+1;
			index += 2;
		}
		functionsMetadata.push_back(metadata);
	}

	return functionsMetadata;
}

void FunctionAnalyzeMetadata::initSystem()
{
	unsigned matrixLen = 1;// + terminatingBasicBlocks.size();
	for (Function::iterator bbIt=function.begin(), bbEndIt = function.end(); bbIt != bbEndIt; ++bbIt)
	{
		BasicBlock* bb = bbIt.operator->();
		matrixLen += 1 + pred_size(bb);
	}
	A.resize(matrixLen, 2*function.size());
	B.resize(matrixLen, 1);
	A.setZero();
	B.setZero();
}

void FunctionAnalyzeMetadata::addEquation(const std::list<std::tuple<llvm::BasicBlock&,int,IndexType >>& vars, int result)
{
	B(numberOfEquations, 0) = result;
	for (auto var : vars)
	{
		A(numberOfEquations, indexes[&std::get<0>(var)][std::get<2>(var)]) = std::get<1>(var);
	}

	numberOfEquations++;
}

bool X87FpuAnalysis::checkArchAndCallConvException(llvm::Function* fun)
{
	using CallingConvention = common::CallingConvention::eCC;

	auto configFunctionMetadata = _config->getConfig().functions.getFunctionByName(fun->getName());
	if (!configFunctionMetadata)
		return false;

	auto convention = configFunctionMetadata->callingConvention.getID();

	if (_config->getConfig().architecture.isX86_16() || _config->getConfig().architecture.isX86_32())
	{
		switch (convention)
		{
			case CallingConvention::CC_CDECL:
			case CallingConvention::CC_STDCALL:
			case CallingConvention::CC_PASCAL:
			case CallingConvention::CC_FASTCALL:
			case CallingConvention::CC_THISCALL:
			case CallingConvention::CC_UNKNOWN:
			default:
				return true;
			case CallingConvention::CC_WATCOM:
				return false; //inconsisten
		}
	}
	else // x86-64bit architecture
	{
		return false;
	}
}

bool X87FpuAnalysis::run()
{
	if (_config == nullptr || _abi == nullptr)
	{
		return ANALYZE_FAIL;
	}
	if (!_abi->isX86())
	{
		return ANALYZE_FAIL;
	}

	top = _abi->getRegister(X87_REG_TOP);
	if (top == nullptr)
	{
		return ANALYZE_FAIL;
	}

	auto analyzedFunctionsMetadata = getFunctions2Analyze(top);

	for (auto& funMd: analyzedFunctionsMetadata)
	{
		funMd.initSystem();
		BasicBlock& enterBlock = funMd.function.begin().operator*();
		funMd.addEquation({{enterBlock, 1, funMd.inIndex}}, EMPTY_FPU_STACK);

		for (Function::iterator bbIt=funMd.function.begin(),
			bbEndIt = funMd.function.end(); bbIt != bbEndIt; ++bbIt)
		{
			BasicBlock* bb = bbIt.operator->();
			int relativeOutBbTop = 0;

			if (!analyzeBasicBlock(analyzedFunctionsMetadata, funMd, bb, relativeOutBbTop))
			{
				funMd.analyzeSuccess = false;
			}

			funMd.addEquation({{*bb, -1, funMd.inIndex},{*bb, 1, funMd.outIndex}}, relativeOutBbTop);

			//if (_config->getConfig().architecture.isX86_16() || _config->getConfig().architecture.isX86_64()
			//	&& std::find(funMd.terminatingBasicBlocks.begin(), funMd.terminatingBasicBlocks.end(), bb) != funMd.terminatingBasicBlocks.end())
			//{
			//	funMd.addEquation({{*bb, 1, funMd.outIndex}}, EMPTY_FPU_STACK);
			//}

			for (auto it = pred_begin(bb), et=pred_end(bb); it != et; ++it)
			{
				BasicBlock *pred = it.operator*();
				funMd.addEquation({{*bb, 1, funMd.inIndex},{*pred, -1, funMd.outIndex}}, 0);
			}
		}

		if (funMd.A.rows() <= PERFORMANCE_CEIL)
		{
			const auto& pivHouseholderQr = funMd.A.colPivHouseholderQr();
			int matRank = pivHouseholderQr.rank();
			int augmentedMatRank = augmentedRank(funMd.A, funMd.B);

			if (matRank == augmentedMatRank) // there is exactly one solution
			{
				funMd.x = pivHouseholderQr.solve(funMd.B);
			}
			else
			{
				funMd.analyzeSuccess = false;
			}
		}
		else // worst scenario => due to performance ceil turn to simple no CFG analyse
		{
			int height = funMd.A.rows();
			funMd.x.resize(height, 1);
			for (int i = 0; i < height; ++i)
			{
				funMd.x(i, 0) = EMPTY_FPU_STACK;
			}
		}
	}

	return optimizeAnalyzedFpuInstruction(analyzedFunctionsMetadata);
}

std::list<FunctionAnalyzeMetadata>::iterator X87FpuAnalysis::getFunMd(
		std::list<FunctionAnalyzeMetadata>& analyzedFunctionsMetadata,
		llvm::Function* fun)
{
	std::list<FunctionAnalyzeMetadata>::iterator it;
	for (it = analyzedFunctionsMetadata.begin(); it != analyzedFunctionsMetadata.end(); ++it)
	{
		auto& funMd = it.operator*();
		if (&funMd.function == fun)
		{
			return it;
		}
	}

	return analyzedFunctionsMetadata.end();
}

bool X87FpuAnalysis::analyzeInstruction(
		std::list<FunctionAnalyzeMetadata>& analyzedFunctionsMetadata,
		FunctionAnalyzeMetadata& funMd,
		Instruction* i,
		int& outTop)
{
	auto *callFunction = dyn_cast<CallInst>(i);
	auto *loadFpuTop = dyn_cast<LoadInst>(i);
	auto *storeFpuTop = dyn_cast<StoreInst>(i);
	auto *add = dyn_cast<AddOperator>(i);
	auto *sub = dyn_cast<SubOperator>(i);
	auto *callStore = _config->isLlvmX87StorePseudoFunctionCall(i);
	auto *callLoad = _config->isLlvmX87LoadPseudoFunctionCall(i);

	// read actual value of fpu top
	if (loadFpuTop && loadFpuTop->getPointerOperand() == top)
	{
		funMd.topVals[i] = outTop;
	}
	// store actual value of fpu top
	else if (storeFpuTop && storeFpuTop->getPointerOperand() == top && funMd.topVals.find(storeFpuTop->getValueOperand()) != funMd.topVals.end())
	{
		outTop = funMd.topVals.find(storeFpuTop->getValueOperand())->second;
	}
	// function call -> possible change value of fpu top
	else if (callFunction && !callStore && !callLoad && !callFunction->getCalledFunction()->isIntrinsic())
	{
		auto it = getFunMd(
				analyzedFunctionsMetadata,
				callFunction->getCalledFunction()
		);

		if (it != analyzedFunctionsMetadata.end())
		{
			auto& fun = it.operator*();
			if (fun.expectedTopAnalyzed)
			{
				outTop += fun.expectedTop;
			}
			else
			{
				outTop += expectedTopBasedOnRestOfBlock(analyzedFunctionsMetadata, *i);
			}
		}
		else // some library function e.g "roundf()"
		{
			outTop += expectedTopBasedOnRestOfBlock(analyzedFunctionsMetadata, *i);
		}
	}
	// increment fpu top
	else if (add && isa<ConstantInt>(add->getOperand(1)) && funMd.topVals.find(add->getOperand(0)) != funMd.topVals.end())
	{
		//auto *op0 = dyn_cast<Instruction>(add->getOperand(0));
		int oldTopValue = funMd.topVals.find(add->getOperand(0))->second;
		int constValue = cast<ConstantInt>(add->getOperand(1))->getZExtValue();//it should be 1
		int newTopValue = oldTopValue + constValue;
		funMd.topVals[i] = newTopValue;
	}
	// decrement fpu top
	else if (sub && isa<ConstantInt>(sub->getOperand(1)) && funMd.topVals.find(sub->getOperand(0)) != funMd.topVals.end())
	{
		//auto *op0 = dyn_cast<Instruction>(sub->getOperand(0));
		int oldTopValue = funMd.topVals.find(sub->getOperand(0))->second;
		int constValue = cast<ConstantInt>(sub->getOperand(1))->getZExtValue();//it should be 1
		int newTopValue = oldTopValue - constValue;
		funMd.topVals[i] = newTopValue;
	}
	// pseudo load/store of fpu top
	else if (callStore || callLoad)
	{
		//pseudo call will be replaced by store/load of concrete register but only if whole analyze succed
		int tmp;
		if (callStore && funMd.topVals.find(callStore->getArgOperand(0)) != funMd.topVals.end())
		{
			tmp = funMd.topVals.find(callStore->getArgOperand(0))->second;
		}
		else if (callLoad && funMd.topVals.find(callLoad->getArgOperand(0)) != funMd.topVals.end())
		{
			tmp = funMd.topVals.find(callLoad->getArgOperand(0))->second;
		}
		else
		{
			return ANALYZE_FAIL;
		}

		funMd.pseudoCalls.push_back({tmp, i});
	}

	return ANALYZE_SUCCESS;
}

int X87FpuAnalysis::expectedTopBasedOnRestOfBlock(
		std::list<FunctionAnalyzeMetadata>& analyzedFunctionsMetadata,
		llvm::Instruction& analyzedInstr)
{
	if (!checkArchAndCallConvException(analyzedInstr.getParent()->getParent()))
	{
		return NOP_FPU_STACK;
	}

	std::map<llvm::Value*, bool> topVals;
	BasicBlock* bb = analyzedInstr.getParent();
	Instruction *next = analyzedInstr.getNextNode();

	if (!next || next->getParent() != bb)
	{
		return NOP_FPU_STACK;
	}

	for (BasicBlock::iterator it = next->getIterator(), e = bb->end(); it != e; ++it)
	{
		Instruction *i = it.operator->();
		auto *loadFpuTop = dyn_cast<LoadInst>(i);
		auto *sub = dyn_cast<SubOperator>(i);
		auto *callLoad = _config->isLlvmX87LoadPseudoFunctionCall(i);
		auto *callFunction = dyn_cast<CallInst>(i);

		if (loadFpuTop && loadFpuTop->getPointerOperand() == top)
		{
			topVals[i] = true;
		}
		else if (sub && isa<ConstantInt>(sub->getOperand(1)) && topVals.find(sub->getOperand(0)) != topVals.end())
		{
			return NOP_FPU_STACK;
		}
		else if (callFunction && !callLoad)
		{
			return NOP_FPU_STACK;
		}
		else if (callLoad && topVals.find(callLoad->getArgOperand(0)) != topVals.end())
		{
			auto *callFunction = dyn_cast<CallInst>(&analyzedInstr);
			auto it = getFunMd(
					analyzedFunctionsMetadata,
					callFunction->getCalledFunction()
			);
			if (it != analyzedFunctionsMetadata.end())
			{
				auto& fun = it.operator*();
				fun.expectedTop = RETURN_VALUE_PASSED_THROUGH_ST0;
				fun.expectedTopAnalyzed = true;
			}
			return DECREMENT_FPU_STACK;
		}
	}

	return NOP_FPU_STACK;
}

bool X87FpuAnalysis::analyzeBasicBlock(
	std::list<FunctionAnalyzeMetadata>& analyzedFunctionsMetadata,
	FunctionAnalyzeMetadata& funMd,
	llvm::BasicBlock* bb,
	int& outTop)
{
	std::map<llvm::Value*, int> topVals;
	for (BasicBlock::iterator it = bb->begin(), e = bb->end(); it != e; ++it)
	{
		Instruction* inst = it.operator->();
		if (!analyzeInstruction(analyzedFunctionsMetadata, funMd, inst, outTop))
		{
			return ANALYZE_FAIL;
		}
	}

	return ANALYZE_SUCCESS;
}

bool X87FpuAnalysis::isValidRegisterIndex(int index)
{
	return (X86_REG_ST0 <= index && index <= X86_REG_ST7);
}

bool X87FpuAnalysis::optimizeAnalyzedFpuInstruction(
		std::list<FunctionAnalyzeMetadata>& analyzedFunctionsMetadata)
{
	bool analyzeSucces = true;
	for (auto& funMd : analyzedFunctionsMetadata)
	{
		if (!funMd.analyzeSuccess)
		{
			analyzeSucces = false;
			continue;
		}

		for (auto& i : funMd.pseudoCalls)
		{
			int regBase = uint32_t(X86_REG_ST0);
			auto *callStore = _config->isLlvmX87StorePseudoFunctionCall(i.second);
			auto *callLoad = _config->isLlvmX87LoadPseudoFunctionCall(i.second);

			double bbIn = funMd.x(funMd.indexes[i.second->getParent()][funMd.inIndex], 0);
			int diff = (int)i.first % EMPTY_FPU_STACK; // correction of possible stack over/under-flow
			int top = (int)round(bbIn) + diff; // value of stack at the beginnig of BB + difference at actual instr

			int registerIndex;
			GlobalVariable *reg;
			if (!isValidRegisterIndex(registerIndex = regBase + top%EMPTY_FPU_STACK) || !(reg =_abi->getRegister(registerIndex)))
			{
				analyzeSucces = false;
				continue;
			}

			if (callStore)
			{
				new StoreInst(callStore->getArgOperand(1), reg, callStore);
				callStore->eraseFromParent();
			}
			if (callLoad)
			{
				auto *lTmp = new LoadInst(reg, "", callLoad);
				auto *conv = IrModifier::convertValueToType(lTmp, callLoad->getType(), callLoad);
				callLoad->replaceAllUsesWith(conv);
				callLoad->eraseFromParent();
			}
		}
	}

	return analyzeSucces;
}

} // namespace bin2llvmir
} // namespace retdec


/*
@copyright Louis Dionne 2014
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/hana/list/mcd.hpp>

#include <boost/hana/bool.hpp>
#include <boost/hana/comparable/equal_mcd.hpp>
#include <boost/hana/detail/assert.hpp>
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/detail/minimal/list.hpp>
#include <boost/hana/functional.hpp>
using namespace boost::hana;

struct EqClass;
template <int equivalence_class> struct X { using hana_datatype = EqClass; };
template <int equivalence_class> struct Y { using hana_datatype = EqClass; };
template <int equivalence_class> constexpr X<equivalence_class> x{};
template <int equivalence_class> constexpr Y<equivalence_class> y{};

namespace boost { namespace hana {
    template <>
    struct Comparable::instance<EqClass, EqClass> : Comparable::equal_mcd {
        template <typename T, typename U>
        static constexpr auto equal_impl(T, U)
        { return false_; }

        template <typename T>
        static constexpr auto equal_impl(T, T)
        { return true_; }
    };
}}

constexpr struct _predicate {
    template <int i, int j, template <int> class X, template <int> class Y>
    constexpr auto operator()(X<i>, Y<j>) const
    { return bool_<(i < j)>; }
} pred{};

BOOST_HANA_CONSTEXPR_LAMBDA auto check = [](auto sorted_list) {
    auto perms = fmap(partial(sort_by, pred), permutations(sorted_list));
    BOOST_HANA_CONSTANT_ASSERT(all(perms, _ == sorted_list));
};

template <typename mcd>
void test() {
    BOOST_HANA_CONSTEXPR_LAMBDA auto list = detail::minimal::list<mcd>;

    check(list());
    check(list(x<1>));
    check(list(x<1>, x<2>));
    check(list(x<1>, x<2>, x<3>));

    // check stability
    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(x<1>, y<1>)) == list(x<1>, y<1>));
    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(y<1>, x<1>)) == list(y<1>, x<1>));

    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(x<1>, y<1>, x<2>, y<2>)) == list(x<1>, y<1>, x<2>, y<2>));
    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(x<1>, x<2>, y<1>, y<2>)) == list(x<1>, y<1>, x<2>, y<2>));
    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(y<1>, x<1>, x<2>, y<2>)) == list(y<1>, x<1>, x<2>, y<2>));
    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(x<2>, y<1>, y<2>, x<1>)) == list(y<1>, x<1>, x<2>, y<2>));

    BOOST_HANA_CONSTANT_ASSERT(sort_by(pred, list(x<1>, x<3>, y<1>, x<2>, y<3>)) == list(x<1>, y<1>, x<2>, x<3>, y<3>));
}

int main() {
    test<List::mcd<void>>();
}


#include "cnn/grad-check.h"
#include "cnn/nodes.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/gru.h"
#include "cnn/deep-lstm.h"
#include "cnn/lstm.h"
#include "cnn/dict.h"
# include "cnn/expr.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

using namespace std;
using namespace cnn;

unsigned LAYERS = 2;
unsigned INPUT_DIM = 16;  //256
unsigned HIDDEN_DIM = 32;  // 1024
unsigned VOCAB_SIZE = 0;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLengthPredictor {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLengthPredictor(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, {INPUT_DIM});
    p_R = model.add_parameters({1, HIDDEN_DIM});
    p_bias = model.add_parameters({1});
  }

  // return Expression of total loss
  Expression BuildLMGraph(const vector<int>& sent, unsigned len, ComputationGraph& cg, bool flag = false) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();
    Expression R = parameter(cg, p_R);
    Expression bias = parameter(cg, p_bias);
    vector<Expression> errs;
    for (unsigned t = 0; t < slen; ++t) {
      Expression i_x_t = lookup(cg, p_c, sent[t]);
      // y_t = RNN(x_t)
      builder.add_input(i_x_t);
    }
    Expression pred = affine_transform({bias, R, builder.back()});
    if (flag) {
      unsigned x = exp(as_scalar(cg.incremental_forward()));
      cerr << "PRED=" << x << " TRUE=" << len << "\t(DIFF=" << ((int)x - (int)len) << ")" << endl;
    }
    return poisson_loss(pred, len);
  }
};

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv);
  if (argc != 3 && argc != 4) {
    cerr << "Usage: " << argv[0] << " corpus.txt dev.txt [model.params]\n";
    return 1;
  }
  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  vector<pair<vector<int>,unsigned>> training, dev;
  string line;
  int tlc = 0;
  int ttoks = 0;
  cerr << "Reading training data from " << argv[1] << "...\n";
  {
    Dict td;
    ifstream in(argv[1]);
    assert(in);
    while(getline(in, line)) {
      ++tlc;
      vector<int> x, ty;
      ReadSentencePair(line, &x, &d, &ty, &td);
      assert(ty.size() == 1);
      const string& v = td.Convert(ty[0]);
      for(auto c : v) { assert(c >= '0' && c <= '9'); }
      unsigned y = atoi(v.c_str());
      training.push_back(make_pair(x,y));
      ttoks += training.back().first.size();
      if (training.back().first.front() != kSOS && training.back().first.back() != kEOS) {
        cerr << "Training sentence in " << argv[1] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << tlc << " lines, " << ttoks << " tokens, " << d.size() << " types\n";
  }
  d.Freeze(); // no new word types allowed
  VOCAB_SIZE = d.size();

  int dlc = 0;
  int dtoks = 0;
  cerr << "Reading dev data from " << argv[2] << "...\n";
  {
    ifstream in(argv[2]);
    assert(in);
    Dict td;
    while(getline(in, line)) {
      ++dlc;
      vector<int> x, ty;
      ReadSentencePair(line, &x, &d, &ty, &td);
      assert(ty.size() == 1);
      const string& v = td.Convert(ty[0]);
      for(auto c : v) { assert(c >= '0' && c <= '9'); }
      unsigned y = atoi(v.c_str());
      dev.push_back(make_pair(x,y));
      dtoks += dev.back().first.size();
      if (dev.back().first.front() != kSOS && dev.back().first.back() != kEOS) {
        cerr << "Dev sentence in " << argv[2] << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << dlc << " lines, " << dtoks << " tokens\n";
  }
  ostringstream os;
  os << "lm"
     << '_' << LAYERS
     << '_' << INPUT_DIM
     << '_' << HIDDEN_DIM
     << "-pid" << getpid() << ".params";
  const string fname = os.str();
  cerr << "Parameters will be written to: " << fname << endl;
  double best = 9e+99;

  Model model;
  Trainer* sgd = nullptr;
  sgd = new SimpleSGDTrainer(&model);

  RNNLengthPredictor<LSTMBuilder> lm(model);
  if (argc == 4) {
    string fname = argv[3];
    ifstream in(fname);
    boost::archive::text_iarchive ia(in);
    ia >> model;
  }

  unsigned report_every_i = 50;
  unsigned dev_every_i_reports = 20;
  unsigned si = training.size();
  vector<unsigned> order(training.size());
  for (unsigned i = 0; i < order.size(); ++i) order[i] = i;
  bool first = true;
  int report = 0;
  unsigned lines = 0;
  while(1) {
    Timer iteration("completed in");
    double loss = 0;
    unsigned chars = 0;
    for (unsigned i = 0; i < report_every_i; ++i) {
      if (si == training.size()) {
        si = 0;
        if (first) { first = false; } else { sgd->update_epoch(); }
        cerr << "**SHUFFLE\n";
        shuffle(order.begin(), order.end(), *rndeng);
      }

      // build graph for this instance
      ComputationGraph cg;
      auto& sent = training[order[si]];
      ++si;
      lm.BuildLMGraph(sent.first, sent.second, cg);
      loss += as_scalar(cg.forward());
      cg.backward();
      sgd->update();
      ++lines;
      ++chars;
    }
    sgd->status();
    cerr << " E = " << (loss / chars) << " ppl=" << exp(loss / chars) << ' ';

    // show score on dev data?
    report++;
    if (report % dev_every_i_reports == 0) {
      double dloss = 0;
      int dchars = 0;
      for (auto& sent : dev) {
        ComputationGraph cg;
        lm.BuildLMGraph(sent.first, sent.second, cg, true);
        dloss += as_scalar(cg.forward());
        dchars++;
      }
      if (dloss < best) {
        best = dloss;
        ofstream out(fname);
        boost::archive::text_oarchive oa(out);
        oa << model;
      }
      cerr << "\n***DEV [epoch=" << (lines / (double)training.size()) << "] E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
    }
  }
  delete sgd;
}


/*
 * @Author: Hsuan-Wei Fan
 * @Date: 2020-04-23 23:17:24
 * @LastEditors: Hsuan-Wei Fan
 * @LastEditTime: 2020-04-23 23:17:40
 * @Description:
 */

#include "network_utils.h"
#include <fstream>
#include <Eigen/Core>

namespace pbrt {

void NetworkUtils::onb(const Eigen::Vector3f &n, Eigen::Vector3f &b1, Eigen::Vector3f &b2) {
    float sign = copysignf(1.0f, n[2]);
    const float a = -1.0f / (sign + n[2]);
    const float b = n[0] * n[1] * a;
    b1 = Eigen::Vector3f(1.0f + sign * n[0] * n[0] * a, sign * b, -sign * n[0]);
    b2 = Eigen::Vector3f(b, sign + n[1] * n[1] * a, -n[1]);
}

Eigen::VectorXf NetworkUtils::LoadVectorDynamic(const std::string &filename) {
    std::ifstream f(filename, std::ios::binary);
    if (!f.is_open())
        LOG(ERROR) << "FILE NOT FOUND: " << filename;
    LOG(INFO) << "Loading " << filename << std::endl;
    int32_t nDims;
    f.read(reinterpret_cast<char *>(&nDims), sizeof(nDims));
    int32_t size;
    f.read(reinterpret_cast<char *>(&size), sizeof(size));
    Eigen::VectorXf ret(size);
    for (int i = 0; i < size; ++i) {
        f.read(reinterpret_cast<char *>(&ret[i]), sizeof(ret[i]));
    }
    return ret;
}

Eigen::MatrixXf NetworkUtils::LoadMatrixDynamic(const std::string &filename) {

    std::ifstream f(filename, std::ios::binary);
    if (!f.is_open())
        LOG(ERROR) << "FILE NOT FOUND " << filename;
    LOG(INFO) << "Loading " << filename;

    int32_t nDims;
    f.read(reinterpret_cast<char *>(&nDims), sizeof(nDims));

    int32_t rows, cols;
    f.read(reinterpret_cast<char *>(&rows), sizeof(rows));
    f.read(reinterpret_cast<char *>(&cols), sizeof(cols));
    Eigen::MatrixXf ret(rows, cols);
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            f.read(reinterpret_cast<char *>(&ret(i, j)), sizeof(ret(i, j)));
        }
    }
    return ret;
}

Eigen::Vector3f NetworkUtils::LocalToWorld(const Eigen::Vector3f &inPos, const Eigen::Vector3f &inNormal,
                                           const Eigen::Vector3f &outPosLocal, bool predictInTangentSpace) {
    if (predictInTangentSpace) {
        Eigen::Vector3f tangent1, tangent2;
        onb(inNormal, tangent1, tangent2);
        return inPos + outPosLocal[0] * tangent1 + outPosLocal[1] * tangent2 + outPosLocal[2] * inNormal;
    } else {
        return inPos + outPosLocal;
    }
}

}


/**
 * @file test_crypto_CRC.cpp
 * @author Bensuperpc (bensuperpc@gmail.com)
 * @brief
 * @version 1.0.0
 * @date 2021-04-01
 *
 * MIT License
 *
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE string_CRC

#include <boost/predef.h>
#include <boost/test/unit_test.hpp>
#include "crypto/crypto_CRC32.hpp"

BOOST_AUTO_TEST_CASE(test_crypto_CRC_1)
{
    const std::string str = "Bonjour";
    const uint32_t CRC_VALUE = 0x6A0BC954;
    const uint32_t JAMCRC_VALUE = 0x95F436AB;

    const auto &&crc_boost = my::crypto::CRC32_Boost(str);
    BOOST_REQUIRE(crc_boost == CRC_VALUE);
    const auto &&crc_stackoverflow = my::crypto::CRC32_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_stackoverflow == CRC_VALUE);
    const auto &&crc_1byte_tableless = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless == CRC_VALUE);
    // const auto &&crc_1byte_tableless2 = my::crypto::CRC32_1byte_tableless2(str.c_str(), str.length(), 0);
    // BOOST_REQUIRE(crc_1byte_tableless2 == CRC_VALUE);
    const auto &&crc_1byte = my::crypto::CRC32_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte == CRC_VALUE);
    const auto &&crc_bitwise = my::crypto::CRC32_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_bitwise == CRC_VALUE);
    const auto &&crc_halfbyte = my::crypto::CRC32_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_halfbyte == CRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_4bytes = my::crypto::CRC32_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_8bytes = my::crypto::CRC32_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_8bytes == CRC_VALUE);
    const auto &&crc_4x8bytes = my::crypto::CRC32_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4x8bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&crc_16bytes = my::crypto::CRC32_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes == CRC_VALUE);
    const auto &&crc_16bytes_prefetch = my::crypto::CRC32_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes_prefetch == CRC_VALUE);
#endif

    const auto &&jam_boost = my::crypto::JAMCRC_Boost(str);
    BOOST_REQUIRE(jam_boost == JAMCRC_VALUE);
    const auto &&jam_stackoverflow = my::crypto::JAMCRC_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_stackoverflow == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless = my::crypto::JAMCRC_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless2 = my::crypto::JAMCRC_1byte_tableless2(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless2 == JAMCRC_VALUE);
    const auto &&jam_1byte = my::crypto::JAMCRC_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte == JAMCRC_VALUE);
    const auto &&jam_bitwise = my::crypto::JAMCRC_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_bitwise == JAMCRC_VALUE);
    const auto &&jam_halfbyte = my::crypto::JAMCRC_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_halfbyte == JAMCRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4
    const auto &&jam_4bytes = my::crypto::JAMCRC_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&jam_8bytes = my::crypto::JAMCRC_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_8bytes == JAMCRC_VALUE);
    const auto &&jam_4x8bytes = my::crypto::JAMCRC_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4x8bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&jam_16bytes = my::crypto::JAMCRC_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes == JAMCRC_VALUE);
    const auto &&jam_16bytes_prefetch = my::crypto::JAMCRC_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes_prefetch == JAMCRC_VALUE);
#endif
}

BOOST_AUTO_TEST_CASE(test_crypto_CRC_2)
{
    const std::string str = "Il est 16h30, c'est la fin des cours !";
    const uint32_t CRC_VALUE = 0x15BF4A09;
    const uint32_t JAMCRC_VALUE = 0xEA40B5F6;

    const auto &&crc_boost = my::crypto::CRC32_Boost(str);
    BOOST_REQUIRE(crc_boost == CRC_VALUE);
    const auto &&crc_stackoverflow = my::crypto::CRC32_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_stackoverflow == CRC_VALUE);
    const auto &&crc_1byte_tableless = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless == CRC_VALUE);
    const auto &&crc_1byte_tableless2 = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless2 == CRC_VALUE);
    const auto &&crc_1byte = my::crypto::CRC32_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte == CRC_VALUE);
    const auto &&crc_bitwise = my::crypto::CRC32_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_bitwise == CRC_VALUE);
    const auto &&crc_halfbyte = my::crypto::CRC32_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_halfbyte == CRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_4bytes = my::crypto::CRC32_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_8bytes = my::crypto::CRC32_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_8bytes == CRC_VALUE);
    const auto &&crc_4x8bytes = my::crypto::CRC32_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4x8bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&crc_16bytes = my::crypto::CRC32_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes == CRC_VALUE);
    const auto &&crc_16bytes_prefetch = my::crypto::CRC32_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes_prefetch == CRC_VALUE);
#endif

    const auto &&jam_boost = my::crypto::JAMCRC_Boost(str);
    BOOST_REQUIRE(jam_boost == JAMCRC_VALUE);
    const auto &&jam_stackoverflow = my::crypto::JAMCRC_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_stackoverflow == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless = my::crypto::JAMCRC_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless2 = my::crypto::JAMCRC_1byte_tableless2(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless2 == JAMCRC_VALUE);
    const auto &&jam_1byte = my::crypto::JAMCRC_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte == JAMCRC_VALUE);
    const auto &&jam_bitwise = my::crypto::JAMCRC_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_bitwise == JAMCRC_VALUE);
    const auto &&jam_halfbyte = my::crypto::JAMCRC_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_halfbyte == JAMCRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4
    const auto &&jam_4bytes = my::crypto::JAMCRC_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&jam_8bytes = my::crypto::JAMCRC_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_8bytes == JAMCRC_VALUE);
    const auto &&jam_4x8bytes = my::crypto::JAMCRC_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4x8bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&jam_16bytes = my::crypto::JAMCRC_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes == JAMCRC_VALUE);
    const auto &&jam_16bytes_prefetch = my::crypto::JAMCRC_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes_prefetch == JAMCRC_VALUE);
#endif
}

BOOST_AUTO_TEST_CASE(test_crypto_CRC_3)
{
    const std::string str = "I'm king of the world ! :D";
    const uint32_t CRC_VALUE = 0xC3212D08;
    const uint32_t JAMCRC_VALUE = 0x3CDED2F7;

    const auto &&crc_boost = my::crypto::CRC32_Boost(str);
    BOOST_REQUIRE(crc_boost == CRC_VALUE);
    const auto &&crc_stackoverflow = my::crypto::CRC32_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_stackoverflow == CRC_VALUE);
    const auto &&crc_1byte_tableless = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless == CRC_VALUE);
    const auto &&crc_1byte_tableless2 = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless2 == CRC_VALUE);
    const auto &&crc_1byte = my::crypto::CRC32_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte == CRC_VALUE);
    const auto &&crc_bitwise = my::crypto::CRC32_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_bitwise == CRC_VALUE);
    const auto &&crc_halfbyte = my::crypto::CRC32_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_halfbyte == CRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_4bytes = my::crypto::CRC32_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_8bytes = my::crypto::CRC32_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_8bytes == CRC_VALUE);
    const auto &&crc_4x8bytes = my::crypto::CRC32_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4x8bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&crc_16bytes = my::crypto::CRC32_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes == CRC_VALUE);
    const auto &&crc_16bytes_prefetch = my::crypto::CRC32_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes_prefetch == CRC_VALUE);
#endif

    const auto &&jam_boost = my::crypto::JAMCRC_Boost(str);
    BOOST_REQUIRE(jam_boost == JAMCRC_VALUE);
    const auto &&jam_stackoverflow = my::crypto::JAMCRC_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_stackoverflow == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless = my::crypto::JAMCRC_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless2 = my::crypto::JAMCRC_1byte_tableless2(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless2 == JAMCRC_VALUE);
    const auto &&jam_1byte = my::crypto::JAMCRC_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte == JAMCRC_VALUE);
    const auto &&jam_bitwise = my::crypto::JAMCRC_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_bitwise == JAMCRC_VALUE);
    const auto &&jam_halfbyte = my::crypto::JAMCRC_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_halfbyte == JAMCRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4
    const auto &&jam_4bytes = my::crypto::JAMCRC_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&jam_8bytes = my::crypto::JAMCRC_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_8bytes == JAMCRC_VALUE);
    const auto &&jam_4x8bytes = my::crypto::JAMCRC_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4x8bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&jam_16bytes = my::crypto::JAMCRC_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes == JAMCRC_VALUE);
    const auto &&jam_16bytes_prefetch = my::crypto::JAMCRC_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes_prefetch == JAMCRC_VALUE);
#endif
}

BOOST_AUTO_TEST_CASE(test_crypto_CRC_4)
{
    const std::string str = "+-*/$~#[](){}&=/:;?;.!";
    const uint32_t CRC_VALUE = 0xEAFC7C67;
    // const uint32_t JAMCRC_VALUE = 0x5038398;

    const auto &&crc_boost = my::crypto::CRC32_Boost(str);
    BOOST_REQUIRE(crc_boost == CRC_VALUE);
    const auto &&crc_stackoverflow = my::crypto::CRC32_StackOverflow((const unsigned char *)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_stackoverflow == CRC_VALUE);
    const auto &&crc_1byte_tableless = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless == CRC_VALUE);
    const auto &&crc_1byte_tableless2 = my::crypto::CRC32_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte_tableless2 == CRC_VALUE);
    const auto &&crc_1byte = my::crypto::CRC32_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_1byte == CRC_VALUE);
    const auto &&crc_bitwise = my::crypto::CRC32_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_bitwise == CRC_VALUE);
    const auto &&crc_halfbyte = my::crypto::CRC32_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_halfbyte == CRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_4bytes = my::crypto::CRC32_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&crc_8bytes = my::crypto::CRC32_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_8bytes == CRC_VALUE);
    const auto &&crc_4x8bytes = my::crypto::CRC32_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_4x8bytes == CRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&crc_16bytes = my::crypto::CRC32_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes == CRC_VALUE);
    const auto &&crc_16bytes_prefetch = my::crypto::CRC32_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(crc_16bytes_prefetch == CRC_VALUE);
#endif
    /*
    const auto &&jam_boost = my::crypto::JAMCRC_Boost(str);
    BOOST_REQUIRE(jam_boost == JAMCRC_VALUE);
    const auto &&jam_stackoverflow = my::crypto::JAMCRC_StackOverflow((const unsigned char*)str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_stackoverflow == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless = my::crypto::JAMCRC_1byte_tableless(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless == JAMCRC_VALUE);
    const auto &&jam_1byte_tableless2 = my::crypto::JAMCRC_1byte_tableless2(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte_tableless2 == JAMCRC_VALUE);
    const auto &&jam_1byte = my::crypto::JAMCRC_1byte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_1byte == JAMCRC_VALUE);
    const auto &&jam_bitwise = my::crypto::JAMCRC_bitwise(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_bitwise == JAMCRC_VALUE);
    const auto &&jam_halfbyte = my::crypto::JAMCRC_halfbyte(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_halfbyte == JAMCRC_VALUE);
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4
    const auto &&jam_4bytes = my::crypto::JAMCRC_4bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8
    const auto &&jam_8bytes = my::crypto::JAMCRC_8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_8bytes == JAMCRC_VALUE);
    const auto &&jam_4x8bytes= my::crypto::JAMCRC_4x8bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_4x8bytes == JAMCRC_VALUE);
#endif
#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16
    const auto &&jam_16bytes = my::crypto::JAMCRC_16bytes(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes == JAMCRC_VALUE);
    const auto &&jam_16bytes_prefetch = my::crypto::JAMCRC_16bytes_prefetch(str.c_str(), str.length(), 0);
    BOOST_REQUIRE(jam_16bytes_prefetch == JAMCRC_VALUE);
#endif*/
}

BOOST_AUTO_TEST_CASE(test_crypto_CRC_5)
{
    const std::string str = "Where is Brian? Brian is in the kitchen";
    const auto &&crc = my::crypto::CRC32_Boost(str);
    BOOST_REQUIRE(crc == 0x60ECAB66);
    // const auto &&jam = my::crypto::JAMCRC_Boost(str);
    // BOOST_REQUIRE((~jam) == -0x60ecab67);
}


#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
namespace mp = boost::multiprecision;
using namespace std;
int main()
{
    mp::cpp_int u;
    mp::cpp_int v;
    mp::cpp_int z;
    cin>>u>>v;
    z=u*v;
    cout<<z<<endl;
    return 0;
}


/*
==== Author:

Relja Arandjelovic (relja@robots.ox.ac.uk)
Visual Geometry Group,
Department of Engineering Science
University of Oxford

==== Copyright:

The library belongs to Relja Arandjelovic and the University of Oxford.
No usage or redistribution is allowed without explicit permission.
*/

#include "wgc.h"

#include <fstream>

#include <boost/filesystem.hpp>

#include "tfidf_v2.h"
#include "tfidf_data.pb.h"
#include "timing.h"
#include "weighter_v2.h"

wgc::wgc( protoIndex const &iidx, protoIndex const *fidx, std::string wgcFn ) : retrieverFromIter(&iidx, fidx, false, true), iidx_(&iidx) {

    if ( wgcFn.length()>0 && boost::filesystem::exists( wgcFn ) ){

        tfidfV2::load(wgcFn, idf_, docL2_);
        numDocs_= docL2_.size();

    } else {

        tfidfV2::computeIdf(*iidx_, idf_, fidx_);
        computeDocL2();
        numDocs_= docL2_.size();

        if (wgcFn.length()>0)
            tfidfV2::save(wgcFn, idf_, docL2_);

    }

}

void
wgc::queryExecute( rr::indexEntry &queryRep, ueIterator *ueIter, std::vector<indScorePair> &queryRes, uint32_t toReturn ) const {
    std::vector<double> scores;
    queryExecute(queryRep, ueIter, scores);
    retriever::sortResults( scores, queryRes, toReturn );
}

void
wgc::queryExecute( rr::indexEntry &queryRep, ueIterator *ueIter, std::vector<double> &scores ) const {

    // weight query BoW with idf
    tfidfV2::weightStatic(queryRep, NULL, &idf_);

    // query
    weighterV2::queryExecuteWGC(queryRep, ueIter, idf_, docL2_, scores, 128);

}

void
wgc::computeDocL2() {

    uint32_t numWords= iidx_->numIDs();
    ASSERT(fidx_!=NULL); // if needed, this could be replaced by computing numDocs as max(all ids)
    uint32_t numDocs= fidx_->numIDs();

    docL2_.clear();
    docL2_.resize( numDocs, 0.0 );
    std::vector<rr::indexEntry> entries;

    uint32_t numWords_printStep= std::max(static_cast<uint32_t>(1),numWords/20);

    std::cout<<"wgc::computeDocL2\n";
    double time= timing::tic();

    for (uint32_t wordID= 0; wordID < numWords; ++wordID){
        if (wordID % numWords_printStep == 0)
            std::cout<<"wgc::computeDocL2: wordID= "<<wordID<<" / "<<numWords<<" "<<timing::toc(time)<<" ms\n";

        iidx_->getEntries( wordID, entries );

        for (uint32_t iEntry= 0; iEntry<entries.size(); ++iEntry){
            rr::indexEntry &entry= entries[iEntry];

            // set/add weights and multiply by idf
            tfidfV2::weightStatic(entry, &idf_[wordID], NULL);

            for (int i= 0; i<entry.id_size(); ++i)
                docL2_[ entry.id(i) ]+= entry.weight(i) * entry.weight(i);
        }

    }

    for (uint32_t docID= 0; docID < numDocs; ++docID){
        if ( docL2_[docID] <= 1e-7 )
            docL2_[docID]= 1.0;
        else
            docL2_[docID]= sqrt( docL2_[docID] );
    }

    std::cout<<"wgc::computeDocL2: DONE ("<<timing::toc(time)<<" ms)\n";

}


#include <boost/test/unit_test.hpp>
#include "logs.h"
#include "route.h"
#include "track.h"

using namespace GPS;

BOOST_AUTO_TEST_SUITE( Track_RateOfAscent_N0687265 )

	/*
	 *  Required to create a track object.
	 */
	const bool FileName = true;

	/*
	 *	Tests a gpx file with a standard elevation and timebetween.
	 *  Also uses negative elevation values to ensure that difference in elevation can handle
	 *	a difference in both positive and negative values. Also ensures that the correct
	 *  calculation is carried out (elevation difference / time)
	 */
	BOOST_AUTO_TEST_CASE( NormalValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_NormalValues.gpx", FileName);
		BOOST_CHECK_EQUAL( track.maxRateOfAscent() , 20);
	}

	/*
	 *  Tests a gpx file with a large difference in elevation to ensure the calculated value
	 *  is still correct.
	 */
	BOOST_AUTO_TEST_CASE( LargeElevationValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_LargeElevationValues.gpx", FileName);
		BOOST_CHECK_EQUAL( track.maxRateOfAscent() , 200);
	}

	/*
	 *  Tests a gpx file with a small difference in elevation to ensure the calculated value
	 *  is still correct. Also checks the precesion of the returned value and checks its within
	 *	1% of the correct value.
	 */
	BOOST_AUTO_TEST_CASE( SmallElevationValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_SmallElevationValues.gpx", FileName);
		BOOST_CHECK_CLOSE( track.maxRateOfAscent() , 0.02, 1);
	}

	/*
	 *  Tests a gpx file with only descending elevation values and checks that the returned
	 *  value is 0.
	 */
	BOOST_AUTO_TEST_CASE( DescendingElevationValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_DescendingElevationValues.gpx", FileName);
		BOOST_CHECK_EQUAL( track.maxRateOfAscent() , 0);
	}

	/*
	 *  Tests a gpx file with no difference in elevation, and checks that the returned
	 *  value is 0.
	 */
	BOOST_AUTO_TEST_CASE( NoElevationValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_NoElevationValues.gpx", FileName);
		BOOST_CHECK_EQUAL( track.maxRateOfAscent() , 0);
	}

	/*
	 *  Tests a gpx file with a large time for travel between each point. Checks the precision of the
	 *  returned value is within 1% of the correct value which is given to a standard 3 decimal places.
	 */
	BOOST_AUTO_TEST_CASE( LongTimeValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_LongTimeValues.gpx", FileName);
		BOOST_CHECK_CLOSE( track.maxRateOfAscent() , 0.667, 1);
	}

	/*
	 *  Tests a gpx file with a short time for travel between each point, and ensures the calculated value
	 *  is still correct.
	 */
	BOOST_AUTO_TEST_CASE( ShortTimeValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_ShortTimeValues.gpx", FileName);
		BOOST_CHECK_EQUAL( track.maxRateOfAscent() , 200);
	}

	/*
	 *  Tests a gpx file with a zero time value to ensure that the implementation throws
	 *  an overflow_error before the program tries to divide by 0 and breaks the program.
	 */
	BOOST_AUTO_TEST_CASE( ZeroTimeValues ){
		Track track = Track(LogFiles::GPXTracksDir + "N0687265_ZeroTimeValues.gpx", FileName);
		BOOST_CHECK_THROW( track.maxRateOfAscent() , std::overflow_error);
	}

BOOST_AUTO_TEST_SUITE_END()


//  Copyright John Maddock 2006.
//  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)
//
// Basic sanity check that header <boost/math/tools/toms748_solve.hpp>
// #includes all the files that it needs to.
//
#include <boost/math/tools/toms748_solve.hpp>

#define T double
#define Tol boost::math::tools::eps_tolerance<double>

typedef T (*F)(T);

template std::pair<T, T> boost::math::tools::toms748_solve<F, T, Tol >(F, const T&, const T&, const T&, const T&, Tol, boost::uintmax_t&);
template std::pair<T, T> boost::math::tools::toms748_solve<F, T, Tol>(F f, const T& ax, const T& bx, Tol tol, boost::uintmax_t& max_iter);
template std::pair<T, T> boost::math::tools::bracket_and_solve_root<F, T, Tol>(F f, const T& guess, const T& factor, bool rising, Tol tol, boost::uintmax_t& max_iter);


/*
 * File:   NoArvore.cpp
 * Author: arthur
 *
 * Created on 11 de Setembro de 2015, 09:30
 */

#include "headers/NoArvore.hpp"
#include "headers/Heapsort.hpp"
#include "headers/Box.hpp"

#include <armadillo>
#include <vector>

using namespace arma;
using namespace std;

bool NoArvore::Folha(NoArvore * &No){
    if (No->getEsq() == NULL && No->getDir() == NULL){
	return true;
    }

    return false;
}

NoArvore * NoArvore::construirArvore(vector <Object *> &objetos, unsigned int &porc, int nivel){

  NoArvore * No = new NoArvore();
  vector<Object *> esq, dir;
  vec min, max;
  Box bounds;

  max = objetos[0]->getMax();
  min = objetos[0]->getMin();

    for (unsigned int i=1;i<objetos.size();i++)
      {
	if (objetos[i]->getMin()(0) < min(0)) { min(0) = objetos[i]->getMin()(0); }
	if (objetos[i]->getMin()(1) < min(1)) { min(1) = objetos[i]->getMin()(1); }
	if (objetos[i]->getMin()(2) < min(2)) { min(2) = objetos[i]->getMin()(2); }

	if (objetos[i]->getMax()(0) > max(0)) { max(0) = objetos[i]->getMax()(0); }
	if (objetos[i]->getMax()(1) > max(1)) { max(1) = objetos[i]->getMax()(1); }
	if (objetos[i]->getMax()(2) > max(2)) { max(2) = objetos[i]->getMax()(2); }
      }

  No->setBounds(Box(min, max));
  No->setObjetos(objetos);
  No->setEixo(nivel % 3);

    if (nivel >= 20 || objetos.size() <= porc)
      {
	No->setEsq(NULL);
	No->setDir(NULL);
	return No;
      }

  Heapsort::heapsort(objetos, objetos.size(), No->getEixo());

  No->setSplit (objetos[objetos.size()/2]->getCentro()(No->getEixo()));
    if (objetos.size()%2==0) {
        No->setSplit(No->getSplit() + objetos[(objetos.size()/2)-1]->getCentro()(No->getEixo()));
        No->setSplit(No->getSplit()/2);
    }

    for (unsigned int w=0;w<objetos.size();w++)
    {
	if ((objetos[w]->getMin()(No->getEixo()) <= No->getSplit()) && (objetos[w]->getMax()(No->getEixo()) <= No->getSplit())){
	    esq.push_back(objetos[w]);
	}

	else if ((objetos[w]->getMin()(No->getEixo()) > No->getSplit()) && (objetos[w]->getMax()(No->getEixo()) > No->getSplit())){
	    dir.push_back(objetos[w]);
	}

	else{
	    esq.push_back(objetos[w]);
	    dir.push_back(objetos[w]);
	}
      }

      No->setEsq(NoArvore::construirArvore(esq, porc, nivel+1));
      No->setDir(NoArvore::construirArvore(dir, porc, nivel+1));

return No;
}

NoArvore * NoArvore::percorrerArvore(NoArvore * &No, Ray &r, bool &colide, double &Tmin, double &T, int &indice){

  NoArvore * NoAtual = No;
  vector <NoArvore *> pilha;
  int nivelDaPilha=0;

  while(nivelDaPilha!=-1){

      if (!Folha(NoAtual)){

	  Ray r0=r, r1=r;

	  bool intersecta0 = NoAtual->getEsq()->getBounds().intersect(r0);
	  bool intersecta1 = NoAtual->getDir()->getBounds().intersect(r1);

	  if (intersecta0 && intersecta1){

	      if (r1.GetTmin() < r0.GetTmin()){

                pilha.push_back(NoAtual->getEsq());
                NoAtual=NoAtual->getDir();
              }

	      else{

		pilha.push_back(NoAtual->getDir());
  		NoAtual=NoAtual->getEsq();
              }

	    nivelDaPilha++;
	  }

	  else{
	    if (intersecta0){
		NoAtual=NoAtual->getEsq();
            }

	    else if (intersecta1){
                NoAtual=NoAtual->getDir();
            }

	    else{
		nivelDaPilha--;

                if (nivelDaPilha!=-1){
                    NoAtual=pilha[nivelDaPilha];
                    pilha.resize(nivelDaPilha);
		}
            }
	}
    }

    else{
	for(unsigned int i=0; i<NoAtual->getObjetos().size(); i++){

            if(NoAtual->getObjetos()[i]->colide(r.GetD(), T, r.GetOrigem())) {
                colide=true;

                if (T>=0 && T<=Tmin){
                    Tmin = T;
                    indice = i;
		}
            }
	}

            if (colide)
                return NoAtual;

            else{
                nivelDaPilha--;

                if (nivelDaPilha!=-1){
                    NoAtual=pilha[nivelDaPilha];
                    pilha.resize(nivelDaPilha);
                }
            }
	}
    }

return NoAtual;
}


//   Copyright 2015 Patrick Putnam
//
//   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 <boost/test/unit_test.hpp>

#include "../unittest_config.h"

#include "clotho/utility/debruijn_bit_walker.hpp"
#include "clotho/utility/popcount.hpp"
#include <vector>

template < class Type >
void validate_set_bits( std::vector< unsigned int > & indices, Type origin ) {

    std::vector< unsigned int >::iterator it = indices.begin();

    while( it != indices.end() ) {
        Type obs_bit = ((Type)1 << *it);

        BOOST_REQUIRE_MESSAGE( (obs_bit & origin), "Unexpected set bit index: Observed bit: " << obs_bit );

        origin ^= obs_bit;
        ++it;
    }

    BOOST_REQUIRE_MESSAGE( origin == 0, "Unexpected set bits remaining: Observed: " << origin << "; Expected: 0" );
}

BOOST_AUTO_TEST_SUITE( test_utility )

BOOST_AUTO_TEST_CASE( test_debruijn_walker_char ) {
    typedef char block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type > walker_type;

    block_type origin = 0x13;

    block_type b = origin;
    size_t exp_size = popcount( b );

    std::vector< unsigned int > indices;

    while( b ) {
        unsigned int idx = walker_type::unset_next_index( b );
        indices.push_back( idx );
    }

    size_t obs_size = indices.size();

    BOOST_REQUIRE_MESSAGE( obs_size == exp_size, "Unexpected number of set bits returned; Observed: " << obs_size << "; Expected: " << exp_size );

    validate_set_bits( indices, origin );
}

BOOST_AUTO_TEST_CASE( test_debruijn_walker_uchar ) {
    typedef unsigned char block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type > walker_type;

    block_type origin = 0x13;

    block_type b = origin;
    size_t exp_size = popcount( b );

    std::vector< unsigned int > indices;

    while( b ) {
        unsigned int idx = walker_type::unset_next_index( b );
        indices.push_back( idx );
    }

    size_t obs_size = indices.size();

    BOOST_REQUIRE_MESSAGE( obs_size == exp_size, "Unexpected number of set bits returned; Observed: " << obs_size << "; Expected: " << exp_size );

    validate_set_bits( indices, origin );
}

BOOST_AUTO_TEST_CASE( test_debruijn_walker_unlonglong ) {
    typedef unsigned long long block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type > walker_type;

    block_type origin = 0x1000F33210220307;

    block_type b = origin;
    size_t exp_size = popcount( b );

    std::vector< unsigned int > indices;

    while( b ) {
        unsigned int idx = walker_type::unset_next_index( b );
        indices.push_back( idx );
    }

    size_t obs_size = indices.size();

    BOOST_REQUIRE_MESSAGE( obs_size == exp_size, "Unexpected number of set bits returned; Observed: " << obs_size << "; Expected: " << exp_size );

    validate_set_bits( indices, origin );
}

BOOST_AUTO_TEST_SUITE_END()


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

  @copyright 2016 NumScale SAS

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

#include <boost/simd/config.hpp>
#include <boost/simd/detail/nsm.hpp>
#include <boost/simd/detail/dispatch.hpp>
#include <boost/simd/detail/constant_traits.hpp>
#include <boost/simd/detail/dispatch/function/make_callable.hpp>
#include <boost/simd/detail/dispatch/hierarchy/functions.hpp>
#include <boost/simd/detail/dispatch/as.hpp>

/*

    @ingroup group-constant

    Generates constant MaxLog2 used in logarithm/exponential computations
    log2(x) return inf if x is greater than Maxlog2 (overflow)

    @par Semantic:

    @code
    T r = Maxlog2<T>();
    @endcode

    is similar to:

    @code
    if T is double
    r = 1023.0;
    else if T is float
    r = 127.0;

    @endcode

*/

namespace boost { namespace simd
{
  namespace tag
  {
    struct maxlog2_ : boost::dispatch::constant_value_<maxlog2_>
    {
      BOOST_DISPATCH_MAKE_CALLABLE(ext,maxlog2_,boost::dispatch::constant_value_<maxlog2_>);
      BOOST_SIMD_REGISTER_CONSTANT( 0, 0x42fe0000UL, 0x408ff80000000000ULL);
    };
  }

  namespace ext
  {
    BOOST_DISPATCH_FUNCTION_DECLARATION(tag, maxlog2_)
  }

  namespace detail
  {
    BOOST_DISPATCH_CALLABLE_DEFINITION(tag::maxlog2_,maxlog2);
  }

  template<typename T> BOOST_FORCEINLINE auto Maxlog2()
  BOOST_NOEXCEPT_DECLTYPE(detail::maxlog2( boost::dispatch::as_<T>{}))
  {
    return detail::maxlog2( boost::dispatch::as_<T>{} );
  }
} }

#include <boost/simd/arch/common/scalar/constant/constant_value.hpp>
#include <boost/simd/arch/common/simd/constant/constant_value.hpp>

#endif


#ifndef PYTHONIC_INCLUDE_NUMPY_ARCTANH_HPP
#define PYTHONIC_INCLUDE_NUMPY_ARCTANH_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"

#include <boost/simd/function/atanh.hpp>

PYTHONIC_NS_BEGIN

namespace numpy
{
  namespace wrapper
  {
    template <class T>
    auto atanh(T const &v) -> decltype(boost::simd::atanh(v))
    {
      return boost::simd::atanh(v);
    }
    template <class T>
    std::complex<T> atanh(std::complex<T> const &v)
    {
      return std::atanh(v);
    }
  }
#define NUMPY_NARY_FUNC_NAME arctanh
#define NUMPY_NARY_FUNC_SYM wrapper::atanh
#include "pythonic/include/types/numpy_nary_expr.hpp"
}
PYTHONIC_NS_END

#endif