text:
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE rhea
#include <boost/test/unit_test.hpp>

#include <random>
#include <boost/range/algorithm.hpp>

#include "../rhea/simplex_solver.hpp"
#include "../rhea/linear_equation.hpp"
#include "../rhea/iostream.hpp"
#include "../rhea/errors_expl.hpp"
#include "../rhea/link_variable.hpp"

using namespace rhea;

struct point
{
    variable x, y;

    point(double a = 0, double b = 0)
        : x(a)
        , y(b)
    {
    }

    bool operator==(const std::pair<int, int>& p) const
    {
        return x.value() == p.first && y.value() == p.second;
    }
};

namespace std
{
template <typename a, typename b>
std::ostream& operator<<(std::ostream& s, const std::pair<a, b>& p)
{
    return s << p.first << "," << p.second;
}

inline std::ostream& operator<<(std::ostream& s, const point& p)
{
    return s << p.x << " " << p.y;
}
}

BOOST_AUTO_TEST_CASE(strength_test)
{
    BOOST_CHECK(strength::required().is_required());
    BOOST_CHECK(!strength::strong().is_required());
    BOOST_CHECK(!strength::medium().is_required());
    BOOST_CHECK(!strength::weak().is_required());

    BOOST_CHECK(strength::required() > strength::strong());
    BOOST_CHECK(strength::strong() > strength::medium());
    BOOST_CHECK(strength::medium() > strength::weak());

    double z = 10000000.0;
    BOOST_CHECK(strength(0, 0, z) < strength(0, 1, 0));
    BOOST_CHECK(strength(0, z, z) < strength(1, 0, 0));
}

BOOST_AUTO_TEST_CASE(variable_test)
{
    variable a;
    variable m(variable::nil_var()), n(variable::nil_var());
    variable x(3.0);
    variable y(x);
    variable z(3.0);

    BOOST_CHECK(n.is_nil());
    n = x;
    a = y;
    BOOST_CHECK(m.is_nil());
    BOOST_CHECK(!n.is_nil());
    BOOST_CHECK(!x.is_nil());
    BOOST_CHECK(!y.is_nil());
    BOOST_CHECK(!x.is_fd());
    BOOST_CHECK(!x.is_dummy());
    BOOST_CHECK(x.is_float());
    BOOST_CHECK(x.is_external());

    BOOST_CHECK_EQUAL(x.value(), 3);
    BOOST_CHECK_EQUAL(x.int_value(), 3);
    BOOST_CHECK_EQUAL(y.value(), 3);
    BOOST_CHECK_EQUAL(a.value(), 3);

    std::hash<variable> h;
    BOOST_CHECK_EQUAL(h(x), h(y));
    BOOST_CHECK(x.is(y));
    BOOST_CHECK(h(x) != h(z));
    BOOST_CHECK(!x.is(z));
    BOOST_CHECK(a.is(x));

    y.set_value(3.7);
    BOOST_CHECK_EQUAL(n.value(), 3.7);
    BOOST_CHECK_EQUAL(x.value(), 3.7);
    BOOST_CHECK_EQUAL(x.int_value(), 4);

    y.set_value(-3.7);
    BOOST_CHECK_EQUAL(x.int_value(), -4);

    variable_set s;
    s.insert(x);
    BOOST_CHECK(s.count(x) > 0);
    BOOST_CHECK(s.count(y) > 0);

    s.erase(y);
    BOOST_CHECK(s.empty());

    BOOST_CHECK(!objective_variable().is_float());
    BOOST_CHECK(!objective_variable().is_fd());
    BOOST_CHECK(!objective_variable().is_external());
    BOOST_CHECK_EQUAL(objective_variable().value(), 0.0);
    BOOST_CHECK_EQUAL(objective_variable().int_value(), 0);
    BOOST_CHECK_EQUAL(objective_variable().to_string(), "objective");
}

BOOST_AUTO_TEST_CASE(variable_stream_test)
{
    std::stringstream s;
    s << variable{3};
    BOOST_CHECK_EQUAL("{var10:3}", s.str());
}

BOOST_AUTO_TEST_CASE(constraint_stream_test)
{
    std::stringstream s;
    s << constraint{ variable{1} + 42 == variable{2} };
    BOOST_CHECK(   s.str() == "linear [required, 1] {var11:2}*-1 + {var12:1}*1 + 42 == 0"
                || s.str() == "linear [required, 1] {var11:1}*1 + {var12:2}*-1 + 42 == 0");
}

BOOST_AUTO_TEST_CASE(strength_stream_test)
{
    std::stringstream s;
    s << strength::required();
    BOOST_CHECK_EQUAL(s.str(), "required");
}

BOOST_AUTO_TEST_CASE(linearexpr1_test)
{
    linear_expression expr1(5);
    BOOST_CHECK_EQUAL(expr1.evaluate(), 5);
    expr1 *= -1;
    BOOST_CHECK_EQUAL(expr1.evaluate(), -5);

    variable x(3.0), y(2.0);
    linear_expression expr2(x, 2.0, 1.0);
    BOOST_CHECK_EQUAL(expr2.evaluate(), 7);
    BOOST_CHECK_EQUAL((expr2 + 2.0).evaluate(), 9);
    BOOST_CHECK_EQUAL((expr2 - 1.0).evaluate(), 6);

    expr2 += x;
    BOOST_CHECK_EQUAL(expr2.evaluate(), 10);
    expr2 -= x;
    BOOST_CHECK_EQUAL(expr2.evaluate(), 7);

    expr2 += linear_expression::term(y, 5);
    BOOST_CHECK_EQUAL(expr2.evaluate(), 17);

    y.set_value(1);
    BOOST_CHECK_EQUAL(expr2.evaluate(), 12);
    x.set_value(10);
    BOOST_CHECK_EQUAL(expr2.evaluate(), 26);

    expr2 *= -1;
    BOOST_CHECK_EQUAL(expr2.evaluate(), -26);
}

BOOST_AUTO_TEST_CASE(linearexpr2_test)
{
    variable x(3);
    linear_expression test1(x, 5, 2);
    linear_expression test2(test1);

    BOOST_CHECK_EQUAL(test1.evaluate(), 17);
    BOOST_CHECK_EQUAL(test1.evaluate(), 17);

    linear_expression test3(std::move(test1));
    BOOST_CHECK_EQUAL(test3.evaluate(), 17);
}

BOOST_AUTO_TEST_CASE(linearexpr3_test)
{
    variable x(5), y(2);

    linear_expression expr(x * 2 + y - 1);
    BOOST_CHECK_EQUAL(expr.evaluate(), 11);

    x.set_value(4);
    BOOST_CHECK_EQUAL(expr.evaluate(), 9);

    BOOST_CHECK_EQUAL((x + 3).evaluate(), 7);
    BOOST_CHECK_EQUAL((x - 2).evaluate(), 2);
    BOOST_CHECK_EQUAL((x + y).evaluate(), 6);
    BOOST_CHECK_EQUAL((x - y).evaluate(), 2);
}

BOOST_AUTO_TEST_CASE(linear_equation1_test)
{
    variable x(2.0);
    linear_expression expr(x, 4.0, 1.0);
    variable answer(9.0);

    linear_equation eq1(expr, answer);
    BOOST_CHECK(eq1.is_satisfied());

    linear_expression expr2(x, 3.0, 3.0);
    linear_equation eq2(expr, expr2);
    BOOST_CHECK(eq2.is_satisfied());

    linear_equation eq3(expr, variable(42.0));
    BOOST_CHECK(!eq3.is_satisfied());
}

BOOST_AUTO_TEST_CASE(linear_equation2_test)
{
    variable x(2.0), y(3.0);

    BOOST_CHECK((x == y - 1).is_satisfied());
    BOOST_CHECK(!(x == y).is_satisfied());
    BOOST_CHECK((x * 2 == y + 1).is_satisfied());
    BOOST_CHECK(!(x * 3 == y * 4).is_satisfied());
}

BOOST_AUTO_TEST_CASE(linear_inequality1_test)
{
    variable x(2.0);
    linear_expression expr(x, 4.0, 1.0);
    variable answer(5.0);

    linear_inequality eq1(answer, relation::leq, expr);
    BOOST_CHECK(eq1.is_satisfied());
    x.set_value(0);
    BOOST_CHECK(!eq1.is_satisfied());
}

BOOST_AUTO_TEST_CASE(linear_inequality2_test)
{
    variable x(2.0), y(3.0);
    BOOST_CHECK((x <= y).is_satisfied());
    BOOST_CHECK((x + 1 <= y).is_satisfied());
    BOOST_CHECK((x * 2 + y >= 4).is_satisfied());
    BOOST_CHECK((x * 3 >= y * 2).is_satisfied());
    BOOST_CHECK(!(x >= y).is_satisfied());
}

BOOST_AUTO_TEST_CASE(constraint_map_test)
{
    variable x;
    constraint c1{x == 1};
    std::unordered_map<constraint, int> map;
    map[c1] = 5;

    constraint c2 = c1;
    BOOST_CHECK(c1 == c2);

    std::hash<constraint> hasher;
    BOOST_CHECK(hasher(c1) == hasher(c2));
    BOOST_CHECK(map.count(c1) == 1);
    BOOST_CHECK(map.count(c2) == 1);
}

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

BOOST_AUTO_TEST_CASE(simple1_test)
{
    variable x(167);
    variable y(2);

    simplex_solver solver;

    constraint c(std::make_shared<linear_equation>(x, linear_expression(y)));
    solver.add_stay(x);
    solver.add_stay(y);
    solver.add_constraint(c);

    BOOST_CHECK(solver.is_valid());
    BOOST_CHECK_EQUAL(x.value(), y.value());

    BOOST_CHECK(!edit_constraint(x).is_satisfied());
    BOOST_CHECK(!stay_constraint(x).is_satisfied());
}

BOOST_AUTO_TEST_CASE(simple2_test)
{
    variable x(167);

    simplex_solver solver;

    BOOST_CHECK_THROW((solver.begin_edit(),
                       solver.suggest_value(x, 100), solver.end_edit()),
                      edit_misuse);

    BOOST_CHECK_EQUAL(std::string(edit_misuse().what()),
                      "edit protocol usage violation");
}

BOOST_AUTO_TEST_CASE(constraint1_test)
{
    variable x(0);
    simplex_solver solver;
    solver.add_constraint(
        std::make_shared<linear_equation>(x, 10, strength::weak()));
    BOOST_CHECK_EQUAL(x.value(), 10.0);
}

BOOST_AUTO_TEST_CASE(juststay1_test)
{
    variable x(5), y(10);
    simplex_solver solver;

    solver.add_stay(x).add_stay(y);

    BOOST_CHECK_EQUAL(x.value(), 5);
    BOOST_CHECK_EQUAL(y.value(), 10);

    solver.suggest({{x, 6}, {y, 7}});

    BOOST_CHECK_EQUAL(x.value(), 6);
    BOOST_CHECK_EQUAL(y.value(), 7);
}

BOOST_AUTO_TEST_CASE(juststaylink1_test)
{
    float ox = 5.0f, oy = 10.0f;
    variable x(ox, linked()), y(oy, linked());
    simplex_solver solver;

    BOOST_CHECK_EQUAL(x.value(), 5);

    solver.add_stay(x).add_stay(y);

    BOOST_CHECK_EQUAL(ox, 5);
    BOOST_CHECK_EQUAL(oy, 10);

    solver.suggest({{x, 6}, {y, 7}});

    BOOST_CHECK_EQUAL(x.value(), 6);
    BOOST_CHECK_EQUAL(ox, 6);
    BOOST_CHECK_EQUAL(oy, 7);
}

