#include <boost/test/unit_test.hpp>
#include <memory>
#include "composite-shape.hpp"
#include "rectangle.hpp"
#include "circle.hpp"
#include <cmath>

const double accuracy = 0.00001;

// =====================test initialization shape=====================
BOOST_AUTO_TEST_SUITE(InitializeShape)

    BOOST_AUTO_TEST_CASE(InitializeShape_DefaultConstructors)
    {
      jianing::CompositeShape com_shape;

      BOOST_REQUIRE_EQUAL(0, com_shape.getSize());
      BOOST_REQUIRE_EQUAL(3, com_shape.getCapacity());
      BOOST_REQUIRE_EQUAL(true, com_shape.empty());
      BOOST_REQUIRE_EQUAL(0.0, com_shape.getArea());

      BOOST_REQUIRE_THROW(com_shape.getCenter().x, std::logic_error);
      BOOST_REQUIRE_THROW(com_shape.getCenter().y, std::logic_error);
      BOOST_REQUIRE_THROW(com_shape.removeShape(0), std::logic_error);
      BOOST_REQUIRE_THROW(com_shape.printShape(), std::domain_error);
      BOOST_REQUIRE_THROW(com_shape.scale(0), std::domain_error);
    }

    BOOST_AUTO_TEST_CASE(InitializeShape_DefaultParameterConstructorOnCorrectShape_NoError)
    {
      // init
      jianing::point_t center = {1.1, 2.2};
      double r_cirle = 3.3;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      jianing::CompositeShape com_shape;
      com_shape.pushShape(circle);

      BOOST_REQUIRE_EQUAL(1, com_shape.getSize());
      BOOST_REQUIRE_EQUAL(3, com_shape.getCapacity());
      BOOST_REQUIRE_EQUAL(false, com_shape.empty());

      BOOST_REQUIRE_CLOSE(1.1, com_shape.getCenter().x, accuracy);
      BOOST_REQUIRE_CLOSE(2.2, com_shape.getCenter().y, accuracy);
      BOOST_REQUIRE_CLOSE(M_PI * 3.3 * 3.3, com_shape.getArea(), accuracy);
    }

    BOOST_AUTO_TEST_CASE(InitializeShape_TestCopyConstructor_NoError)
    {
      jianing::point_t center = {1.1, 2.2};
      double r_cirle = 3.3;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      jianing::CompositeShape old_com_shape;

      old_com_shape.pushShape(circle);

      jianing::CompositeShape new_com_shape = old_com_shape;

      BOOST_REQUIRE_EQUAL(1, new_com_shape.getSize());
      BOOST_REQUIRE_EQUAL(3, new_com_shape.getCapacity());
      BOOST_REQUIRE_EQUAL(false, new_com_shape.empty());

      BOOST_REQUIRE_CLOSE(1.1, new_com_shape.getCenter().x, accuracy);
      BOOST_REQUIRE_CLOSE(2.2, new_com_shape.getCenter().y, accuracy);
      BOOST_REQUIRE_CLOSE(M_PI * 3.3 * 3.3, new_com_shape.getArea(), accuracy);

      BOOST_REQUIRE_EQUAL(1, old_com_shape.getSize());
      BOOST_REQUIRE_EQUAL(3, old_com_shape.getCapacity());
      BOOST_REQUIRE_EQUAL(false, old_com_shape.empty());

      BOOST_REQUIRE_CLOSE(1.1, old_com_shape.getCenter().x, accuracy);
      BOOST_REQUIRE_CLOSE(2.2, old_com_shape.getCenter().y, accuracy);
      BOOST_REQUIRE_CLOSE(M_PI * 3.3 * 3.3, old_com_shape.getArea(), accuracy);
    }

BOOST_AUTO_TEST_SUITE_END()

