#include "denominator.hpp"
#include "ast.hpp"
#include "parsers.hpp"
#include "types.hpp"
#include <boost/variant.hpp>
#include <stdexcept>
namespace HT
{
    void denominator(PASTNode astnode, ParsersHelper& ph)
    {
        auto myParserHelper(ph);
        if (astnode->ch.size()!=2)
          throw std::runtime_error("denominator can only have one parameter");
        auto & secondCh = *astnode->ch.rbegin();
        ph.parse(secondCh);
        if (secondCh->token.tokenType != Complex || ! boost::get<ComplexType>(secondCh->token.info).isReal())
          throw std::runtime_error("The argument of denominator must be real");
        auto cast = boost::get<ComplexType>(secondCh->token.info);

        astnode->token.tokenType = Complex;
        astnode->type = Simple;
        astnode->token.info = ComplexType(cast.toexact().getRealR().getDown());

        astnode->remove();
    }

}


#include <boost/test/unit_test.hpp>

#include <set>
#include <iostream>

// using namespace std;
using namespace crave;

BOOST_FIXTURE_TEST_SUITE(Operators_t, Context_Fixture)

BOOST_AUTO_TEST_CASE(logical_not_t1) {
  Variable<unsigned int> a;
  Generator gen;
  gen(!(a != 0));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[a], 0);
}

BOOST_AUTO_TEST_CASE(logical_not_t2) {
  Variable<unsigned char> a;
  Variable<unsigned int> b;
  Generator gen;

  gen(if_then_else(!(a % 2 == 0), b > 0 && b <= 50, b > 50 && b <= 100));

  BOOST_REQUIRE(gen.next());
  std::cout << "a =" << gen[a] << ", b = " << gen[b] << std::endl;
  if (gen[a] % 2 != 0) {
    BOOST_REQUIRE_GT(gen[b], 0u);
    BOOST_REQUIRE_LE(gen[b], 50u);
  } else {
    BOOST_REQUIRE_GT(gen[b], 50u);
    BOOST_REQUIRE_LE(gen[b], 100u);
  }
}

BOOST_AUTO_TEST_CASE(logical_and_t1) {
  Variable<bool> a;
  Variable<bool> b;
  Variable<bool> c;
  Generator gen(a == true);
  gen(b == true);

  BOOST_REQUIRE(gen.next());
  gen(c == (a && b));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[c], true);

  Generator gen2(a == true);
  gen2(b == false);

  BOOST_REQUIRE(gen2.next());
  gen2(c == (a && b));

  BOOST_REQUIRE(gen2.next());
  BOOST_REQUIRE_EQUAL(gen2[c], false);
}

BOOST_AUTO_TEST_CASE(logical_or_t1) {
  Variable<bool> a;
  Variable<bool> b;
  Variable<bool> c;
  Generator gen(a == false);
  gen(b == false);

  BOOST_REQUIRE(gen.next());
  gen(c == (a || b));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[c], false);

  Generator gen2(a == true);
  gen2(b == false);

  BOOST_REQUIRE(gen2.next());
  gen2(c == (a || b));

  BOOST_REQUIRE(gen2.next());
  BOOST_REQUIRE_EQUAL(gen2[c], true);
}

BOOST_AUTO_TEST_CASE(equal_t1) {
  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Generator gen(a == 65535);
  gen(b == a);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[a], gen[b]);
}

BOOST_AUTO_TEST_CASE(not_equal_t1) {
  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Generator gen(a < 65535);
  gen(b != a);

  for (int i = 0; i < 300; ++i) {
    BOOST_REQUIRE(gen.next());
    BOOST_REQUIRE_NE(gen[a], gen[b]);
  }
}

BOOST_AUTO_TEST_CASE(less) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;

  Generator gen;
  gen(a < 256u);

  std::set<unsigned> generated;
  for (unsigned iterations = 0; gen.next(); ++iterations) {
    unsigned av = gen[a];
    generated.insert(av);
    gen(a != av);
    BOOST_REQUIRE_LT(iterations, 300);
  }

  BOOST_REQUIRE_EQUAL(generated.size(), 256);

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(less_equal) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;

  Generator gen;
  gen(a <= 256u);

  std::set<unsigned> generated;
  for (unsigned iterations = 0; gen.next(); ++iterations) {
    unsigned av = gen[a];
    generated.insert(av);
    gen(a != av);
    BOOST_REQUIRE_LT(iterations, 300);
  }

  BOOST_REQUIRE_EQUAL(generated.size(), 257);

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(greater) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;

  Generator gen;
  gen(a > (std::numeric_limits<unsigned>::max() - 256));

  std::set<unsigned> generated;
  for (unsigned iterations = 0; gen.next(); ++iterations) {
    unsigned av = gen[a];
    generated.insert(av);
    gen(a != av);
    BOOST_REQUIRE_LT(iterations, 300);
  }

  BOOST_REQUIRE_EQUAL(generated.size(), 256);

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(greater_equal) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;

  Generator gen;
  gen(a >= (std::numeric_limits<unsigned>::max() - 256));

  std::set<unsigned> generated;
  for (unsigned iterations = 0; gen.next(); ++iterations) {
    unsigned av = gen[a];
    generated.insert(av);
    gen(a != av);
    BOOST_REQUIRE_LT(iterations, 300);
  }

  BOOST_REQUIRE_EQUAL(generated.size(), 257);

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(neg_t1) {
  Variable<int> a;
  Variable<int> b;
  Generator gen(a == -1337);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[a], -1337);
  gen(b == -a);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[b], 1337);
}

BOOST_AUTO_TEST_CASE(neg_t2) {
  Variable<bool> a;
  Variable<int> b;
  Variable<int> c;
  Variable<int> d;
  Generator gen(dist(a, distribution<bool>::create(0.5)));
  gen(b == 1337 && c == 42);
  gen(if_then_else(a, d == -b, d == -c));

  for (int i = 0; i < 50; ++i) {
    BOOST_REQUIRE(gen.next());
    if (gen[a])
      BOOST_REQUIRE_EQUAL(gen[d], -1337);
    else
      BOOST_REQUIRE_EQUAL(gen[d], -42);
  }
}

BOOST_AUTO_TEST_CASE(complement_t1) {
  Variable<int> a;
  Variable<int> b;
  Generator gen(a == 0);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[a], 0);
  gen(b == ~a);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[b], -1);
}

BOOST_AUTO_TEST_CASE(bitwise_and_t1) {
  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Variable<unsigned int> c;
  Generator gen(a == 42);
  gen(b == 1337);

  BOOST_REQUIRE(gen.next());
  gen(c == (a & b));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[c], 40);
}

BOOST_AUTO_TEST_CASE(bitwise_or_t1) {
  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Variable<unsigned int> c;
  Generator gen(a == 42);
  gen(b == 1337);

  BOOST_REQUIRE(gen.next());
  gen(c == (a | b));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[c], 1339);
}

BOOST_AUTO_TEST_CASE(bitwise_xor_t1) {
  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Variable<unsigned int> c;
  Generator gen(a == 65535);
  gen(b == 4080);

  BOOST_REQUIRE(gen.next());
  gen(c == (a ^ b));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL(gen[c], 61455);
}

BOOST_AUTO_TEST_CASE(shiftleft) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;
  Variable<unsigned> b;
  Variable<unsigned> c;

  Generator gen;
  gen(a < 256u)(b < (unsigned)(sizeof(unsigned) * 8u))(c == (a << b));

  int count = 0;
  int max_count = 200;
  while (gen.next() && ++count < max_count) {
    unsigned av = gen[a];
    unsigned bv = gen[b];
    unsigned r = av << bv;

    BOOST_REQUIRE_EQUAL(r, gen[c]);

    gen(a != gen[a] || b != gen[b]);
  }

  VariableDefaultSolver::bypass_constraint_analysis = false;
  BOOST_REQUIRE_EQUAL(count, max_count);
}

BOOST_AUTO_TEST_CASE(shiftright) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned> a;
  Variable<unsigned> b;
  Variable<unsigned> c;

  Generator gen;
  gen(a > 256u)(b < 8u)(c == (a >> b));

  int count = 0;
  int max_count = 300;
  while (gen.next() && ++count < max_count) {
    unsigned av = gen[a];
    unsigned bv = gen[b];
    unsigned r = av >> bv;

    BOOST_REQUIRE_EQUAL(r, gen[c]);

    gen(a != gen[a] || b != gen[b]);
  }

  VariableDefaultSolver::bypass_constraint_analysis = false;
  BOOST_REQUIRE_EQUAL(count, max_count);
}

BOOST_AUTO_TEST_CASE(plus_minus) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned int> a;
  Variable<unsigned int> b;
  Variable<unsigned int> q;
  Variable<unsigned int> r;

  Generator gen;
  gen(b != 0u)(b < a)(q == a + b)(r == a - b);

  unsigned int cnt = 0u;
  while (gen.next() && cnt < 300) {
    BOOST_REQUIRE_EQUAL(gen[a] + gen[b], gen[q]);
    BOOST_REQUIRE_EQUAL(gen[a] - gen[b], gen[r]);

    gen(a != gen[a] || b != gen[b]);
    std::cout << "#" << cnt++ << ": result: a=" << gen[a] << ", b=" << gen[b] << ", q=" << gen[q] << ", r=" << gen[r]
              << "\n" << std::endl;
  }

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(mult_mod) {
  Variable<int> a;
  Variable<int> b;

  Generator gen;
  gen(-3 <= a && a <= 3)(-3 <= b && b <= 3)(a * b % 6 == 0);

  int cnt = 0;
  for (int i = -3; i <= 3; i++)
    for (int j = -3; j <= 3; j++)
      if (i * j % 6 == 0) cnt++;

  int cnt1 = 0;
  while (gen.next()) {
    cnt1++;
    BOOST_REQUIRE_EQUAL(gen[a] * gen[b] % 6, 0);
    gen(a != gen[a] || b != gen[b]);
    std::cout << "result: a1=" << gen[a] << ", b1=" << gen[b] << "\n" << std::endl;
    BOOST_REQUIRE_LE(cnt1, cnt);
  }

  BOOST_REQUIRE_EQUAL(cnt, cnt1);
}

