// Boost.Polygon library polygon_set_data_test.cpp file

//          Copyright Andrii Sydorchuk 2015.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

// See http://www.boost.org for updates, documentation, and revision history.

#include <boost/core/lightweight_test.hpp>
#include <boost/polygon/polygon.hpp>
#include <vector>

using namespace boost::polygon;
using namespace boost::polygon::operators;

void polygon_set_data_test1()
{
    typedef point_data<int> point_type;
    typedef polygon_with_holes_data<int> polygon_with_holes_type;
    typedef polygon_set_data<int> polygon_set_type;

    polygon_set_type pset;
    std::vector<point_type> outbox;
    outbox.push_back(point_type(0, 0));
    outbox.push_back(point_type(100, 0));
    outbox.push_back(point_type(100, 100));
    outbox.push_back(point_type(0, 100));
    pset.insert_vertex_sequence(outbox.begin(), outbox.end(), COUNTERCLOCKWISE, false);
    std::vector<point_type> inbox;
    inbox.push_back(point_type(20, 20));
    inbox.push_back(point_type(80, 20));
    inbox.push_back(point_type(80, 80));
    inbox.push_back(point_type(20, 80));
    pset.insert_vertex_sequence(inbox.begin(), inbox.end(), COUNTERCLOCKWISE, true);

    BOOST_TEST(!pset.empty());
    BOOST_TEST(!pset.sorted());
    BOOST_TEST(pset.dirty());
    BOOST_TEST_EQ(8, pset.size());

    std::vector<polygon_with_holes_type> vpoly;
    pset.get(vpoly);
    BOOST_TEST_EQ(1, vpoly.size());

    polygon_with_holes_type poly = vpoly[0];
    BOOST_TEST_EQ(5, poly.size());
    BOOST_TEST_EQ(1, poly.size_holes());
}

void polygon_set_data_test2()
{
    typedef point_data<int> point_type;
    typedef polygon_data<int> polygon_type;
    typedef polygon_set_data<int> polygon_set_type;

    std::vector<point_type> data;
    data.push_back(point_type(2,0));
    data.push_back(point_type(4,0));
    data.push_back(point_type(4,3));
    data.push_back(point_type(0,3));
    data.push_back(point_type(0,0));
    data.push_back(point_type(2,0));
    data.push_back(point_type(2,1));
    data.push_back(point_type(1,1));
    data.push_back(point_type(1,2));
    data.push_back(point_type(3,2));
    data.push_back(point_type(3,1));
    data.push_back(point_type(2,1));
    data.push_back(point_type(2,0));

    polygon_type polygon;
    set_points(polygon, data.begin(), data.end());

    polygon_set_type pset;
    pset.insert(polygon);

    std::vector<polygon_type> traps;
    get_trapezoids(traps, pset, HORIZONTAL);

    BOOST_TEST_EQ(4, traps.size());
}

void polygon_set_data_test3()
{
    typedef point_data<int> point_type;
    typedef polygon_data<int> polygon_type;
    typedef polygon_set_data<int> polygon_set_type;

    std::vector<point_type> data;
    data.push_back(point_type(0,0));
    data.push_back(point_type(6,0));
    data.push_back(point_type(6,4));
    data.push_back(point_type(4,6));
    data.push_back(point_type(0,6));
    data.push_back(point_type(0,0));
    data.push_back(point_type(4,4));
    data.push_back(point_type(5,4));

    polygon_type polygon(data.begin(), data.end());
    polygon_set_type pset;
    pset += polygon;

    BOOST_TEST_EQ(32.0, area(polygon));
    BOOST_TEST_EQ(32.0, area(polygon));
}

int main()
{
    polygon_set_data_test1();
    polygon_set_data_test2();
    polygon_set_data_test3();
    return boost::report_errors();
}


////////////////////////////////////////////////////////////////////////////////
//  Copyright (c) 2015 Bryce Adelstein Lelbach aka wash
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
////////////////////////////////////////////////////////////////////////////////

#include <mdspan>

#include <boost/core/lightweight_test.hpp>

using std::is_same;

using std::integral_constant;
using std::experimental::detail::integer_sequence;
using std::experimental::detail::integral_pair;

using std::experimental::detail::type_list;
using std::experimental::detail::type_list_sort;

using std::experimental::detail::make_key_value_type_list_from_integer_sequence;
using std::experimental::detail::make_integer_sequence_inverse_mapping;