BOOST_AUTO_TEST_CASE(juststaylink2_test)
{
    int ox = 5, oy = 10;
    variable x(ox, linked()), y(oy, linked());
    simplex_solver solver;

    solver.add_stay(x).add_stay(y);

    BOOST_CHECK_EQUAL(ox, 5);
    BOOST_CHECK_EQUAL(oy, 10);

    solver.suggest({{x, 6.2}, {y, 7.4}});

    BOOST_CHECK_EQUAL(ox, 6);
    BOOST_CHECK_EQUAL(oy, 7);
}

BOOST_AUTO_TEST_CASE(juststaylink3_test)
{
    double ox = 5, oy = 10;
    variable x([&](double v) { ox = v; }, 5.0);
    variable y([&](double v) { oy = v; }, 10.0);
    simplex_solver solver;

    solver.add_stay(x).add_stay(y);

    BOOST_CHECK_EQUAL(ox, 5);
    BOOST_CHECK_EQUAL(oy, 10);

    solver.suggest({{x, 6}, {y, 7}});

    BOOST_CHECK_EQUAL(ox, 6);
    BOOST_CHECK_EQUAL(oy, 7);
}

BOOST_AUTO_TEST_CASE(editleak1_test)
{
    variable x(0);
    simplex_solver solver;
    solver.add_stay(x);

    BOOST_CHECK_EQUAL(solver.columns().size(), 2);
    BOOST_CHECK_EQUAL(solver.rows().size(), 2);

    solver.add_edit_var(x);
    solver.begin_edit();
    solver.suggest_value(x, 2);

    BOOST_CHECK_EQUAL(solver.columns().size(), 3);
    BOOST_CHECK_EQUAL(solver.rows().size(), 3);

    solver.end_edit();

    BOOST_CHECK_EQUAL(x.value(), 2.0);
    BOOST_CHECK_EQUAL(solver.columns().size(), 2);
    BOOST_CHECK_EQUAL(solver.rows().size(), 2);
}

BOOST_AUTO_TEST_CASE(editleak2_test)
{
    variable x(0), y(0);
    simplex_solver solver;
    solver.add_stay(x).add_stay(y);

    BOOST_CHECK_EQUAL(solver.columns().size(), 4);
    BOOST_CHECK_EQUAL(solver.rows().size(), 3);

    solver.add_edit_var(x).add_edit_var(y);

    solver.begin_edit();
    solver.suggest_value(x, 2);
    solver.suggest_value(y, 4);

    BOOST_CHECK_EQUAL(solver.columns().size(), 6);
    BOOST_CHECK_EQUAL(solver.rows().size(), 5);

    solver.end_edit();

    BOOST_CHECK_EQUAL(x.value(), 2.0);
    BOOST_CHECK_EQUAL(y.value(), 4.0);
    BOOST_CHECK_EQUAL(solver.columns().size(), 4);
    BOOST_CHECK_EQUAL(solver.rows().size(), 3);
}

BOOST_AUTO_TEST_CASE(delete1_test)
{
    variable x(0);
    simplex_solver solver;

    constraint init(x == 100, strength::weak());
    solver.add_constraint(init);
    BOOST_CHECK_EQUAL(x.value(), 100);

    constraint c10(x <= 10), c20(x <= 20);

    solver.add_constraint(c10).add_constraint(c20);

    BOOST_CHECK_EQUAL(x.value(), 10.0);
    solver.remove_constraint(c10);
    BOOST_CHECK_EQUAL(x.value(), 20.0);
    solver.remove_constraint(c20);
    BOOST_CHECK_EQUAL(x.value(), 100.0);

    solver.add_constraint(c10);
    BOOST_CHECK_EQUAL(x.value(), 10.0);
    solver.remove_constraint(c10);
    BOOST_CHECK_EQUAL(x.value(), 100.0);

    solver.remove_constraint(init);

    BOOST_CHECK_EQUAL(solver.columns().size(), 0);
    BOOST_CHECK_EQUAL(solver.rows().size(), 1);
}

BOOST_AUTO_TEST_CASE(delete2_test)
{
    variable x(0), y(0);
    simplex_solver solver;

    solver.add_constraint(x == 100, strength::weak())
        .add_constraint(y == 120, strength::strong());

    BOOST_CHECK_EQUAL(x.value(), 100);
    BOOST_CHECK_EQUAL(y.value(), 120);

    constraint c10(x <= 10), c20(x <= 20);

    solver.add_constraint(c10).add_constraint(c20);

    BOOST_CHECK_EQUAL(x.value(), 10);
    solver.remove_constraint(c10);
    BOOST_CHECK_EQUAL(x.value(), 20);

    constraint cxy(x * 2 == y);
    solver.add_constraint(cxy);

    BOOST_CHECK_EQUAL(x.value(), 20);
    BOOST_CHECK_EQUAL(y.value(), 40);

    solver.remove_constraint(c20);
    BOOST_CHECK_EQUAL(x.value(), 60);
    BOOST_CHECK_EQUAL(y.value(), 120);

    solver.remove_constraint(cxy);
    BOOST_CHECK_EQUAL(x.value(), 100);
    BOOST_CHECK_EQUAL(y.value(), 120);
}

BOOST_AUTO_TEST_CASE(delete3_test)
{
    variable x(0);
    simplex_solver solver;

    solver.add_constraint(x == 100, strength::weak());
    ;

    BOOST_CHECK_EQUAL(x.value(), 100);

    constraint c10(x <= 10), c10b(x <= 10);

    solver.add_constraint(c10).add_constraint(c10b);

    BOOST_CHECK_EQUAL(x.value(), 10);
    solver.remove_constraint(c10);
    BOOST_CHECK_EQUAL(x.value(), 10);
    solver.remove_constraint(c10b);
    BOOST_CHECK_EQUAL(x.value(), 100);
}

BOOST_AUTO_TEST_CASE(casso1_test)
{
    variable x(0), y(0);
    simplex_solver solver;

    solver.add_constraint(x <= y)
        .add_constraint(y == x + 3)
        .add_constraint(x == 10.0, strength::weak())
        .add_constraint(y == 10.0, strength::weak());

    BOOST_CHECK((x.value() == 10 && y.value() == 13)
                || (x.value() == 7 && y.value() == 10));
}

BOOST_AUTO_TEST_CASE(casso2_test)
{
    variable x(0), y(0);
    simplex_solver solver;

    solver.add_constraints({x <= y, y == x + 3, x == 10});
    BOOST_CHECK_EQUAL(x.value(), 10);
    BOOST_CHECK_EQUAL(y.value(), 13);
}

BOOST_AUTO_TEST_CASE(inconsistent1_test)
{
    variable x(0);
    simplex_solver solver;

    solver.add_constraint(x == 10);

    BOOST_CHECK_THROW(solver.add_constraint(x == 5), required_failure);
}

BOOST_AUTO_TEST_CASE(inconsistent2_test)
{
    variable x(0);
    simplex_solver solver;

    BOOST_CHECK_THROW(solver.add_constraints({x >= 10, x <= 5}),
                      required_failure);
}

BOOST_AUTO_TEST_CASE(inconsistent3_test)
{
    variable v(0), w(0), x(0), y(0);
    simplex_solver solver;

    solver.add_constraints({v >= 10, w >= v, x >= w, y >= x});
    BOOST_CHECK_THROW(solver.add_constraint(y <= 5), required_failure);
}

BOOST_AUTO_TEST_CASE(inconsistent4_test)
{
    variable v(0), w(0), x(0), y(0);
    simplex_solver solver;

    solver.set_explaining(true);
    solver.add_constraints({v >= 10, w >= v, x >= w, y >= x});

    try {
        solver.add_constraint(y <= 5);
    } catch (required_failure_with_explanation& e) {
        BOOST_CHECK_EQUAL(e.explanation().size(), 5);
    } catch (...) {
        BOOST_CHECK(false);
    }
}

BOOST_AUTO_TEST_CASE(multiedit1_test)
{
    variable x(3), y(-5), w(0), h(0);
    simplex_solver solver;

    solver.add_stay(x).add_stay(y).add_stay(w).add_stay(h);
    solver.add_edit_var(x).add_edit_var(y);
    {
        scoped_edit outer_edit(solver);

        solver.suggest_value(x, 10).suggest_value(y, 20);
        solver.resolve();

        BOOST_CHECK_EQUAL(x.value(), 10);
        BOOST_CHECK_EQUAL(y.value(), 20);
        BOOST_CHECK_EQUAL(w.value(), 0);
        BOOST_CHECK_EQUAL(h.value(), 0);

        solver.add_edit_var(w).add_edit_var(h);
        {
            scoped_edit inner_edit(solver);
            solver.suggest_value(w, 30).suggest_value(h, 40);
        }

        BOOST_CHECK_EQUAL(x.value(), 10);
        BOOST_CHECK_EQUAL(y.value(), 20);
        BOOST_CHECK_EQUAL(w.value(), 30);
        BOOST_CHECK_EQUAL(h.value(), 40);

        solver.suggest_value(x, 50).suggest_value(y, 60);
    }

    BOOST_CHECK_EQUAL(x.value(), 50);
    BOOST_CHECK_EQUAL(y.value(), 60);
    BOOST_CHECK_EQUAL(w.value(), 30);
    BOOST_CHECK_EQUAL(h.value(), 40);
}

BOOST_AUTO_TEST_CASE(multiedit2_test)
{
    variable x(3), y(0), w(0), h(0);
    simplex_solver solver;

    solver.add_stay(x).add_stay(y).add_stay(w).add_stay(h);
    solver.add_edit_var(x).add_edit_var(y);
    {
        scoped_edit outer_edit(solver);

        solver.suggest_value(x, 10).suggest_value(y, 20);
        solver.resolve();

        BOOST_CHECK_EQUAL(x.value(), 10);
        BOOST_CHECK_EQUAL(y.value(), 20);
        BOOST_CHECK_EQUAL(w.value(), 0);
        BOOST_CHECK_EQUAL(h.value(), 0);

        solver.add_edit_var(x).add_edit_var(y).add_edit_var(w).add_edit_var(h);

        {
            scoped_edit inner_edit(solver);
            solver.suggest_value(w, 30).suggest_value(h, 40);
        }

        BOOST_CHECK_EQUAL(x.value(), 10);
        BOOST_CHECK_EQUAL(y.value(), 20);
        BOOST_CHECK_EQUAL(w.value(), 30);
        BOOST_CHECK_EQUAL(h.value(), 40);

        solver.suggest_value(x, 50).suggest_value(y, 60);
    }

    BOOST_CHECK_EQUAL(x.value(), 50);
    BOOST_CHECK_EQUAL(y.value(), 60);
    BOOST_CHECK_EQUAL(w.value(), 30);
    BOOST_CHECK_EQUAL(h.value(), 40);
}

BOOST_AUTO_TEST_CASE(a_variable_can_be_made_editable_multiple_times_stack_like_test)
{
    variable x;
    simplex_solver solver;

    solver.add_stay(x);
    solver.add_edit_var(x);
    {
        solver.add_edit_var(x);
        solver.suggest_value(x, 10);
        solver.resolve();
        solver.remove_edit_var(x);
    }
    BOOST_CHECK_EQUAL(x.value(), 10);

    solver.suggest_value(x, 20);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 20);

    {
        solver.add_edit_var(x);
        solver.suggest_value(x, 30);
        solver.resolve();
        solver.remove_edit_var(x);
    }
    BOOST_CHECK_EQUAL(x.value(), 30);
}