BOOST_AUTO_TEST_CASE(divide) {
  VariableDefaultSolver::bypass_constraint_analysis = true;

  Variable<unsigned char> a;
  Variable<unsigned char> b;
  Variable<unsigned char> q;
  Variable<unsigned char> r;

  Generator gen;
  gen(b != (unsigned char)0u)(a < (unsigned char)16u)(b < (unsigned char)16u)(q == a / b)(r == a % b);

  while (gen.next()) {
    BOOST_REQUIRE_EQUAL(gen[a] / gen[b], gen[q]);
    BOOST_REQUIRE_EQUAL(gen[a] % gen[b], gen[r]);

    gen(a != gen[a] || b != gen[b]);
    std::cout << "result: a=" << gen[a] << ", b=" << gen[b] << ", q=" << gen[q] << ", r=" << gen[r] << "\n"
              << std::endl;
  }

  VariableDefaultSolver::bypass_constraint_analysis = false;
}

BOOST_AUTO_TEST_CASE(element_inside_set) {
  std::set<unsigned> s;
  s.insert(1);
  s.insert(7);
  s.insert(9);

  Variable<unsigned> x;

  Generator gen;
  gen(inside(x, s));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(s.find(gen[x]) != s.end());

  unsigned first = gen[x];
  gen(x != first);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(s.find(gen[x]) != s.end());

  unsigned second = gen[x];
  BOOST_REQUIRE_NE(first, second);
  gen(x != second);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(s.find(gen[x]) != s.end());

  unsigned third = gen[x];
  BOOST_REQUIRE_NE(third, second);
  BOOST_REQUIRE_NE(first, third);
  gen(x != third);

  BOOST_REQUIRE(!gen.next());
}

BOOST_AUTO_TEST_CASE(element_inside_vec) {
  std::vector<unsigned> v;
  v.push_back(1);
  v.push_back(7);
  v.push_back(9);

  Variable<unsigned> x;

  Generator gen;
  gen(inside(x, v));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(v.begin(), v.end(), gen[x]) != v.end());

  unsigned first = gen[x];
  gen(x != first);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(v.begin(), v.end(), gen[x]) != v.end());

  unsigned second = gen[x];
  BOOST_REQUIRE_NE(first, second);
  gen(x != second);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(v.begin(), v.end(), gen[x]) != v.end());

  unsigned third = gen[x];
  BOOST_REQUIRE_NE(third, second);
  BOOST_REQUIRE_NE(first, third);
  gen(x != third);

  BOOST_REQUIRE(!gen.next());
}

BOOST_AUTO_TEST_CASE(element_inside_array) {
  unsigned a[3];
  a[0] = 1;
  a[1] = 7;
  a[2] = 9;

  Variable<unsigned> x;
  Generator gen;
  gen(inside(x, a));

  BOOST_REQUIRE(gen.next());

  unsigned first = gen[x];
  gen(x != first);

  BOOST_REQUIRE(gen.next());

  unsigned second = gen[x];
  BOOST_REQUIRE_NE(first, second);
  gen(x != second);

  BOOST_REQUIRE(gen.next());
  unsigned third = gen[x];
  BOOST_REQUIRE_NE(third, second);
  BOOST_REQUIRE_NE(first, third);
  gen(x != third);

  BOOST_REQUIRE(!gen.next());
}

BOOST_AUTO_TEST_CASE(element_inside_list) {
  std::list<unsigned> l;
  l.push_back(1);
  l.push_back(7);
  l.push_back(9);

  Variable<unsigned> x;

  Generator gen;
  gen(inside(x, l));

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(l.begin(), l.end(), gen[x]) != l.end());

  unsigned first = gen[x];
  gen(x != first);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(l.begin(), l.end(), gen[x]) != l.end());

  unsigned second = gen[x];
  BOOST_REQUIRE_NE(first, second);
  gen(x != second);

  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE(find(l.begin(), l.end(), gen[x]) != l.end());

  unsigned third = gen[x];
  BOOST_REQUIRE_NE(third, second);
  BOOST_REQUIRE_NE(first, third);
  gen(x != third);

  BOOST_REQUIRE(!gen.next());
}

BOOST_AUTO_TEST_CASE(element_not_inside) {
  {
    std::set<unsigned> s;

    Variable<unsigned> x;

    Generator gen;
    gen(inside(x, s));

    BOOST_REQUIRE(!gen.next());
  }
  {
    std::vector<unsigned> v;

    Variable<unsigned> x;

    Generator gen;
    gen(inside(x, v));

    BOOST_REQUIRE(!gen.next());
  }
  {
    std::vector<unsigned> l;

    Variable<unsigned> x;

    Generator gen;
    gen(inside(x, l));

    BOOST_REQUIRE(!gen.next());
  }
}

BOOST_AUTO_TEST_CASE(if_then_else_t1) {
  unsigned int a;
  Variable<unsigned int> b;
  Generator gen;

  gen(if_then_else(reference(a)<5, b> 0 && b <= 50, b > 50 && b <= 100));

  for (a = 0; a < 10; ++a) {
    BOOST_REQUIRE(gen.next());
    std::cout << "a =" << a << ", b = " << gen[b] << std::endl;
    if (a < 5) {
      BOOST_REQUIRE_GT(gen[b], 0);
      BOOST_REQUIRE_LE(gen[b], 50);
    } else {
      BOOST_REQUIRE_GT(gen[b], 50);
      BOOST_REQUIRE_LE(gen[b], 100);
    }
  }
}

BOOST_AUTO_TEST_CASE(if_then_t1) {
  unsigned int a;
  Variable<unsigned int> b;
  Generator gen;

  gen(if_then(reference(a)<5, b> 0 && b <= 100));
  gen(if_then(reference(a) >= 5, b > 100 && b <= 1000));

  for (a = 0; a < 10; ++a) {
    BOOST_REQUIRE(gen.next());
    std::cout << "a =" << a << ", b = " << gen[b] << std::endl;
    if (a < 5) {
      BOOST_REQUIRE_GT(gen[b], 0);
      BOOST_REQUIRE_LE(gen[b], 100);
    } else {
      BOOST_REQUIRE_GT(gen[b], 100);
      BOOST_REQUIRE_LE(gen[b], 1000);
    }
  }
}

BOOST_AUTO_TEST_CASE(bitslice_t) {
  Variable<short> x;

  Generator gen;
  gen(bitslice(10, 3, x) == 0xFF);
  BOOST_REQUIRE(gen.next());
  BOOST_REQUIRE_EQUAL((gen[x] >> 3) & 0xFF, 0xFF);

  BOOST_REQUIRE_THROW(gen(bitslice(3, 10, x) == 0xFF), std::runtime_error);
  BOOST_REQUIRE_THROW(gen(bitslice(16, 3, x) == 0xFF), std::runtime_error);
}

BOOST_AUTO_TEST_SUITE_END()  // Context


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

// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.

// This file was modified by Oracle on 2014, 2015.
// Modifications copyright (c) 2014-2015 Oracle and/or its affiliates.

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

// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

#include "test_within.hpp"

#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/multi_point.hpp>
#include <boost/geometry/geometries/multi_linestring.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>

template <typename P>
void test_all()
{
    typedef bg::model::box<P> box_type;

    test_geometry<P, box_type>("POINT(1 1)", "BOX(0 0,2 2)", true);
    test_geometry<P, box_type>("POINT(0 0)", "BOX(0 0,2 2)", false);
    test_geometry<P, box_type>("POINT(2 2)", "BOX(0 0,2 2)", false);
    test_geometry<P, box_type>("POINT(0 1)", "BOX(0 0,2 2)", false);
    test_geometry<P, box_type>("POINT(1 0)", "BOX(0 0,2 2)", false);

    test_geometry<box_type, box_type>("BOX(1 1,2 2)", "BOX(0 0,3 3)", true);
    test_geometry<box_type, box_type>("BOX(0 0,3 3)", "BOX(1 1,2 2)", false);

    test_geometry<box_type, box_type>("BOX(1 1,3 3)", "BOX(0 0,3 3)", true);
    test_geometry<box_type, box_type>("BOX(3 1,3 3)", "BOX(0 0,3 3)", false);

    /*
    test_within_code<P, box_type>("POINT(1 1)", "BOX(0 0,2 2)", 1);
    test_within_code<P, box_type>("POINT(1 0)", "BOX(0 0,2 2)", 0);
    test_within_code<P, box_type>("POINT(0 1)", "BOX(0 0,2 2)", 0);
    test_within_code<P, box_type>("POINT(0 3)", "BOX(0 0,2 2)", -1);
    test_within_code<P, box_type>("POINT(3 3)", "BOX(0 0,2 2)", -1);

    test_within_code<box_type, box_type>("BOX(1 1,2 2)", "BOX(0 0,3 3)", 1);
    test_within_code<box_type, box_type>("BOX(0 1,2 2)", "BOX(0 0,3 3)", 0);
    test_within_code<box_type, box_type>("BOX(1 0,2 2)", "BOX(0 0,3 3)", 0);
    test_within_code<box_type, box_type>("BOX(1 1,2 3)", "BOX(0 0,3 3)", 0);
    test_within_code<box_type, box_type>("BOX(1 1,3 2)", "BOX(0 0,3 3)", 0);
    test_within_code<box_type, box_type>("BOX(1 1,3 4)", "BOX(0 0,3 3)", -1);
    */
}

template <typename Point>
void test_spherical()
{
    // Test spherical boxes
    // See also http://www.gcmap.com/mapui?P=1E45N-19E45N-19E55N-1E55N-1E45N,10E55.1N,10E45.1N
    bg::model::box<Point> box;
    bg::read_wkt("POLYGON((1 45,19 55))", box);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 55.1), box), true);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 55.2), box), true);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 55.3), box), true);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 55.4), box), false);

    BOOST_CHECK_EQUAL(bg::within(Point(10, 45.1), box), false);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 45.2), box), false);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 45.3), box), false);
    BOOST_CHECK_EQUAL(bg::within(Point(10, 45.4), box), true);

    // Crossing the dateline (Near Tuvalu)
    // http://www.gcmap.com/mapui?P=178E10S-178W10S-178W6S-178E6S-178E10S,180W5.999S,180E9.999S
    // http://en.wikipedia.org/wiki/Tuvalu

    bg::model::box<Point> tuvalu(Point(178, -10), Point(-178, -6));
    BOOST_CHECK_EQUAL(bg::within(Point(180, -8), tuvalu), true);
    BOOST_CHECK_EQUAL(bg::within(Point(-180, -8), tuvalu), true);
    BOOST_CHECK_EQUAL(bg::within(Point(180, -5.999), tuvalu), false);
    BOOST_CHECK_EQUAL(bg::within(Point(180, -10.001), tuvalu), true);
}