int main()
{
    // type_list_sort {{{

    { // 01 {{{

        using A = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 10 {{{

        using A = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 0>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 012 {{{

        using A = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 021 {{{

        using A = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 2>
          , integral_constant<int, 1>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 102 {{{

        using A = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 0>
          , integral_constant<int, 2>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 120 {{{

        using A = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 2>
          , integral_constant<int, 0>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 201 {{{

        using A = type_list<
            integral_constant<int, 2>
          , integral_constant<int, 0>
          , integral_constant<int, 1>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 210 {{{

        using A = type_list<
            integral_constant<int, 2>
          , integral_constant<int, 1>
          , integral_constant<int, 0>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 139 {{{

        using A = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 3>
          , integral_constant<int, 9>
        >;

        using B = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 3>
          , integral_constant<int, 9>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 391 {{{

        using A = type_list<
            integral_constant<int, 3>
          , integral_constant<int, 9>
          , integral_constant<int, 1>
        >;

        using B = type_list<
            integral_constant<int, 1>
          , integral_constant<int, 3>
          , integral_constant<int, 9>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);

    } // }}}

    { // 9123547806 {{{
        using A = type_list<
            integral_constant<int, 9>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
          , integral_constant<int, 3>
          , integral_constant<int, 5>
          , integral_constant<int, 4>
          , integral_constant<int, 7>
          , integral_constant<int, 8>
          , integral_constant<int, 0>
          , integral_constant<int, 6>
        >;

        using B = type_list<
            integral_constant<int, 0>
          , integral_constant<int, 1>
          , integral_constant<int, 2>
          , integral_constant<int, 3>
          , integral_constant<int, 4>
          , integral_constant<int, 5>
          , integral_constant<int, 6>
          , integral_constant<int, 7>
          , integral_constant<int, 8>
          , integral_constant<int, 9>
        >;

        using A_sorted = type_list_sort<A>::type;

        BOOST_TEST_EQ((!is_same<A, B>::value), true);
        BOOST_TEST_EQ((is_same<A_sorted, B>::value), true);
    } // }}}

    // }}}

    // make_key_value_type_list_from_integer_sequence {{{

    { // 01 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 0, 1>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 0>
          , integral_pair<std::size_t, int, 1, 1>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 10 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 1, 0>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 1>
          , integral_pair<std::size_t, int, 1, 0>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 012 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 0, 1, 2>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 0>
          , integral_pair<std::size_t, int, 1, 1>
          , integral_pair<std::size_t, int, 2, 2>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 021 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 0, 2, 1>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 0>
          , integral_pair<std::size_t, int, 1, 2>
          , integral_pair<std::size_t, int, 2, 1>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 102 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 1, 0, 2>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 1>
          , integral_pair<std::size_t, int, 1, 0>
          , integral_pair<std::size_t, int, 2, 2>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 120 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 1, 2, 0>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 1>
          , integral_pair<std::size_t, int, 1, 2>
          , integral_pair<std::size_t, int, 2, 0>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 201 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 2, 0, 1>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 2>
          , integral_pair<std::size_t, int, 1, 0>
          , integral_pair<std::size_t, int, 2, 1>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 210 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 2, 1, 0>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 2>
          , integral_pair<std::size_t, int, 1, 1>
          , integral_pair<std::size_t, int, 2, 0>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 0123 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 0, 1, 2, 3>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 0>
          , integral_pair<std::size_t, int, 1, 1>
          , integral_pair<std::size_t, int, 2, 2>
          , integral_pair<std::size_t, int, 3, 3>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 3210 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 3, 2, 1, 0>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 3>
          , integral_pair<std::size_t, int, 1, 2>
          , integral_pair<std::size_t, int, 2, 1>
          , integral_pair<std::size_t, int, 3, 0>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 1320 {{{

        using A = make_key_value_type_list_from_integer_sequence<
            integer_sequence<int, 1, 3, 2, 0>
        >::type;

        using B = type_list<
            integral_pair<std::size_t, int, 0, 1>
          , integral_pair<std::size_t, int, 1, 3>
          , integral_pair<std::size_t, int, 2, 2>
          , integral_pair<std::size_t, int, 3, 0>
        >;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    // }}}

    // make_integer_sequence_inverse_mapping {{{

    { // 01 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 0, 1>
        >::type;

        using B = integer_sequence<std::size_t, 0, 1>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 10 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 1, 0>
        >::type;

        using B = integer_sequence<std::size_t, 1, 0>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 012 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 0, 1, 2>
        >::type;

        using B = integer_sequence<std::size_t, 0, 1, 2>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 021 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 0, 2, 1>
        >::type;

        using B = integer_sequence<std::size_t, 0, 2, 1>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 102 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 1, 0, 2>
        >::type;

        using B = integer_sequence<std::size_t, 1, 0, 2>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 120 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 1, 2, 0>
        >::type;

        using B = integer_sequence<std::size_t, 2, 0, 1>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 201 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 2, 0, 1>
        >::type;

        using B = integer_sequence<std::size_t, 1, 2, 0>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 210 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 2, 1, 0>
        >::type;

        using B = integer_sequence<std::size_t, 2, 1, 0>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 0123 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 0, 1, 2, 3>
        >::type;

        using B = integer_sequence<std::size_t, 0, 1, 2, 3>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 3210 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 3, 2, 1, 0>
        >::type;

        using B = integer_sequence<std::size_t, 3, 2, 1, 0>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    { // 1320 {{{

        using A = make_integer_sequence_inverse_mapping<
            integer_sequence<int, 1, 3, 2, 0>
        >::type;

        using B = integer_sequence<std::size_t, 3, 0, 2, 1>;

        BOOST_TEST_EQ((is_same<A, B>::value), true);

    } // }}}

    // }}}

    return boost::report_errors();
}


#ifndef IMGTOGB_TILEMAP_HPP
#define IMGTOGB_TILEMAP_HPP

#include <map>
#include <ostream>
#include <string>
#include <boost/numeric/ublas/matrix.hpp>
#include <imgtogb/Image.hpp>
#include <imgtogb/Tile.hpp>

namespace imgtogb {
	class Tilemap {
		public:
			Tilemap(const Image &img, int offset);

			size_t getTilesX() const;
			size_t getTilesY() const;
			size_t getTileDataSize() const;
			void getTileMap(std::vector<unsigned char> &out) const;
			void getTileData(std::vector<unsigned char> &out) const;

		private:
			const Image *img;
			int offset;
			size_t tiles_x, tiles_y, ntiles;
			boost::numeric::ublas::matrix<int> tilemap;
			std::multimap<int, Tile> map;
	};
}

#endif


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

#include "corner_orientation.h"

class CornerOrientationTest
{
public:
    CornerOrientation co;

    void test_four_identical_moves(std::vector<int> state, int move)
    {
        std::vector<int> current_state(state);
        for (int i = 1; i <= 4; i++)
        {
            co.apply_move(current_state, 0);
        }

        BOOST_CHECK(state == current_state);
    }

    std::vector<std::vector<int>> get_all_states()
    {
        std::vector<std::vector<int>> states;
        for (int ternary_rep = 0; ternary_rep < 6561; ternary_rep++)
        {
            std::vector<int> state(8);
            int ternary_rep_cur = ternary_rep;
            for (int i = 0; i < 8; i++)
            {
                state[i] = ternary_rep_cur % 3;
                ternary_rep_cur /= 3;
            }
            states.push_back(state);
        }
        return states;
    }
};

BOOST_AUTO_TEST_SUITE(corner_orientation_tests)

    BOOST_AUTO_TEST_CASE(four_identical_moves)
    {
        auto cot = CornerOrientationTest();
        for (auto state : cot.get_all_states()) {
            for (int move = 0; move < 6; move++) {
                cot.test_four_identical_moves(state, move);
            }
        }
    }

    BOOST_AUTO_TEST_CASE(solved_state)
    {
        auto cot = CornerOrientationTest();
        std::vector<int> state(8, 0);
        std::vector<int> current_state(state);

        cot.co.apply_move(current_state, 0); // U
        BOOST_CHECK(state == current_state);

        cot.co.apply_move(current_state, 1); // D
        BOOST_CHECK(state == current_state);

        cot.co.apply_move(current_state, 2); // R
        BOOST_CHECK(state != current_state);
        cot.co.apply_move(current_state, 2); // R2
        BOOST_CHECK(state == current_state);

        cot.co.apply_move(current_state, 3); // L
        BOOST_CHECK(state != current_state);
        cot.co.apply_move(current_state, 3); // L2
        BOOST_CHECK(state == current_state);

        cot.co.apply_move(current_state, 4); // F
        BOOST_CHECK(state != current_state);
        cot.co.apply_move(current_state, 4); // F2
        BOOST_CHECK(state == current_state);

        cot.co.apply_move(current_state, 5); // B
        BOOST_CHECK(state != current_state);
        cot.co.apply_move(current_state, 5); // B2
        BOOST_CHECK(state == current_state);
    }

BOOST_AUTO_TEST_CASE(opposite_independance)
{
    auto cot = CornerOrientationTest();
    for (auto state : cot.get_all_states())
    {
        std::vector<int> current_state(state);
        for (int axis = 0; axis < 3; axis++)
        {
            int move1 = axis * 2;
            int move2 = axis * 2 + 1;

            for (int i = 0; i < 4; i++) {
                cot.co.apply_move(current_state, move1);
                cot.co.apply_move(current_state, move2);
            }

            BOOST_CHECK(state == current_state);
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()


#include "generator.hpp"
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

namespace randnum {
	generator::generator()
			: position(0) {
		using namespace boost::posix_time;

		// Using assignment operator for the epoch results in conversion error
		const ptime epoch(boost::gregorian::date(1970, 1, 1));
		const auto timeOfDay = boost::posix_time::microsec_clock::universal_time();
		const auto td = boost::posix_time::time_duration(epoch - timeOfDay);
		rngSeed = td.total_microseconds();

		rng.seed(rngSeed);
	}

	generator::generator(const uint32_t suppliedSeed)
			: rngSeed(suppliedSeed),
			position(0) {
		rng.seed(rngSeed);
	}
}


/**
 * Copyright (c) 2009 Carnegie Mellon University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://www.graphlab.ml.cmu.edu
 *
 */

#ifndef GRAPHLAB_RANDOM_HPP
#define GRAPHLAB_RANDOM_HPP

#include <cstdlib>
#include <stdint.h>

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

#include <boost/random.hpp>
#include <graphlab/util/timer.hpp>
#include <graphlab/parallel/pthread_tools.hpp>

namespace graphlab {

  /**
   * \ingroup random
   * A collection of thread safe random number routines.  Each thread
   * is assigned its own generator however assigning a seed affects
   * all current and future generators.
   */
  namespace random {

    ///////////////////////////////////////////////////////////////////////
    //// Underlying generator definition

    namespace distributions {
      /**
       * The uniform distribution struct is used for partial function
       * specialization. Generating uniform random real numbers is
       * accomplished slightly differently than for integers.
       * Therefore the base case is for integers and we then
       * specialize the two real number types (floats and doubles).
       */
      template<typename IntType>
      struct uniform {
        typedef boost::uniform_int<IntType> distribution_type;
        template<typename RealRNG, typename DiscreteRNG>
        static inline IntType sample(RealRNG& real_rng,
                                     DiscreteRNG& discrete_rng,
                                     const IntType& min, const IntType& max) {
          return distribution_type(min, max)(discrete_rng);
        }
      };
      template<>
      struct uniform<double> {
        typedef boost::uniform_real<double> distribution_type;
        template<typename RealRNG, typename DiscreteRNG>
        static inline double sample(RealRNG& real_rng,
                                    DiscreteRNG& discrete_rng,
                                    const double& min, const double& max) {
          return distribution_type(min, max)(real_rng);
        }
      };
      template<>
      struct uniform<float> {
        typedef boost::uniform_real<float> distribution_type;
        template<typename RealRNG, typename DiscreteRNG>
        static inline float sample(RealRNG& real_rng,
                                  DiscreteRNG& discrete_rng,
                                  const float& min, const float& max) {
          return distribution_type(min, max)(real_rng);
        }
      };
    }; // end of namespace distributions

    /**
     * The generator class is the base underlying type used to
     * generate random numbers.  User threads should use the functions
     * provided in the random namespace.
     */
    class generator {
    public:
      // base Generator types
      typedef boost::lagged_fibonacci607 real_rng_type;
      typedef boost::mt11213b            discrete_rng_type;
      typedef boost::rand48              fast_discrete_rng_type;

      generator() {
        time_seed();
      }

      //! Seed the generator using the default seed
      inline void seed() {
        mut.lock();
        real_rng.seed();
        discrete_rng.seed();
        fast_discrete_rng.seed();
        mut.unlock();
      }

      //! Seed the generator nondeterministically
      void nondet_seed();

      //! Seed the generator using the current time in microseconds
      inline void time_seed() {
        seed( graphlab::timer::usec_of_day() );
      }

      //! Seed the random number generator based on a number
      void seed(size_t number) {
        mut.lock();
        fast_discrete_rng.seed(number);
        real_rng.seed(fast_discrete_rng);
        discrete_rng.seed(fast_discrete_rng);
        mut.unlock();
      }

      //! Seed the generator using another generator
      void seed(generator& other){
        mut.lock();
        real_rng.seed(other.real_rng);
        discrete_rng.seed(other.discrete_rng);
        fast_discrete_rng.seed(other.fast_discrete_rng());
        mut.unlock();
      }

      /**
       * Generate a random number in the uniform real with range [min,
       * max) or [min, max] if the number type is discrete.
       */
      template<typename NumType>
      inline NumType uniform(const NumType min, const NumType max) {
        mut.lock();
        const NumType result = distributions::uniform<NumType>::
          sample(real_rng, discrete_rng, min, max);
        mut.unlock();
        return result;
      } // end of uniform

      /**
       * Generate a random number in the uniform real with range [min,
       * max) or [min, max] if the number type is discrete.
       */
      template<typename NumType>
      inline NumType fast_uniform(const NumType min, const NumType max) {
        mut.lock();
        const NumType result = distributions::uniform<NumType>::
          sample(real_rng, fast_discrete_rng, min, max);
        mut.unlock();
        return result;
      } // end of fast_uniform

      /**
       * Generate a random number in the uniform real with range [min,
       * max);
       */
      inline double gamma(const double alpha = double(1)) {
        boost::gamma_distribution<double> gamma_dist(alpha);
        mut.lock();
        const double result = gamma_dist(real_rng);
        mut.unlock();
        return result;
      } // end of gamma

      /**
       * Generate a gaussian random variable with zero mean and unit
       * variance.
       */
      inline double gaussian(const double mean = double(0),
                             const double stdev = double(1)) {
        boost::normal_distribution<double> normal_dist(mean,stdev);
        mut.lock();
        const double result = normal_dist(real_rng);
        mut.unlock();
        return result;
      } // end of gaussian

      /**
       * Generate a gaussian random variable with zero mean and unit
       * variance.
       */
      inline double normal(const double mean = double(0),
                           const double stdev = double(1)) {
        return gaussian(mean, stdev);
      } // end of normal

      inline bool bernoulli(const double p = double(0.5)) {
        boost::bernoulli_distribution<double> dist(p);
        mut.lock();
        const double result(dist(discrete_rng));
        mut.unlock();
        return result;
      } // end of bernoulli

      inline bool fast_bernoulli(const double p = double(0.5)) {
        boost::bernoulli_distribution<double> dist(p);
        mut.lock();
        const double result(dist(fast_discrete_rng));
        mut.unlock();
        return result;
      } // end of bernoulli

      /**
       * Draw a random number from a multinomial
       */
      template<typename Double>
      size_t multinomial(const std::vector<Double>& prb) {
        ASSERT_GT(prb.size(),0);
        if (prb.size() == 1) { return 0; }
        Double sum(0);
        for(size_t i = 0; i < prb.size(); ++i) {
          ASSERT_GE(prb[i], 0); // Each entry must be P[i] >= 0
          sum += prb[i];
        }
        ASSERT_GT(sum, 0); // Normalizer must be positive
        // actually draw the random number
        const Double rnd(uniform<Double>(0,1));
        size_t ind = 0;
        for(Double cumsum(prb[ind]/sum);
            rnd > cumsum && (ind+1) < prb.size();
            cumsum += (prb[++ind]/sum));
        return ind;
      } // end of multinomial

      /**
       * Generate a draw from a multinomial using a CDF.  This is
       * slightly more efficient since normalization is not required
       * and a binary search can be used.
       */
      template<typename Double>
      inline size_t multinomial_cdf(const std::vector<Double>& cdf) {
        return std::upper_bound(cdf.begin(), cdf.end(),
                                uniform<Double>(0,1)) - cdf.begin();

      } // end of multinomial_cdf

      /**
       * Construct a random permutation
       */
      template<typename T>
      inline std::vector<T> permutation(const size_t nelems) {
        std::vector<T> perm(nelems);
        for(T i = 0; i < nelems; ++i) perm[i] = i;
        shuffle(perm);
        return perm;
      } // end of construct a permutation

      /**
       * Shuffle a standard vector
       */
      template<typename T>
      void shuffle(std::vector<T>& vec) { shuffle(vec.begin(), vec.end()); }

      /**
       * Shuffle a range using the begin and end iterators
       */
      template<typename Iterator>
      void shuffle(Iterator begin, Iterator end) {
        mut.lock();
        shuffle_functor functor(*this);
        std::random_shuffle(begin, end, functor);
        mut.unlock();
      } // end of shuffle

    private:
      //////////////////////////////////////////////////////
      /// Data members
      struct shuffle_functor {
        generator& gen;
        inline shuffle_functor(generator& gen) : gen(gen) { }
        inline std::ptrdiff_t operator()(std::ptrdiff_t end) {
          return distributions::uniform<ptrdiff_t>::
            sample(gen.real_rng, gen.fast_discrete_rng, 0, end-1);
        }
      };

      //! The real random number generator
      real_rng_type real_rng;
      //! The discrete random number generator
      discrete_rng_type discrete_rng;
      //! The fast discrete random number generator
      fast_discrete_rng_type fast_discrete_rng;
      //! lock used to access local members
      mutex mut;
    }; // end of class generator

    /**
     * \ingroup random
     * Seed all generators using the default seed
     */
    void seed();

    /**
     * \ingroup random
     * Seed all generators using an integer
     */
    void seed(size_t seed_value);

    /**
     * \ingroup random
     * Seed all generators using a nondeterministic source
     */
    void nondet_seed();

    /**
     * \ingroup random
     * Seed all generators using the current time in microseconds
     */
    void time_seed();

    /**
     * \ingroup random
     * Get the local generator
     */
    generator& get_source();

    /**
     * \ingroup random
     * Generate a random number in the uniform real with range [min,
     * max) or [min, max] if the number type is discrete.
     */
    template<typename NumType>
    inline NumType uniform(const NumType min, const NumType max) {
      if (min == max) return min;
      return get_source().uniform<NumType>(min, max);
    } // end of uniform

    /**
     * \ingroup random
     * Generate a random number in the uniform real with range [min,
     * max) or [min, max] if the number type is discrete.
     */
    template<typename NumType>
    inline NumType fast_uniform(const NumType min, const NumType max) {
      if (min == max) return min;
      return get_source().fast_uniform<NumType>(min, max);
    } // end of fast_uniform

    /**
     * \ingroup random
     * Generate a random number between 0 and 1
     */
    inline double rand01() { return uniform<double>(0, 1); }

    /**
     * \ingroup random
     * Simulates the standard rand function as defined in cstdlib
     */
    inline int rand() { return fast_uniform(0, RAND_MAX); }

    /**
     * \ingroup random
     * Generate a random number from a gamma distribution.
     */
    inline double gamma(const double alpha = double(1)) {
      return get_source().gamma(alpha);
    }

    /**
     * \ingroup random
     * Generate a gaussian random variable with zero mean and unit
     * standard deviation.
     */
    inline double gaussian(const double mean = double(0),
                           const double stdev = double(1)) {
      return get_source().gaussian(mean, stdev);
    }

    /**
     * \ingroup random
     * Generate a gaussian random variable with zero mean and unit
     * standard deviation.
     */
    inline double normal(const double mean = double(0),
                         const double stdev = double(1)) {
      return get_source().normal(mean, stdev);
    }

    /**
     * \ingroup random
     * Draw a sample from a bernoulli distribution
     */
    inline bool bernoulli(const double p = double(0.5)) {
      return get_source().bernoulli(p);
    }

    /**
     * \ingroup random
     * Draw a sample form a bernoulli distribution using the faster generator
     */
    inline bool fast_bernoulli(const double p = double(0.5)) {
      return get_source().fast_bernoulli(p);
    }

    /**
     * \ingroup random
     * Generate a draw from a multinomial.  This function
     * automatically normalizes as well.
     */
    template<typename Double>
    inline size_t multinomial(const std::vector<Double>& prb) {
      return get_source().multinomial(prb);
    }

    /**
     * \ingroup random
     * Generate a draw from a cdf;
     */
    template<typename Double>
    inline size_t multinomial_cdf(const std::vector<Double>& cdf) {
      return get_source().multinomial_cdf(cdf);
    }

    /**
     * \ingroup random
     * Construct a random permutation
     */
    template<typename T>
    inline std::vector<T> permutation(const size_t nelems) {
      return get_source().permutation<T>(nelems);
    }

    /**
     * \ingroup random
     * Shuffle a standard vector
     */
    template<typename T>
    inline void shuffle(std::vector<T>& vec) {
      get_source().shuffle(vec);
    }

    /**
     * \ingroup random
     * Shuffle a range using the begin and end iterators
     */
    template<typename Iterator>
    inline void shuffle(Iterator begin, Iterator end) {
      get_source().shuffle(begin, end);
    }

    /**
     * Converts a discrete PDF into a CDF
     */
    void pdf2cdf(std::vector<double>& pdf);

  }; // end of random
}; // end of graphlab

#endif


#include "debug_helper.h"
#include "../../core/math_helper.h"
#include "../base/helper_opencv.h"
#include "../base/eval_helper.h"
#include "../../core/math_helper.h"

#include <Eigen/Core>
#include <opencv2/core/eigen.hpp>
#include <opencv2/highgui/highgui.hpp>

namespace track {

namespace
{
void analyze_track(const core::Point& orig_pt, const cv::Mat& orig_desc,
                   const refiner::FeatureData& rfdata, double scale_sz,
                   double max_dist)
{
  if(rfdata.residue_ > rfdata.first_residue_)
    printf("[Warn] Residue increase detected: %f -> %f", rfdata.first_residue_, rfdata.residue_);
  const core::Point ref_pt = rfdata.pt();
  std::cout << "Orig pt:\n" << orig_pt << "\n" << "Refined pt:\n" << ref_pt << '\n';
  double dist2d = core::MathHelper::getDist2D(orig_pt, ref_pt);
  printf("pixel dist = %f\n", dist2d);
  if(dist2d < max_dist)
    return;
  cv::Point pt1, pt2;
  pt1.x = orig_pt.x_;
  pt1.y = orig_pt.y_;
  pt2.x = ref_pt.x_;
  pt2.y = ref_pt.y_;
  //cv::line(img_lp2, pt1, pt2, color_prev, 2, 8);
  //cv::circle(img_lp2, pt1, 2, color_prev, -1, 8);
  //cv::circle(img_lp2, pt2, 2, color_curr, -1, 8);
  //cout << pt1.x << ", " << pt1.y << " --> " << pt2.x << ", " << pt2.y << endl;
  //cv::putText(img_rp2, std::to_string(i), pt1, cv::FONT_HERSHEY_SIMPLEX, font_size, cv::Scalar::all(0), 1, 8);
  //track::FeatureData t_fdata = tracker_->getLeftFeatureData(i);
  // draw patches
  cv::Mat r_patch_ref, r_patch_track, t_patch_track;
  track::HelperOpencv::FloatImageToMat(rfdata.ref_, r_patch_ref);
  track::HelperOpencv::FloatImageToMat(rfdata.warped_, r_patch_track);
  cv::resize(r_patch_ref, r_patch_ref, cv::Size(), scale_sz, scale_sz, cv::INTER_NEAREST);
  cv::resize(r_patch_track, r_patch_track, cv::Size(), scale_sz, scale_sz, cv::INTER_NEAREST);
  cv::resize(orig_desc, t_patch_track, cv::Size(), scale_sz, scale_sz, cv::INTER_NEAREST);
  cv::imshow("refiner_ref", r_patch_ref);
  cv::imshow("refiner_track", r_patch_track);
  cv::imshow("orig_track", t_patch_track);
  cv::waitKey(0);
}

}

void DebugHelper::DebugStereoRefiner(const cv::Mat& img_lp, const cv::Mat& img_rp, const cv::Mat& img_lc,
    const cv::Mat& img_rc, StereoTrackerRefiner& refiner, const cv::Mat& cvRt, const double* cam_params)
{
  Eigen::Matrix4d Rt;
  cv::cv2eigen(cvRt, Rt);

  cv::Mat draw_lp, draw_lc, draw_rp, draw_rc;
  double error_3d, left_error, right_error, ref_left_error, ref_right_error;
  //double reproj_error_thr = 1.0;
  std::cout << "GT motion:\n" << Rt << "\n";
  StereoTrackerBase& tracker = *refiner.tracker_;
  double scale_sz = 13.0;
  cv::Mat orig_patch_ref;
  int bad_left_refinemets = 0;
  int bad_right_refinemets = 0;
  for(int i = 0; i < refiner.countFeatures(); i++) {
    track::FeatureInfo feat_left = tracker.featureLeft(i);
    track::FeatureInfo feat_right = tracker.featureRight(i);
    if(feat_left.age_ < 1) continue;

    track::FeatureData left_data = tracker.getLeftFeatureData(i);
    track::FeatureData right_data = tracker.getRightFeatureData(i);
    EvalHelper::GetStereoReprojErrors(feat_left.prev_, feat_right.prev_, feat_left.curr_, feat_right.curr_,
                                      Rt, cam_params, error_3d, left_error, right_error);
    //if(left_error < reproj_error_thr && right_error < reproj_error_thr) continue;
    EvalHelper::GetStereoReprojErrors(refiner.fdata_lp_[i].pt(), refiner.fdata_rp_[i].pt(),
        refiner.fdata_lc_[i].pt(), refiner.fdata_rc_[i].pt(), Rt, cam_params, error_3d,
        ref_left_error, ref_right_error);

    if(left_error > ref_left_error && right_error > ref_right_error)
      continue;
    if(left_error < ref_left_error)
      bad_left_refinemets++;
    if(right_error < ref_right_error)
      bad_right_refinemets++;

    // dont draw
    continue;

    printf("\nPoint idx = %d\n", i);
    //std::cout << "[Tracker] Curr 3D euclid error = " << error_3d << "\n";
    std::cout << "[Tracker] Curr 2D reproj error left = " << left_error << "\n";
    std::cout << "[Tracker] Curr 2D reproj error right = " << right_error << "\n";
    //std::cout << "[Refiner] Curr 3D euclid error = " << ref_error_3d << "\n";
    std::cout << "[Refiner] Curr 2D reproj error left = " << ref_left_error << "\n";
    std::cout << "[Refiner] Curr 2D reproj error right = " << ref_right_error << "\n";

    cv::cvtColor(img_lp, draw_lp, cv::COLOR_GRAY2RGB);
    cv::cvtColor(img_lc, draw_lc, cv::COLOR_GRAY2RGB);
    cv::cvtColor(img_rp, draw_rp, cv::COLOR_GRAY2RGB);
    cv::cvtColor(img_rc, draw_rc, cv::COLOR_GRAY2RGB);
    cv::Scalar color(0,0,255);
    drawPoint(feat_left.prev_, color, draw_lp);
    drawPoint(feat_left.curr_, color, draw_lc);
    drawPoint(feat_right.prev_, color, draw_rp);
    drawPoint(feat_right.curr_, color, draw_rc);
    //cv::resize(img_lp, img_lp, cv::Size(), ssz, ssz);
    //cv::resize(img_rp, img_rp, cv::Size(), ssz, ssz);
    //cv::resize(img_lc, img_lc, cv::Size(), ssz, ssz);
    //cv::resize(img_rc, img_rc, cv::Size(), ssz, ssz);
    cv::imshow("left_prev", draw_lp);
    cv::imshow("left_curr", draw_lc);
    cv::imshow("right_prev", draw_rp);
    cv::imshow("right_curr", draw_rc);

    cv::resize(left_data.desc_prev_, orig_patch_ref, cv::Size(), scale_sz, scale_sz, cv::INTER_NEAREST);
    cv::imshow("orig_ref", orig_patch_ref);
    // we skip the left previous points - no need to look them
    printf("Right prev:\n");
    analyze_track(feat_right.prev_, right_data.desc_prev_, refiner.fdata_rp_[i], scale_sz, 1.0);
    printf("Left curr:\n");
    analyze_track(feat_left.curr_, left_data.desc_curr_, refiner.fdata_lc_[i], scale_sz, 1.0);
    printf("Right curr:\n");
    analyze_track(feat_right.curr_, right_data.desc_curr_, refiner.fdata_rc_[i], scale_sz, 1.0);
    //analyze_track(feat_left.curr_, points_lc_[i], fdata_lc_[i]);
    //refiner::FeatureData r_data = refiner_->getFeature(i);
    //if(std::get<1>(fdata_rp[i]) > std::get<0>(fdata_rp[i])
    //   || std::get<1>(fdata_lc_[i]) > std::get<0>(fdata_lc_[i])
    //   || std::get<1>(fdata_rc_[i]) > std::get<0>(fdata_rc_[i]))
  }
  int num_active = refiner.countActiveTracks();
  printf("[Left]: num of bad refinements = %d / %d = %.2f%%\n", bad_left_refinemets, num_active,
      ((double)bad_left_refinemets / num_active) * 100.0);
  printf("[Right]: num of bad refinements = %d / %d = %.2f%%\n", bad_right_refinemets, num_active,
      ((double)bad_right_refinemets / num_active) * 100.0);
}

void DebugHelper::renderPatch(const FeaturePatch& patch, cv::Mat& img)
{
  cv::Size imgsz = cv::Size(200, 200);
  img = patch.mat_.clone();
  img = img.reshape(0, 11);
  cv::resize(img, img, imgsz, 0, 0, cv::INTER_NEAREST);
}

void DebugHelper::drawFeatures(const std::vector<core::Point>& feats, const cv::Scalar& color, cv::Mat& img)
{
  cv::Point2f pt;
  for(size_t i = 0; i < feats.size(); i++) {
    pt.x = feats[i].x_;
    pt.y = feats[i].y_;
    cv::circle(img, pt, 2, color, -1, 8);
  }
}

void DebugHelper::drawPoint(const core::Point& pt, const cv::Scalar& color, cv::Mat& img) {
  cv::Point2f cvpt;
  cvpt.x = pt.x_;
  cvpt.y = pt.y_;
  cv::circle(img, cvpt, 2, color, -1, 8);
}

}


#ifndef _VINECOPULACPP_HEADER_HPP_
#define _VINECOPULACPP_HEADER_HPP_

// headers
#include <iostream>
#include <string>
#define _USE_MATH_DEFINES
#include <cmath>
#include <vector>
#include <nlopt.hpp>
#include <algorithm>
#include <utility>
#include <omp.h>

#include <stdlib.h>
#include <stdio.h>

#include<fstream>
#include<time.h>

// headers from the boost library
#include <boost/math/distributions/normal.hpp>
#include <boost/math/distributions/students_t.hpp>
//#include <boost/math/special_functions/detail/t_distribution_inv.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/random.hpp>

// gsl library
//#include <stdio.h>
//#include <gsl/gsl_cdf.h>

#ifndef DBL_MAX
#define DBL_MAX 1.79769e+308
#endif

// User written headers
#include "VineCopulaCPP_helper.hpp"
#include "VineCopulaCPP_PC.hpp"
#include "VineCopulaCPP_PathToBoundsAndSeed.hpp"

#endif