BOOST_AUTO_TEST_CASE(manually_adding_multiple_edit_constraints_for_same_variable_test)
{
    variable x;
    simplex_solver solver;

    constraint e1 = std::make_shared<edit_constraint>(x);
    constraint e2 = std::make_shared<edit_constraint>(x);

    solver.add_stay(x);

    solver.add_constraint(e1);
    solver.suggest_value(x, 1);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 1);

    solver.add_constraint(e2);
    solver.suggest_value(x, 2);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 2);

    solver.remove_constraint(e1);
    solver.suggest_value(x, 3);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 3);

    solver.remove_constraint(e2);
    solver.add_constraint(e1);
    solver.add_constraint(e2);
    solver.suggest_value(x, 5);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 5);

    solver.remove_constraint(e2);
    solver.suggest_value(x, 6);
    solver.resolve();
    BOOST_CHECK_EQUAL(x.value(), 6);

    solver.remove_constraint(e1);
    BOOST_CHECK(solver.is_valid());
}

BOOST_AUTO_TEST_CASE(bounds_test)
{
    variable x(1);
    simplex_solver solver;

    solver.add_stay(x).add_bounds(x, 0, 10);

    BOOST_CHECK_EQUAL(x.value(), 1);
    solver.add_edit_var(x);
    solver.begin_edit().suggest_value(x, 20).end_edit();
    BOOST_CHECK_EQUAL(x.value(), 10);
}

BOOST_AUTO_TEST_CASE(bug0_test)
{
    variable x(7), y(8), z(9);
    simplex_solver solver;

    solver.add_stay(x).add_stay(y).add_stay(z);

    solver.add_edit_var(x).add_edit_var(y).add_edit_var(z);
    solver.begin_edit();

    solver.suggest_value(x, 1);
    solver.suggest_value(z, 2);

    solver.remove_edit_var(y);

    solver.suggest_value(x, 3);
    solver.suggest_value(z, 4);

    solver.end_edit();
}

BOOST_AUTO_TEST_CASE(quad_test)
{
    std::vector<point> c{{50, 50}, {50, 250}, {250, 250}, {250, 50}};
    std::vector<point> m(4);
    simplex_solver solver;

    double factor(1);
    for (point& corner : c) {
        solver.add_stay(corner.x, strength::weak(), factor);
        solver.add_stay(corner.y, strength::weak(), factor);
        factor *= 2;
    }

    // Midpoint constraints
    for (int i(0); i < 4; ++i) {
        int j((i + 1) % 4);
        solver.add_constraint(m[i].x == (c[i].x + c[j].x) / 2)
            .add_constraint(m[i].y == (c[i].y + c[j].y) / 2);
    }

    // Don't turn inside out
    typedef std::vector<std::pair<int, int>> pairs;
    for (auto a : pairs{{0, 2}, {0, 3}, {1, 2}, {1, 3}})
        solver.add_constraint(c[a.first].x + 1 <= c[a.second].x);

    for (auto a : pairs{{0, 1}, {0, 2}, {3, 1}, {3, 2}})
        solver.add_constraint(c[a.first].y + 1 <= c[a.second].y);

    // Limits
    for (auto& corner : c) {
        solver.add_bounds(corner.x, 0, 300);
        solver.add_bounds(corner.y, 0, 300);
    }

    // Now for the actual tests
    BOOST_CHECK_EQUAL(c[0], std::make_pair(50, 50));
    BOOST_CHECK_EQUAL(m[0], std::make_pair(50, 150));
    BOOST_CHECK_EQUAL(c[1], std::make_pair(50, 250));
    BOOST_CHECK_EQUAL(m[1], std::make_pair(150, 250));
    BOOST_CHECK_EQUAL(c[2], std::make_pair(250, 250));
    BOOST_CHECK_EQUAL(m[2], std::make_pair(250, 150));

    // Move one of the corners
    solver.suggest({{c[0].x, 100}});

    BOOST_CHECK_EQUAL(c[0], std::make_pair(100, 50));
    BOOST_CHECK_EQUAL(m[0], std::make_pair(75, 150));
    BOOST_CHECK_EQUAL(c[1], std::make_pair(50, 250));
    BOOST_CHECK_EQUAL(m[1], std::make_pair(150, 250));
    BOOST_CHECK_EQUAL(c[3], std::make_pair(250, 50));
    BOOST_CHECK_EQUAL(m[3], std::make_pair(175, 50));

    // Move one of the midpoints
    solver.suggest({{m[0].x, 50}, {m[0].y, 150}});

    BOOST_CHECK_EQUAL(m[0], std::make_pair(50, 150));
    BOOST_CHECK_EQUAL(c[0], std::make_pair(50, 50));
    BOOST_CHECK_EQUAL(m[0], std::make_pair(50, 150));
    BOOST_CHECK_EQUAL(m[3], std::make_pair(150, 50));
}

BOOST_AUTO_TEST_CASE(required_strength) // issue 18
{
    variable v(0);
    simplex_solver solver;

    solver.add_stay(v, strength::strong());

    BOOST_CHECK_EQUAL(v.value(), 0);

    solver.add_edit_var(v, strength::required());
    solver.begin_edit();
    solver.suggest_value(v, 2);
    solver.end_edit();

    BOOST_CHECK_EQUAL(v.value(), 2);
}

BOOST_AUTO_TEST_CASE(required_strength2)
{
    variable v(0);
    simplex_solver solver;

    solver.add_stay(v, strength::required());
    solver.resolve();

    BOOST_CHECK_EQUAL(v.value(), 0);

    solver.add_edit_var(v, strength::strong());
    solver.begin_edit();
    solver.suggest_value(v, 2);
    solver.end_edit();

    BOOST_CHECK_EQUAL(v.value(), 0);
}

BOOST_AUTO_TEST_CASE(bug_16)
{
    variable a(1), b(2);
    simplex_solver solver;

    solver.set_autosolve(false);
    solver.add_stay(a);
    BOOST_CHECK(solver.is_valid());

    solver.add_constraints({a == b});

    BOOST_CHECK(solver.is_valid());
    solver.add_edit_var(a);

    solver.begin_edit();
    solver.suggest_value(a, 3);
    solver.end_edit();

    BOOST_CHECK(solver.is_valid());

    BOOST_CHECK_EQUAL(a.value(), 3);
    BOOST_CHECK_EQUAL(b.value(), 3);
}

BOOST_AUTO_TEST_CASE(bug_16b)
{
    simplex_solver solver;
    variable a, b, c;

    solver.set_autosolve(false);

    solver.add_stays({a, c});

    solver.add_constraints({a == 10, b == c});

    solver.suggest({{c, 100}});

    BOOST_CHECK_EQUAL(a.value(), 10);
    BOOST_CHECK_EQUAL(b.value(), 100);
    BOOST_CHECK_EQUAL(c.value(), 100);

    solver.suggest({{c, 90}});

    BOOST_CHECK_EQUAL(a.value(), 10);
    BOOST_CHECK_EQUAL(b.value(), 90);
    BOOST_CHECK_EQUAL(c.value(), 90);
}

BOOST_AUTO_TEST_CASE(nonlinear) // issue 26
{
    variable x, y;
    simplex_solver solver;

    BOOST_CHECK_THROW(solver.add_constraint(x == 5 / y), nonlinear_expression);
    BOOST_CHECK_THROW(solver.add_constraint(x == y * y), nonlinear_expression);
}

BOOST_AUTO_TEST_CASE(change_strength_test) // issue 33
{
    variable x;
    simplex_solver solver;

    constraint c1{x == 1, strength::weak()};
    constraint c2{x == 2, strength::medium()};
    solver.add_constraints({c1, c2});
    BOOST_CHECK_EQUAL(x.value(), 2);

    solver.change_strength(c1, strength::strong());
    BOOST_CHECK_EQUAL(x.value(), 1);
}

BOOST_AUTO_TEST_CASE(change_weight_test) // issue 33
{
    variable x;
    simplex_solver solver;

    constraint c1{x == 1, strength::strong(), 1};
    constraint c2{x == 2, strength::strong(), 2};
    solver.add_constraints({c1, c2});
    BOOST_CHECK_EQUAL(x.value(), 2);

    solver.change_weight(c1, 3);
    BOOST_CHECK_EQUAL(x.value(), 1);
}

BOOST_AUTO_TEST_CASE(edit_unconstrained_variable)
{
    auto v = variable{ 0 };
    auto solver = simplex_solver{};

    solver.add_edit_var(v);
    BOOST_CHECK_EQUAL(v.value(), 0);
    BOOST_CHECK(solver.is_valid());

    solver.suggest_value(v, 2);
    solver.resolve();
    BOOST_CHECK_EQUAL(v.value(), 2);
    BOOST_CHECK(solver.is_valid());
}

BOOST_AUTO_TEST_CASE(add_constraints_after_marking_edit_variable)
{
    auto v = variable{ 0 };
    auto solver = simplex_solver{};

    solver.add_edit_var(v);
    solver.suggest_value(v, 2);
    solver.resolve();
    BOOST_CHECK_EQUAL(v.value(), 2);
    BOOST_CHECK(solver.is_valid());

    // Constraint overrides users desire
    auto fixed = constraint { v == 42 };
    solver.add_constraint(fixed);
    BOOST_CHECK_EQUAL(v.value(), 42);
    solver.suggest_value(v, 3);
    solver.resolve();
    BOOST_CHECK_EQUAL(v.value(), 42);
    BOOST_CHECK(solver.is_valid());

    // Goes back to last edited value
    solver.remove_constraint(fixed);
    BOOST_CHECK_EQUAL(v.value(), 3);
    BOOST_CHECK(solver.is_valid());
}

BOOST_AUTO_TEST_CASE(contains_constraint)
{
    auto c = constraint{ variable{} == 42 };
    auto solver = simplex_solver{};

    BOOST_CHECK(!solver.contains_constraint(c));

    solver.add_constraint(c);
    BOOST_CHECK(solver.contains_constraint(c));

    solver.remove_constraint(c);
    BOOST_CHECK(!solver.contains_constraint(c));
}

max_stars_repo_name: jbo-ableton/rhea

max_issues_repo_name: arximboldi/rhea

max_forks_repo_name: arximboldi/rhea


text:
// Copyright Louis Dionne 2013-2016
// 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/concept/constant.hpp>
#include <boost/hana/concept/integral_constant.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/fwd/core/to.hpp>
#include <boost/hana/value.hpp>
namespace hana = boost::hana;

// Define a simple model of IntegralConstant
struct constant_tag { using value_type = int; };
template <int i>
struct constant {
    static constexpr int value = i;
    using hana_tag = constant_tag;
};

namespace boost { namespace hana {
    template <>
    struct IntegralConstant<constant_tag> {
        static constexpr bool value = true;
    };

    template <typename From>
    struct to_impl<constant_tag, From, when<IntegralConstant<From>::value>> {
        template <typename N>
        static constexpr auto apply(N const&)
        { return constant<N::value>{}; }
    };
}}

// Make sure we really satisfy IntegralConstant<>.
static_assert(hana::IntegralConstant<constant<0>>::value, "");
static_assert(hana::IntegralConstant<constant<1>>::value, "");
static_assert(hana::IntegralConstant<constant<2>>::value, "");

// Make sure we're also a model of Constant automatically.
static_assert(hana::Constant<constant<0>>::value, "");
static_assert(hana::Constant<constant<1>>::value, "");
static_assert(hana::Constant<constant<2>>::value, "");

// Make sure we have the hana::value<> function defined automatically.
static_assert(hana::value<constant<0>>() == 0, "");
static_assert(hana::value<constant<1>>() == 1, "");
static_assert(hana::value<constant<2>>() == 2, "");
static_assert(hana::value<constant<3>>() == 3, "");