void test_3d()
{
    typedef boost::geometry::model::point<double, 3, boost::geometry::cs::cartesian> point_type;
    typedef boost::geometry::model::box<point_type> box_type;
    box_type box(point_type(0, 0, 0), point_type(4, 4, 4));
    BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 2), box), true);
    BOOST_CHECK_EQUAL(bg::within(point_type(2, 4, 2), box), false);
    BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 4), box), false);
    BOOST_CHECK_EQUAL(bg::within(point_type(2, 2, 5), box), false);

    box_type box2(point_type(2, 2, 2), point_type(3, 3, 3));
    BOOST_CHECK_EQUAL(bg::within(box2, box), true);

}

template <typename P1, typename P2>
void test_mixed_of()
{
    typedef boost::geometry::model::polygon<P1> polygon_type1;
    typedef boost::geometry::model::polygon<P2> polygon_type2;
    typedef boost::geometry::model::box<P1> box_type1;
    typedef boost::geometry::model::box<P2> box_type2;

    polygon_type1 poly1;
    polygon_type2 poly2;
    boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly1);
    boost::geometry::read_wkt("POLYGON((0 0,0 5,5 5,5 0,0 0))", poly2);

    box_type1 box1(P1(1, 1), P1(4, 4));
    box_type2 box2(P2(0, 0), P2(5, 5));
    P1 p1(3, 3);
    P2 p2(3, 3);

    BOOST_CHECK_EQUAL(bg::within(p1, poly2), true);
    BOOST_CHECK_EQUAL(bg::within(p2, poly1), true);
    BOOST_CHECK_EQUAL(bg::within(p2, box1), true);
    BOOST_CHECK_EQUAL(bg::within(p1, box2), true);
    BOOST_CHECK_EQUAL(bg::within(box1, box2), true);
    BOOST_CHECK_EQUAL(bg::within(box2, box1), false);
}

void test_mixed()
{
    // Mixing point types and coordinate types
    test_mixed_of
        <
            boost::geometry::model::d2::point_xy<double>,
            boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>
        >();
    test_mixed_of
        <
            boost::geometry::model::d2::point_xy<float>,
            boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>
        >();
    test_mixed_of
        <
            boost::geometry::model::d2::point_xy<int>,
            boost::geometry::model::d2::point_xy<double>
        >();
}

void test_strategy()
{
    // Test by explicitly specifying a strategy
    typedef bg::model::d2::point_xy<double> point_type;
    typedef bg::model::box<point_type> box_type;
    point_type p(3, 3);
    box_type b(point_type(0, 0), point_type(5, 5));
    box_type b0(point_type(0, 0), point_type(5, 0));

    bool r = bg::within(p, b,
        bg::strategy::within::point_in_box<point_type, box_type>());
    BOOST_CHECK_EQUAL(r, true);

    r = bg::within(b, b,
        bg::strategy::within::box_in_box<box_type, box_type>());
    BOOST_CHECK_EQUAL(r, true);

    r = bg::within(b0, b0,
        bg::strategy::within::box_in_box<box_type, box_type>());
    BOOST_CHECK_EQUAL(r, false);

    r = bg::within(p, b,
        bg::strategy::within::point_in_box_by_side<point_type, box_type>());
    BOOST_CHECK_EQUAL(r, true);
}

int test_main( int , char* [] )
{
    test_all<bg::model::d2::point_xy<int> >();
    test_all<bg::model::d2::point_xy<double> >();

    test_spherical<bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree> > >();

    test_mixed();
    test_3d();
    test_strategy();

#if defined(HAVE_TTMATH)
    test_all<bg::model::d2::point_xy<ttmath_big> >();
    test_spherical<bg::model::point<ttmath_big, 2, bg::cs::spherical_equatorial<bg::degree> > >();
#endif

    return 0;
}


#pragma once

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

#include "../../geometry/LineSegment/LineSegment2/LineSegment2i/linesegment2i.hh"
#include "../linefinder.hh"

namespace bold
{
  template<typename> class Setting;

  class MaskWalkLineFinder : public LineFinder
  {
  public:
    MaskWalkLineFinder();

    void walkLine(Eigen::Vector2i const& start, float theta, bool forward, std::function<bool(int/*x*/,int/*y*/)> const& callback, uchar width = 1);

    std::vector<LineSegment2i> findLineSegments(std::vector<Eigen::Vector2i>& lineDots) override;

  private:
    void rebuild();

    // configuration options
    Setting<double>* d_drThreshold;
    Setting<double>* d_dtThresholdDegs;
    Setting<int>* d_voteThreshold;
    Setting<int>* d_minLineLength;
    Setting<int>* d_maxLineGap;
    Setting<int>* d_maxLineSegmentCount;

    // constant
    const int d_imageWidth;
    const int d_imageHeight;

    // cached
    cv::Mat d_mask;
    cv::Mat d_accumulator;

    // calculated
    int d_tSteps;
    int d_rSteps;
    std::vector<float> d_trigTable;
  };
}


//  Copyright (C) Toon Knapen 2003
//
//  Permission to copy, use, modify, sell and
//  distribute this software is granted provided this copyright notice appears
//  in all copies. This software is provided "as is" without express or implied
//  warranty, and with no claim as to its suitability for any purpose.

#ifndef BOOST_NUMERIC_BINDINGS_BLAS_BLAS1_OVERLOADS_HPP
#define BOOST_NUMERIC_BINDINGS_BLAS_BLAS1_OVERLOADS_HPP

#include <boost/numeric/bindings/blas/blas.h>
#include <boost/numeric/bindings/traits/type.hpp>
#include <boost/numeric/bindings/traits/type_traits.hpp>

namespace boost { namespace numeric { namespace bindings { namespace blas { namespace detail {

  using namespace boost::numeric::bindings::traits ;

  // x *= alpha
  inline void scal(const int& n, const float&     alpha, float*     x, const int& incx) { BLAS_SSCAL( &n,              &alpha,                x  , &incx ) ; }
  inline void scal(const int& n, const double&    alpha, double*    x, const int& incx) { BLAS_DSCAL( &n,              &alpha,                x  , &incx ) ; }
  inline void scal(const int& n, const complex_f& alpha, complex_f* x, const int& incx) { BLAS_CSCAL( &n, complex_ptr( &alpha ), complex_ptr( x ), &incx ) ; }
  inline void scal(const int& n, const complex_d& alpha, complex_d* x, const int& incx) { BLAS_ZSCAL( &n, complex_ptr( &alpha ), complex_ptr( x ), &incx ) ; }

  // y += alpha * x
  inline void axpy(const int& n, const float    & alpha, const float    * x, const int& incx, float    * y, const int& incy) { BLAS_SAXPY( &n,            &alpha  ,            x  , &incx,            y  , &incy ) ; }
  inline void axpy(const int& n, const double   & alpha, const double   * x, const int& incx, double   * y, const int& incy) { BLAS_DAXPY( &n,            &alpha  ,            x  , &incx,            y  , &incy ) ; }
  inline void axpy(const int& n, const complex_f& alpha, const complex_f* x, const int& incx, complex_f* y, const int& incy) { BLAS_CAXPY( &n, complex_ptr( &alpha ), complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }
  inline void axpy(const int& n, const complex_d& alpha, const complex_d* x, const int& incx, complex_d* y, const int& incy) { BLAS_ZAXPY( &n, complex_ptr( &alpha ), complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }

  // x^T . y
  inline float  dot(const int& n, const float * x, const int& incx, const float * y, const int& incy) { return BLAS_SDOT( &n, x, &incx, y, &incy ) ; }
  inline double dot(const int& n, const double* x, const int& incx, const double* y, const int& incy) { return BLAS_DDOT( &n, x, &incx, y, &incy ) ; }

  // x^T . y
  inline void dotu(complex_f& ret, const int& n, const complex_f* x, const int& incx, const complex_f* y, const int& incy) { BLAS_CDOTU( complex_ptr( &ret ), &n, complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }
  inline void dotu(complex_d& ret, const int& n, const complex_d* x, const int& incx, const complex_d* y, const int& incy) { BLAS_ZDOTU( complex_ptr( &ret ), &n, complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }

  // x^H . y
  inline void dotc(complex_f& ret, const int& n, const complex_f* x, const int& incx, const complex_f* y, const int& incy) { BLAS_CDOTC( complex_ptr( &ret ), &n, complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }
  inline void dotc(complex_d& ret, const int& n, const complex_d* x, const int& incx, const complex_d* y, const int& incy) { BLAS_ZDOTC( complex_ptr( &ret ), &n, complex_ptr( x ), &incx, complex_ptr( y ), &incy ) ; }

  // euclidean norm
  inline float  nrm2(const int& n, const float*   x, const int& incx) { return BLAS_SNRM2( &n, x, &incx ) ; }
  inline double nrm2(const int& n, const double*  x, const int& incx) { return BLAS_DNRM2( &n, x, &incx ) ; }
  inline float  nrm2(const int& n, const complex_f*   x, const int& incx) { return BLAS_SCNRM2( &n, complex_ptr(x), &incx ) ; }
  inline double nrm2(const int& n, const complex_d*  x, const int& incx) { return BLAS_DZNRM2( &n, complex_ptr(x), &incx ) ; }

  // 1-norm
  inline float  asum(const int& n, const float*   x, const int& incx) { return BLAS_SASUM( &n, x, &incx ) ; }
  inline double asum(const int& n, const double*  x, const int& incx) { return BLAS_DASUM( &n, x, &incx ) ; }
  inline float  asum(const int& n, const complex_f*   x, const int& incx) { return BLAS_SCASUM( &n, complex_ptr(x), &incx ) ; }
  inline double asum(const int& n, const complex_d*  x, const int& incx) { return BLAS_DZASUM( &n, complex_ptr(x), &incx ) ; }

}}}}}

#endif // BOOST_NUMERIC_BINDINGS_BLAS_BLAS1_OVERLOADS_HPP


#include <sparse.h>

#include <sparse_fill.h>

#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>

BOOST_AUTO_TEST_SUITE(SPARSE);

BOOST_AUTO_TEST_CASE(fale_transpose_test)
{
  typedef sparse::Block<4,6,float> block_type;
	typedef sparse::TwoColumnMatrix<block_type>  tcm_type;
	typedef sparse::CompressedRowMatrix<block_type>   crm_type;

	tcm_type J(1, 2, 2);
	block_type b1;
	block_type b2;

  sparse::fill(b1, 1.0f);
  sparse::fill(b2, 2.0f);
	J(0,0) = b1;
	J(0,1) = b2;

	crm_type JT;
  sparse::fake_transpose(J, JT);
	BOOST_CHECK( JT.size() == 2         );
	BOOST_CHECK( JT.nrows() == J.ncols());
	BOOST_CHECK( JT.ncols() == J.nrows());
	BOOST_CHECK( JT(0,0) == J(0,0)      );
  BOOST_CHECK( JT(1,0) == J(0,1)      );

	J.resize(2,4,4);
	block_type b3;
  block_type b4;

  sparse::fill(b3, 3.0f);
  sparse::fill(b4, 4.0f);

  J(1,0) = b1;
  J(1,3) = b2;
  sparse::fake_transpose(J, JT);

  BOOST_CHECK(JT.size() == 4);
  BOOST_CHECK(JT.nrows() == J.ncols());
  BOOST_CHECK(JT.ncols() == J.nrows());
  BOOST_CHECK(JT(0,0) == J(0,0));
  BOOST_CHECK(JT(1,0) == J(0,1));
  BOOST_CHECK(JT(0,1) == J(1,0));
  BOOST_CHECK(JT(3,1) == J(1,3));

}

BOOST_AUTO_TEST_SUITE_END();


#ifndef STAN_MATH_PRIM_SCAL_FUN_FDIM_HPP
#define STAN_MATH_PRIM_SCAL_FUN_FDIM_HPP

#include <stan/math/prim/scal/fun/is_nan.hpp>
#include <boost/math/tools/promotion.hpp>
#include <limits>

namespace stan {
  namespace math {