// =====================test initialization shape(FrameRect)=====================
BOOST_AUTO_TEST_SUITE(TestFrameRectWhenInitializeShape)

  BOOST_AUTO_TEST_CASE(TestFrameRectWhenInitializeShape_DefaultConstructors_ThrowError)
  {
    jianing::CompositeShape com_shape;

    BOOST_REQUIRE_THROW(com_shape.getFrameRect().pos.x, std::logic_error);
    BOOST_REQUIRE_THROW(com_shape.getFrameRect().pos.y, std::logic_error);
    BOOST_REQUIRE_THROW(com_shape.getFrameRect().width, std::logic_error);
    BOOST_REQUIRE_THROW(com_shape.getFrameRect().height, std::logic_error);
  }

  BOOST_AUTO_TEST_CASE(TestFrameRectWhenInitializeShape_DefaultParameterConstructor_NoError)
  {
    jianing::point_t center = {1.1, 2.2};
    double r_cirle = 3.3;
    jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

    jianing::CompositeShape com_shape;
    com_shape.pushShape(circle);

    BOOST_REQUIRE_CLOSE(1.1, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_REQUIRE_CLOSE(2.2, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, com_shape.getFrameRect().width, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, com_shape.getFrameRect().height, accuracy);
  }

  BOOST_AUTO_TEST_CASE(TestFrameRectWhenInitializeShape_TestCopyConstructor_NoError)
  {
    jianing::point_t center = {1.1, 2.2};
    double r_cirle = 3.3;
    jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

    jianing::CompositeShape old_com_shape;
    old_com_shape.pushShape(circle);

    jianing::CompositeShape new_com_shape = old_com_shape;

    BOOST_REQUIRE_CLOSE(1.1, new_com_shape.getFrameRect().pos.x, accuracy);
    BOOST_REQUIRE_CLOSE(2.2, new_com_shape.getFrameRect().pos.y, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, new_com_shape.getFrameRect().width, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, new_com_shape.getFrameRect().height, accuracy);

    BOOST_REQUIRE_CLOSE(1.1, old_com_shape.getFrameRect().pos.x, accuracy);
    BOOST_REQUIRE_CLOSE(2.2, old_com_shape.getFrameRect().pos.y, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, old_com_shape.getFrameRect().width, accuracy);
    BOOST_REQUIRE_CLOSE(3.3 * 2.0, old_com_shape.getFrameRect().height, accuracy);
  }

BOOST_AUTO_TEST_SUITE_END()

// =====================test function pushShape=====================
BOOST_AUTO_TEST_SUITE(TestpushShape)

    BOOST_AUTO_TEST_CASE(TestpushShape_PushCorrectShape_NoError)
    {
      jianing::point_t center = {1.1, 2.2};
      double r_cirle = 3.3;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      jianing::CompositeShape com_shape;

      com_shape.pushShape(circle);

      BOOST_CHECK_EQUAL(1, com_shape.getSize());
      BOOST_CHECK_EQUAL(3, com_shape.getCapacity());
      BOOST_CHECK_EQUAL(false, com_shape.empty());
      BOOST_CHECK_CLOSE(1.1, com_shape.getCenter().x, accuracy);
      BOOST_CHECK_CLOSE(2.2, com_shape.getCenter().y, accuracy);
      BOOST_CHECK_CLOSE(M_PI * 3.3 * 3.3, com_shape.getArea(), accuracy);
    }

    BOOST_AUTO_TEST_CASE(TestpushShape_PushNullptr_ThrowError)
    {
      jianing::CompositeShape com_shape;

      BOOST_CHECK_THROW(com_shape.pushShape(nullptr), std::invalid_argument);
    }

BOOST_AUTO_TEST_SUITE_END()

// =====================test function pushShape(FrameRect)=====================
BOOST_AUTO_TEST_SUITE(TestFrameRectAfterpushShape)

    BOOST_AUTO_TEST_CASE(TestFrameRectAfterpushShape_PushCorrectShape_NoError)
    {
      jianing::point_t center = {1.1, 2.2};
      double r_cirle = 3.3;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      jianing::CompositeShape com_shape;

      com_shape.pushShape(circle);

      BOOST_CHECK_CLOSE(1.1, com_shape.getFrameRect().pos.x, accuracy);
      BOOST_CHECK_CLOSE(2.2, com_shape.getFrameRect().pos.y, accuracy);
      BOOST_CHECK_CLOSE(3.3 * 2.0, com_shape.getFrameRect().width, accuracy);
      BOOST_CHECK_CLOSE(3.3 * 2.0, com_shape.getFrameRect().height, accuracy);
    }

BOOST_AUTO_TEST_SUITE_END()

// =====================test function removeShape=====================
BOOST_AUTO_TEST_SUITE(TestRemoveShape)

    BOOST_AUTO_TEST_CASE(TestRemoveShape_CorrectValueAfterPushShape_NoError)
    {
      jianing::CompositeShape com_shape;

      // push first shape
      jianing::point_t center = {1.2, 2.2};
      double r_cirle = 3.2;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      com_shape.pushShape(circle);

      // push second shape
      jianing::rectangle_t center_width_height_rec = {5.1, 9.3, 13.6, 21.3};
      jianing::Shape::ShapePtr rectangle = std::make_shared<jianing::Rectangle>(center_width_height_rec);

      com_shape.pushShape(rectangle);

      //remove first shape
      com_shape.removeShape(0);

      BOOST_CHECK_EQUAL(1, com_shape.getSize());

      BOOST_CHECK_CLOSE(13.6, com_shape.getCenter().x, accuracy);
      BOOST_CHECK_CLOSE(21.3, com_shape.getCenter().y, accuracy);
      BOOST_CHECK_CLOSE(5.1 * 9.3, com_shape.getArea(), accuracy);

      //remove second shape
      com_shape.removeShape(0);

      BOOST_CHECK_EQUAL(0, com_shape.getSize());
      BOOST_CHECK_EQUAL(0.0, com_shape.getArea());

      BOOST_CHECK_THROW(com_shape.getCenter().x, std::logic_error);
      BOOST_CHECK_THROW(com_shape.getCenter().y, std::logic_error);
    }

    BOOST_AUTO_TEST_CASE(TestRemoveShape_RemoveShapeWhenArrayEmpty_ThrowError)
    {
      jianing::CompositeShape com_shape;

      BOOST_CHECK_THROW(com_shape.removeShape(0), std::out_of_range);

      // push one shape
      jianing::point_t center = {4.5, 7.7};
      double r_cirle = 8.9;
      jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

      com_shape.pushShape(circle);

      BOOST_CHECK_THROW(com_shape.removeShape(8), std::out_of_range);
    }

BOOST_AUTO_TEST_SUITE_END()

// =====================Test Frame Rect After Remove Shape=====================
BOOST_AUTO_TEST_SUITE(TestFrameRectAfterPushAndRemoveShape)

  BOOST_AUTO_TEST_CASE(TestFrameRectAfterRemoveShape_CorrectValueAfterPushShape_Noerror)
  {
    jianing::CompositeShape com_shape;

    // push first shape
    jianing::point_t center = {1.0, 2.0};
    double r_cirle = 1.0;
    jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

    com_shape.pushShape(circle);

    BOOST_CHECK_CLOSE(1.0, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_CHECK_CLOSE(2.0, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().width, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().height, accuracy);

    // push second shape
    jianing::rectangle_t center_width_height_rec = {1.0, 2.0, 0.5, 1.0};
    jianing::Shape::ShapePtr rectangle = std::make_shared<jianing::Rectangle>(center_width_height_rec);

    com_shape.pushShape(rectangle);

    BOOST_CHECK_CLOSE((1.0 + 1.0) / 2, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_CHECK_CLOSE((1.0 + 2.0) / 2, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().width, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 2.0, com_shape.getFrameRect().height, accuracy);

    //remove first shape
    com_shape.removeShape(0);

    BOOST_CHECK_CLOSE(0.5, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_CHECK_CLOSE(1.0, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_CHECK_CLOSE(1.0, com_shape.getFrameRect().width, accuracy);
    BOOST_CHECK_CLOSE(2.0, com_shape.getFrameRect().height, accuracy);

    //remove second shape
    com_shape.removeShape(0);

    BOOST_CHECK_THROW(com_shape.getFrameRect().pos.x, std::logic_error);
    BOOST_CHECK_THROW(com_shape.getFrameRect().pos.y, std::logic_error);
    BOOST_CHECK_THROW(com_shape.getFrameRect().width, std::logic_error);
    BOOST_CHECK_THROW(com_shape.getFrameRect().height, std::logic_error);
  }

BOOST_AUTO_TEST_SUITE_END()

// =====================Test size and capacity=====================
BOOST_AUTO_TEST_SUITE(TestSizeAndCapacity)

  BOOST_AUTO_TEST_CASE(TestSizeAndCapacity_OnCorrectValue_NoError)
  {
    jianing::CompositeShape com_shape;

    BOOST_CHECK_EQUAL(0, com_shape.getSize());
    BOOST_CHECK_EQUAL(3, com_shape.getCapacity());

    // push one shape
    jianing::rectangle_t first_center_width_height_rec = {3.3, 2.2, 3.5, 1.4};
    jianing::Shape::ShapePtr first_rectangle = std::make_shared<jianing::Rectangle>(first_center_width_height_rec);

    com_shape.pushShape(first_rectangle);

    BOOST_CHECK_EQUAL(1, com_shape.getSize());
    BOOST_CHECK_EQUAL(3, com_shape.getCapacity());

    // test resever
    com_shape.reserve(22);

    BOOST_CHECK_EQUAL(1, com_shape.getSize());
    BOOST_CHECK_EQUAL(22, com_shape.getCapacity());

    // reduce capacity
    com_shape.reserve(1);

    BOOST_CHECK_EQUAL(1, com_shape.getSize());
    BOOST_CHECK_EQUAL(1, com_shape.getCapacity());
    BOOST_CHECK_EQUAL(3.5, com_shape.getCenter().x);
    BOOST_CHECK_EQUAL(1.4, com_shape.getCenter().y);
    BOOST_CHECK_CLOSE(3.3 * 2.2, com_shape.getArea(), accuracy);
  }

BOOST_AUTO_TEST_SUITE_END()

// =====================Test scale shape=====================
BOOST_AUTO_TEST_SUITE(TestSacle)

  BOOST_AUTO_TEST_CASE(TestSacle_OnCorrectValue_NoError)
  {
  jianing::CompositeShape com_shape;

  // push first shape
  jianing::point_t center = {1.0, 1.0};
  double r_cirle = 1.0;
  jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

  com_shape.pushShape(circle);

  // push second shape
  jianing::rectangle_t center_width_height_rec = {2.0, 4.0, 2.0, 2.0};
  jianing::Shape::ShapePtr rectangle = std::make_shared<jianing::Rectangle>(center_width_height_rec);

  com_shape.pushShape(rectangle);

  BOOST_CHECK_CLOSE((2.0 + 1.0) / 2.0, com_shape.getFrameRect().pos.x, accuracy);
  BOOST_CHECK_CLOSE((2.0 + 2.0) / 2.0, com_shape.getFrameRect().pos.y, accuracy);
  BOOST_CHECK_CLOSE(1.0 + 2.0, com_shape.getFrameRect().width, accuracy);
  BOOST_CHECK_CLOSE(4.0, com_shape.getFrameRect().height, accuracy);

  //remove first shape
  com_shape.scale(2.0);

  BOOST_CHECK_CLOSE((-1.5 + 4.5) / 2.0, com_shape.getFrameRect().pos.x, accuracy);
  BOOST_CHECK_CLOSE((-1.5 + 5.5) / 2.0, com_shape.getFrameRect().pos.y, accuracy);
  BOOST_CHECK_CLOSE(1.5 + 4.5, com_shape.getFrameRect().width, accuracy);
  BOOST_CHECK_CLOSE(2.5 + 5.5, com_shape.getFrameRect().height, accuracy);
  }

  BOOST_AUTO_TEST_CASE(TestSacle_OnValueOne_ShapeNoChange)
  {
    jianing::CompositeShape com_shape;

    // push first shape
    jianing::point_t center = {1.0, 2.0};
    double r_cirle = 1.0;
    jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

    com_shape.pushShape(circle);

    BOOST_CHECK_CLOSE(1.0, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_CHECK_CLOSE(2.0, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().width, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().height, accuracy);

    // push second shape
    jianing::rectangle_t center_width_height_rec = {1.0, 2.0, 0.5, 1.0};
    jianing::Shape::ShapePtr rectangle = std::make_shared<jianing::Rectangle>(center_width_height_rec);

    com_shape.pushShape(rectangle);

    com_shape.scale(1.0);

    BOOST_CHECK_CLOSE((1.0 + 1.0) / 2, com_shape.getFrameRect().pos.x, accuracy);
    BOOST_CHECK_CLOSE((1.0 + 2.0) / 2, com_shape.getFrameRect().pos.y, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 1.0, com_shape.getFrameRect().width, accuracy);
    BOOST_CHECK_CLOSE(1.0 + 2.0, com_shape.getFrameRect().height, accuracy);
  }

  BOOST_AUTO_TEST_CASE(TestSacle_OnWrongValue_ThrowError)
  {
    jianing::CompositeShape com_shape;

    jianing::point_t center = {2.5, 3.5};
    double r_cirle = 3.0;
    jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(center, r_cirle);

    com_shape.pushShape(circle);

    BOOST_CHECK_THROW(com_shape.scale(-2.3), std::domain_error);
  }

BOOST_AUTO_TEST_SUITE_END()

// =====================test rotate composize shape=====================
BOOST_AUTO_TEST_SUITE(TestSacleComposizeShape)

  BOOST_AUTO_TEST_CASE(TestSacleComposizeShape_InPositiveDirection_CorrectWigthHeightXYAfterRotate)
  {
  jianing::CompositeShape com_shape;

  // push first shape
  jianing::point_t circle_center = {1.0, 1.0};
  double r_cirle = 2.0;
  jianing::Shape::ShapePtr circle = std::make_shared<jianing::Circle>(circle_center, r_cirle);

  com_shape.pushShape(circle);

  // push second shape
  jianing::rectangle_t center_width_height_rec = {2.0, 4.0, 2.0, 2.0};
  jianing::Shape::ShapePtr rectangle = std::make_shared<jianing::Rectangle>(center_width_height_rec);

  com_shape.pushShape(rectangle);

  jianing::point_t center_rotation = com_shape.getCenter();
  const double area = com_shape.getArea();

  //remove first shape
  com_shape.rotate(30);

  const double cos = std::cos(2 * M_PI * 30 / 360);
  const double sin = std::sin(2 * M_PI * 30 / 360);

  // test cirle
  const double dx_circle = (circle_center.x - center_rotation.x) * cos - (circle_center.y - center_rotation.y) * sin;
  const double dy_ciecle = (circle_center.x - center_rotation.x) * sin + (circle_center.y - center_rotation.y) * cos;

  BOOST_CHECK_CLOSE(center_rotation.x + dx_circle, com_shape[0]->getFrameRect().pos.x, accuracy);
  BOOST_CHECK_CLOSE(center_rotation.y + dy_ciecle, com_shape[0]->getFrameRect().pos.y, accuracy);
  BOOST_CHECK_CLOSE(r_cirle * 2.0, com_shape[0]->getFrameRect().width, accuracy);
  BOOST_CHECK_CLOSE(r_cirle * 2.0, com_shape[0]->getFrameRect().height, accuracy);
  BOOST_CHECK_CLOSE(M_PI * r_cirle * r_cirle, com_shape[0]->getArea(), accuracy);

  // test rectangle
  const double dx_rectangle = (center_width_height_rec.pos.x - center_rotation.x) * cos - (center_width_height_rec.pos.y - center_rotation.y) * sin;
  const double dy_rectangle = (center_width_height_rec.pos.x - center_rotation.x) * sin + (center_width_height_rec.pos.y - center_rotation.y) * cos;
  const double width_rectange = center_width_height_rec.width * std::fabs(cos) + center_width_height_rec.height * std::fabs(sin);
  const double height_rectange = center_width_height_rec.height * std::fabs(cos) + center_width_height_rec.width * std::fabs(sin);

  BOOST_CHECK_CLOSE(center_rotation.x + dx_rectangle, com_shape[1]->getFrameRect().pos.x, accuracy);
  BOOST_CHECK_CLOSE(center_rotation.y + dy_rectangle, com_shape[1]->getFrameRect().pos.y, accuracy);
  BOOST_CHECK_CLOSE(width_rectange, com_shape[1]->getFrameRect().width, accuracy);
  BOOST_CHECK_CLOSE(height_rectange, com_shape[1]->getFrameRect().height, accuracy);
  BOOST_CHECK_CLOSE(center_width_height_rec.width * center_width_height_rec.height, com_shape[1]->getArea(), accuracy);

  // test all the composize shape
  const double top = com_shape[1]->getFrameRect().pos.y + com_shape[1]->getFrameRect().height / 2.0;
  const double bottom = com_shape[0]->getFrameRect().pos.y - com_shape[0]->getFrameRect().height / 2.0;
  const double left = com_shape[0]->getFrameRect().pos.x - com_shape[0]->getFrameRect().width / 2.0;
  const double right = com_shape[1]->getFrameRect().pos.x + com_shape[1]->getFrameRect().width / 2.0;

  BOOST_CHECK_CLOSE((right - left) / 2.0 + left, com_shape.getFrameRect().pos.x, accuracy);
  BOOST_CHECK_CLOSE((top - bottom) / 2.0 + bottom, com_shape.getFrameRect().pos.y, accuracy);
  BOOST_CHECK_CLOSE(right - left, com_shape.getFrameRect().width, accuracy);
  BOOST_CHECK_CLOSE(top - bottom, com_shape.getFrameRect().height, accuracy);
  BOOST_CHECK_CLOSE(area, com_shape.getArea(), accuracy);
  }

BOOST_AUTO_TEST_SUITE_END()


#ifdef STAN_OPENCL

#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/copy.hpp>
#include <test/unit/math/opencl/kernel_generator/reference_kernel.hpp>
#include <Eigen/Dense>
#include <gtest/gtest.h>
#include <string>

using Eigen::Matrix;
using Eigen::MatrixXd;
using Eigen::MatrixXi;
using stan::math::matrix_cl;

#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(A(i), B(i), DELTA);

TEST(KernelGenerator, select_errors) {
  using stan::math::select;

  matrix_cl<double> m_double(2, 3);
  matrix_cl<double> m_rows(3, 3);
  matrix_cl<double> m_cols(2, 4);
  matrix_cl<int> m_int(2, 3);
  matrix_cl<bool> m_bool(2, 3);

  EXPECT_NO_THROW(select(m_bool, m_double, m_double));
  EXPECT_NO_THROW(select(m_bool, m_double, m_int));
  EXPECT_NO_THROW(select(m_bool, m_int, m_double));
  EXPECT_NO_THROW(select(m_int, m_double, m_double));
  EXPECT_THROW(select(m_rows, m_double, m_double), std::invalid_argument);
  EXPECT_THROW(select(m_cols, m_double, m_double), std::invalid_argument);
  EXPECT_THROW(select(m_bool, m_rows, m_double), std::invalid_argument);
  EXPECT_THROW(select(m_bool, m_cols, m_double), std::invalid_argument);
  EXPECT_THROW(select(m_bool, m_double, m_rows), std::invalid_argument);
  EXPECT_THROW(select(m_bool, m_double, m_cols), std::invalid_argument);
}

TEST(KernelGenerator, select_zero_size) {
  matrix_cl<double> m_bool_zero(0, 0);
  matrix_cl<double> m_double_zero(0, 0);
  matrix_cl<int> m_int_zero(0, 0);
  matrix_cl<int> m_int_zero_rows(0, 1);

  EXPECT_NO_THROW(select(m_bool_zero, m_double_zero, m_double_zero));
  EXPECT_NO_THROW(select(m_bool_zero, m_double_zero, m_int_zero));
  EXPECT_NO_THROW(select(m_bool_zero, m_int_zero, m_double_zero));
  EXPECT_THROW(select(m_bool_zero, m_double_zero, m_int_zero_rows),
               std::invalid_argument);
}

TEST(KernelGenerator, select_test) {
  std::string kernel_filename = "select.cl";
  using stan::math::select;
  MatrixXd m1(2, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3;
  MatrixXd m2(2, 3);
  m2 << 10, 100, 1000, 30.5, 12.1, 0.3;
  Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> m_cond(2, 3);
  m_cond << true, false, false, true, true, false;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);
  matrix_cl<bool> m_cond_cl(m_cond);

  auto tmp = select(m_cond_cl, m1_cl, m2_cl);

  matrix_cl<double> res_cl;
  std::string kernel_src = tmp.get_kernel_source_for_evaluating_into(res_cl);
  stan::test::store_reference_kernel_if_needed(kernel_filename, kernel_src);
  std::string expected_kernel_src
      = stan::test::load_reference_kernel(kernel_filename);
  EXPECT_EQ(expected_kernel_src, kernel_src);

  res_cl = tmp;
  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m_cond.select(m1, m2);
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

TEST(KernelGenerator, multiple_operations) {
  using stan::math::select;
  MatrixXd m1(2, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3;
  MatrixXi m2(2, 3);
  m2 << 10, 100, 1000, 30, 12, 0;
  MatrixXd m3(2, 3);
  m3 << 1.4, 12.5, 6.3, 34.4, -5, -6.3;
  Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> m_cond(2, 3);
  m_cond << true, false, false, true, true, false;
  Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> m_cond2(2, 3);
  m_cond2 << false, false, true, true, false, true;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<int> m2_cl(m2);
  matrix_cl<double> m3_cl(m3);
  matrix_cl<bool> m_cond_cl(m_cond);
  matrix_cl<bool> m_cond2_cl(m_cond2);
  auto tmp = select(m_cond_cl, m1_cl, select(m_cond2_cl, m2_cl, m3_cl));
  matrix_cl<double> res_cl = tmp;

  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m_cond.select(m1, m_cond2.select(m2.cast<double>(), m3));
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

TEST(KernelGenerator, multiple_operations_size_zero) {
  using stan::math::select;

  matrix_cl<double> m1_cl(0, 0);
  matrix_cl<int> m2_cl(0, 0);
  matrix_cl<double> m3_cl(0, 0);
  matrix_cl<bool> m_cond_cl(0, 0);
  matrix_cl<bool> m_cond2_cl(0, 0);
  auto tmp = select(m_cond_cl, m1_cl, select(m_cond2_cl, m2_cl, m3_cl));
  matrix_cl<double> res_cl = tmp;

  EXPECT_EQ(0, res_cl.rows());
  EXPECT_EQ(0, res_cl.cols());
}

TEST(KernelGenerator, multiple_operations_accepts_lvalue) {
  using stan::math::select;
  MatrixXd m1(2, 3);
  m1 << 1, 2.5, 3, 4, 5, 6.3;
  MatrixXi m2(2, 3);
  m2 << 10, 100, 1000, 30, 12, 0;
  MatrixXd m3(2, 3);
  m3 << 1.4, 12.5, 6.3, 34.4, -5, -6.3;
  Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> m_cond(2, 3);
  m_cond << true, false, false, true, true, false;
  Matrix<bool, Eigen::Dynamic, Eigen::Dynamic> m_cond2(2, 3);
  m_cond2 << false, false, true, true, false, true;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<int> m2_cl(m2);
  matrix_cl<double> m3_cl(m3);
  matrix_cl<bool> m_cond_cl(m_cond);
  matrix_cl<bool> m_cond2_cl(m_cond2);
  auto tmp2 = select(m_cond2_cl, m2_cl, m3_cl);
  auto tmp = select(m_cond_cl, m1_cl, tmp2);
  matrix_cl<double> res_cl = tmp;

  MatrixXd res = stan::math::from_matrix_cl(res_cl);

  MatrixXd correct = m_cond.select(m1, m_cond2.select(m2.cast<double>(), m3));
  EXPECT_MATRIX_NEAR(res, correct, 1e-9);
}

#endif


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

/*
 Copyright (C) 2013 Peter Caspers

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file nonstandardswap.hpp
    \brief vanilla swap but possibly with period dependent nominal and strike
*/

#ifndef quantlib_nonstandard_swap_hpp
#define quantlib_nonstandard_swap_hpp

#include <ql/instruments/swap.hpp>
#include <ql/instruments/vanillaswap.hpp>
#include <ql/time/daycounter.hpp>
#include <ql/time/schedule.hpp>
#include <boost/optional.hpp>

namespace QuantLib {

    class IborIndex;
    class SwapIndex;

    //! nonstandard swap

    class NonstandardSwap : public Swap {
      public:
        class arguments;
        class results;
        class engine;
        NonstandardSwap(const VanillaSwap &fromVanilla);
        NonstandardSwap(
            const VanillaSwap::Type type, const std::vector<Real> &fixedNominal,
            const std::vector<Real> &floatingNominal,
            const Schedule &fixedSchedule, const std::vector<Real> &fixedRate,
            const DayCounter &fixedDayCount, const Schedule &floatingSchedule,
            const boost::shared_ptr<IborIndex> &iborIndex, const Real gearing,
            const Spread spread, const DayCounter &floatingDayCount,
            const bool intermediateCapitalExchange = false,
            const bool finalCapitalExchange = false,
            boost::optional<BusinessDayConvention> paymentConvention =
                boost::none);
        //! \name Inspectors
        //@{
        VanillaSwap::Type type() const;
        const std::vector<Real> &fixedNominal() const;
        const std::vector<Real> &floatingNominal() const;

        const Schedule &fixedSchedule() const;
        const std::vector<Real> &fixedRate() const;
        const DayCounter &fixedDayCount() const;

        const Schedule &floatingSchedule() const;
        const boost::shared_ptr<IborIndex> &iborIndex() const;
        const Spread spread() const;
        const Real gearing() const;
        const DayCounter &floatingDayCount() const;

        BusinessDayConvention paymentConvention() const;

        const Leg &fixedLeg() const;
        const Leg &floatingLeg() const;
        //@}

        //! \name Results
        //@{
        //@}
        // other
        void setupArguments(PricingEngine::arguments *args) const;
        void fetchResults(const PricingEngine::results *) const;

      private:
        void init();
        void setupExpired() const;
        VanillaSwap::Type type_;
        std::vector<Real> fixedNominal_, floatingNominal_;
        Schedule fixedSchedule_;
        std::vector<Real> fixedRate_;
        DayCounter fixedDayCount_;
        Schedule floatingSchedule_;
        boost::shared_ptr<IborIndex> iborIndex_;
        Spread spread_;
        Real gearing_;
        DayCounter floatingDayCount_;
        BusinessDayConvention paymentConvention_;
        const bool intermediateCapitalExchange_;
        const bool finalCapitalExchange_;
        // results
    };

    //! %Arguments for nonstandard swap calculation
    class NonstandardSwap::arguments : public Swap::arguments {
      public:
        arguments() : type(VanillaSwap::Receiver) {}
        VanillaSwap::Type type;
        std::vector<Real> fixedNominal, floatingNominal;

        std::vector<Date> fixedResetDates;
        std::vector<Date> fixedPayDates;
        std::vector<Time> floatingAccrualTimes;
        std::vector<Date> floatingResetDates;
        std::vector<Date> floatingFixingDates;
        std::vector<Date> floatingPayDates;

        std::vector<Real> fixedCoupons;
        std::vector<Real> fixedRate;
        std::vector<Spread> floatingSpreads;
        std::vector<Real> floatingGearings;
        std::vector<Real> floatingCoupons;

        boost::shared_ptr<IborIndex> iborIndex;

        std::vector<bool> fixedIsRedemptionFlow;
        std::vector<bool> floatingIsRedemptionFlow;

        void validate() const;
    };

    //! %Results from nonstandard swap calculation
    class NonstandardSwap::results : public Swap::results {
      public:
        void reset();
    };

    class NonstandardSwap::engine
        : public GenericEngine<NonstandardSwap::arguments,
                               NonstandardSwap::results> {};

    // inline definitions

    inline VanillaSwap::Type NonstandardSwap::type() const { return type_; }

    inline const std::vector<Real> &NonstandardSwap::fixedNominal() const {
        return fixedNominal_;
    }

    inline const std::vector<Real> &NonstandardSwap::floatingNominal() const {
        return floatingNominal_;
    }

    inline const Schedule &NonstandardSwap::fixedSchedule() const {
        return fixedSchedule_;
    }

    inline const std::vector<Real> &NonstandardSwap::fixedRate() const {
        return fixedRate_;
    }

    inline const DayCounter &NonstandardSwap::fixedDayCount() const {
        return fixedDayCount_;
    }

    inline const Schedule &NonstandardSwap::floatingSchedule() const {
        return floatingSchedule_;
    }

    inline const boost::shared_ptr<IborIndex> &
    NonstandardSwap::iborIndex() const {
        return iborIndex_;
    }

    inline const Spread NonstandardSwap::spread() const { return spread_; }

    inline const Real NonstandardSwap::gearing() const { return gearing_; }

    inline const DayCounter &NonstandardSwap::floatingDayCount() const {
        return floatingDayCount_;
    }

    inline BusinessDayConvention NonstandardSwap::paymentConvention() const {
        return paymentConvention_;
    }

    inline const Leg &NonstandardSwap::fixedLeg() const { return legs_[0]; }

    inline const Leg &NonstandardSwap::floatingLeg() const { return legs_[1]; }
}

#endif


//=====================================================
// File   :  MTL_LU_solve_interface.hh
// Author :  L. Plagne <laurent.plagne@edf.fr)>
// Copyright (C) EDF R&D,  lun sep 30 14:23:27 CEST 2002
//=====================================================
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
#ifndef MTL_LU_SOLVE_INTERFACE_HH
#define MTL_LU_SOLVE_INTERFACE_HH

#include "mtl/matrix.h"
#include "mtl/mtl.h"
#include "mtl/utils.h"
#include "utilities.h"
#include <vector>
#include <string>
#include <mtl/lu.h>

using namespace mtl;

template<class real>
class MTL_LU_solve_interface : public MTL_interface<real>
{

public :

  typedef typename MTL_interface<real>::gene_matrix gene_matrix;
  typedef typename MTL_interface<real>::gene_vector gene_vector;

  typedef dense1D<int> Pivot_Vector;

  inline static void new_Pivot_Vector(Pivot_Vector & pivot,int N)
  {

    pivot.resize(N);

  }

  inline static void free_Pivot_Vector(Pivot_Vector & pivot)
  {

    return;

  }

  inline static void LU_factor(gene_matrix & LU, Pivot_Vector & pivot, int N)
  {

    lu_factor(LU,pivot);

  }

  inline static void LU_solve(const gene_matrix & LU, const Pivot_Vector pivot, const gene_vector &B, gene_vector X, int N)
  {

    lu_solve(LU,pivot,B,X);

  }

};

#endif


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_CONSTANT_CONSTANTS_VALMAX_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_CONSTANTS_VALMAX_HPP_INCLUDED

#include <boost/simd/include/functor.hpp>
#include <boost/simd/meta/int_c.hpp>
#include <boost/simd/meta/float.hpp>
#include <boost/simd/meta/double.hpp>
#include <boost/simd/constant/hierarchy.hpp>

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4310) // cast truncate constants
#endif

namespace boost { namespace simd
{
  namespace tag
  {
   /*!
     @brief Valmax generic tag

     Represents the Valmax constant in generic contexts.

     @par Models:
        Hierarchy
   **/
    struct Valmax : ext::pure_constant_<Valmax>
    {
      typedef double default_type;
      typedef ext::pure_constant_<Valmax> parent;

      /// INTERNAL ONLY
      template<class Target, class Dummy=void>
      struct  apply
      {
        // MSVC has some problem parsing this directly as a base class ...
        typedef typename Target::type target_t;
        static const target_t value = ~(typename Target::type
                                        (   typename Target::type(1)
                                          <<  ( sizeof(typename Target::type)
                                              * CHAR_BIT-1
                                              )
                                        )
                                       );

        typedef  meta::int_c < target_t, value> type;
      };
      template<class... Args>
      static BOOST_FORCEINLINE BOOST_AUTO_DECLTYPE dispatch(Args&&... args)
      BOOST_AUTO_DECLTYPE_BODY( dispatching_Valmax( ext::adl_helper(), static_cast<Args&&>(args)... ) )
    };

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply< boost::dispatch::meta::single_<T>,Dummy>
          : meta::single_<0x7F7FFFFF> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply<boost::dispatch::meta::double_<T>,Dummy>
          : meta::double_<0x7FEFFFFFFFFFFFFFULL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply<boost::dispatch::meta::uint8_<T>,Dummy>
          : meta::int_c<T, 0xFF> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply<boost::dispatch::meta::uint16_<T>,Dummy>
          : meta::int_c<T, 0xFFFF> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply<boost::dispatch::meta::uint32_<T>,Dummy>
          : meta::int_c<T, 0xFFFFFFFFUL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmax::apply<boost::dispatch::meta::uint64_<T>,Dummy>
          : meta::int_c<T, 0xFFFFFFFFFFFFFFFFULL> {};
  }
  namespace ext
  {
   template<class Site, class... Ts>
   BOOST_FORCEINLINE generic_dispatcher<tag::Valmax, Site> dispatching_Valmax(adl_helper, boost::dispatch::meta::unknown_<Site>, boost::dispatch::meta::unknown_<Ts>...)
   {
     return generic_dispatcher<tag::Valmax, Site>();
   }
   template<class... Args>
   struct impl_Valmax;
  }
  /*!
    Generates the greatest finite value of a type.

    @par Semantic:

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

    is similar to:

    @code
    if T is unsigned integral
      r = Allbits<T>();
    if T is signed integral
      r = Allbits<T>()^Signmask<T>();
    else if T is double
      r = 1.7976931348623157e+308
    else if T is float
      r = 3.4028234e+38f
    @endcode
  **/
  BOOST_SIMD_CONSTANT_IMPLEMENTATION(boost::simd::tag::Valmax, Valmax)
} }

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#include <boost/simd/constant/common.hpp>

#endif


// (C) 2014 Arek Olek

#include <iostream>

#include <boost/graph/adjacency_list.hpp>

#include "debug.hpp"
#include "options.hpp"
#include "test_suite.hpp"
#include "range.hpp"

using namespace std;

typedef boost::adjacency_list<
  boost::hash_setS, boost::vecS, boost::undirectedS
  > graph;

int main(int argc, char** argv) {
  options opt(argc, argv);
  int z = opt.get<int>("-z", 1);
  int n = opt.get<int>("-n", 5);
  float p = opt.get<float>("-p", 1);

  test_suite<graph> suite("gnp", z, n, p);

  cout << suite.size() << endl;

  for(auto const& G : suite) {

    show("tego.dot", G, G);

    cout << num_vertices(G) << " " << num_edges(G) << endl;
    for(auto e : range(edges(G)))
      cout << source(e, G) << " " << target(e, G) << endl;

  }

  return 0;
}


// Copyright (c) 2005 - 2014 Marc de Kamps
// 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 the copyright holder 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.
//
//      If you use this software in work leading to a scientific publication, you should include a reference there to
//      the 'currently valid reference', which can be found at http://miind.sourceforge.net
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <GeomLib.hpp>

using namespace GeomLib;
using namespace MPILib;

BOOST_AUTO_TEST_CASE(LeakingOdeSystemCreationTest){

	Number n_plus = 3;

	Time t_mem        =  10e-3;
	Time t_ref        =  0.0;
	Potential V_min   = -0.1;
	Potential V_peak  =  20e-3;
	Potential V_reset =  0.0;
	Potential V_rev   =  0.0;

	NeuronParameter par_neuron(V_peak, V_rev, V_reset, t_ref, t_mem);

	OdeParameter
		par_ode
		(
		 n_plus,
		 V_min,
		 par_neuron,
		 InitialDensityParameter(V_reset,0.0)
		);

	double lambda = 0.01;

	LifNeuralDynamics dyn(par_ode,lambda);
	LeakingOdeSystem syst(dyn);

	pair<Number,Number> bins = syst.BinDistribution();

	BOOST_CHECK(bins.first == 3 && bins.second == 4);
	BOOST_CHECK_CLOSE(syst.TStep(),0.0230259,1e-3);

	double v_0  = syst.InterpretationBuffer()[0];
	double v_1  = syst.InterpretationBuffer()[4];
	double v_2  = syst.InterpretationBuffer()[6];

	BOOST_CHECK_CLOSE(v_0, -0.2, 1e-3);
	BOOST_CHECK      (v_1 == 0.0 );
	BOOST_CHECK_CLOSE(v_2, 0.002, 1e-3);

	BOOST_CHECK( syst.IndexResetBin() == 4);

	BOOST_CHECK(syst.MassBuffer()[0] == 0.0);
	BOOST_CHECK(syst.MassBuffer()[3] == 0.0);
	BOOST_CHECK(syst.MassBuffer()[4] == 1.0);
	BOOST_CHECK(syst.MassBuffer()[5] == 0.0);

}

BOOST_AUTO_TEST_CASE(DensityInitialization)
{
	Number n_plus = 3;

	Time t_mem        =  10e-3;
	Time t_ref        =  0.0;
	Potential V_min   = -0.1;
	Potential V_peak  =  20e-3;
	Potential V_reset =  0.0;
	Potential V_rev   =  0.0;

	NeuronParameter par_neuron(V_peak, V_rev, V_reset, t_ref, t_mem);

	OdeParameter
		par_ode
		(
		 n_plus,
		 V_min,
		 par_neuron,
		 InitialDensityParameter(V_reset,0.0)
		);

	double lambda = 0.01;

	LifNeuralDynamics dyn(par_ode, lambda);
	LeakingOdeSystem syst(dyn);

	pair<Number,Number> number_bins = syst.BinDistribution();

	vector<Potential> array_interpretation(number_bins.first + number_bins.second);
	vector<Potential> array_density(number_bins.first + number_bins.second);

	syst.PrepareReport(&(array_interpretation[0]),&(array_density[0]));
}

BOOST_AUTO_TEST_CASE(BinMapTest)
{
	Number n_plus = 3;

	Time t_mem        =  10e-3;
	Time t_ref        =  0.0;
	Potential V_min   = -0.1;
	Potential V_peak  =  20e-3;
	Potential V_reset =  0.0;
	Potential V_rev   =  0.0;

	NeuronParameter par_neuron(V_peak, V_rev, V_reset, t_ref, t_mem);

	OdeParameter
		par_ode
		(
		 n_plus,
		 V_min,
		 par_neuron,
		 InitialDensityParameter(V_reset,0.0)
		);

	double lambda = 0.01;

	LifNeuralDynamics dyn(par_ode, lambda);
	LeakingOdeSystem syst(dyn);
	pair<Number,Number> number_bins = syst.BinDistribution();

	Number n_bins = number_bins.first + number_bins.second;

	for (Index i = 0; i < n_bins; i++)
		BOOST_CHECK( syst.MapProbabilityToPotentialBin(i) == i );

	syst.Evolve(syst.TStep());

	BOOST_CHECK(syst.MapProbabilityToPotentialBin(0) == 1);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(1) == 2);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(2) == 3);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(3) == 0);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(4) == 6);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(5) == 4);
	BOOST_CHECK(syst.MapProbabilityToPotentialBin(6) == 5);

	for (Index i = 0 ; i < n_bins; i++)
		BOOST_CHECK( syst.MapProbabilityToPotentialBin(syst.MapPotentialToProbabilityBin(i)) == i);
}

BOOST_AUTO_TEST_CASE(TestReversalScoop)
{
	Number n_plus = 3;

	Time t_mem        =  10e-3;
	Time t_ref        =  0.0;
	Potential V_min   = -0.1;
	Potential V_peak  =  20e-3;
	Potential V_reset =  0.0;
	Potential V_rev   =  0.0;

	NeuronParameter par_neuron(V_peak, V_rev, V_reset, t_ref, t_mem);

	OdeParameter
		par_ode
		(
		 n_plus,
		 V_min,
		 par_neuron,
		 InitialDensityParameter(V_peak,0.0)
		);

	double lambda = 0.01;

	LifNeuralDynamics dyn(par_ode, lambda);
	LeakingOdeSystem syst(dyn);
	pair<Number,Number> number_bins = syst.BinDistribution();

	BOOST_CHECK( syst.MassBuffer()[number_bins.first + number_bins.second - 1] == 1.0);

	syst.Evolve(syst.TStep()); // t = 1
	syst.Evolve(syst.TStep()); // t = 2
	BOOST_CHECK( syst.MassBuffer()[number_bins.first + number_bins.second - 1] == 1.0);
	syst.Evolve(syst.TStep()); // t = 3

	// after N_+ evolutions, the probability mass should be in the reversal bin,
	// and stay there, i.e. it moves along with the reversal bin from now on.
	BOOST_CHECK( syst.MassBuffer()[number_bins.first + number_bins.second - 1] == 0.0) ;
	BOOST_CHECK( syst.MassBuffer()[syst.FindBin(V_rev)] == 1.0 );

	syst.Evolve(syst.TStep()); // t = 4
	BOOST_CHECK (syst.MassBuffer()[5] == 1.0);

	syst.Evolve(syst.TStep()); // t = 5
	BOOST_CHECK( syst.MassBuffer()[6] == 1.0 );
}

BOOST_AUTO_TEST_CASE(DecayTest){
	Number n_plus = 3;

	Time t_mem        =  10e-3;
	Time t_ref        =  0.0;
	Potential V_min   = -0.1;
	Potential V_peak  =  20e-3;
	Potential V_reset =  0.0;
	Potential V_rev   =  0.0;

	NeuronParameter par_neuron(V_peak, V_rev, V_reset, t_ref, t_mem);

	OdeParameter
		par_ode
		(
		 n_plus,
		 V_min,
		 par_neuron,
		 InitialDensityParameter(V_min,0.0)
		);

	double lambda = 0.01;

	LifNeuralDynamics dyn(par_ode, lambda);
	LeakingOdeSystem syst(dyn);
	pair<Number,Number> number_bins = syst.BinDistribution();

	Number n_bins = number_bins.first + number_bins.second;

	vector<double> array_interpretation(n_bins);
	vector<double> array_mass(n_bins);

	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);
	BOOST_CHECK (array_mass[0]  > 0.0);
	for (Index i = 1; i < 5; i++)
		BOOST_CHECK (array_mass[i] == 0);

	syst.Evolve(syst.TStep());
	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);

	BOOST_CHECK(array_mass[1] > 0.0);
	for (Index i = 0; i < 5; i++)
		if (i != 1)
			BOOST_CHECK(array_mass[i] == 0.0);

	syst.Evolve(syst.TStep());
	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);
	syst.Evolve(syst.TStep());
	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);
	syst.Evolve(syst.TStep());
	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);
	syst.Evolve(syst.TStep());
	syst.PrepareReport(&array_interpretation[0],&array_mass[0]);

	// Although 5 evolutions have now taken place, the mass remains
	// in the reset bin (i=3). Above it was decaying towards it.
	BOOST_CHECK( array_mass[3] > 0.0 );
	for (Index i = 0; i < 5; i++ )
		if (i != 3)
			BOOST_CHECK( array_mass[i] == 0.0 );
}