int main() { }

ext: cpp

max_stars_repo_name: nxplatform/nx-mobile

max_issues_repo_name: nxplatform/nx-mobile

max_forks_repo_name: nxplatform/nx-mobile


text:
#include "Log.h"

#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#include <chrono>

#include <boost/shared_ptr.hpp>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/syslog_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/detail/process_id.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/detail/thread_id.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/expressions/formatters/stream.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/format.hpp>

using boost::shared_ptr;

using namespace std;

void LogInit(bool consoleLogEnabled, bool fileLogEnabled)
{
  boost::log::add_console_log(
    std::cout,
    boost::log::keywords::format = (
      boost::log::expressions::stream
      << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f")
      << " "
      << boost::log::trivial::severity
      << " "
      << boost::log::expressions::message
      )
    );

  boost::log::add_file_log
    (
      boost::log::keywords::file_name = "world_%5N.log",
      boost::log::keywords::rotation_size = 10 * 1024 * 1024,
      boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
      boost::log::keywords::format = (
        boost::log::expressions::stream
        << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S.%f")
        << " "
        << boost::log::trivial::severity
        << " "
        << boost::log::expressions::message
        )
      );

  boost::log::core::get()->set_filter
    (
      boost::log::trivial::severity >= boost::log::trivial::trace
    );

  boost::log::add_common_attributes();
}

max_stars_repo_name: ishellstrike/MinecraftLike

max_issues_repo_name: ishellstrike/MinecraftLike

max_forks_repo_name: ishellstrike/MinecraftLike


text:
/* Copyright (c) 2018-2019 the `graphkernels` developers
 * All rights reserved.
 */

#include "rest.h"

#include <Eigen/Sparse>
#include <unsupported/Eigen/MatrixFunctions>

#include <algorithm>
#include <utility>

using std::vector;
using std::pair;

using Eigen::MatrixXd;
using Eigen::MatrixXi;
using Eigen::SparseMatrix;
using Eigen::VectorXd;

auto order_by_labels(const vector<int>& labels) {
    vector<pair<int, int>> map;
    map.reserve(labels.size());

    auto idx = 0;
    for (const auto label : labels) {
        map.emplace_back(label, idx++);
    }

    sort(map.begin(), map.end());
    return map;
}

auto compute_valid_vertex_pairs(
        const vector<pair<int, int>>& map1,
        const vector<pair<int, int>>& map2) {
    vector<pair<int, int>> pairs;
    pairs.reserve(map1.size() * map2.size());

    const auto comp = [](const auto& p_a, const auto& p_b){
        return p_a.first < p_b.first;
    };

    auto p = map2.cbegin();  // Memoize low limit (see below).
    for (auto i1 = map1.cbegin(); i1 != map1.cend(); ) {
        // Find range of map2 that contains vertices labelled "label1".
        auto [eq_cbegin, eq_cend] = std::equal_range(p, map2.cend(), *i1, comp);

        // Iterate over all equal values in map1.
        const auto label1 = i1->first;
        do {
            const auto num1 = i1->second;

            // Create all pairs between vertex of map1 and range of map2.
            for (auto p = eq_cbegin; p != eq_cend; ++p) {
                pairs.emplace_back(num1, p->second);
            }

            ++i1;
        } while (i1 != map1.cend() && i1->first == label1);

        // All vertices with that label have been exhausted in both maps.
        p = eq_cend;
    }

    sort(pairs.begin(), pairs.end());
    return pairs;
}

auto productAdjacency(
        const MatrixXi& e1,
        const MatrixXi& e2,
        const vector<int>& v1_label,
        const vector<int>& v2_label) {
    // Step 1: Order vertices by labels; compute all valid vertex pairs
    const auto pairs = compute_valid_vertex_pairs(
            order_by_labels(v1_label),
            order_by_labels(v2_label));

    // Step 2: Compute new labels for vertices of the product graph.
    Eigen::Matrix<int, -1, -1, Eigen::RowMajor> H(v1_label.size(), v2_label.size());

    auto next_label = 0;
    for (const auto& [v1, v2] : pairs) {
        H(v1, v2) = next_label++;
    }

    // Step 3: Compute the adjacency matrix of the direct product graph.
    vector<Eigen::Triplet<double>> v;
    for (auto i = 0; i < e1.rows(); ++i) {
        const auto e1_s = e1(i, 0);
        const auto e1_t = e1(i, 1);
        const auto e1_label = e1(i, 2);

        for (auto j = 0; j < e2.rows(); ++j) {
            if (e1_label == e2(j, 2)) {
                const auto e2_s = e2(j, 0);
                const auto e2_t = e2(j, 1);

                if (v1_label[e1_s] == v2_label[e2_s]
                &&  v1_label[e1_t] == v2_label[e2_t]
                   ) {
                    v.emplace_back(H(e1_s, e2_s), H(e1_t, e2_t), 1.0);
                    v.emplace_back(H(e1_t, e2_t), H(e1_s, e2_s), 1.0);
                }

                if (v1_label[e1_s] == v2_label[e2_t]
                &&  v1_label[e1_t] == v2_label[e2_s]
                   ) {
                    v.emplace_back(H(e1_s, e2_t), H(e1_t, e2_s), 1.0);
                    v.emplace_back(H(e1_t, e2_s), H(e1_s, e2_t), 1.0);
                }
            }
        }
    }

    SparseMatrix<double> Ax(next_label, next_label);
    Ax.setFromTriplets(v.cbegin(), v.cend());

    return Ax;
}

double geometricRandomWalkKernel(
        const MatrixXi& e1,
        const MatrixXi& e2,
        const vector<int>& v1_label,
        const vector<int>& v2_label,
        double lambda,
        int max_iterations,
        double eps) {
    // compute the adjacency matrix Ax of the direct product graph
    const SparseMatrix<double> Lx = lambda * productAdjacency(
            e1, e2, v1_label, v2_label);

    // inverse of I - lambda * Ax by fixed-poInt iterations
    const auto n_rows = Lx.rows();
    const VectorXd ones = VectorXd::Ones(n_rows);
    auto x = ones;
    VectorXd x_pre = VectorXd::Zero(n_rows);

    auto count = 0;
    do {
        x_pre = x;
        x = ones + Lx * x_pre;
        ++count;
    } while (count <= max_iterations && (x - x_pre).squaredNorm() > eps);
    return x.sum();
}

MatrixXd CalculateGeometricRandomWalkKernelPy(
        const vector<MatrixXi>& E,
        const vector<vector<int>>& V_label,
        double lambda,
        int max_iterations,
        double eps) {
    MatrixXd K(V_label.size(), V_label.size());

    for (auto j = 0; j < V_label.size(); ++j) {
        for (auto i = 0; i <= j; ++i) {
            K(i, j) = geometricRandomWalkKernel(
                    E[i], E[j], V_label[i], V_label[j], lambda,
                    max_iterations, eps);
        }
    }

    return K.selfadjointView<Eigen::Upper>();
}

double exponentialRandomWalkKernel(
        const MatrixXi& e1,
        const MatrixXi& e2,
        const vector<int>& v1_label,
        const vector<int>& v2_label,
        double beta) {
    // compute the adjacency matrix Ax of the direct product graph
    const MatrixXd Ax = productAdjacency(e1, e2, v1_label, v2_label);

    return Ax.exp().sum();
}

MatrixXd CalculateExponentialRandomWalkKernelPy(
        const vector<MatrixXi>& E,
        const vector<vector<int>>& V_label,
        double beta) {
    MatrixXd K(V_label.size(), V_label.size());

    for (auto j = 0; j < V_label.size(); ++j) {
        for (auto i = 0; i <= j; ++i) {
            K(i, j) = exponentialRandomWalkKernel(
                    E[i], E[j], V_label[i], V_label[j], beta);
        }
    }

    return K.selfadjointView<Eigen::Upper>();
}

double kstepRandomWalkKernel(
        const MatrixXi& e1,
        const MatrixXi& e2,
        const vector<int>& v1_label,
        const vector<int>& v2_label,
        const vector<double>& lambda_list) {
    // compute the adjacency matrix Ax of the direct product graph
    const SparseMatrix<double> Ax = productAdjacency(e1, e2, v1_label, v2_label);

    // prepare identity matrix
    const auto n_rows = Ax.rows();
    SparseMatrix<double> I{n_rows, n_rows};
    I.setIdentity();

    auto Sum = SparseMatrix<double>{n_rows, n_rows};
    Sum.setZero();

    // Compute products until k using:
    // https://en.wikipedia.org/wiki/Horner%27s_method
    auto k = lambda_list.size();
    while (k-- > 0) {
        Sum = (Sum * Ax) + lambda_list[k] * I;
    }

    return Sum.sum();
}

MatrixXd CalculateKStepRandomWalkKernelPy(
        const vector<MatrixXi>& E,
        const vector<vector<int>>& V_label,
        const vector<double>& par) {
    MatrixXd K(V_label.size(), V_label.size());

    for (auto j = 0; j < V_label.size(); ++j) {
        for (auto i = 0; i <= j; ++i) {
            K(i, j) = kstepRandomWalkKernel(
                    E[i], E[j], V_label[i], V_label[j], par);
        }
    }

    return K.selfadjointView<Eigen::Upper>();
}

max_stars_repo_name: Renelvon/GraphKernels

max_issues_repo_name: Renelvon/GraphKernels

max_forks_repo_name: Renelvon/GraphKernels


text:
/* ----------------------------------------------------------------------------

 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
 * Atlanta, Georgia 30332-0415
 * All Rights Reserved
 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)

 * See LICENSE for the license information

 * -------------------------------------------------------------------------- */

/**
 * @file VectorValues.cpp
 * @brief Implementations for VectorValues
 * @author Richard Roberts
 * @author Alex Cunningham
 */

#include <gtsam/base/FastVector.h>
#include <gtsam/inference/Permutation.h>
#include <gtsam/linear/VectorValues.h>

#include <boost/iterator/counting_iterator.hpp>

using namespace std;