    /**
     * Return the positive difference of the specified values (C++11).
     *
     * The function is defined by
     *
     * fdim(x, y) = (x > y) ? (x - y) : 0.
     *
     * @param x First value.
     * @param y Second value.
     * @return max(x- y, 0)
     */
    template <typename T1, typename T2>
    inline typename boost::math::tools::promote_args<T1, T2>::type
    fdim(T1 x, T2 y) {
      typedef typename boost::math::tools::promote_args<T1, T2>::type return_t;
      using std::numeric_limits;
      if (is_nan(x) || is_nan(y))
        return numeric_limits<return_t>::quiet_NaN();
      return (x <= y) ? 0 : x - y;
    }

  }
}
#endif


/*
 * Copyright (c) 2015 Claus Christmann <hcc |ä| gatech.edu>.
 *
 * Licensed under the Apache Lice*nse, 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 <Eigen/Geometry>
#include <Eigen/Dense>

#include <iostream>
#include <cmath>

#include "amg.hpp"

using namespace Eigen;

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

  using namespace AMG;

  FrameOfReference* ecef = new FrameOfReference;
  CoSy::setECEF(ecef);

  { std::cout << "\nWGS 84:\n"
              <<   "=======" << std::endl;

    using namespace AMG::GIS;

    std::cout
    << "WGS84\n"
    << "|- a     : " << WGS84::a << "\n"
    << "|- finv  : " << WGS84::finv << "\n"
    << "|- omega : " << WGS84::omega << "\n"
    << "|- GM    : " << WGS84::GM << "\n"
    << "|\n"
    << "|- f     : " << WGS84::f << "\n"
    << "|- b     : " << WGS84::b << "\n"
    << "|- e2    : " << WGS84::e2 << "\n"
    << "|- ep2   : " << WGS84::ep2 << "\n"
    << "|- g0    : " << WGS84::g0 << "\n"
    << std::endl;

  }

  { std::cout << "\nGeodetic to ECEF conversions:\n"
              <<   "=============================" << std::endl;

    auto g2e = [] (double lat_deg, double lon_deg, double alt_m)
    {
      double x_ecef, y_ecef, z_ecef;

      GIS::geodetic2ecef(Units::degree2radian(lon_deg),
                        Units::degree2radian( lat_deg),
                        alt_m,x_ecef,y_ecef,z_ecef);

      std::cout << "Lat,Lon,Alt :" << lat_deg << ", "
                                   << lon_deg << ", "
                                   << alt_m   << "\n"
                << "X,Y,Z       :" << x_ecef << ", " << y_ecef << ", " << z_ecef
      << std::endl;
    };

    g2e(0,0,0);
    g2e(0,0,1000);
    g2e(45,45,0);
    g2e(90,90,0);
    g2e(33.772022,-84.396188,0);
  }

  { std::cout << "\nECEF to Geodetic conversions:\n"
              <<   "=============================" << std::endl;

    auto e2g = [] (double x_ecef, double y_ecef, double z_ecef)
    {
      double lat_rad, lon_rad, alt_m;

      GIS::ecef2geodetic( x_ecef,y_ecef,z_ecef,lon_rad,lat_rad,alt_m);

      std::cout << "X,Y,Z       :" << x_ecef << ", " << y_ecef << ", " << z_ecef << "\n"
                << "Lat,Lon,Alt :" << Units::radian2degree(lat_rad) << ", "
                                   << Units::radian2degree(lon_rad) << ", "
                                   << alt_m
      << std::endl;
    };

    e2g(518259,-5.28199e+06, 3.52545e+06);

  }

  FrameOfReference* datum = CoSy::newNorthEastDown<Units::degree>( -84.396188, 33.772022 );
  CoSy::setDatumFrame(datum);
  datum->outputRelativePositionToParent();
  std::cout
    << "Datum attitude (roll, pitch, yaw; in degrees) : "
    << datum->attitude<Units::degree>().transpose() << "\n"
    << std::endl;

  double x_ecef,y_ecef,z_ecef;

  GIS::geodetic2ecef(Units::degree2radian(-84.396188),
                      Units::degree2radian( 33.772022),
                      0,x_ecef,y_ecef,z_ecef);
  Vector southCorner(x_ecef,y_ecef,z_ecef,CoSy::getECEF());

  double lat,lon,alt;
  GIS::ecef2geodetic(southCorner.coords(0),southCorner.coords(1),southCorner.coords(2),
                     lon,lat,alt);

  std::cout
  << "South Corner in Lat, Lon, Alt  : " << Units::radian2degree(lat) << ", "
                                         << Units::radian2degree(lon) << ", "
                                         << alt << "\n"
  << "South Corner in ECEF           : "
  << southCorner.coords().transpose() << "\n"
  << "South Corner in absolute Datum : "
  << southCorner.absoluteCoordsIn(datum).transpose() << "\n"
  << std::endl;

  std::cout << AMG::GIS::geodeticPositionString(southCorner) << std::endl;

  GIS::geodetic2ecef(Units::degree2radian(-84.396188),
                      Units::degree2radian( 33.772111),
                      0,x_ecef,y_ecef,z_ecef);
  Vector northCorner(x_ecef,y_ecef,z_ecef,CoSy::getECEF());
  std::cout
  << "North Corner in ECEF           : "
  << northCorner.coords().transpose() << "\n"
  << "North Corner in absolute Datum : "
  << northCorner.absoluteCoordsIn(datum).transpose() << "\n"
  << std::endl;

  std::cout << AMG::GIS::geodeticPositionString(northCorner) << std::endl;

  Vector delta = northCorner - southCorner;

  std::cout
  << "Delta Corner in ECEF           : "
  << delta.coords().transpose() << "\n"
  << "Delta Corner in relative Datum : "
  << delta.coordsIn(datum).transpose() << "\n"
  << std::endl;

  AMG::RigidBody body;
  body.outputRelativePositionToParent();

  body.setPositionTo<Units::degree>(-84.396188 , 33.772111 , 0.0 );
  body.outputRelativePositionToParent();

  body.rotate<Units::degree>(90.0,0,0);
  body.outputRelativePositionToParent();

  std::cout
    << "Body Euler attitude (phi, theat, psi):\n"
    << "(degree) : " << body.attitude<Units::degree>().transpose() << "\n"
    << "(radian) : " << body.attitude<Units::radian>().transpose() << "\n"
    << "(quaternions) : " << body.attitude().transpose() << "\n"
    << "yaw (deg) : " << body.yaw<Units::degree>() << "\n"
    << "pitch (deg) : " << body.pitch<Units::degree>() << "\n"
    << "roll (deg) : " << body.roll<Units::degree>() << "\n"
    << std:: endl;

  {
    using namespace AMG::GIS;

    std:: cout << "isInLeftHalfCircle( 0,   1) = " << isInLeftHalfCircle(0,    1) << std::endl;
    std:: cout << "isInLeftHalfCircle( 0,   0) = " << isInLeftHalfCircle(0,    0) << std::endl;
    std:: cout << "isInLeftHalfCircle( 0,  -1) = " << isInLeftHalfCircle(0,   -1) << std::endl;
    std:: cout << "isInLeftHalfCircle(10, 190) = " << isInLeftHalfCircle(10, 190) << std::endl;
    std:: cout << "isInLeftHalfCircle(10,-190) = " << isInLeftHalfCircle(10,-190) << std::endl;
    std:: cout << "isInLeftHalfCircle(10,-170) = " << isInLeftHalfCircle(10,-170) << std::endl;
    std:: cout << "isInLeftHalfCircle(10,-175) = " << isInLeftHalfCircle(10,-175) << std::endl;
    std:: cout << "isInLeftHalfCircle(10,-165) = " << isInLeftHalfCircle(10,-165) << std::endl;
    std:: cout << "isInLeftHalfCircle(10, 370) = " << isInLeftHalfCircle(10, 370) << std::endl;
    std:: cout << "isInLeftHalfCircle(10, 365) = " << isInLeftHalfCircle(10, 365) << std::endl;

  }

  { std::cout << "Testing \"headingToCompassPoint()\""<< std::endl;
    for( double hdg = 0; hdg <=360; hdg += 5 )
    { std::cout << hdg << "° => "<< AMG::GIS::headingToCompassPoint(hdg) << std::endl; }
  }

  return 0;
}


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2016, Sebastian Schlenkrich

*/

/*! \file mcscriptT.hpp
    \brief script payoffs for MC simulation

*/

#ifndef quantlib_templatemcscript_hpp
#define quantlib_templatemcscript_hpp

#include <ql/experimental/templatemodels/montecarlo/mcpayoffT.hpp>

#include <ql/experimental/templatemodels/montecarlo/scripting/flexbisondriver.hpp>
#include <ql/experimental/templatemodels/montecarlo/scripting/expression.hpp>

#include <ql/time/date.hpp>

#include <boost/regex.hpp>

namespace QuantLib {