/*
 * LightIntensityFilter.cpp
 *
 *  Created on: Sep 23, 2017
 *      Author: Peter Fankhauser
 *   Institute: ETH Zurich, ANYbotics
 */

#include <grid_map_filters/LightIntensityFilter.hpp>

#include <grid_map_core/grid_map_core.hpp>
#include <pluginlib/class_list_macros.h>

#include <Eigen/Dense>

using namespace filters;

namespace grid_map {

template<typename T>
LightIntensityFilter<T>::LightIntensityFilter()
{
}

template<typename T>
LightIntensityFilter<T>::~LightIntensityFilter()
{
}

template<typename T>
bool LightIntensityFilter<T>::configure()
{
  if (!FilterBase < T > ::getParam(std::string("input_layers_prefix"), inputLayersPrefix_)) {
    ROS_ERROR("Light intensity filter did not find parameter `input_layers_prefix`.");
    return false;
  }
  ROS_DEBUG("Light intensity filter input layers prefix is = %s.", inputLayersPrefix_.c_str());

  if (!FilterBase < T > ::getParam(std::string("output_layer"), outputLayer_)) {
    ROS_ERROR("Light intensity filter did not find parameter `output_layer`.");
    return false;
  }
  ROS_DEBUG("Light intensity filter output_layer = %s.", outputLayer_.c_str());

  std::vector<double> lightDirection;
  if (!FilterBase < T > ::getParam(std::string("light_direction"), lightDirection)) {
    ROS_ERROR("Light intensity filter did not find parameter `light_direction`.");
    return false;
  }
  if (lightDirection.size() != 3) {
    ROS_ERROR("Light intensity filter parameter `light_direction` needs to be of size 3.");
    return false;
  }
  lightDirection_ << lightDirection[0], lightDirection[1], lightDirection[2];
  lightDirection_.normalize();
  ROS_DEBUG_STREAM("Light intensity filter light_direction: " << lightDirection_.transpose() << ".");

  return true;
}

template<typename T>
bool LightIntensityFilter<T>::update(const T& mapIn, T& mapOut)
{
  const auto& normalX = mapIn[inputLayersPrefix_ + "x"];
  const auto& normalY = mapIn[inputLayersPrefix_ + "y"];
  const auto& normalZ = mapIn[inputLayersPrefix_ + "z"];

  mapOut = mapIn;
  mapOut.add(outputLayer_);
  auto& color = mapOut[outputLayer_];

  // For each cell in map.
  for (Eigen::Index i = 0; i < color.size(); ++i) {
    if (!std::isfinite(normalZ(i))) {
      color(i) = NAN;
      continue;
    }
    const Eigen::Vector3f normal(normalX(i), normalY(i), normalZ(i));
    const float intensity = std::max<float>(-normal.dot(lightDirection_), 0.0);
    const Eigen::Vector3f colorVector = Eigen::Vector3f::Ones() * intensity;
    colorVectorToValue(colorVector, color(i));
  }

  return true;
}

} /* namespace */