namespace gtsam {

/* ************************************************************************* */
VectorValues VectorValues::Zero(const VectorValues& x) {
  VectorValues result;
  result.values_.resize(x.size());
  for(size_t j=0; j<x.size(); ++j)
    result.values_[j] = Vector::Zero(x.values_[j].size());
  return result;
}

/* ************************************************************************* */
vector<size_t> VectorValues::dims() const {
  std::vector<size_t> result(this->size());
  for(Index j = 0; j < this->size(); ++j)
    result[j] = this->dim(j);
  return result;
}

/* ************************************************************************* */
void VectorValues::insert(Index j, const Vector& value) {
  // Make sure j does not already exist
  if(exists(j))
    throw invalid_argument("VectorValues: requested variable index to insert already exists.");

  // If this adds variables at the end, insert zero-length entries up to j
  if(j >= size())
    values_.resize(j+1);

  // Assign value
  values_[j] = value;
}

/* ************************************************************************* */
void VectorValues::print(const std::string& str, const IndexFormatter& formatter) const {
  std::cout << str << ": " << size() << " elements\n";
  for (Index var = 0; var < size(); ++var)
    std::cout << "  " << formatter(var) << ": \n" << (*this)[var] << "\n";
  std::cout.flush();
}

/* ************************************************************************* */
bool VectorValues::equals(const VectorValues& x, double tol) const {
  if(this->size() != x.size())
    return false;
  for(Index j=0; j < size(); ++j)
    if(!equal_with_abs_tol(values_[j], x.values_[j], tol))
      return false;
  return true;
}

/* ************************************************************************* */
void VectorValues::resize(Index nVars, size_t varDim) {
  values_.resize(nVars);
  for(Index j = 0; j < nVars; ++j)
    values_[j] = Vector(varDim);
}

/* ************************************************************************* */
void VectorValues::resizeLike(const VectorValues& other) {
  values_.resize(other.size());
  for(Index j = 0; j < other.size(); ++j)
    values_[j].resize(other.values_[j].size());
}

/* ************************************************************************* */
VectorValues VectorValues::SameStructure(const VectorValues& other) {
  VectorValues ret;
  ret.resizeLike(other);
  return ret;
}

/* ************************************************************************* */
VectorValues VectorValues::Zero(Index nVars, size_t varDim) {
  VectorValues ret(nVars, varDim);
  ret.setZero();
  return ret;
}

/* ************************************************************************* */
void VectorValues::setZero() {
  BOOST_FOREACH(Vector& v, *this) {
    v.setZero();
  }
}

/* ************************************************************************* */
const Vector VectorValues::asVector() const {
  return internal::extractVectorValuesSlices(*this,
    boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(this->size()), true);
}

/* ************************************************************************* */
const Vector VectorValues::vector(const std::vector<Index>& indices) const {
  return internal::extractVectorValuesSlices(*this, indices.begin(), indices.end());
}

/* ************************************************************************* */
bool VectorValues::hasSameStructure(const VectorValues& other) const {
  if(this->size() != other.size())
    return false;
  for(size_t j = 0; j < size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    if(this->values_[j].rows() != other.values_[j].rows())
      return false;
  return true;
}

/* ************************************************************************* */
void VectorValues::permuteInPlace(const Permutation& permutation) {
  // Allocate new values
  Values newValues(this->size());

  // Swap values from this VectorValues to the permuted VectorValues
  for(size_t i = 0; i < this->size(); ++i)
    newValues[i].swap(this->at(permutation[i]));

  // Swap the values into this VectorValues
  values_.swap(newValues);
}

/* ************************************************************************* */
void VectorValues::permuteInPlace(const Permutation& selector, const Permutation& permutation) {
  if(selector.size() != permutation.size())
    throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes.");
  // Create new index the size of the permuted entries
  Values reorderedEntries(selector.size());
  // Permute the affected entries into the new index
  for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot)
    reorderedEntries[dstSlot].swap(values_[selector[permutation[dstSlot]]]);
  // Put the affected entries back in the new order
  for(size_t slot = 0; slot < selector.size(); ++slot)
    values_[selector[slot]].swap(reorderedEntries[slot]);
}

/* ************************************************************************* */
void VectorValues::swap(VectorValues& other) {
  this->values_.swap(other.values_);
}

/* ************************************************************************* */
double VectorValues::dot(const VectorValues& v) const {
  double result = 0.0;
  if(this->size() != v.size())
    throw invalid_argument("VectorValues::dot called with different vector sizes");
  for(Index j = 0; j < this->size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    if(this->values_[j].size() == v.values_[j].size())
      result += this->values_[j].dot(v.values_[j]);
    else
      throw invalid_argument("VectorValues::dot called with different vector sizes");
  return result;
}

/* ************************************************************************* */
double VectorValues::norm() const {
  return std::sqrt(this->squaredNorm());
}

/* ************************************************************************* */
double VectorValues::squaredNorm() const {
  double sumSquares = 0.0;
  for(Index j = 0; j < this->size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    sumSquares += this->values_[j].squaredNorm();
  return sumSquares;
}

/* ************************************************************************* */
VectorValues VectorValues::operator+(const VectorValues& c) const {
  VectorValues result = SameStructure(*this);
  if(this->size() != c.size())
    throw invalid_argument("VectorValues::operator+ called with different vector sizes");
  for(Index j = 0; j < this->size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    if(this->values_[j].size() == c.values_[j].size())
      result.values_[j] = this->values_[j] + c.values_[j];
    else
      throw invalid_argument("VectorValues::operator- called with different vector sizes");
  return result;
}

/* ************************************************************************* */
VectorValues VectorValues::operator-(const VectorValues& c) const {
  VectorValues result = SameStructure(*this);
  if(this->size() != c.size())
    throw invalid_argument("VectorValues::operator- called with different vector sizes");
  for(Index j = 0; j < this->size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    if(this->values_[j].size() == c.values_[j].size())
      result.values_[j] = this->values_[j] - c.values_[j];
    else
      throw invalid_argument("VectorValues::operator- called with different vector sizes");
  return result;
}

/* ************************************************************************* */
void VectorValues::operator+=(const VectorValues& c) {
  if(this->size() != c.size())
    throw invalid_argument("VectorValues::operator+= called with different vector sizes");
  for(Index j = 0; j < this->size(); ++j)
    // Directly accessing maps instead of using VV::dim in case some values are empty
    if(this->values_[j].size() == c.values_[j].size())
      this->values_[j] += c.values_[j];
    else
      throw invalid_argument("VectorValues::operator+= called with different vector sizes");
}

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

} // \namespace gtsam

max_stars_repo_name: malcolmreynolds/GTSAM

max_issues_repo_name: malcolmreynolds/GTSAM

max_forks_repo_name: malcolmreynolds/GTSAM


text:
//
// Created by Blink on 2018/7/23.
//

#ifndef THKVS_TCP_CONNECTION_HPP
#define THKVS_TCP_CONNECTION_HPP

#include <boost/asio.hpp>
#include "message.hpp"
#include "msg_queue.hpp"
#include <boost/bind.hpp>
#include "manager.hpp"

namespace as = boost::asio;

class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:
    TcpConnection() = delete;

    static std::shared_ptr<TcpConnection> create(as::io_service& io_service) {
        std::shared_ptr<TcpConnection> tmp = std::shared_ptr<TcpConnection> (new TcpConnection(io_service));
        return tmp;
    }

    std::shared_ptr<TcpConnection> ptr() {
        return shared_from_this();
    }

    as::ip::tcp::socket& socket() {
        return socket_;
    }

    void init_from_accept();

    void start_handle_message();

    void handle_header(const boost::system::error_code& error);

    void handle_body(const boost::system::error_code& error);

    void finalize(const boost::system::error_code& error);

    void write_message();

private:
    TcpConnection(as::io_service& io_service);
    as::ip::address peerIp;
    as::ip::tcp::socket socket_;
    SerialzedMessage read_msg;
    std::vector<as::const_buffer> buffers;
};

#endif //THKVS_TCP_CONNECTION_HPP

ext: hpp

max_stars_repo_name: JohndeVostok/THKVS

max_issues_repo_name: JohndeVostok/THKVS

max_forks_repo_name: JohndeVostok/THKVS


text:
//Copyright (c) 2015 Zachary Kann
//
//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.

// ---
// Author: Zachary Kann

// Implementation of MoleculeGroup class. See include/z_atom_group.hpp for
// more details about the class.

#include "z_molecule_group.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include "z_string.hpp"
#include "z_vec.hpp"
#include <algorithm>

void MoleculeGroup::WriteGro(const std::string& gro, const arma::rowvec& box,
                             const std::string description) {
    std::ofstream gro_file;
    gro_file.open(gro.c_str());
    assert(gro_file.is_open());
    gro_file << description << std::endl;
    gro_file << group_size_ << std::endl;
    for (int i_atom = 0; i_atom < group_size_; i_atom++) {
      gro_file << boost::format("%5d%-5s%5s%5d%8.3f%8.3f%8.3f%8.4f%8.4f%8.4f") %
          (index_to_molecular_index_[i_atom]+1) %
          molecule_name(index_to_molecular_index_[i_atom]) %
          atom_name(i_atom) % (indices_[i_atom]+1) % positions_(i_atom,0) %
          positions_(i_atom,1) % positions_(i_atom,2) %
          velocities_(i_atom,0) % velocities_(i_atom,1) %
          velocities_(i_atom,2) << std::endl;
    }
    gro_file << boost::format("%10.5f%10.5f%10.5f") % box(0) % box(1) % box(2);
    gro_file.close();
}

void MoleculeGroup::RemoveMolecule(const int molecule_id,
                               arma::rowvec& old_com_position,
                               arma::rowvec& old_com_velocity) {
  std::vector<int> mark_for_rem;
  const int marked_molecule = molecular_index_to_molecule_[molecule_id];
  for (std::vector<int>::iterator i_mol = index_to_molecule_.begin();
       i_mol != index_to_molecule_.end(); i_mol++) {
    if (*i_mol == marked_molecule)
      mark_for_rem.push_back(std::distance(index_to_molecule_.begin(),i_mol));
    else if (*i_mol > marked_molecule)
      (*i_mol) -= 1;
  }
  for (std::vector<int>::iterator i_mol = index_to_molecular_index_.begin(),
           i_atom = indices_.begin();
       i_mol != index_to_molecular_index_.end(); ++i_mol, ++i_atom) {
    // Decrements molecular and atomic indices to eliminate gap
    if ((*i_mol) > molecule_id) {
      (*i_mol) -= 1;
      (*i_atom) -= mark_for_rem.size();
    }
  }
  assert(!mark_for_rem.empty());
  for (std::vector<int>::iterator i_mol =
           molecular_index_to_molecule_.begin()+molecule_id+1;
       i_mol != molecular_index_to_molecule_.end(); ++i_mol) {
    (*i_mol) -= 1;
  }
  molecular_index_to_mass_.erase(
      molecular_index_to_mass_.begin() + molecule_id);
  molecular_index_to_molecule_.erase(
      molecular_index_to_molecule_.begin() + molecule_id);
  molecule_names_.erase(
      molecule_names_.begin() + molecule_id);
  // Save references to position/velocity for later replacement.
  old_com_position = com_positions_.row(molecule_id);
  old_com_velocity = com_velocities_.row(molecule_id);
  com_positions_.shed_row(molecule_id);
  com_velocities_.shed_row(molecule_id);
  for (std::vector<int>::reverse_iterator i_atom = mark_for_rem.rbegin();
       i_atom != mark_for_rem.rend(); i_atom++) {
    RemoveAtom(*i_atom);
  }
  num_molecules_--;
}

void MoleculeGroup::AddMolecule(const int molecule_id, const Molecule& molecule,
                            const arma::rowvec& position,
                            const arma::rowvec& velocity)
{
    // TODO(Zak): Allow for polyatomic molecules by randomly
    // orienting around center of mass position.
    // This assert is a placeholder until then.
    assert (molecule.num_atoms() == 1);
    molecule_names_.push_back(molecule.name());
    molecular_index_to_mass_.push_back(molecule.mass());
    molecular_index_to_molecule_.push_back(molecule_id);
    for (std::vector<Atom>::const_iterator i_atom = molecule.begin();
         i_atom != molecule.end(); ++i_atom) {
      AddAtom(*i_atom, molecule_id, position, velocity);
    }
    num_molecules_++;
    com_positions_.insert_rows(com_positions_.n_rows, position);
    com_velocities_.insert_rows(com_velocities_.n_rows, velocity);
}

void MoleculeGroup::UpdateCom() {
  ZeroCom();
  for (int i_atom = 0; i_atom < group_size_; i_atom++) {
    com_positions_.row(index_to_molecular_index_[i_atom]) +=
        index_to_mass_[i_atom]*positions_.row(i_atom);
    com_velocities_.row(index_to_molecular_index_[i_atom]) +=
        index_to_mass_[i_atom]*velocities_.row(i_atom);
  }
  for (int i_mol = 0; i_mol < num_molecules_; ++i_mol) {
    com_positions_.row(i_mol) /= molecular_index_to_mass_[i_mol];
    com_velocities_.row(i_mol) /= molecular_index_to_mass_[i_mol];
  }
}

void MoleculeGroup::RemoveAtom(const int index) {
  indices_.erase(indices_.begin() + index);
  atom_names_.erase(atom_names_.begin() + index);
  index_to_mass_.erase(index_to_mass_.begin() + index);
  index_to_molecule_.erase(index_to_molecule_.begin() + index);
  index_to_sigma_.erase(index_to_sigma_.begin() + index);
  index_to_epsilon_.erase(index_to_epsilon_.begin() + index);
  index_to_molecular_index_.erase(
      index_to_molecular_index_.begin() + index);
  positions_.shed_row(index);
  velocities_.shed_row(index);
  group_size_--;
}

void MoleculeGroup::AddAtom(const Atom atom_to_add, const int molecule_id,
                        const arma::rowvec& position,
                        const arma::rowvec& velocity) {
  atom_names_.push_back(atom_to_add.name());
  index_to_mass_.push_back(atom_to_add.mass());
  index_to_molecule_.push_back(molecule_id);
  index_to_sigma_.push_back(atom_to_add.sigma());
  index_to_epsilon_.push_back(atom_to_add.epsilon());
  index_to_molecular_index_.push_back(num_molecules_);
  // TODO(Zak): Fix to work outside of all_atoms group.
  indices_.push_back(group_size_);
  group_size_++;
  positions_.insert_rows(positions_.n_rows, position);
  velocities_.insert_rows(velocities_.n_rows, velocity);
}

void MoleculeGroup::Init(const std::string& name,
                         const SystemGroup& all_atoms) {
  last_index_in_molecule_.resize(group_size_);
  for (std::vector<int>::iterator i_index = indices_.begin();
       i_index != indices_.end(); ++i_index) {
    index_to_mass_.push_back(all_atoms.mass(*i_index));
    index_to_molecule_.push_back(all_atoms.index_to_molecule(*i_index));
    index_to_sigma_.push_back(all_atoms.sigma(*i_index));
    index_to_epsilon_.push_back(all_atoms.epsilon(*i_index));
    index_to_charge_.push_back(all_atoms.charge(*i_index));
    atom_names_.push_back(all_atoms.atom_name(*i_index));
  }
  std::vector<double>::iterator i_mass = index_to_mass_.begin();
  for (std::vector<int>::iterator i_mol = index_to_molecule_.begin();
       i_mol != index_to_molecule_.end(); ++i_mol, ++i_mass) {
    std::vector<int>::iterator mol_index;
    mol_index = std::find(molecular_index_to_molecule_.begin(),
                          molecular_index_to_molecule_.end(), *i_mol);
    if (mol_index == molecular_index_to_molecule_.end()) {
      molecular_index_to_mass_.push_back(0.0);
      first_index_in_molecule_.push_back(index_to_molecular_index_.size());
      index_to_molecular_index_.push_back(molecular_index_to_molecule_.size());
      molecular_index_to_molecule_.push_back(*i_mol);
      molecule_names_.push_back(molecule_name(*i_mol));
      // TODO(Zak): Find better way to determine identity of marker atoms.
      //            For now, just use first atom as this works for water.
      molecule_position_markers_.push_back(
          std::distance(index_to_molecule_.begin(), i_mol));
    } else {
      double mol_number = std::distance(molecular_index_to_molecule_.begin(),
                                        mol_index);
      last_index_in_molecule_[mol_number] = (index_to_molecular_index_.size());
      index_to_molecular_index_.push_back(mol_number);
      }
    molecular_index_to_mass_.back() += *i_mass;
  }
  num_molecules_ = molecular_index_to_molecule_.size();
  com_positions_.set_size(num_molecules_, DIMS);
  com_velocities_.set_size(num_molecules_, DIMS);

  CalculateMolecularCharges(all_atoms.molecular_charges());
  set_has_molecules(true);
}


text:
/*
 * Copyright 2017-2019 Janek Bevendorff, Webis Group
 *
 * 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 "AbstractWordOperator.hpp"
#include <boost/algorithm/string.hpp>
#include <fstream>

/**
 * Mutex for static bounds cache access.
 */
std::mutex AbstractWordOperator::s_boundsCacheMutex{};

/**
 * Cached operator working data.
 */
bd::lru_cache<std::string, AbstractWordOperator::WordBoundsListPair> AbstractWordOperator::s_cachedWordBounds{500};

/**
 * Mutex for static dictionary access.
 */
std::mutex AbstractWordOperator::s_dictMutex{};

/**
 * Loaded word lists.
 */
std::unordered_map<std::string, std::shared_ptr<AbstractWordOperator::Dictionary>> AbstractWordOperator::s_dictionaries{};

AbstractWordOperator::AbstractWordOperator(std::string const& name, double cost, std::string const& description)
        : ObfuscationOperator(name, cost, description)
{
}

/**
 * Check if a character represents a word boundary.
 *
 * @param c character
 * @return true if character is a non-word character
 */
bool AbstractWordOperator::isWordBoundary(char c)
{
    return std::isspace(c) || std::ispunct(c);
}

/**
 * Get an iterator to the beginning of the current word.
 * If <tt>pos</tt> points at a word boundary, the beginning of the next word is returned
 * and if there is no next word, the iterator is returned unchanged.
 *
 * The returned position can be less than, equal to, or greater than the original position.
 *
 * @param text input text
 * @param pos iterator to the current position
 * @param numWords number of previous words to skip
 * @return iterator
 */
AbstractWordOperator::StrPos AbstractWordOperator::parseWordStart(std::string const& text, std::string::const_iterator pos)
{
    if (pos >= text.end() || pos <= text.begin()) {
        return pos;
    }

    // navigate to the beginning of the next word if we
    // started on a word boundary character
    bool isBoundary = isWordBoundary(*pos);
    auto origPos = pos;
    while (isBoundary) {
        ++pos;
        if (pos >= text.end()) {
            return origPos;
        }
        isBoundary = isWordBoundary(*pos);
        if (!isBoundary) {
            return pos;
        }
    }

    // navigate to the beginning of the current word or the beginning of the text
    while (pos > text.begin()) {
        --pos;
        if (isWordBoundary(*pos)) {
            // step one forward again to point at actual word beginning
            ++pos;
            break;
        }
    }

    return pos;
}

/**
 * Get an iterator past the end of the current word.
 * If <tt>pos</tt> points at a word boundary, an iterator past the end of the previous word is returned
 * and if there is no previous word, the iterator is returned unchanged.
 *
 * The returned position can be less than, equal to, or greater than the original position.
 *
 * @param text input text
 * @param pos iterator to the current position
 * @return iterator
 */
AbstractWordOperator::StrPos AbstractWordOperator::parseWordEnd(std::string const& text, std::string::const_iterator pos)
{
    if (pos >= text.end() || pos <= text.begin()) {
        return pos;
    }

    // navigate to the end of the previous word if we
    // started on a word boundary character
    bool isBoundary = isWordBoundary(*pos);
    auto origPos = pos;
    while (isBoundary) {
        --pos;
        if (pos <= text.begin()) {
            return origPos;
        }
        isBoundary = isWordBoundary(*pos);
        if (!isBoundary) {
            return pos + 1;
        }
    }

    // navigate to the end of the current word or the end of the text
    while (pos < text.end()) {
        ++pos;
        if (isWordBoundary(*pos)) {
            break;
        }
    }

    return pos;
}

/**
 * Get two vectors containing \link WordBounds for the <tt>wordsBefore</tt> and <tt>wordsAfter</tt> next words
 * parsed from the text around the given \link FocusPoint.
 * The first element of the second vector is always the current word. The first vector can be empty if
 * <tt>wordsBefore</tt> is 0.
 * Results are cached, so successive calls with identical parameters may be served faster.
 *
 * @param focusPoint operator focus point
 * @param wordsBefore number of words before the current one
 * @param wordsAfter number of words after the current one
 * @return pair of vectors containing \link WordBounds
 */
AbstractWordOperator::WordBoundsListPair AbstractWordOperator::parseWordBounds(
        FocusPoint const& focusPoint, std::size_t wordsBefore, std::size_t wordsAfter)
{
    auto const& text = *focusPoint.text;
    auto pos = text.begin() + focusPoint.ngramOffset;

    auto const cacheKey = std::to_string(reinterpret_cast<std::size_t>(&*pos))
            .append(":")
            .append(std::to_string(wordsBefore))
            .append(":")
            .append(std::to_string(wordsAfter));
    {
        std::lock_guard<std::mutex> lock(s_boundsCacheMutex);
        auto cached = s_cachedWordBounds.get(cacheKey);
        if (cached) {
            return cached.get();
        }
    }

    std::vector<WordBounds> boundsBefore;
    boundsBefore.reserve(wordsBefore);
    std::vector<WordBounds> boundsAfter;
    boundsAfter.reserve(wordsAfter + 1);

    auto start = parseWordStart(text, pos);
    auto end = parseWordEnd(text, start);
    boundsAfter.emplace_back(start, end);

    while (wordsAfter > 0 && end < text.end()) {
        auto nextStart = parseWordStart(text, end + 1);
        auto nextEnd = parseWordEnd(text, nextStart);
        if (nextEnd <= nextStart || start == nextStart) {
            break;
        }
        start = nextStart;
        end = nextEnd;
        boundsAfter.emplace_back(start, end);
        --wordsAfter;
    }

    start = boundsAfter[0].first;
    while (wordsBefore > 0 && start > text.begin()) {
        auto prevEnd = parseWordEnd(text, start - 1);
        auto prevStart = parseWordStart(text, prevEnd - 1);
        if (prevEnd <= prevStart || start == prevStart) {
            break;
        }
        start = prevStart;
        end = prevEnd;
        boundsBefore.emplace_back(start, end);
        --wordsBefore;
    }
    std::reverse(boundsBefore.begin(), boundsBefore.end());

    auto pair = std::make_pair(boundsBefore, boundsAfter);
    std::lock_guard<std::mutex> lock(s_boundsCacheMutex);
    s_cachedWordBounds.insert(cacheKey, pair);
    return pair;
}

/**
 * Load and cache a dictionary. A dictionary maps a specific word to a list of alternative words.
 * Successive calls to this function will return the same dictionary instance.
 * This method is thread-safe.
 *
 * @param dictFile path to input file
 * @param separator entry separator inside the input file
 * @return shared pointer to dictionary or nullptr if dictionary could not be loaded
 */
std::shared_ptr<AbstractWordOperator::Dictionary const> AbstractWordOperator::loadDictionary(std::string const& dictFile, char separator)
{
    std::lock_guard<std::mutex> lock(s_dictMutex);

    auto dictIt = s_dictionaries.find(dictFile);
    if (dictIt != s_dictionaries.end()) {
        return dictIt->second;
    }

    std::ifstream stream;
    stream.open(dictFile);
    if (!stream) {
        std::cerr << "Could not open file '" << dictFile << "'" << std::endl;
        return nullptr;
    }

    auto dictPtr = std::make_shared<Dictionary>();
    auto& dict = *dictPtr;

    std::string line;
    while (std::getline(stream, line)) {
        std::deque<std::string> tokens;
        boost::split(tokens, line, [separator](char c) { return c == separator; });

        if (tokens.size() < 2) {
            continue;
        }

        std::string key = boost::to_lower_copy(tokens[0]);
        tokens.pop_front();
        dict[key] = {std::make_move_iterator(tokens.begin()), std::make_move_iterator(tokens.end())};
    }

    s_dictionaries[dictFile] = dictPtr;
    return dictPtr;
}


text:
#ifndef BOOST_METAPARSE_V1_ACCEPT_WHEN_HPP
#define BOOST_METAPARSE_V1_ACCEPT_WHEN_HPP

// Copyright Abel Sinkovics (abel@sinkovics.hu)  2009 - 2010.
// 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 <boost/metaparse/v1/get_result.hpp>
#include <boost/metaparse/v1/reject.hpp>
#include <boost/metaparse/v1/is_error.hpp>

#include <boost/mpl/if.hpp>
#include <boost/mpl/eval_if.hpp>

namespace boost
{
  namespace metaparse
  {
    namespace v1
    {
      template <class P, class Pred, class Msg>
      struct accept_when
      {
      private:
        struct unchecked
        {
          template <class S, class Pos>
          struct apply :
            boost::mpl::eval_if<
              typename Pred::template apply<
                typename get_result<typename P::template apply<S, Pos> >::type
              >::type,
              typename P::template apply<S, Pos>,
              reject<Msg, Pos>
            >
          {};
        };
      public:
        typedef accept_when type;

        template <class S, class Pos>
        struct apply :
          boost::mpl::if_<
            is_error<typename P::template apply<S, Pos> >,
            P,
            unchecked
          >::type::template apply<
            S,
            Pos
          >
        {};
      };
    }
  }
}

#endif

max_stars_repo_name: rudylee/expo

max_issues_repo_name: rudylee/expo

max_forks_repo_name: rudylee/expo


text:
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .

#include <key_io.h>

#include <base58.h>
#include <bech32.h>
#include <script/script.h>
#include <utilstrencodings.h>

#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>

#include "pbaas/identity.h"
#include "cc/CCinclude.h"
#include "boost/algorithm/string.hpp"

#include <assert.h>
#include <string.h>
#include <algorithm>

extern uint160 VERUS_CHAINID;
extern std::string VERUS_CHAINNAME;

CIdentityID VERUS_DEFAULTID;
bool VERUS_PRIVATECHANGE;
std::string VERUS_DEFAULT_ZADDR;

namespace
{
class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
    const CChainParams& m_params;

public:
    DestinationEncoder(const CChainParams& params) : m_params(params) {}

    std::string operator()(const CKeyID& id) const
    {
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
        data.insert(data.end(), id.begin(), id.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const CPubKey& key) const
    {
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
        CKeyID id = key.GetID();
        data.insert(data.end(), id.begin(), id.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const CScriptID& id) const
    {
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
        data.insert(data.end(), id.begin(), id.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const CIdentityID& id) const
    {
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::IDENTITY_ADDRESS);
        data.insert(data.end(), id.begin(), id.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const CQuantumID& id) const
    {
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::QUANTUM_ADDRESS);
        data.insert(data.end(), id.begin(), id.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const CNoDestination& no) const { return {}; }
};

class DestinationBytes : public boost::static_visitor<std::vector<unsigned char>>
{
public:
    DestinationBytes() {}

    std::vector<unsigned char> operator()(const CKeyID& id) const
    {
        return std::vector<unsigned char>(id.begin(), id.end());
    }

    std::vector<unsigned char> operator()(const CPubKey& key) const
    {
        return std::vector<unsigned char>(key.begin(), key.end());
    }

    std::vector<unsigned char> operator()(const CScriptID& id) const
    {
        return std::vector<unsigned char>(id.begin(), id.end());
    }

    std::vector<unsigned char> operator()(const CIdentityID& id) const
    {
        return std::vector<unsigned char>(id.begin(), id.end());
    }

    std::vector<unsigned char> operator()(const CQuantumID& id) const
    {
        return std::vector<unsigned char>(id.begin(), id.end());
    }

    std::vector<unsigned char> operator()(const CNoDestination& no) const { return {}; }
};

class DestinationID : public boost::static_visitor<uint160>
{
public:
    DestinationID() {}

    uint160 operator()(const CKeyID& id) const
    {
        return (uint160)id;
    }

    uint160 operator()(const CPubKey& key) const
    {
        return (uint160)key.GetID();
    }

    uint160 operator()(const CScriptID& id) const
    {
        return (uint160)id;
    }

    uint160 operator()(const CIdentityID& id) const
    {
        return (uint160)id;
    }

    uint160 operator()(const CQuantumID& id) const
    {
        return (uint160)id;
    }

    uint160 operator()(const CNoDestination& no) const { return CKeyID(); }
};

CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
    std::vector<unsigned char> data;
    uint160 hash;
    if (DecodeBase58Check(str, data)) {
        // base58-encoded Bitcoin addresses.
        // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
        const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
        if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
            std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
            return CKeyID(hash);
        }

        // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
        const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
        if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
            std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
            return CScriptID(hash);
        }

        const std::vector<unsigned char>& identity_prefix = params.Base58Prefix(CChainParams::IDENTITY_ADDRESS);
        if (data.size() == hash.size() + identity_prefix.size() && std::equal(identity_prefix.begin(), identity_prefix.end(), data.begin())) {
            std::copy(data.begin() + identity_prefix.size(), data.end(), hash.begin());
            return CIdentityID(hash);
        }

        const std::vector<unsigned char>& quantum_prefix = params.Base58Prefix(CChainParams::QUANTUM_ADDRESS);
        if (data.size() == hash.size() + quantum_prefix.size() && std::equal(quantum_prefix.begin(), quantum_prefix.end(), data.begin())) {
            std::copy(data.begin() + quantum_prefix.size(), data.end(), hash.begin());
            return CQuantumID(hash);
        }
    }
    else if (std::count(str.begin(), str.end(), '@') == 1)
    {
        uint160 parent;
        return CIdentityID(CIdentity::GetID(str, parent));
    }

    return CNoDestination();
}

class PaymentAddressEncoder : public boost::static_visitor<std::string>
{
private:
    const CChainParams& m_params;

public:
    PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}

    std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << zaddr;
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
        data.insert(data.end(), ss.begin(), ss.end());
        return EncodeBase58Check(data);
    }

    std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << zaddr;
        // ConvertBits requires unsigned char, but CDataStream uses char
        std::vector<unsigned char> seraddr(ss.begin(), ss.end());
        std::vector<unsigned char> data;
        // See calculation comment below
        data.reserve((seraddr.size() * 8 + 4) / 5);
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, seraddr.begin(), seraddr.end());
        return bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS), data);
    }

    std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};