    template <class DateType, class PassiveType, class ActiveType>
    class MCScriptT : public MCPayoffT<DateType, PassiveType, ActiveType> {
    protected:
        // easy use of templated types
        typedef MCSimulationT<DateType, PassiveType, ActiveType>        SimulationType;
        typedef MCPayoffT<DateType, PassiveType, ActiveType>            PayoffType;
        typedef BasePayoffT<DateType, PassiveType, ActiveType>          MCBase;
        typedef typename MCSimulationT<DateType, PassiveType, ActiveType>::Path  PathType;

    private:
        std::map<std::string, ext::shared_ptr<PayoffType>>   payoffs_;      // the actual payoffs which may be accessed
        std::vector<std::string>                             expressions_;  // resulting expressions after parsing the script but before syntactic analysis
        std::vector<std::string>                             scriptLog_;    // log messages when parsing the script
        ext::shared_ptr<PayoffType>                          result_;       // result payoff for MCPayoff interface implementation
    public:
        MCScriptT(const std::vector<std::string>&                    keys,
                  const std::vector <ext::shared_ptr<PayoffType>>&   payoffs,
                  const std::vector<std::string>&                    script,
                  const bool                                         overwrite=true) : MCPayoffT<DateType, PassiveType, ActiveType>(0.0) {
            QL_REQUIRE(keys.size()==payoffs.size(), "MCScript error: key vs. value size missmatch");
            for (Size k = 0; k < keys.size(); ++k) { // initialize map
                typename std::map< std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find(keys[k]);
                if (it == payoffs_.end()) { // insert a new element
                    payoffs_.insert( std::make_pair(keys[k], payoffs[k]) );
                } else { // potentially overwrite existing element
                    QL_REQUIRE(overwrite, "MCScript error: overwrite not allowed");
                    it->second = payoffs[k];
                }
            }
            if ((script.size() > 0) && (script[0].compare("NonRecursive") == 0)) {
                //parseScript(script, overwrite);           // deprecated and for debugging purpose
            } else {
                parseFlexBisonScript(script, overwrite);  // for briefty we delegate parsing to separate method
            }
            QL_REQUIRE(payoffs_.size()>0, "MCScript error: no payoffs stored.");
            result_ = payoffs_.rbegin()->second; // pick the last element as fall back

            // we need to find a 'result' payoff
            typename std::map< std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find("payoff");
            if (it != payoffs_.end()) result_ = it->second;
            else result_ = payoffs_.rbegin()->second; // pick the last element as fall back
            PayoffType::observationTime_ = result_->observationTime();
        }

        inline virtual ActiveType at(const ext::shared_ptr<PathType>& p) {
            return result_->at(p);
        }

        // inspector
        inline const std::map<std::string, ext::shared_ptr<PayoffType>>&  payoffs()     { return payoffs_;   }
        inline const std::vector<std::string>&                            expressions() { return expressions_; }
        inline const std::vector<std::string>&                            scriptLog()   { return scriptLog_; }

        // return all keys
        std::vector<std::string> payoffsKeys() {
            std::vector<std::string> keyVector;
            for (typename std::map<std::string, ext::shared_ptr<PayoffType>>::iterator it = payoffs_.begin(); it != payoffs_.end(); ++it) {
                keyVector.push_back(it->first);
            }
            return keyVector;
        }

        // return all payoffs (values in map)
        std::vector < ext::shared_ptr<PayoffType> > payoffValues() {
            std::vector < ext::shared_ptr<PayoffType> > payoffVector;
            for (typename std::map<std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.begin(); it != payoffs_.end(); ++it) {
                payoffVector.push_back(it->second);
            }
            return payoffVector;
        }

        std::vector<DateType> observationTimes(const std::vector<std::string>& keys) {
            std::vector<ext::shared_ptr<PayoffType>> payoffs = findPayoffs(keys);
            std::set<DateType> s;
            for (size_t k = 0; k < payoffs.size(); ++k) s = PayoffType::unionTimes(s, payoffs[k]->observationTimes());
            return std::vector<DateType>(s.begin(), s.end());
        }

        // MC valuation
        inline std::vector<ActiveType> NPV(const ext::shared_ptr<SimulationType>&    simulation,
                                           const std::vector<std::string>&           keys) {
            std::vector<ext::shared_ptr<PayoffType>> payoffs = findPayoffs(keys);
            std::vector<ActiveType> npv(payoffs.size(), (ActiveType)0.0);
            for (Size n = 0; n < simulation->nPaths(); ++n) {
                const ext::shared_ptr<PathType> p(simulation->path(n));
                for (Size k = 0; k < payoffs.size(); ++k) {
                    npv[k] += payoffs[k]->discountedAt(p);
                }
            }
            for (Size k = 0; k < payoffs.size(); ++k) npv[k] /= simulation->nPaths();
            return npv;
        }

        // some helper functions to simplify Asset payoff handling
        inline static bool add_FixingTimes_to_Asset(
            ext::shared_ptr<PayoffType>        payoff,
            const std::vector<DateType>&       fixingTimes,
            const std::vector<PassiveType>&    fixingValues) {
            ext::shared_ptr<typename MCBase::Asset>  assetPayoff =
                boost::dynamic_pointer_cast<typename MCBase::Asset>(payoff);
            QL_REQUIRE(assetPayoff, "Payoff is no Asset");
            QL_REQUIRE(fixingTimes.size() == fixingValues.size(), "fixingTimes.size()==fixingValues.size() required");
            std::vector< std::pair<DateType, PassiveType> > history;
            for (size_t k = 0; k < fixingTimes.size(); ++k)
                history.push_back(std::make_pair(fixingTimes[k], fixingValues[k]));
            assetPayoff->addFixings(history);
            return true;
        }

        inline static bool add_FixingDates_to_Asset(
            ext::shared_ptr<PayoffType>        payoff,
            const std::vector<Date>&           fixingDates,
            const std::vector<PassiveType>&    fixingValues) {
            std::vector<DateType> fixingTimes(fixingDates.size());
            Date today = Settings::instance().evaluationDate();
            for (size_t k = 0; k < fixingDates.size(); ++k)
                fixingTimes[k] = (DateType)(((fixingDates[k].serialNumber() - today.serialNumber()) / 365.0));
            return add_FixingTimes_to_Asset(payoff, fixingTimes, fixingValues);
        }

    private:

        // convert string to number
        inline static bool to_Number(const std::string str, ActiveType& number) {
            double res;
            std::string::size_type sz;
            try {
                res = std::stod(str, &sz);
            }
            catch (std::exception e) {
                return false;
            }
            number = res;
            return true;
        }

        // convert a Date to number
        inline static DateType date_to_Number(const Date& d) {
            Date today = Settings::instance().evaluationDate();
            DateType number = (DateType)(((d.serialNumber() - today.serialNumber()) / 365.0));
            return number;
        }

        // convert date string with format ddmmmyyyy to number
        inline static bool date_to_Number(const std::string str, ActiveType& number) {
            if (str.length() != 9) return false;
            std::string::size_type sz;
            try {
                Day  day  = std::stol(str.substr(0,2), &sz);
                Year year = std::stol(str.substr(5,4), &sz);
                Month month;
                std::string s = str.substr(2, 3);
                if (s.compare("Jan") == 0) month = Month::Jan;
                else if (s.compare("Feb") == 0) month = Month::Feb;
                else if (s.compare("Mar") == 0) month = Month::Mar;
                else if (s.compare("Apr") == 0) month = Month::Apr;
                else if (s.compare("May") == 0) month = Month::May;
                else if (s.compare("Jun") == 0) month = Month::Jun;
                else if (s.compare("Jul") == 0) month = Month::Jul;
                else if (s.compare("Aug") == 0) month = Month::Aug;
                else if (s.compare("Sep") == 0) month = Month::Sep;
                else if (s.compare("Oct") == 0) month = Month::Oct;
                else if (s.compare("Nov") == 0) month = Month::Nov;
                else if (s.compare("Dec") == 0) month = Month::Dec;
                else return false;
                Date d(day, month, year);
                Date today = Settings::instance().evaluationDate();
                number = (ActiveType)(((d.serialNumber() - today.serialNumber()) / 365.0));
            }
            catch (std::exception e) {
                return false;
            }
            return true;
        }

        // we define that helper function to simplify code in forthcoming expression parsing
        inline bool hasChilds(const ext::shared_ptr<Scripting::Expression> tree, Size nArgs, Size lineNr) {
            // make sure we can actually do something with the tree
            if (!tree) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": Empty expression tree."));
                return false;
            }
            if (tree->childs().size() != nArgs) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": " + std::to_string(nArgs) + " child expressions expected, but " + std::to_string(tree->childs().size()) + " found." ));
                return false;
            }
            return true;
        }