PLUGINLIB_EXPORT_CLASS(grid_map::LightIntensityFilter<grid_map::GridMap>, filters::FilterBase<grid_map::GridMap>)


#include "SMPSInput.hpp"
#include "CbcLagrangeSolver.hpp"
#include "CbcRecourseSolver.hpp"
#include "combineScenarios.hpp"
#include "lagrangeRootNode.hpp"
#include <boost/scoped_ptr.hpp>

using namespace std;
using boost::scoped_ptr;

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

	MPI_Init(&argc, &argv);

	int mype;
	MPI_Comm_rank(MPI_COMM_WORLD,&mype);

	if (argc != 3) {
		if (mype == 0) printf("Usage: %s [SMPS root name] [number per subproblem]\n",argv[0]);
		return 1;
	}

	string smpsrootname(argv[1]);
	int nper = atoi(argv[2]);

	SMPSInput input(smpsrootname+".cor",smpsrootname+".tim",smpsrootname+".sto");
	combinedInput in = combineScenarios(input,nper,true);

	lagrangeRootNode<CbcLagrangeSolver,CbcRecourseSolver>(in);

	MPI_Finalize();

	return 0;

}


// Copyright (c) Dietmar Wolz.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory.

// Eigen based implementation of differential evolution using on the DE/best/1 strategy.
// Uses two deviations from the standard DE algorithm:
// a) temporal locality introduced in
// https://www.researchgate.net/publication/309179699_Differential_evolution_for_protein_folding_optimization_based_on_a_three-dimensional_AB_off-lattice_model
// b) reinitialization of individuals based on their age.
// requires https://github.com/imneme/pcg-cpp