class ViewingKeyEncoder : public boost::static_visitor<std::string>
{
private:
    const CChainParams& m_params;

public:
    ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}

    std::string operator()(const libzcash::SproutViewingKey& vk) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << vk;
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
        data.insert(data.end(), ss.begin(), ss.end());
        std::string ret = EncodeBase58Check(data);
        memory_cleanse(data.data(), data.size());
        return ret;
    }

    std::string operator()(const libzcash::SaplingIncomingViewingKey& vk) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << vk;
        std::vector<unsigned char> serkey(ss.begin(), ss.end());
        std::vector<unsigned char> data;
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
        std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY), data);
        memory_cleanse(serkey.data(), serkey.size());
        memory_cleanse(data.data(), data.size());
        return ret;
    }

    std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};

class SpendingKeyEncoder : public boost::static_visitor<std::string>
{
private:
    const CChainParams& m_params;

public:
    SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}

    std::string operator()(const libzcash::SproutSpendingKey& zkey) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << zkey;
        std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
        data.insert(data.end(), ss.begin(), ss.end());
        std::string ret = EncodeBase58Check(data);
        memory_cleanse(data.data(), data.size());
        return ret;
    }

    std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
    {
        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << zkey;
        // ConvertBits requires unsigned char, but CDataStream uses char
        std::vector<unsigned char> serkey(ss.begin(), ss.end());
        std::vector<unsigned char> data;
        // See calculation comment below
        data.reserve((serkey.size() * 8 + 4) / 5);
        ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
        std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data);
        memory_cleanse(serkey.data(), serkey.size());
        memory_cleanse(data.data(), data.size());
        return ret;
    }

    std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};