        // we define that helper function to simplify code in forthcoming expression parsing
        inline bool hasChildsInRange(const ext::shared_ptr<Scripting::Expression> tree, Size nArgsMin, Size nArgsMax, Size lineNr) {
            // make sure we can actually do something with the tree
            if (!tree) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": Empty expression tree."));
                return false;
            }
            if ((tree->childs().size() < nArgsMin)||(tree->childs().size() > nArgsMax)) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": [" + std::to_string(nArgsMin) + ", " + std::to_string(nArgsMax) +
                    "] child expressions expected, but " + std::to_string(tree->childs().size()) + " found."));
                return false;
            }
            return true;
        }

        // we define that helper function to simplify code in forthcoming expression parsing
        inline bool hasLeafs(const ext::shared_ptr<Scripting::Expression> tree, Size nArgs, Size lineNr) {
            // make sure we can actually do something with the tree
            if (!tree) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": Empty expression tree."));
                return false;
            }
            if (tree->leafs().size() != nArgs) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": " + std::to_string(nArgs) + " leafs expected, but " + std::to_string(tree->leafs().size()) + " found."));
                return false;
            }
            return true;
        }

        // we define that helper function to simplify code in forthcoming expression parsing
        inline bool hasLeafsInRange(const ext::shared_ptr<Scripting::Expression> tree, Size nArgsMin, Size nArgsMax, Size lineNr) {
            // make sure we can actually do something with the tree
            if (!tree) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": Empty expression tree."));
                return false;
            }
            if ((tree->leafs().size()<nArgsMin)|| (tree->leafs().size()>nArgsMax)) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": [" + std::to_string(nArgsMin) + ", " + std::to_string(nArgsMax) +
                    "] leafs expected, but " + std::to_string(tree->leafs().size()) + " found."));
                return false;
            }
            return true;
        }

        // check if a list of payoffs exists before doing some computationally expensive stuff with them
        std::vector< ext::shared_ptr<PayoffType> > findPayoffs(const std::vector<std::string>& keys, bool throwException = true) {
            std::vector<ext::shared_ptr<PayoffType>> payoffs;
            for (Size k = 0; k < keys.size(); ++k) {
                typename std::map<std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find(keys[k]);
                if (it != payoffs_.end()) {
                    payoffs.push_back(it->second);
                    continue; // all done for this key
                }
                if (throwException) QL_FAIL("MCScript error: payoff '" + keys[k] + "' not found");
            }
            return payoffs;
        }

        // convert an abstract expression tree into a payoff
        // this function does the actual work...
        ext::shared_ptr<PayoffType> payoff(const ext::shared_ptr<Scripting::Expression> tree, Size k) {
            // make sure we can actually do something with the tree
            if (!tree) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Empty expression tree."));
                QL_FAIL("Cannot interprete payoff");
            }
            // check any possible expression
            switch (tree->type()) {
            // expressions based on tokens
            case Scripting::Expression::NUMBER: {
                if (!hasChilds(tree, 0, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k)) 	QL_FAIL("Cannot interprete payoff");
                ActiveType number;
                if (to_Number(tree->leafs()[0], number)) {
                    return ext::shared_ptr<PayoffType>(new typename MCBase::FixedAmount(number));
                }
                scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[0] + " to number."));
                QL_FAIL("Cannot interprete payoff");
            }
            case Scripting::Expression::IDENTIFIER: {
                if (!hasChilds(tree, 0, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k))  QL_FAIL("Cannot interprete payoff");
                // check for existing payoff in map
                typename std::map<std::string, ext::shared_ptr<PayoffType>>::iterator it = payoffs_.find(tree->leafs()[0]);
                if (it != payoffs_.end()) {
                    scriptLog_.push_back(std::string("Payoff line " + std::to_string(k) + ": '" + tree->leafs()[0] + "' is in map"));
                    return it->second;
                }
                // if we end up here no conversion was successfull
                scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": '" + tree->leafs()[0] + "' is no payoff"));
                QL_FAIL("Cannot interprete payoff");
            }
            // expressions basen on unary operators
            case Scripting::Expression::UNARYPLUS: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return this->payoff(tree->childs()[0], k);
            }
            case Scripting::Expression::UNARYMINUS: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(-1.0, payoff(tree->childs()[0], k), 0));
            }
            case Scripting::Expression::PLUS: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(1.0, payoff(tree->childs()[0], k), payoff(tree->childs()[1], k)));
            }
            case Scripting::Expression::MINUS: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(-1.0, payoff(tree->childs()[1], k), payoff(tree->childs()[0], k)));
            }
            case Scripting::Expression::MULT: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Mult(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k)));
            }
            case Scripting::Expression::DIVISION: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Division(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k)));
            }
            case Scripting::Expression::IFTHENELSE: {
                if (!hasChilds(tree, 3, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::IfThenElse(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k), payoff(tree->childs()[2], k)));
            }
            case Scripting::Expression::MIN: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Min(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k)));
            }
            case Scripting::Expression::MAX: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Max(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k)));
            }
            case Scripting::Expression::EXPONENTIAL: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Exponential(payoff(tree->childs()[0], k)));
            }
            case Scripting::Expression::LOGARITHM: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Logarithm(payoff(tree->childs()[0], k)));
            }
            case Scripting::Expression::SQUAREROOT: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Squareroot(payoff(tree->childs()[0], k)));
            }
            case Scripting::Expression::LOGICAL: {
                if (!hasChilds(tree, 2, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Logical(payoff(tree->childs()[0], k), payoff(tree->childs()[1], k), tree->leafs()[0]));
            }
            case Scripting::Expression::PAY: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k))  QL_FAIL("Cannot interprete payoff");
                ActiveType number;
                if (!to_Number(tree->leafs()[0], number)) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[0] + " to number."));
                    QL_FAIL("Cannot interprete payoff");
                }
                return ext::shared_ptr<PayoffType>(new typename MCBase::Pay(payoff(tree->childs()[0], k), number));
            }
            case Scripting::Expression::PAY_WITHDATE: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k))  QL_FAIL("Cannot interprete payoff");
                ActiveType number;
                if (!date_to_Number(tree->leafs()[0], number)) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[0] + " to number."));
                    QL_FAIL("Cannot interprete payoff");
                }
                return ext::shared_ptr<PayoffType>(new typename MCBase::Pay(payoff(tree->childs()[0], k), number));
            }
            case Scripting::Expression::CACHE: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 0, k))  QL_FAIL("Cannot interprete payoff");
                return ext::shared_ptr<PayoffType>(new typename MCBase::Cache(payoff(tree->childs()[0], k)));
            }
            case Scripting::Expression::PAYOFFAT: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafsInRange(tree, 1, 2, k)) QL_FAIL("Cannot interprete payoff");
                ActiveType number;
                if (!to_Number(tree->leafs()[0], number)) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[0] + " to number."));
                    QL_FAIL("Cannot interprete payoff");
                }
                ActiveType sign = 1.0;
                if (tree->leafs().size()>1) { // we expect a negative number
                    if (tree->leafs()[1].compare("-") != 0) {
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[1] + tree->leafs()[0] + " to negative number."));
                        QL_FAIL("Cannot interprete payoff");
                    }
                    sign = -1.0;
                }
                ext::shared_ptr<PayoffType> p = payoff(tree->childs()[0], k);
                if (p) return p->at(sign*number);
                QL_FAIL("Cannot interprete payoff");
            }
            case Scripting::Expression::PAYOFFAT_WITHDATE: {
                if (!hasChilds(tree, 1, k)) QL_FAIL("Cannot interprete payoff");
                if (!hasLeafs(tree, 1, k))  QL_FAIL("Cannot interprete payoff");
                ActiveType number;
                if (!date_to_Number(tree->leafs()[0], number)) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": cannot convert " + tree->leafs()[0] + " to number."));
                    QL_FAIL("Cannot interprete payoff");
                }
                ext::shared_ptr<PayoffType> p = payoff(tree->childs()[0], k);
                if (p) return p->at(number);
                QL_FAIL("Cannot interprete payoff");
            }
            // we don't need a default because we returned in each of the previous cases
            } // finished all switch types
            // if we end up here there is an expression which we didn't interprete
            scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": unknown expression type."));
            QL_FAIL("Cannot interprete payoff");
            return 0; // this should never be reached
        }

        // parse the script and set up payoffs
        inline void parseFlexBisonScript(const std::vector<std::string>&  script,
                                         const bool                       overwrite = true) {
            for (Size k = 0; k < script.size(); ++k) {  // first line should equal 'FlexBison' and is skipped anyway
                Scripting::FlexBisonDriver driver(script[k], false, false);
                // in any case we want to know the parsing result
                if (driver.expressionTree()) expressions_.push_back("L" + std::to_string(k) + ":" + driver.expressionTree()->toString());
                if (driver.returnValue() == 0) {
                    if (!driver.expressionTree()) {
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Empty expression tree."));
                        continue;
                    }
                    if (driver.expressionTree()->type() != Scripting::Expression::ASSIGNMENT ) {
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Assignment expected."));
                        continue;
                    }
                    if (!hasChilds(driver.expressionTree(), 1, k)) continue;
                    if (!hasLeafs(driver.expressionTree(), 1, k)) continue;
                    // interprete right side of assignment
                    ext::shared_ptr<PayoffType> p;
                    try {
                        p = payoff(driver.expressionTree()->childs()[0], k);
                    }
                    catch (std::exception e) {  // something went wrong, for details check scriptLog_
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Exception caught: " + e.what()));
                        continue;
                    }
                    if (!p) {
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": No payoff found."));
                        continue;
                    }
                    // just define an abbreviation
                    std::string var = driver.expressionTree()->leafs()[0];
                    if (var.compare("") == 0) {
                        scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Non-empty identifier expected."));
                        continue;
                    }
                    // now we have a payoff which we may store in the map
                    typename std::map<std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find(var);
                    if (it == payoffs_.end()) { // insert a new element
                        payoffs_.insert(std::make_pair(var, p));
                        scriptLog_.push_back(std::string("Insert line " + std::to_string(k) + ": '" + script[k] + "'"));
                        continue;
                    }
                    if (overwrite) {
                        it->second = p;
                        scriptLog_.push_back(std::string("Replace line " + std::to_string(k) + ": '" + script[k] + "'"));
                        continue;
                    }
                    else scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": Cannot replace line '" + script[k] + "'"));
                }
                else {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": " + driver.errorMsg()));
                    continue;
                }
            }
        }

        /*

        we implement the following non-recursive grammar

        line  =  var '=' expr
        var   =  [a-zA-Z][a-zA-Z0-9]*           { RegEx }
        expr  =  operator | function | payoff   { apply from left to right }

        operator   =  operator1 | operator2
        operator1  =  ['+' | '-'] payoff
        operator2  =  payoff ['+' | '-' | '*' | == | != | < | <= | > | >= | && | || ] payoff

        function   =  function3 | function2 | function1
        function3  =  fname3 '(' payoff ',' payoff ',' payoff ')'
        function2  =  fname2 '(' payoff ',' payoff ')'
        function1  =  fname1 '(' payoff ')'

        fname3     =  'IfThenElse'
        fname2     =  'Min' | 'Max | Pay'
        fname1     =  'Cache'

        payoff  =  number | string              { try double conversion and lookup in map }

        */

        // parse the script and set up payoffs
        inline void parseScript(const std::vector<std::string>&  script,
            const bool                       overwrite = true) {
            for (Size k = 0; k < script.size(); ++k) {  // parse lines
                std::string line = boost::regex_replace(script[k], boost::regex(" "), ""); // remove whitespaces
                boost::smatch what;

                bool isAssignment = boost::regex_match(line, what, boost::regex("([a-zA-Z][a-zA-Z0-9]*)(=)(.+)"));
                if (!isAssignment) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": '" + line + "' is no valid assignment"));
                    continue; // move to next item in script
                }
                std::string var(what[1]), expr(what[3]);

                ext::shared_ptr<PayoffType> p;

                if (boost::regex_match(expr, what, boost::regex("(\\+|-)(.+)"))) {
                    p = operator1(std::string(what[1]), std::string(what[2]), k);
                }
                else if (boost::regex_match(expr, what, boost::regex("(.+)(\\+|-|\\*|==|!=|<=|<|>=|>|&&|\\|\\|)(.+)"))) {
                    p = operator2(std::string(what[2]), std::string(what[1]), std::string(what[3]), k);
                }
                else if (boost::regex_match(expr, what, boost::regex("([a-zA-Z]+)\\((.+),(.+),(.+)\\)"))) {
                    p = function3(std::string(what[1]), std::string(what[2]), std::string(what[3]), std::string(what[4]), k);
                }
                else if (boost::regex_match(expr, what, boost::regex("([a-zA-Z]+)\\((.+),(.+)\\)"))) {
                    p = function2(std::string(what[1]), std::string(what[2]), std::string(what[3]), k);
                }
                else if (boost::regex_match(expr, what, boost::regex("([a-zA-Z]+)\\((.+)\\)"))) {
                    p = function1(std::string(what[1]), std::string(what[2]), k);
                }
                else p = payoff(expr, k); // action of last resort

                if (!p) {
                    scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": '" + expr + "' is no valid expression"));
                    continue; // move to next item in script
                }

                // now we have a payoff which we may store in the map
                typename std::map<std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find(var);
                if (it == payoffs_.end()) { // insert a new element
                    payoffs_.insert(std::make_pair(var, p));
                    scriptLog_.push_back(std::string("Insert line " + std::to_string(k) + ": '" + line + "'"));
                    continue;
                }
                if (overwrite) {
                    it->second = p;
                    scriptLog_.push_back(std::string("Replace line " + std::to_string(k) + ": '" + line + "'"));
                    continue;
                }
                // if we end up here we have a valid payoff but are not allowed to overwrite existing map entry
                scriptLog_.push_back(std::string("Error line " + std::to_string(k) + ": '" + var + "' can not be replaced"));
            }
            if (script.size() == 0) { // in this case the previous loop was not executed and we just print some help details
                scriptLog_.push_back(std::string("we implement the following non-recursive grammar                                     "));
                scriptLog_.push_back(std::string("                                                                                "));
                scriptLog_.push_back(std::string("line  =  var '=' expr                                                                "));
                scriptLog_.push_back(std::string("var   =  [a-zA-Z][a-zA-Z0-9]*           { RegEx }                                    "));
                scriptLog_.push_back(std::string("expr  =  operator | function | payoff   { apply from left to right }                 "));
                scriptLog_.push_back(std::string("                                                                                "));
                scriptLog_.push_back(std::string("operator   =  operator1 | operator2                                                  "));
                scriptLog_.push_back(std::string("operator1  =  ['+' | '-'] payoff                                                     "));
                scriptLog_.push_back(std::string("operator2  =  payoff ['+' | '-' | '*' |                                              "));
                scriptLog_.push_back(std::string("                      '==' | '!=' | '<=' |'<' | '>=' | '>' | '&&' | '||' ] payoff    "));
                scriptLog_.push_back(std::string("                                                                                "));
                scriptLog_.push_back(std::string("function   =  function3 | function2 | function1                                      "));
                scriptLog_.push_back(std::string("function3  =  fname3 '(' payoff ',' payoff ',' payoff ')'                            "));
                scriptLog_.push_back(std::string("function2  =  fname2 '(' payoff ',' payoff ')'                                       "));
                scriptLog_.push_back(std::string("function1  =  fname1 '(' payoff ')'                                                  "));
                scriptLog_.push_back(std::string("                                                                                "));
                scriptLog_.push_back(std::string("fname3     =  'IfThenElse'                                                           "));
                scriptLog_.push_back(std::string("fname2     =  'Min' | 'Max' | 'Pay'                                                  "));
                scriptLog_.push_back(std::string("fname1     =  'Cache'                                                                "));
                scriptLog_.push_back(std::string("                                                                                "));
                scriptLog_.push_back(std::string("payoff  =  number | string              { try double conversion and lookup in map }  "));
            }
        }

        // compile fixed cash flow or lookup in map
        inline ext::shared_ptr<PayoffType> payoff(const std::string expr, const Size lineNr) {
            ActiveType amount;
            bool isFixed = to_Number(expr, amount);
            if (isFixed) {
                scriptLog_.push_back(std::string("Payoff line " + std::to_string(lineNr) + ": '" + boost::lexical_cast<std::string>(amount) + "' is fixed amount"));
                return ext::shared_ptr<PayoffType>(new typename MCBase::FixedAmount(amount));
            }
            typename std::map<std::string, ext::shared_ptr<PayoffType> >::iterator it = payoffs_.find(expr);
            if (it != payoffs_.end()) {
                scriptLog_.push_back(std::string("Payoff line " + std::to_string(lineNr) + ": '" + expr + "' is in map"));
                return it->second;
            }
            // if we end up here no conversion was successfull
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + expr + "' is no payoff"));
            return 0;
        }

        // compile single operand function
        inline ext::shared_ptr<PayoffType> function1(const std::string fname, const std::string operand, const Size lineNr) {
            ext::shared_ptr<PayoffType> p = payoff(operand, lineNr);
            if (!p) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + operand + "' is no valid operand"));
                return 0;
            }
            boost::smatch what;
            if (boost::regex_match(fname, what, boost::regex("Cache")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Cache(p));
            // if we end up here the function name is not valid
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + fname + "' is no valid unary function name"));
            return 0;
        }

        // compile dual operand function
        inline ext::shared_ptr<PayoffType> function2(const std::string fname, const std::string oper1, const std::string oper2, const Size lineNr) {
            ext::shared_ptr<PayoffType> p1 = payoff(oper1, lineNr);
            if (!p1) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper1 + "' is no valid operand"));
                return 0;
            }
            ext::shared_ptr<PayoffType> p2 = payoff(oper2, lineNr);
            if (!p2) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper2 + "' is no valid operand"));
                return 0;
            }
            boost::smatch what;
            if (boost::regex_match(fname, what, boost::regex("Min")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Min(p1, p2));
            if (boost::regex_match(fname, what, boost::regex("Max")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Max(p1, p2));
            if (boost::regex_match(fname, what, boost::regex("Pay"))) {
                DateType t;
                if (to_Number(oper2, t)) return ext::shared_ptr<PayoffType>(new typename MCBase::Pay(p1, t)); // usual application
                return ext::shared_ptr<PayoffType>(new typename MCBase::Pay(p1, p2->observationTime())); // fall back
            }
            // if we end up here the function name is not valid
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + fname + "' is no valid binary function name"));
            return 0;
        }

        // compile three operand function
        inline ext::shared_ptr<PayoffType> function3(const std::string fname, const std::string oper1, const std::string oper2, const std::string oper3, const Size lineNr) {
            ext::shared_ptr<PayoffType> p1 = payoff(oper1, lineNr);
            if (!p1) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper1 + "' is no valid operand"));
                return 0;
            }
            ext::shared_ptr<PayoffType> p2 = payoff(oper2, lineNr);
            if (!p2) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper2 + "' is no valid operand"));
                return 0;
            }
            ext::shared_ptr<PayoffType> p3 = payoff(oper3, lineNr);
            if (!p3) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper3 + "' is no valid operand"));
                return 0;
            }
            boost::smatch what;
            if (boost::regex_match(fname, what, boost::regex("IfThenElse")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::IfThenElse(p1, p2, p3));
            // if we end up here the function name is not valid
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + fname + "' is no valid function name"));
            return 0;
        }

        // compile unary operators
        inline ext::shared_ptr<PayoffType> operator1(const std::string opname, const std::string operand, const Size lineNr) {
            ext::shared_ptr<PayoffType> p = payoff(operand, lineNr);
            if (!p) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + operand + "' is no valid operand"));
                return 0;
            }
            boost::smatch what;
            if (boost::regex_match(opname, what, boost::regex("\\+"))) return p;
            if (boost::regex_match(opname, what, boost::regex("-"))) return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(-1.0, p, 0));
            // if we end up here the function name is not valid
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + opname + "' is no valid unary operator name"));
            return 0;
        }

        // compile binary operators
        inline ext::shared_ptr<PayoffType> operator2(const std::string opname, const std::string oper1, const std::string oper2, const Size lineNr) {
            ext::shared_ptr<PayoffType> p1 = payoff(oper1, lineNr);
            if (!p1) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper1 + "' is no valid operand"));
                return 0;
            }
            ext::shared_ptr<PayoffType> p2 = payoff(oper2, lineNr);
            if (!p2) {
                scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + oper2 + "' is no valid operand"));
                return 0;
            }
            boost::smatch what;
            if (boost::regex_match(opname, what, boost::regex("\\+")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(1.0, p1, p2));
            if (boost::regex_match(opname, what, boost::regex("-")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Axpy(-1.0, p2, p1));
            if (boost::regex_match(opname, what, boost::regex("\\*")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Mult(p1, p2));
            if (boost::regex_match(opname, what, boost::regex("==|!=|<|<=|>|>=|&&|\\|\\|")))
                return ext::shared_ptr<PayoffType>(new typename MCBase::Logical(p1, p2, opname));
            // if we end up here the function name is not valid
            scriptLog_.push_back(std::string("Error line " + std::to_string(lineNr) + ": '" + opname + "' is no valid binary operator name"));
            return 0;
        }

    };

}