#include <Eigen/Core>
#include <iostream>
#include <float.h>
#include <ctime>
#include <random>
#include "pcg_random.hpp"
#include "call_java.hpp"
#include "biteopt.h"

using namespace std;

typedef Eigen::Matrix<double, Eigen::Dynamic, 1> vec;
typedef Eigen::Matrix<int, Eigen::Dynamic, 1> ivec;
typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> mat;

typedef double (*callback_type)(int, double[]);

namespace biteopt {

// wrapper around the Fitness function, scales according to boundaries

class Fitness {

public:

    Fitness(CallJava *pfunc, const vec &lower_limit, const vec &upper_limit) {
        func = pfunc;
        lower = lower_limit;
        upper = upper_limit;
        evaluationCounter = 0;
        if (lower.size() > 0) // bounds defined
            scale = (upper - lower);
    }

    double eval(const double *const p) {
        int n = lower.size();
        double parg[n];
        for (int i = 0; i < n; i++)
            parg[i] = p[i];
        double res = func->evalJava1(n, parg);
        evaluationCounter++;
        return res;
    }

    int getEvaluations() {
        return evaluationCounter;
    }

    void getMinValues(double *const p) const {
        for (int i = 0; i < lower.size(); i++)
            p[i] = lower[i];
    }

    void getMaxValues(double *const p) const {
        for (int i = 0; i < upper.size(); i++)
            p[i] = upper[i];
    }

private:
    CallJava *func;
    vec lower;
    vec upper;
    long evaluationCounter;
    vec scale;
};

class BiteOptimizer: public CBiteOptDeep {

public:

    BiteOptimizer(long runid_, Fitness *fitfun_, int dim_, double *init_,
            int seed_, int M_, int stallLimit_, int maxEvaluations_, double stopfitness_) {
        // runid used to identify a specific run
        runid = runid_;
        // fitness function to minimize
        fitfun = fitfun_;
        // Number of objective variables/problem dimension
        dim = dim_;
        // Depth to use, 1 for plain CBiteOpt algorithm, >1 for CBiteOptDeep. Expected range is [1; 36].
        M = M_ > 0 ? M_ : 1;
        // stop after stallLimit iters without progress
        stallLimit = stallLimit_ > 0 ? stallLimit_ : 64;
        // maximal number of evaluations allowed.
        maxEvaluations = maxEvaluations_ > 0 ? maxEvaluations_ : 50000;
        // Number of iterations already performed.
        // Limit for fitness value.
        stopfitness = stopfitness_;
        // stop criteria
        stop = 0;

        iterations = 0;
        bestY = DBL_MAX;
        rnd.init(seed_);
        updateDims(dim_, M);
        init(rnd, init_);
    }

    virtual void getMinValues(double *const p) const {
        fitfun->getMinValues(p);
    }

    virtual void getMaxValues(double *const p) const {
        fitfun->getMaxValues(p);
    }

    virtual double optcost(const double *const p) {
        return fitfun->eval(p);
    }

    vec getBestX() {
        vec bestX = vec(dim);
        const double *bx = getBestParams();
        for (int i = 0; i < dim; i++)
            bestX[i] = bx[i];
        return bestX;
    }

    double getBestValue() {
        return getBestCost();
    }

    double getIterations() {
        return iterations;
    }

    double getStop() {
        return stop;
    }

    void doOptimize() {

        // -------------------- Generation Loop --------------------------------
        for (iterations = 1; fitfun->getEvaluations() < maxEvaluations;
                iterations++) {
            int stallCount = optimize(rnd);
            if (getBestCost() < stopfitness) {
                stop = 1;
                break;
            }
            if (stallCount > stallLimit*dim) {
                stop = 2;
                break;
            }
        }
    }

private:
    long runid;
    Fitness *fitfun;
    int M; // deepness
    int stallLimit; // stop after stallLimit iters without progress
    int dim;
    int maxEvaluations;
    double stopfitness;
    int iterations;
    double bestY;
    int stop;
    vec bestX;
    CBiteRnd rnd;
};

}

using namespace biteopt;

/*
 * Class:     fcmaes_core_Jni
 * Method:    optimizeBite
 * Signature: (Lfcmaes/core/Fitness;[D[D[DIDIIJI)I
 */
JNIEXPORT jint JNICALL Java_fcmaes_core_Jni_optimizeBite(JNIEnv *env,
        jclass cls, jobject func, jdoubleArray jlower, jdoubleArray jupper,
        jdoubleArray jinit, jint maxEvals, jdouble stopfitness, jint M,
        jint stallLimit, jlong seed, jint runid) {

    double *init = env->GetDoubleArrayElements(jinit, JNI_FALSE);
    double *lower = env->GetDoubleArrayElements(jlower, JNI_FALSE);
    double *upper = env->GetDoubleArrayElements(jupper, JNI_FALSE);
    int dim = env->GetArrayLength(jinit);
    vec lower_limit(dim), upper_limit(dim);
    bool useLimit = false;
    for (int i = 0; i < dim; i++) {
        lower_limit[i] = lower[i];
        upper_limit[i] = upper[i];
        useLimit |= (lower[i] != 0);
        useLimit |= (upper[i] != 0);
    }
    if (useLimit == false) {
        lower_limit.resize(0);
        upper_limit.resize(0);
    }
    CallJava callJava(func, env);
    Fitness fitfun(&callJava, lower_limit, upper_limit);

    BiteOptimizer opt(runid, &fitfun, dim, init, seed, M, stallLimit, maxEvals,
            stopfitness);

    try {
        opt.doOptimize();
        vec bestX = opt.getBestX();
        double bestY = opt.getBestValue();

        for (int i = 0; i < dim; i++)
            init[i] = bestX[i];

        env->SetDoubleArrayRegion(jinit, 0, dim, (jdouble*) init);
        env->ReleaseDoubleArrayElements(jinit, init, 0);
        env->ReleaseDoubleArrayElements(jupper, upper, 0);
        env->ReleaseDoubleArrayElements(jlower, lower, 0);
        return fitfun.getEvaluations();

    } catch (std::exception &e) {
        cout << e.what() << endl;
        return fitfun.getEvaluations();
    }
    return 0;
}


#include <boost/graph/smallest_last_ordering.hpp>


// ---------------------------------------------------------------------
//
// Copyright (c) 2020 - 2021 by the IBAMR developers
// All rights reserved.
//
// This file is part of IBAMR.
//
// IBAMR is free software and is distributed under the 3-clause BSD
// license. The full text of the license can be found in the file
// COPYRIGHT at the top level directory of IBAMR.
//
// ---------------------------------------------------------------------

/////////////////////////////// INCLUDES /////////////////////////////////////

#include <ibtk/FischerGuess.h>
#include <ibtk/ibtk_utilities.h>

#include <tbox/TimerManager.h>

#include <Eigen/Dense>

#include <ibtk/app_namespaces.h>

namespace IBTK
{
namespace
{
static Timer* t_submit;
static Timer* t_guess;
} // namespace

FischerGuess::FischerGuess()
{
    using namespace SAMRAI::tbox;
    IBTK_DO_ONCE(t_submit = TimerManager::getManager()->getTimer("IBTK::FischerGuess::submit()");
                 t_guess = TimerManager::getManager()->getTimer("IBTK::FischerGuess::guess()"););
}

FischerGuess::FischerGuess(const int n_vectors) : FischerGuess()
{
    d_n_max_vectors = n_vectors;
}

void
FischerGuess::submit(const libMesh::NumericVector<double>& solution, const libMesh::NumericVector<double>& rhs)
{
    if (d_n_max_vectors == 0) return;
    IBTK_TIMER_START(t_submit);
    // update our list of vectors:
    if (d_n_stored_vectors == d_n_max_vectors)
    {
        // oldest entry is first
        d_solutions.erase(d_solutions.begin());
        d_solutions.push_back(solution.clone());
        d_rhs.erase(d_rhs.begin());
        d_rhs.push_back(rhs.clone());

        // shift the computed dot products up and to the left:
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> mat_copy(d_correlation_matrix);
        for (int i = 1; i < d_n_max_vectors; ++i)
        {
            for (int j = 1; j < d_n_max_vectors; ++j)
            {
                d_correlation_matrix(i - 1, j - 1) = mat_copy(i, j);
            }
        }
    }
    else
    {
        ++d_n_stored_vectors;
        d_solutions.push_back(solution.clone());
        d_rhs.push_back(rhs.clone());

        // Save the prior dot products in a different way:
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> mat_copy;

        mat_copy = d_correlation_matrix;
        d_correlation_matrix.resize(d_n_stored_vectors, d_n_stored_vectors);
        for (int i = 0; i < d_n_stored_vectors - 1; ++i)
        {
            for (int j = 0; j < d_n_stored_vectors - 1; ++j)
            {
                d_correlation_matrix(i, j) = mat_copy(i, j);
            }
        }
    }

    // Compute the last row and then copy it into the last column.
    for (int j = 0; j < d_n_stored_vectors; ++j)
    {
        const double inner = d_rhs.back()->dot(*d_rhs[j]);
        d_correlation_matrix(d_n_stored_vectors - 1, j) = inner;
        d_correlation_matrix(j, d_n_stored_vectors - 1) = inner;
    }
    IBTK_TIMER_STOP(t_submit);
}

void
FischerGuess::guess(libMesh::NumericVector<double>& solution, const libMesh::NumericVector<double>& rhs) const
{
    if (d_n_stored_vectors == 0)
    {
        return;
    }

    IBTK_TIMER_START(t_guess);
    Eigen::VectorXd coef_rhs(d_n_stored_vectors);
    for (int i = 0; i < d_n_stored_vectors; ++i)
    {
        coef_rhs(i) = d_rhs[i]->dot(rhs);
    }
    // TODO - if we were especially clever we could use these dot
    // products to update d_correlation_matrix for next time.

    // TODO - at some point in the future (if and when we require Eigen 3.3 or
    // newer) we can use the slightly better bcdSvd algorithm here. This isn't
    // worth worrying about yet since the SVD is O(n^3) and typically n = 5.
    Eigen::VectorXd coefs(d_n_stored_vectors);
    // Should the SVD fail for any reason just use the last solution as a guess.
    try
    {
        // SVD doesn't make sense with invalid input - throw something and
        // immediately catch it
        if (!d_correlation_matrix.allFinite()) throw int();
        if (!coef_rhs.allFinite()) throw int();
        Eigen::JacobiSVD<decltype(d_correlation_matrix)> svd(d_correlation_matrix, ComputeThinU | ComputeThinV);
        coefs = svd.solve(coef_rhs);
    }
    catch (...)
    {
        TBOX_WARNING(
            "FischerGuess::guess()\n"
            "  Unable to compute the SVD of the correlation matrix.\n"
            "  This is not a fatal error, but usually indicates that\n"
            "  the finite element solution vectors are not valid,\n"
            "  e.g., they may contain infinities or NaNs.");
        coefs.fill(0.0);
        coefs(d_n_stored_vectors - 1) = 1.0;
    }

    solution = 0.0;
    for (int i = 0; i < d_n_stored_vectors; ++i)
    {
        solution.add(coefs(i), *d_solutions[i]);
    }
    IBTK_TIMER_STOP(t_guess);
}
} // namespace IBTK