// Sizes of SaplingPaymentAddress and SaplingSpendingKey after
// ConvertBits<8, 5, true>(). The calculations below take the
// regular serialized size in bytes, convert to bits, and then
// perform ceiling division to get the number of 5-bit clusters.
const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5;
const size_t ConvertedSaplingIncomingViewingKeySize = (32 * 8 + 4) / 5;
} // namespace

CKey DecodeSecret(const std::string& str)
{
    CKey key;
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
        if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
            std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
            bool compressed = data.size() == 33 + privkey_prefix.size();
            key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
        }
    }
    memory_cleanse(data.data(), data.size());
    return key;
}

std::string EncodeSecret(const CKey& key)
{
    assert(key.IsValid());
    std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
    data.insert(data.end(), key.begin(), key.end());
    if (key.IsCompressed()) {
        data.push_back(1);
    }
    std::string ret = EncodeBase58Check(data);
    memory_cleanse(data.data(), data.size());
    return ret;
}

CExtPubKey DecodeExtPubKey(const std::string& str)
{
    CExtPubKey key;
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
        if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
            key.Decode(data.data() + prefix.size());
        }
    }
    return key;
}

std::string EncodeExtPubKey(const CExtPubKey& key)
{
    std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
    size_t size = data.size();
    data.resize(size + BIP32_EXTKEY_SIZE);
    key.Encode(data.data() + size);
    std::string ret = EncodeBase58Check(data);
    return ret;
}

CExtKey DecodeExtKey(const std::string& str)
{
    CExtKey key;
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
        if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
            key.Decode(data.data() + prefix.size());
        }
    }
    return key;
}

std::string EncodeExtKey(const CExtKey& key)
{
    std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
    size_t size = data.size();
    data.resize(size + BIP32_EXTKEY_SIZE);
    key.Encode(data.data() + size);
    std::string ret = EncodeBase58Check(data);
    memory_cleanse(data.data(), data.size());
    return ret;
}

std::string EncodeDestination(const CTxDestination& dest)
{
    return boost::apply_visitor(DestinationEncoder(Params()), dest);
}

std::vector<unsigned char> GetDestinationBytes(const CTxDestination& dest)
{
    return boost::apply_visitor(DestinationBytes(), dest);
}

uint160 GetDestinationID(const CTxDestination dest)
{
    return boost::apply_visitor(DestinationID(), dest);
}

CTxDestination DecodeDestination(const std::string& str)
{
    return DecodeDestination(str, Params());
}

bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
    return IsValidDestination(DecodeDestination(str, params));
}

bool IsValidDestinationString(const std::string& str)
{
    return IsValidDestinationString(str, Params());
}

std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
{
    return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
}

libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
{
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
        if ((data.size() == libzcash::SerializedSproutPaymentAddressSize + zaddr_prefix.size()) &&
            std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
            CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
            CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SproutPaymentAddress ret;
            ss >> ret;
            return ret;
        }
    }
    data.clear();
    auto bech = bech32::Decode(str);
    if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) &&
        bech.second.size() == ConvertedSaplingPaymentAddressSize) {
        // Bech32 decoding
        data.reserve((bech.second.size() * 5) / 8);
        if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
            CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SaplingPaymentAddress ret;
            ss >> ret;
            return ret;
        }
    }
    return libzcash::InvalidEncoding();
}

bool IsValidPaymentAddressString(const std::string& str, uint32_t consensusBranchId) {
    return IsValidPaymentAddress(DecodePaymentAddress(str), consensusBranchId);
}

std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
{
    return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
}