#endif  /* ifndef quantlib_templatemcscript_hpp */


//
//  EigenLibSolver.hpp
//  DOT
//
//  Created by Minchen Li on 6/30/18.
//

#ifndef EigenLibSolver_hpp
#define EigenLibSolver_hpp

#include "LinSysSolver.hpp"

#include <Eigen/Eigen>

#include <vector>
#include <set>

namespace DOT {

    template <typename vectorTypeI, typename vectorTypeS>
    class EigenLibSolver : public LinSysSolver<vectorTypeI, vectorTypeS>
    {
        typedef LinSysSolver<vectorTypeI, vectorTypeS> Base;

    protected:
        bool useDense;
        Eigen::MatrixXd coefMtr_dense;
        Eigen::LDLT<Eigen::MatrixXd> LDLT;
        Eigen::SparseMatrix<double> coefMtr;
        Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> simplicialLDLT;

    public:
        void set_type(int threadAmt, int _mtype, bool is_upper_half = false);

        void set_pattern(const std::vector<std::set<int>>& vNeighbor,
                         const std::set<int>& fixedVert);
        void set_pattern(const Eigen::SparseMatrix<double>& mtr); //NOTE: mtr must be SPD

        void update_a(const vectorTypeI &II,
                      const vectorTypeI &JJ,
                      const vectorTypeS &SS);
        void update_a(const Eigen::SparseMatrix<double>& mtr);