#include <boost/test/unit_test.hpp>
#include <metaSMT/support/optimization.hpp>
#include <metaSMT/frontend/Logic.hpp>
#include <boost/assign/std/vector.hpp>
#include <vector>

using namespace std;
using namespace metaSMT;
using namespace metaSMT::solver;
using namespace metaSMT::logic;
using namespace metaSMT::cardinality;
using namespace boost::assign;
namespace proto = boost::proto;

BOOST_FIXTURE_TEST_SUITE(optimization_t, Solver_Fixture )

template < typename Context >
void minimize_all( std::string const optimize_with, std::string const constrain_with,
                   Context &ctx, unsigned ub ) {
  set_option( ctx, "cardinality", optimize_with );
  for (unsigned num_vars = 1; num_vars <= ub; ++num_vars) {
    std::vector< logic::predicate > p;
    for ( unsigned u = 0; u < num_vars; ++u ) {
      p.push_back( logic::new_variable() );
    }

    for ( unsigned value = 1; value <= num_vars; ++value ) {
      std::cerr << "#VAR = " << num_vars << " MIN = " << value << '\n';
      push(ctx);
      metaSMT::assertion( ctx, evaluate(ctx,
        metaSMT::cardinality::cardinality(metaSMT::logic::cardinality::tag::ge_tag(), p, value, constrain_with))
      );
      unsigned const min = optimization::minimize(ctx, p);
      BOOST_REQUIRE_EQUAL( min, value );
      pop(ctx);
    }
  }
}

BOOST_AUTO_TEST_CASE( min10_bdd1 ) { minimize_all( "bdd", "bdd",   ctx,  10); }
BOOST_AUTO_TEST_CASE( min20_bdd1 ) { minimize_all( "bdd", "bdd",   ctx,  20); }
BOOST_AUTO_TEST_CASE( min10_bdd2 ) { minimize_all( "bdd", "adder", ctx,  10); }
BOOST_AUTO_TEST_CASE( min20_bdd2 ) { minimize_all( "bdd", "adder", ctx,  20); }

BOOST_AUTO_TEST_CASE( min10_adder1 ) { minimize_all( "adder", "bdd",   ctx,  10); }
BOOST_AUTO_TEST_CASE( min20_adder1 ) { minimize_all( "adder", "bdd",   ctx,  20); }
BOOST_AUTO_TEST_CASE( min10_adder2 ) { minimize_all( "adder", "adder", ctx,  10); }
BOOST_AUTO_TEST_CASE( min20_adder2 ) { minimize_all( "adder", "adder", ctx,  20); }

template < typename Context >
void maximize_all( std::string const optimize_with, std::string const constrain_with,
                   Context &ctx, unsigned ub ) {
  set_option( ctx, "cardinality", optimize_with );
  for (unsigned num_vars = 1; num_vars <= ub; ++num_vars) {
    std::vector< logic::predicate > p;
    for ( unsigned u = 0; u < num_vars; ++u ) {
      p.push_back( logic::new_variable() );
    }

    for ( unsigned value = 1; value <= num_vars; ++value ) {
      std::cerr << "#VAR = " << num_vars << " MAX = " << value << '\n';
      push(ctx);
      metaSMT::assertion( ctx, evaluate(ctx,
        metaSMT::cardinality::cardinality(metaSMT::logic::cardinality::tag::le_tag(), p, value, constrain_with))
      );
      unsigned const max = optimization::maximize(ctx, p);
      BOOST_CHECK_EQUAL( max, value );
      pop(ctx);
    }
  }
}

BOOST_AUTO_TEST_CASE( max10_bdd1 ) { maximize_all( "bdd", "bdd",   ctx,  10); }
BOOST_AUTO_TEST_CASE( max20_bdd1 ) { maximize_all( "bdd", "bdd",   ctx,  20); }
BOOST_AUTO_TEST_CASE( max10_bdd2 ) { maximize_all( "bdd", "adder", ctx,  10); }
BOOST_AUTO_TEST_CASE( max20_bdd2 ) { maximize_all( "bdd", "adder", ctx,  20); }

BOOST_AUTO_TEST_CASE( max10_adder1 ) { maximize_all( "adder", "bdd",   ctx,  10); }
BOOST_AUTO_TEST_CASE( max20_adder1 ) { maximize_all( "adder", "bdd",   ctx,  20); }
BOOST_AUTO_TEST_CASE( max10_adder2 ) { maximize_all( "adder", "adder", ctx,  10); }
BOOST_AUTO_TEST_CASE( max20_adder2 ) { maximize_all( "adder", "adder", ctx,  20); }

BOOST_AUTO_TEST_SUITE_END()


/*
  Copyright 2021 - Rafael Barreto
*/

#ifndef TRAJECTORY_TRACKING_CONTROL_CONTROLLER_HPP_
#define TRAJECTORY_TRACKING_CONTROL_CONTROLLER_HPP_

// Messages
#include <geometry_msgs/Point.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/Twist.h>
#include <std_msgs/Float32MultiArray.h>
#include <nav_msgs/Odometry.h>

// Angles
#include <angles/angles.h>

// TF2
#include <tf2/LinearMath/Quaternion.h>
#include <tf2/LinearMath/Matrix3x3.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>

// Eigen
#include <eigen3/Eigen/Core>

// Action
#include <actionlib/server/simple_action_server.h>
#include <trajectory_tracking_control/ExecuteTrajectoryTrackingAction.h>

#include <vector>
#include <string>
#include <cmath>

#include <boost/bind.hpp>

#include "trajectory_tracking_control/pose_handler.hpp"
#include "trajectory_tracking_control/trajectory_generator.hpp"

using Eigen::MatrixXd;

namespace trajectory_tracking_control {

using ExecuteTrajectoryTrackingActionServer =
  actionlib::SimpleActionServer<trajectory_tracking_control::ExecuteTrajectoryTrackingAction>;

class Controller {
 public:
  Controller(std::string action_name, ros::NodeHandle *nodehandle, tf2_ros::Buffer& tf_buffer);  // NOLINT

  void executeCB(const ExecuteTrajectoryTrackingGoalConstPtr &goal);

  bool isGoalReached();

  bool computeVelocityCommands(geometry_msgs::Twist& cmd_vel); //NOLINT

  virtual void updateReferenceState(int n);

  void loadControllerParams();

  void displayControllerInfo();

 protected:
  PoseHandler pose_handler_;
  std::string action_name_;
  ros::NodeHandle nh_;
  ExecuteTrajectoryTrackingActionServer action_server_;

  ExecuteTrajectoryTrackingFeedback feedback_;
  ExecuteTrajectoryTrackingResult result_;

  /*
    Reference States Matrix(6, n)

    | x_0    x_1    ...  x_n   |
    | y_0    y_1    ...  y_n   |
    | dx_0   dx_1   ...  dx_n  |
    | dy_0   dy_1   ...  dy_n  |
    | ddx_0  ddx_1  ...  ddx_n |
    | ddy_0  ddy_1  ...  ddy_n |

  */
  MatrixXd ref_states_matrix_;

  // Current Pose
  geometry_msgs::Pose curr_pose_;

  // Posture Error Matrix (3x1)
  MatrixXd error_;

  // Transform to global coordinate matrix (3x3)
  MatrixXd tf_to_global_;

  // Current Pose State (x, y, yaw)
  MatrixXd q_curr_;

  // Reference Pose State (x, y, yaw)
  MatrixXd q_ref_;

  // Pose Errors
  double error_x_, error_y_, error_yaw_;

  // Gains
  double k_x_, k_y_, k_yaw_;

  // Control design parameters
  double g_, zeta_;

  // Maximum absolute linear and angular velocities
  double vel_max_, omega_max_;

  // Current reference velocities
  double vel_ref_, omega_ref_;

  // Current reference state
  double x_ref_, y_ref_, dx_ref_, dy_ref_, ddx_ref_, ddy_ref_;

  // Yaw angle
  double yaw_ref_, yaw_curr_;

  ros::Subscriber pose_sub_;

  geometry_msgs::Point goal_position_;

  ros::Publisher ref_pose_pub_;
  ros::Publisher ref_path_pub_;
  ros::Publisher cmd_vel_pub_;
  ros::Publisher ref_cmd_vel_pub_;

  double goal_distance_;

  double vel_old_{0.0};

  bool goal_reached_{false};

  bool constant_gains_{false};

  bool constant_trajectory_{false};

  double xy_goal_tolerance_;

  // TODO(Rafael) remove and set it from action msg
  std::string controller_type_{std::string("Linear")};

  TrajectoryGenerator traj_gen_;

  geometry_msgs::Twist ref_cmd_vel_;

};
}  // namespace trajectory_tracking_control

#endif  // TRAJECTORY_TRACKING_CONTROL_CONTROLLER_HPP_


// Fractool macros
#include <fractool/macros.hpp>
#include <fractool/colormap.hpp>

// FTCore
#include <fractool/ftcore/config.hpp>
#include <fractool/ftcore/cli_parser.hpp>
#include <fractool/ftcore/map_color.hpp>
#include <fractool/ftcore/write_image.hpp>
#include <fractool/ftcore/generate_mandelbrot.hpp>
#include <fractool/ftcore/generate_julia.hpp>

// External
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>

/**
 * Initialize logging severity level
 */
void init_logging() {
    boost::log::core::get()->set_filter(
#ifdef DEBUG
        boost::log::trivial::severity >= boost::log::trivial::debug
#else
        boost::log::trivial::severity >= boost::log::trivial::info
#endif
    );
    BOOST_LOG_TRIVIAL(debug) << "Logging initialized";
};

/**
 * Main program entrypoint
 */
int main(int argc, char **argv) {
    // Initialize logging
    init_logging();

    // Generate config struct from cli
    config conf = config_from_cli(argc, argv);
    conf.log();

    // Resources
    unsigned char* param_buffer = new unsigned char[conf.image_size_x * conf.image_size_y];
    unsigned char* color_buffer = new unsigned char[conf.image_size_x * conf.image_size_y * NUM_CHANS];

    // Run stages
    switch(conf.algorithm) {
        case ALGORITHM::MANDELBROT:
            generate_mandelbrot(conf.image_size_x, conf.image_size_y, param_buffer);
            break;
        case ALGORITHM::JULIA:
            generate_julia(conf.image_size_x, conf.image_size_y, param_buffer);
            break;
        default:
            break;
    }
    map_color(conf.image_size_x, conf.image_size_y, conf.cmap, param_buffer, color_buffer);
    write_image(conf.image_size_x, conf.image_size_y, color_buffer, "fractal.png");

    // Delete resources
    delete[] param_buffer;
    delete[] color_buffer;

    // Exit
    return 0;
}


// @file
// ECIES related declarations
//
#pragma once
#include <logos/request/fields.hpp>
#include <logos/lib/utility.hpp>
#include <logos/consensus/messages/byte_arrays.hpp>