libzcash::ViewingKey DecodeViewingKey(const std::string& str)
{
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
        if ((data.size() == libzcash::SerializedSproutViewingKeySize + vk_prefix.size()) &&
            std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
            CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
            CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SproutViewingKey ret;
            ss >> ret;
            memory_cleanse(serialized.data(), serialized.size());
            memory_cleanse(data.data(), data.size());
            return ret;
        }
    }
    data.clear();
    auto bech = bech32::Decode(str);
    if(bech.first == Params().Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY) &&
       bech.second.size() == ConvertedSaplingIncomingViewingKeySize) {
        // Bech32 decoding
        data.reserve((bech.second.size() * 5) / 8);
        if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
            CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SaplingIncomingViewingKey ret;
            ss >> ret;
            memory_cleanse(data.data(), data.size());
            return ret;
        }
    }
    return libzcash::InvalidEncoding();
}

std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
{
    return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
}

libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
{
    std::vector<unsigned char> data;
    if (DecodeBase58Check(str, data)) {
        const std::vector<unsigned char>& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
        if ((data.size() == libzcash::SerializedSproutSpendingKeySize + zkey_prefix.size()) &&
            std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
            CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
            CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SproutSpendingKey ret;
            ss >> ret;
            memory_cleanse(serialized.data(), serialized.size());
            memory_cleanse(data.data(), data.size());
            return ret;
        }
    }
    data.clear();
    auto bech = bech32::Decode(str);
    if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
        bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
        // Bech32 decoding
        data.reserve((bech.second.size() * 5) / 8);
        if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) {
            CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
            libzcash::SaplingExtendedSpendingKey ret;
            ss >> ret;
            memory_cleanse(data.data(), data.size());
            return ret;
        }
    }
    memory_cleanse(data.data(), data.size());
    return libzcash::InvalidEncoding();
}

uint160 CCrossChainRPCData::GetConditionID(uint160 cid, int32_t condition)
{
    CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
    hw << condition;
    hw << cid;
    uint256 chainHash = hw.GetHash();
    return Hash160(chainHash.begin(), chainHash.end());
}

uint160 CCrossChainRPCData::GetConditionID(std::string name, int32_t condition)
{
    uint160 parent;
    uint160 cid = CIdentity::GetID(name, parent);

    CHashWriter hw(SER_GETHASH, PROTOCOL_VERSION);
    hw << condition;
    hw << cid;
    uint256 chainHash = hw.GetHash();
    return Hash160(chainHash.begin(), chainHash.end());
}

std::string TrimLeading(const std::string &Name, unsigned char ch)
{
    std::string nameCopy = Name;
    int removeSpaces;
    for (removeSpaces = 0; removeSpaces < nameCopy.size(); removeSpaces++)
    {
        if (nameCopy[removeSpaces] != ch)
        {
            break;
        }
    }
    if (removeSpaces)
    {
        nameCopy.erase(nameCopy.begin(), nameCopy.begin() + removeSpaces);
    }
    return nameCopy;
}

std::string TrimTrailing(const std::string &Name, unsigned char ch)
{
    std::string nameCopy = Name;
    int removeSpaces;
    for (removeSpaces = nameCopy.size() - 1; removeSpaces >= 0; removeSpaces--)
    {
        if (nameCopy[removeSpaces] != ch)
        {
            break;
        }
    }
    nameCopy.resize(nameCopy.size() - ((nameCopy.size() - 1) - removeSpaces));
    return nameCopy;
}

std::string TrimSpaces(const std::string &Name)
{
    return TrimTrailing(TrimLeading(Name, ' '), ' ');
}

// this will add the current Verus chain name to subnames if it is not present
// on both id and chain names
std::vector<std::string> ParseSubNames(const std::string &Name, std::string &ChainOut, bool displayfilter, bool addVerus)
{
    std::string nameCopy = Name;
    std::string invalidChars = "\\/:*?\"<>|";
    if (displayfilter)
    {
        invalidChars += "\n\t\r\b\t\v\f\x1B";
    }
    for (int i = 0; i < nameCopy.size(); i++)
    {
        if (invalidChars.find(nameCopy[i]) != std::string::npos)
        {
            return std::vector<std::string>();
        }
    }

    std::vector<std::string> retNames;
    boost::split(retNames, nameCopy, boost::is_any_of("@"));
    if (!retNames.size() || retNames.size() > 2)
    {
        return std::vector<std::string>();
    }

    bool explicitChain = false;
    if (retNames.size() == 2)
    {
        ChainOut = retNames[1];
        explicitChain = true;
    }

    nameCopy = retNames[0];
    boost::split(retNames, nameCopy, boost::is_any_of("."));

    int numRetNames = retNames.size();

    if (addVerus)
    {
        if (explicitChain)
        {
            std::vector<std::string> chainOutNames;
            boost::split(chainOutNames, ChainOut, boost::is_any_of("."));
            if (boost::to_lower_copy(chainOutNames.back()) != boost::to_lower_copy(VERUS_CHAINNAME))
            {
                chainOutNames.push_back(VERUS_CHAINNAME);
            }
        }
        if (boost::to_lower_copy(retNames.back()) != boost::to_lower_copy(VERUS_CHAINNAME))
        {
            retNames.push_back(VERUS_CHAINNAME);
        }
    }

    for (int i = 0; i < retNames.size(); i++)
    {
        if (retNames[i].size() > KOMODO_ASSETCHAIN_MAXLEN - 1)
        {
            retNames[i] = std::string(retNames[i], 0, (KOMODO_ASSETCHAIN_MAXLEN - 1));
        }
        // spaces are allowed, but no sub-name can have leading or trailing spaces
        if (!retNames[i].size() || retNames[i] != TrimTrailing(TrimLeading(retNames[i], ' '), ' '))
        {
            return std::vector<std::string>();
        }
    }

    // if no explicit chain is specified, default to chain of the ID
    if (!explicitChain && retNames.size())
    {
        for (int i = 1; i < retNames.size(); i++)
        {
            if (ChainOut.size())
            {
                ChainOut = ChainOut + ".";
            }
            ChainOut = ChainOut + retNames[i];
        }
    }

    return retNames;
}

// takes a multipart name, either complete or partially processed with a Parent hash,
// hash its parent names into a parent ID and return the parent hash and cleaned, single name
std::string CleanName(const std::string &Name, uint160 &Parent, bool displayfilter)
{
    std::string chainName;
    std::vector<std::string> subNames = ParseSubNames(Name, chainName);

    if (!subNames.size())
    {
        return "";
    }

    if (!Parent.IsNull() &&
        boost::to_lower_copy(subNames.back()) == boost::to_lower_copy(VERUS_CHAINNAME))
    {
        subNames.pop_back();
    }

    for (int i = subNames.size() - 1; i > 0; i--)
    {
        std::string parentNameStr = boost::algorithm::to_lower_copy(subNames[i]);
        const char *parentName = parentNameStr.c_str();
        uint256 idHash;

        if (Parent.IsNull())
        {
            idHash = Hash(parentName, parentName + parentNameStr.size());
        }
        else
        {
            idHash = Hash(parentName, parentName + strlen(parentName));
            idHash = Hash(Parent.begin(), Parent.end(), idHash.begin(), idHash.end());
        }
        Parent = Hash160(idHash.begin(), idHash.end());
        //printf("uint160 for parent %s: %s\n", parentName, Parent.GetHex().c_str());
    }
    return subNames[0];
}

CNameReservation::CNameReservation(const CTransaction &tx, int *pOutNum)
{
    for (int i = 0; i < tx.vout.size(); i++)
    {
        COptCCParams p;
        if (IsPayToCryptoCondition(tx.vout[i].scriptPubKey, p))
        {
            if (p.evalCode == EVAL_IDENTITY_RESERVATION)
            {
                FromVector(p.vData[0], *this);
                return;
            }
        }
    }
}

CIdentity::CIdentity(const CScript &scriptPubKey)
{
    COptCCParams p;
    if (IsPayToCryptoCondition(scriptPubKey, p) && p.IsValid() && p.evalCode == EVAL_IDENTITY_PRIMARY && p.vData.size())
    {
        *this = CIdentity(p.vData[0]);
    }
}

CIdentityID CIdentity::GetID(const std::string &Name, uint160 &parent)
{
    std::string cleanName = CleanName(Name, parent);

    std::string subName = boost::algorithm::to_lower_copy(cleanName);
    const char *idName = subName.c_str();
    //printf("hashing: %s, %s\n", idName, parent.GetHex().c_str());

    uint256 idHash;
    if (parent.IsNull())
    {
        idHash = Hash(idName, idName + strlen(idName));
    }
    else
    {
        idHash = Hash(idName, idName + strlen(idName));
        idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end());
    }
    return Hash160(idHash.begin(), idHash.end());
}

CIdentityID CIdentity::GetID(const std::string &Name) const
{
    uint160 parent;
    std::string cleanName = CleanName(Name, parent);

    std::string subName = boost::algorithm::to_lower_copy(cleanName);
    const char *idName = subName.c_str();
    //printf("hashing: %s, %s\n", idName, parent.GetHex().c_str());

    uint256 idHash;
    if (parent.IsNull())
    {
        idHash = Hash(idName, idName + strlen(idName));
    }
    else
    {
        idHash = Hash(idName, idName + strlen(idName));
        idHash = Hash(parent.begin(), parent.end(), idHash.begin(), idHash.end());

    }
    return Hash160(idHash.begin(), idHash.end());
}

CIdentityID CIdentity::GetID() const
{
    uint160 Parent = parent;
    return GetID(name, Parent);
}

uint160 CCrossChainRPCData::GetID(std::string name)
{
    uint160 parent;
    //printf("uint160 for name %s: %s\n", name.c_str(), CIdentity::GetID(name, parent).GetHex().c_str());
    return CIdentity::GetID(name, parent);
}

CScript CIdentity::TransparentOutput() const
{
    CConditionObj<CIdentity> ccObj = CConditionObj<CIdentity>(0, std::vector<CTxDestination>({CTxDestination(CIdentityID(GetID()))}), 1);
    return MakeMofNCCScript(ccObj);
}

CScript CIdentity::TransparentOutput(const CIdentityID &destinationID)
{
    CConditionObj<CIdentity> ccObj = CConditionObj<CIdentity>(0, std::vector<CTxDestination>({destinationID}), 1);
    return MakeMofNCCScript(ccObj);
}

CScript CIdentity::IdentityUpdateOutputScript() const
{
    CScript ret;

    if (!IsValid())
    {
        return ret;
    }

    std::vector<CTxDestination> dests1({CTxDestination(CIdentityID(GetID()))});
    CConditionObj<CIdentity> primary(EVAL_IDENTITY_PRIMARY, dests1, 1, this);
    std::vector<CTxDestination> dests2({CTxDestination(CIdentityID(revocationAuthority))});
    CConditionObj<CIdentity> revocation(EVAL_IDENTITY_REVOKE, dests2, 1);
    std::vector<CTxDestination> dests3({CTxDestination(CIdentityID(recoveryAuthority))});
    CConditionObj<CIdentity> recovery(EVAL_IDENTITY_RECOVER, dests3, 1);

    std::vector<CTxDestination> indexDests({CTxDestination(CKeyID(CCrossChainRPCData::GetConditionID(GetID(), EVAL_IDENTITY_PRIMARY))),
                                            IsRevoked() ? CTxDestination(CIdentityID(recoveryAuthority)) : CTxDestination(CIdentityID(revocationAuthority)),
                                            primaryAddresses.size() ? primaryAddresses[0] : CKeyID()});

    ret = MakeMofNCCScript(1, primary, revocation, recovery, &indexDests);
    return ret;
}

max_stars_repo_name: josephnicholas/VerusCoin

max_issues_repo_name: josephnicholas/VerusCoin

max_forks_repo_name: josephnicholas/VerusCoin