        void analyze_pattern(void);

        bool factorize(void);

        void solve(Eigen::VectorXd &rhs,
                   Eigen::VectorXd &result);
        void solve_threadSafe(Eigen::VectorXd &rhs,
                              Eigen::VectorXd &result,
                              int dimI);

        double coeffMtr(int rowI, int colI) const;

        void setZero(void);

        virtual void setCoeff(int rowI, int colI, double val);

        virtual void addCoeff(int rowI, int colI, double val);
    };

}

#endif /* EigenLibSolver_hpp */


//
// Copyright 2005-2007 Adobe Systems Incorporated
//
// 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
//
#ifndef BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP
#define BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP

#include <boost/gil/point.hpp>

namespace boost { namespace gil {

////////////////////////////////////////////////////////////////////////////////////////
///
/// Simple matrix to do 2D affine transformations. It is actually 3x3 but the last column is [0 0 1]
///
////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
class matrix3x2 {
public:
    matrix3x2() : a(1), b(0), c(0), d(1), e(0), f(0) {}
    matrix3x2(T A, T B, T C, T D, T E, T F) : a(A),b(B),c(C),d(D),e(E),f(F) {}
    matrix3x2(const matrix3x2& mat) : a(mat.a), b(mat.b), c(mat.c), d(mat.d), e(mat.e), f(mat.f) {}
    matrix3x2& operator=(const matrix3x2& m)           { a=m.a; b=m.b; c=m.c; d=m.d; e=m.e; f=m.f; return *this; }

    matrix3x2& operator*=(const matrix3x2& m)          { (*this) = (*this)*m; return *this; }

    static matrix3x2 get_rotate(T rads)                { T c=std::cos(rads); T s=std::sin(rads); return matrix3x2(c,s,-s,c,0,0); }
    static matrix3x2 get_translate(point<T> const& t)
    {
        return matrix3x2(1, 0, 0, 1, t.x, t.y);
    }
    static matrix3x2 get_translate(T x, T y)           { return matrix3x2(1  ,0,0,1  ,x,  y  ); }
    static matrix3x2 get_scale(point<T> const& s)
    {
        return matrix3x2(s.x, 0, 0, s.y, 0, 0);
    }
    static matrix3x2 get_scale(T x, T y)           { return matrix3x2(x,  0,0,y,  0  ,0  ); }
    static matrix3x2 get_scale(T s)                { return matrix3x2(s  ,0,0,s  ,0  ,0  ); }

    T a,b,c,d,e,f;
};

template <typename T> BOOST_FORCEINLINE
matrix3x2<T> operator*(const matrix3x2<T>& m1, const matrix3x2<T>& m2) {
    return matrix3x2<T>(
                m1.a * m2.a + m1.b * m2.c,
                m1.a * m2.b + m1.b * m2.d,
                m1.c * m2.a + m1.d * m2.c,
                m1.c * m2.b + m1.d * m2.d,
                m1.e * m2.a + m1.f * m2.c + m2.e,
                m1.e * m2.b + m1.f * m2.d + m2.f );
}

template <typename T, typename F>
BOOST_FORCEINLINE
point<F> operator*(point<T> const& p, matrix3x2<F> const& m)
{
    return { m.a*p.x + m.c*p.y + m.e, m.b*p.x + m.d*p.y + m.f };
}

////////////////////////////////////////////////////////////////////////////////////////
/// Define affine mapping that transforms the source coordinates by the affine transformation
////////////////////////////////////////////////////////////////////////////////////////
/*
template <typename MapFn>
concept MappingFunctionConcept {
    typename mapping_traits<MapFn>::result_type;   where PointNDConcept<result_type>;

    template <typename Domain> { where PointNDConcept<Domain> }
    result_type transform(MapFn&, const Domain& src);
};
*/

template <typename T> struct mapping_traits;

template <typename F>
struct mapping_traits<matrix3x2<F>>
{
    using result_type =  point<F>;
};

template <typename F, typename F2>
BOOST_FORCEINLINE
point<F> transform(matrix3x2<F> const& mat, point<F2> const& src)
{
    return src * mat;
}

}} // namespace boost::gil

#endif


/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2009, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "precomp.hpp"

// Eigen
#include <Eigen/Core>

// OpenCV
#include <opencv2/core/eigen.hpp>
#include <opencv2/sfm/robust.hpp>
#include <opencv2/sfm/numeric.hpp>

// libmv headers
#include "libmv/multiview/robust_fundamental.h"

using namespace std;

namespace cv
{
namespace sfm
{

// TODO: unify algorithms
template<typename T>
double
fundamentalFromCorrespondences8PointRobust( const Mat_<T> &_x1,
                                            const Mat_<T> &_x2,
                                            const double max_error,
                                            Mat_<T> _F,
                                            std::vector<int> &_inliers,
                                            const double outliers_probability )
{
  libmv::Mat x1, x2;
  libmv::Mat3 F;
  libmv::vector<int> inliers;

  cv2eigen( _x1, x1 );
  cv2eigen( _x2, x2 );

  T solution_error =
    libmv::FundamentalFromCorrespondences8PointRobust( x1, x2, max_error, &F, &inliers, outliers_probability );

  eigen2cv( F, _F );

  // transform from libmv::vector to std::vector
  int n = inliers.size();
  _inliers.resize(n);
  for( int i=0; i < n; ++i )
  {
    _inliers[i] = inliers.at(i);
  }

  return static_cast<double>(solution_error);
}

double
fundamentalFromCorrespondences8PointRobust( InputArray _x1,
                                            InputArray _x2,
                                            double max_error,
                                            OutputArray _F,
                                            OutputArray _inliers,
                                            double outliers_probability )
{
  const Mat x1 = _x1.getMat(), x2 = _x2.getMat();
  const int depth =  x1.depth();
  CV_Assert(x1.size() == x2.size() && (depth == CV_32F || depth == CV_64F));

  _F.create(3, 3, depth);

  Mat F = _F.getMat();
  std::vector<int>& inliers = *(std::vector<int>*)_inliers.getObj();

  double solution_error = 0.0;

  // type
  if( depth == CV_32F )
  {
    solution_error =
      fundamentalFromCorrespondences8PointRobust<float>(
        x1, x2, max_error, F, inliers, outliers_probability);
  }
  else
  {
    solution_error =
      fundamentalFromCorrespondences8PointRobust<double>(
        x1, x2, max_error, F, inliers, outliers_probability);
  }

  return solution_error;
}

template<typename T>
double
fundamentalFromCorrespondences7PointRobust( const Mat_<T> &_x1,
                                            const Mat_<T> &_x2,
                                            const double max_error,
                                            Mat_<T> _F,
                                            std::vector<int> &_inliers,
                                            const double outliers_probability )
{
  libmv::Mat x1, x2;
  libmv::Mat3 F;
  libmv::vector<int> inliers;

  cv2eigen( _x1, x1 );
  cv2eigen( _x2, x2 );

  T solution_error =
    libmv::FundamentalFromCorrespondences7PointRobust( x1, x2, max_error, &F, &inliers, outliers_probability );

  eigen2cv( F, _F );

  // transform from libmv::vector to std::vector
  int n = inliers.size();
  _inliers.resize(n);
  for( int i=0; i < n; ++i )
  {
    _inliers[i] = inliers.at(i);
  }

  return static_cast<double>(solution_error);
}

double
fundamentalFromCorrespondences7PointRobust( InputArray _x1,
                                            InputArray _x2,
                                            double max_error,
                                            OutputArray _F,
                                            OutputArray _inliers,
                                            double outliers_probability )
{
  const Mat x1 = _x1.getMat(), x2 = _x2.getMat();
  const int depth =  x1.depth();
  CV_Assert(x1.size() == x2.size() && (depth == CV_32F || depth == CV_64F));

  _F.create(3, 3, depth);

  Mat F = _F.getMat();
  std::vector<int>& inliers = *(std::vector<int>*)_inliers.getObj();

  double solution_error = 0.0;

  // type
  if( depth == CV_32F )
  {
    solution_error =
      fundamentalFromCorrespondences7PointRobust<float>(
        x1, x2, max_error, F, inliers, outliers_probability);
  }
  else
  {
    solution_error =
      fundamentalFromCorrespondences7PointRobust<double>(
        x1, x2, max_error, F, inliers, outliers_probability);
  }

  return solution_error;
}

} /* namespace sfm */
} /* namespace cv */