#include <cryptopp/eccrypto.h>
#include <cryptopp/pubkey.h>
#include <cryptopp/ecp.h>
#include <cryptopp/asn.h>
#include <cryptopp/oids.h>
#include <blake2/blake2.h>

#include <boost/property_tree/ptree.hpp>

#include <sstream>
#include <iomanip>

/*#include <cryptopp/cryptlib.h>

#include <cryptopp/osrng.h>
#include <cryptopp/integer.h>*/

using CryptoPP::ECIES;
using CryptoPP::ECP;
using CryptoPP::StringSink;
using CryptoPP::ArraySink;
using CryptoPP::StringSource;
using CryptoPP::PK_EncryptorFilter;
using CryptoPP::PK_DecryptorFilter;
using RawKey = ByteArray<32>;

template<typename Key>
class ECIESKey : public Key {
public:
    ECIESKey() = default;
    virtual ~ECIESKey() = default;

    void FromString(std::string &str, bool is_hex)
    {
        if (is_hex)
        {
            FromHexString(str);
        } else {
            FromString(str);
        }
    }

    virtual std::string ToString() const = 0;
    virtual void FromString(const std::string &in) = 0;

    size_t Serialize(logos::stream &stream, bool is_hex = false) const
    {
        return logos::write(stream, is_hex ? (ToHexString()):(ToString()));
    }

    void SerializeJson(boost::property_tree::ptree & tree, bool is_hex = true) const
    {
        tree.put(request::fields::ECIES_KEY,is_hex?(ToHexString()):ToString());
    }

    std::string ToHexString() const
    {
        return logos::unicode_to_hex(ToString());
    }

    bool Deserialize(logos::stream &stream, bool is_hex = false)
    {
        std::string text;
        if (logos::read(stream, text))
        {
            return true;
        }
        FromString(text, is_hex);
        return false;
    }

    bool DeserializeJson(const boost::property_tree::ptree & tree, bool is_hex = true)
    {
        std::string ecies_key = tree.get<std::string>(request::fields::ECIES_KEY);
        FromString(ecies_key, is_hex);
        return true;
    }

    void FromHexString(const std::string &in)
    {
        FromString(logos::hex_to_unicode(in));
    }

    void Hash(blake2b_state & hash) const
    {
        std::string str = ToString();
        blake2b_update(&hash, str.data(), str.length());
    }
};

class ECIESPrivateKey : public ECIESKey<CryptoPP::DL_PrivateKey_EC<ECP>> {
    using Key = CryptoPP::DL_PrivateKey_EC<ECP>;

public:
    ECIESPrivateKey() : ECIESKey<CryptoPP::DL_PrivateKey_EC<ECP>> () {
        CryptoPP::AutoSeededRandomPool prng;
        Initialize(prng, CryptoPP::ASN1::secp256r1());
    }
    ECIESPrivateKey(std::string &str, bool is_hex) : ECIESKey<CryptoPP::DL_PrivateKey_EC<ECP>> ()
    {
        ECIESKey<CryptoPP::DL_PrivateKey_EC<ECP>>::FromString(str, is_hex);
    }
    ECIESPrivateKey(RawKey const & raw) : ECIESKey<CryptoPP::DL_PrivateKey_EC<ECP>> () {
        CryptoPP::Integer x;
        x.Decode(raw.data(), raw.size());
        Initialize(CryptoPP::ASN1::secp256r1(), x);
    };
    ~ECIESPrivateKey() = default;

    std::string ToString() const override
    {
        std::string out_str;
        StringSink out_sink(out_str);
        GetPrivateExponent().Encode(out_sink, CONSENSUS_PRIV_KEY_SIZE);
        return out_str;
    }

    void FromString(const std::string &in) override
    {
        StringSource src(in, true/*pumpAll*/);
        CryptoPP::Integer x;
        x.Decode(src, CONSENSUS_PRIV_KEY_SIZE);
        Initialize(CryptoPP::ASN1::secp256r1(), x);
    }

    template<typename ... Args>
    void Decrypt(const std::string &cyphertex, Args ... args)
    {
        CryptoPP::AutoSeededRandomPool prng;
        ECIES<ECP>::Decryptor d(*this);
        StringSource stringSource(cyphertex, true, new PK_DecryptorFilter(prng, d, new ArraySink(args ... )));
    }
    void Decrypt(const std::string &cyphertex, std::string &text)
    {
        CryptoPP::AutoSeededRandomPool prng;
        ECIES<ECP>::Decryptor d(*this);
        StringSource stringSource(cyphertex, true, new PK_DecryptorFilter(prng, d, new StringSink(text)));
    }

    bool operator==(const ECIESPrivateKey &rhs) const
    {
        return this->GetPrivateExponent() == rhs.GetPrivateExponent();
    }
};

class ECIESPublicKey : public ECIESKey<CryptoPP::DL_PublicKey_EC<ECP>> {
public:
    ECIESPublicKey() : ECIESKey<CryptoPP::DL_PublicKey_EC<ECP>> () {}
    ECIESPublicKey(const ECIESPrivateKey &pkey) : ECIESKey<CryptoPP::DL_PublicKey_EC<ECP>> ()
    {
        AssignFrom(pkey);
    }
    ECIESPublicKey(std::string &str, bool is_hex = true) : ECIESKey<CryptoPP::DL_PublicKey_EC<ECP>> ()
    {
        ECIESKey<CryptoPP::DL_PublicKey_EC<ECP>>::FromString(str, is_hex);
    }
    ~ECIESPublicKey() = default;

    std::string ToString() const override
    {
        std::string str;
        auto P (GetPublicElement());
        StringSink sink(str);
        P.x.Encode(sink, CONSENSUS_PRIV_KEY_SIZE);
        P.y.Encode(sink, CONSENSUS_PRIV_KEY_SIZE);
        return str;
    }

    void FromString(const std::string &in) override
    {
        StringSource src(in, true/*pumpAll*/);
        typename ECP::Point P;
        P.identity = false;
        P.x.Decode(src, CONSENSUS_PRIV_KEY_SIZE);
        P.y.Decode(src, CONSENSUS_PRIV_KEY_SIZE);
        Initialize(CryptoPP::ASN1::secp256r1(), P);
    }

    template <typename ... Args>
    void Encrypt(std::string &cyphertext, Args ... args)
    {
        CryptoPP::AutoSeededRandomPool prng;
        ECIES<ECP>::Encryptor e(*this);
        StringSource stringSource(args ..., true, new PK_EncryptorFilter(prng, e, new StringSink(cyphertext)));
    }

    bool operator==(const ECIESPublicKey &rhs) const
    {
        return this->GetGroupParameters() == rhs.GetGroupParameters() && this->GetPublicElement() == rhs.GetPublicElement();
    }
};

struct ECIESKeyPair {
    ECIESKeyPair() : prv()
    {
        pub.AssignFrom(prv);
    }
    ~ECIESKeyPair() = default;
    ECIESKeyPair(RawKey const & raw) : prv(raw)
    {
        pub.AssignFrom(prv);
    }

    bool operator==(const ECIESKeyPair &rhs) const
    {
        return this->prv == rhs.prv && this->pub == rhs.pub;
    }

    ECIESPrivateKey prv;
    ECIESPublicKey pub;
};


/* pcmsolver_copyright_start */
/*
 *     PCMSolver, an API for the Polarizable Continuum Model
 *     Copyright (C) 2013-2016 Roberto Di Remigio, Luca Frediani and contributors
 *
 *     This file is part of PCMSolver.
 *
 *     PCMSolver is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     PCMSolver is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with PCMSolver.  If not, see <http://www.gnu.org/licenses/>.
 *
 *     For information on the complete list of contributors to the
 *     PCMSolver API, see: <http://pcmsolver.readthedocs.io/>
 */
/* pcmsolver_copyright_end */

#include "CPCMSolver.hpp"

#include <fstream>
#include <iostream>
#include <string>

#include "Config.hpp"

#include <Eigen/Cholesky>
#include <Eigen/Core>

#include "cavity/Cavity.hpp"
#include "cavity/Element.hpp"
#include "green/IGreensFunction.hpp"
#include "utils/MathUtils.hpp"
#include "SolverImpl.hpp"

void CPCMSolver::buildSystemMatrix_impl(const Cavity & cavity, const IGreensFunction & gf_i, const IGreensFunction & gf_o)
{
  if (!isotropic_) PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!", BOOST_CURRENT_FUNCTION);
  TIMER_ON("Computing S");
  double epsilon = profiles::epsilon(gf_o.permittivity());
  S_ = gf_i.singleLayer(cavity.elements());
  S_ /= (epsilon - 1.0)/(epsilon + correction_);
  // Get in Hermitian form
  if (hermitivitize_) hermitivitize(S_);
  TIMER_OFF("Computing S");

  // Symmetry-pack
  // The number of irreps in the group
  int nrBlocks = cavity.pointGroup().nrIrrep();
  // The size of the irreducible portion of the cavity
  int dimBlock = cavity.irreducible_size();
  // Perform symmetry blocking
  // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix
  // into "block diagonal" when all other manipulations are done.
  if (cavity.pointGroup().nrGenerators() != 0) {
    TIMER_ON("Symmetry blocking");
    symmetryBlocking(S_, cavity.size(), dimBlock, nrBlocks);
    TIMER_OFF("Symmetry blocking");
  }
  symmetryPacking(blockS_, S_, dimBlock, nrBlocks);

  built_ = true;
}

Eigen::VectorXd CPCMSolver::computeCharge_impl(const Eigen::VectorXd & potential, int irrep) const
{
  // The potential and charge vector are of dimension equal to the
  // full dimension of the cavity. We have to select just the part
  // relative to the irrep needed.
  int fullDim = S_.rows();
  Eigen::VectorXd charge = Eigen::VectorXd::Zero(fullDim);
  int nrBlocks = blockS_.size();
  int irrDim = fullDim/nrBlocks;
  charge.segment(irrep*irrDim, irrDim) =
    - blockS_[irrep].ldlt().solve(potential.segment(irrep*irrDim, irrDim));

  return charge;
}

std::ostream & CPCMSolver::printSolver(std::ostream & os)
{
  os << "Solver Type: C-PCM" << std::endl;
  if (hermitivitize_) {
    os << "PCM matrix hermitivitized";
  } else {
    os << "PCM matrix NOT hermitivitized (matches old DALTON)";
  }

  return os;
}


#include <dbconnector/dbconnector.hpp>
#include <boost/math/distributions.hpp>
#include <modules/prob/student.hpp>
#include <modules/prob/boost.hpp>
#include <limits>
#include <string>

#include "clustered_errors.hpp"
#include "clustered_errors_state.hpp"

using namespace madlib::dbal::eigen_integration;

using std::string;

namespace madlib {
namespace modules {
namespace regress {

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

typedef ClusteredState<RootContainer> IClusteredState;
typedef ClusteredState<MutableRootContainer> MutableClusteredState;

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

// function used by linear and logistic transitions
AnyType __clustered_common_transition (AnyType& args, string regressionType,
                                       void (*func)(
                                           MutableClusteredState&,
                                           const MappedColumnVector&,
                                           const double& y))
{
    MutableClusteredState state = args[0].getAs<MutableByteString>();
    double y;
    if (regressionType == "log") //Logistic regression
        y = args[1].getAs<bool>() ? 1. : -1;
    else if(regressionType == "lin") // Linear regression
        y = args[1].getAs<double>();
    else if(regressionType == "mlog")//Multi-logistic regression
    	y = args[1].getAs<int>();

    const MappedColumnVector& x = args[2].getAs<MappedColumnVector>();

    if (!std::isfinite(y))
        throw std::domain_error("Dependent variables are not finite.");
    else if (x.size() > std::numeric_limits<uint16_t>::max())
        throw std::domain_error("Number of independent variables cannot be "
                                "larger than 65535.");

    if (state.numRows == 0) {
        if(regressionType == "mlog")
        {
        	state.numCategories = static_cast<uint16_t>(args[4].getAs<int>());
        	state.refCategory = static_cast<uint16_t>(args[5].getAs<int>());
        }
        else
        {
        	state.numCategories = 2;
        	state.refCategory = 0;
        }

        state.widthOfX = static_cast<uint16_t>(x.size() * (state.numCategories-1));
        state.resize();
        const MappedColumnVector& coef = args[3].getAs<MappedColumnVector>();
        state.coef = coef;
        state.meat_half.setZero();
        //elog(INFO, "widthOfX:%i", static_cast<int>(state.widthOfX));
        //elog(INFO, "size of x:%i", static_cast<int>(x.size()));

    }

    // dimension check
    if (state.widthOfX != static_cast<uint16_t>(x.size() * (state.numCategories-1)))
        throw std::runtime_error("Inconsistent numbers of independent "
                                 "variables.");

    state.numRows++;

    (*func)(state, x, y);
    return state.storage();
}

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

// function used by linear and logistic merges
AnyType __clustered_common_merge (AnyType& args)
{
    MutableClusteredState state1 = args[0].getAs<MutableByteString>();
    IClusteredState state2 = args[1].getAs<ByteString>();

    if (state1.numRows == 0)
        return state2.storage();
    else if (state2.numRows == 0)
        return state1.storage();

    state1.numRows += state2.numRows;
    state1.bread += state2.bread;
    state1.meat_half += state2.meat_half;

    return state1.storage();
}

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

// function used by linear and logistic finals
AnyType __clustered_common_final (AnyType& args)
{
    IClusteredState state = args[0].getAs<ByteString>();

    if (state.numRows == 0) return Null();

    Allocator& allocator = defaultAllocator();

    SymmetricPositiveDefiniteEigenDecomposition<Matrix> decomposition(
        state.bread, EigenvaluesOnly, ComputePseudoInverse);

    int k = static_cast<int>(state.widthOfX);

    Matrix meat(k, k);
    meat = trans(state.meat_half) * state.meat_half;

    MutableNativeColumnVector meatvec;
    MutableNativeColumnVector breadvec;
    meatvec.rebind(allocator.allocateArray<double>(k*k));
    breadvec.rebind(allocator.allocateArray<double>(k*k));
    int count = 0;
    for (int i = 0; i < k; i++)
        for (int j = 0; j < k; j++) {
            meatvec(count) = meat(i,j);
            breadvec(count) = state.bread(i,j);
            count++;
        }

    AnyType tuple;

    tuple << meatvec << breadvec;

    return tuple;
}

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

// Compute the stats from coef and errs
AnyType clustered_compute_stats (AnyType& args,
                                 void (*func)(
                                     MutableNativeColumnVector&,
                                     MutableNativeColumnVector&,
                                     int, int))
{
    const MappedColumnVector& coef = args[0].getAs<MappedColumnVector>();
    const MappedColumnVector& meatvec = args[1].getAs<MappedColumnVector>();
    const MappedColumnVector& breadvec = args[2].getAs<MappedColumnVector>();
    int mcluster = args[3].getAs<int>();
    int numRows = args[4].getAs<int>();
    int k =  coef.size();
    //elog(INFO, "Stats coef size:%i", static_cast<int>(coef.size()));
    //elog(INFO, "Stats k:%i", static_cast<int>(k));
    Matrix bread(k,k);
    Matrix meat(k,k);
    int count = 0;

    for (int i = 0; i < k; i++)
        for (int j = 0; j < k; j++)
        {
            meat(i,j) = meatvec(count);
            bread(i,j) = breadvec(count);
            count++;
            //elog(INFO, "meat, bread: %i, %i, %f, %f", static_cast<int>(i),  static_cast<int>(j),  static_cast<float>(meat(i,j)),  static_cast<float>(bread(i,j)));
        }

    if (mcluster == 1)
        throw std::domain_error ("Clustered variance error: Number of clusters cannot be smaller than 2!");
    double dfc = (mcluster / (mcluster - 1.)) * ((numRows - 1.) / (numRows - k));

    SymmetricPositiveDefiniteEigenDecomposition<Matrix> decomposition(
        bread, EigenvaluesOnly, ComputePseudoInverse);
    Matrix inverse_of_bread = decomposition.pseudoInverse();
    Matrix cov(k, k);
    cov = inverse_of_bread * meat * inverse_of_bread;

    MutableNativeColumnVector errs;
    MutableNativeColumnVector stats;
    MutableNativeColumnVector pValues;
    Allocator& allocator = defaultAllocator();

    errs.rebind(allocator.allocateArray<double>(k));
    stats.rebind(allocator.allocateArray<double>(k));
    pValues.rebind(allocator.allocateArray<double>(k));
    for (int i = 0; i < k; i++)
    {
        if (inverse_of_bread(i,i) < 0)
            errs(i) = 0;
        else
            errs(i) = std::sqrt(cov(i,i) * dfc);

        if (coef(i) == 0 && errs(i) == 0)
            stats(i) = 0;
        else
            stats(i) = coef(i) / errs(i);
    }

    if (numRows > k)
        (*func)(pValues, stats, numRows, k);

    AnyType tuple;

	tuple << coef << errs << stats
		  << (numRows > k
			  ? pValues
			  : Null());
    return tuple;
}

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

// compute t-stats
void __compute_t_stats (MutableNativeColumnVector& pValues,
                        MutableNativeColumnVector& stats,
                        int numRows, int k)
{
    for (int i = 0; i < k; i++)
        pValues(i) = 2. * prob::cdf(
            boost::math::complement(
                prob::students_t(static_cast<double>(numRows - k)),
                std::fabs(stats(i))));
}

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

// compute t-stats
void __compute_z_stats (MutableNativeColumnVector& pValues,
                        MutableNativeColumnVector& stats,
                        int numRows, int k)
{
    (void)numRows;
    for (int i = 0; i < k; i++)
        pValues(i) = 2. * prob::cdf(
            boost::math::complement(prob::normal(), std::fabs(stats(i))));
}

// ------------------------------------------------------------------------
// linear clustered
// ------------------------------------------------------------------------

void __linear_trans_compute (MutableClusteredState& state,
                             const MappedColumnVector& x, const double& y)
{
    // On Redhat, I have to use the next a few lines instead of
    // state.meat_half += (y - trans(state.coef) * x) * x;
    double sm = 0;
    for (int i = 0; i < state.widthOfX; i++) sm += state.coef(i) * x(i);
    sm = y - sm;
    for (int i = 0; i < state.widthOfX; i++)
        state.meat_half(0,i) += sm * x(i);

    state.bread += x * trans(x);
}

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

AnyType __clustered_err_lin_transition::run (AnyType& args)
{
    return __clustered_common_transition(args, "lin", __linear_trans_compute);
}

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

AnyType __clustered_err_lin_merge::run (AnyType& args)
{
    return __clustered_common_merge(args);
}

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

AnyType __clustered_err_lin_final::run (AnyType& args)
{
    return __clustered_common_final(args);
}

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

AnyType clustered_lin_compute_stats::run (AnyType& args)
{
    return clustered_compute_stats(args, __compute_t_stats);
}

// ------------------------------------------------------------------------
// Logistic clustered standard errors
// ------------------------------------------------------------------------

inline double sigma(double x) {
	return 1. / (1. + std::exp(-x));
}

void __logistic_trans_compute (MutableClusteredState& state,
                               const MappedColumnVector& x, const double& y)
{
    double sm = 0;
    for (int i = 0; i < state.widthOfX; i++) sm += state.coef(i) * x(i);

    double sgn = y > 0 ? -1 : 1;
    double t1 = sigma(sgn * sm);
    double t2 = sigma(-sgn * sm);

    for (int i = 0; i < state.widthOfX; i++)
        state.meat_half(0,i) += t1 * sgn * x(i);

    state.bread += (t1 * t2) * (x * trans(x));
}

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

AnyType __clustered_err_log_transition::run (AnyType& args)
{
    return __clustered_common_transition(args, "log", __logistic_trans_compute);
}

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

AnyType __clustered_err_log_merge::run (AnyType& args)
{
    return __clustered_common_merge(args);
}

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

AnyType __clustered_err_log_final::run (AnyType& args)
{
    return __clustered_common_final(args);
}

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

AnyType clustered_log_compute_stats::run (AnyType& args)
{
    return clustered_compute_stats(args, __compute_z_stats);
}

// ------------------------------------------------------------------------
// Multi-Logistic clustered standard errors
// ------------------------------------------------------------------------

void __mlogistic_trans_compute (MutableClusteredState& state,
                               const MappedColumnVector& x, const double& y)
{
	const bool debug = false;
	int numCategories = state.numCategories -1;
	ColumnVector yVec(numCategories);
    yVec.fill(0);

    //Pivot around the reference category
    if (y > state.refCategory) {
        yVec((int)y - 1) = 1;
    } else if (y < state.refCategory) {
        yVec((int)y) = 1;
    }

//    if ((int)y != 0) {
 //       yVec(((int)y) - 1) = 1;
 //   }

	/*
    Compute the parameter vector (the 'pi' vector in the documentation)
    for the data point being processed.
    Casting the coefficients into a matrix makes the calculation simple.
    */
    if(debug)
	    elog(INFO, "Starting mlog compute function");
    Matrix coef = state.coef;
    coef.resize(numCategories, state.widthOfX/numCategories);

    //Store the intermediate calculations because we'll reuse them in the LLH
    ColumnVector t1 = x; //t1 is vector of size state.widthOfX
    t1 = coef*x;
    /*
        Note: The above 2 lines could have been written as:
        ColumnVector t1 = -coef*x;

        but this creates warnings. These warnings are somehow related to the factor
        that x is an immutable type.
    */

    ColumnVector t2 = t1.array().exp();
    double t3 = 1 + t2.sum();
    ColumnVector pi = t2/t3;
    if(debug)
		elog(INFO, "Computing gradient");
    //The gradient matrix has numCatergories rows and widthOfX columns
    Matrix grad = -yVec * x.transpose() + pi * x.transpose();
    //We cast the gradient into a vector to make the math easier.
    grad.resize(state.widthOfX, 1);
    for (int i = 0; i < state.widthOfX; i++)
    {
		state.meat_half(0,i) += grad(i);
	}
	if(debug)
		elog(INFO, "Computing Hessian");
	 // Compute the 'a' matrix.
    Matrix a(numCategories,numCategories);
    Matrix piDiag = pi.asDiagonal();
    a = pi * pi.transpose() - piDiag;

    //Start the Hessian calculations
    //Matrix X_transp_AX(numCategories * state.widthOfX, numCategories * state.widthOfX);
 	Matrix X_transp_AX( (int)state.widthOfX, (int)state.widthOfX);
    /*
        Again: The following 3 lines could have been written as
        Matrix XXTrans = x * x.transpose();
        but it creates warnings related to the type of x. Here is an easy fix
    */
    Matrix cv_x = x;
    Matrix XXTrans = trans(cv_x);
    XXTrans = cv_x * XXTrans;
	if(debug)
		elog(INFO, "Computing outer product");
    //Eigen doesn't supported outer-products for matrices, so we have to do our own.
    //This operation is also known as a tensor-product.
    for (int i1 = 0; i1 < (state.widthOfX/numCategories); i1++){
         for (int i2 = 0; i2 < (state.widthOfX/numCategories); i2++){
            int rowOffset = numCategories * i1;
            int colOffset = numCategories * i2;

            X_transp_AX.block(rowOffset, colOffset, numCategories,  numCategories) = XXTrans(i1, i2) * a;
        }
    }
    if(debug)
    {
		for (int i1 = 0; i1 < (state.widthOfX); i1++){
			 for (int i2 = 0; i2 < (state.widthOfX); i2++){
				elog(INFO, "%i, %i, %f: ", i1,i2,X_transp_AX(i1,i2));
			}
		}
		elog(INFO, "adding Hessian to state");
	}
    state.bread += -1*X_transp_AX;
    if(debug)
	    elog(INFO, "mlog transition finishing");
}

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

AnyType __clustered_err_mlog_transition::run (AnyType& args)
{
	//elog(INFO, "mlog Transition step is running");
    return __clustered_common_transition(args, "mlog", __mlogistic_trans_compute);
}

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

AnyType __clustered_err_mlog_merge::run (AnyType& args)
{
	//elog(INFO, "mlog merge step is running");
    return __clustered_common_merge(args);
}

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

AnyType __clustered_err_mlog_final::run (AnyType& args)
{
	//elog(INFO, "mlog final step is running");
    return __clustered_common_final(args);
}

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

AnyType clustered_mlog_compute_stats::run (AnyType& args)
{
	//elog(INFO, "mlog compute stats is running");
    return clustered_compute_stats(args,  __compute_z_stats);
}

}
}
}