#include "geninput.h"

#include <cstdlib>
#include <cmath>
#include <fstream>
#include <iostream>
#include <cassert>
#include <string>

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <H5hut.h>

using namespace std;

GenInput::GenInput()
{
}

void GenInput::generate(int L, int W, string modeStr)
{
  long numParticle = L * W;

  id_ = new long[numParticle]();
  x_ = new double[numParticle]();
  y_ = new double[numParticle]();
  rx_ = new double[numParticle]();
  ry_ = new double[numParticle]();

  char filename[100];

  bool gen_success = false;

  if (modeStr == "randrand")
  {
    sprintf(filename, "input%ldrandrand.h5part", numParticle);
    gen_success = GenerateRandRand(filename, numParticle, L, W);
  }
  else if (modeStr == "randunif")
  {
    sprintf(filename, "input%ldrandunif.h5part", numParticle);
    gen_success = GenerateRandUnif(filename, numParticle, L, W);
  }
  else if (modeStr == "unifrand")
  {
    sprintf(filename, "input%ldunifrand.h5part", numParticle);
    gen_success = GenerateUnifRand(filename, numParticle, L, W);
  }
  else if (modeStr == "unifunif")
  {
    sprintf(filename, "input%ldunifunif.h5part", numParticle);
    gen_success = GenerateUnifUnif(filename, numParticle, L, W);
  }
  else
  {
    cerr << "Illegal mode!" << endl;
    return;
  }
}

bool GenInput::GenerateRandRand(const char *filename, int numParticle,
                                int L, int W)
{
  boost::random::mt19937 gen;
  boost::random::uniform_real_distribution<> l_dist(0, L);
  boost::random::uniform_real_distribution<> w_dist(0, W);
  boost::random::uniform_real_distribution<> r_dist(0, 2);

  h5_file_p outFile = H5OpenFile(filename, H5_O_WRONLY, 0 /* MPI_Comm */);

  if (H5CheckFile(outFile) == H5_SUCCESS) // In this implementation, SUCCESS returns 0 !
  {
    cerr << "File: " << filename << " NOT exists!" << endl;
    return false;
  }

  H5SetStep(outFile, 0);
  H5PartSetNumParticles(outFile, numParticle);

  double scale = 0.01;
  double r_mean = 3 * scale;

  for(long int i = 0; i < numParticle; i++)
  {
    id_[i] = i;
    x_[i] = l_dist(gen) * scale;
    y_[i] = w_dist(gen) * scale;
    rx_[i] = (r_dist(gen) - 1) * scale * 0.2 + r_mean;
    ry_[i] = (r_dist(gen) - 1) * scale * 0.2 + r_mean;
  }

  WriteFile(outFile);
  H5CloseFile(outFile);

  return true;
}

bool GenInput::GenerateRandUnif(const char *filename,
                                int numParticle, int L, int W)
{
  boost::random::mt19937 gen;
  boost::random::uniform_real_distribution<> l_dist(0, L);
  boost::random::uniform_real_distribution<> w_dist(0, W);

  h5_file_p outFile = H5OpenFile(filename, H5_O_WRONLY, 0 /* MPI_Comm */);

  if (H5CheckFile(outFile) != H5_SUCCESS) // In the implementation, SUCCESS returns 0 !
  {
    cerr << "File: " << filename << " NOT exists!" << endl;
    return false;
  }

  H5SetStep(outFile, 0);
  H5PartSetNumParticles(outFile, numParticle);

  double scale = 0.01;
  double r_mean = 3 * scale;

  for(long int i = 0; i < numParticle; i++)
  {
    id_[i] = i;
    x_[i] = l_dist(gen) * scale;
    y_[i] = w_dist(gen) * scale;
    rx_[i] = r_mean;
    ry_[i] = r_mean;
  }

  WriteFile(outFile);
  H5CloseFile(outFile);
  return true;
}

bool GenInput::GenerateUnifRand(const char *filename,
                                int numParticle, int L, int W)
{
  boost::random::mt19937 gen;
  boost::random::uniform_real_distribution<> r_dist(0, 2);

  h5_file_p outFile = H5OpenFile(filename, H5_O_WRONLY, 0 /* MPI_Comm */);

  if (H5CheckFile(outFile) != H5_SUCCESS) // In the implementation, SUCCESS returns 0 !
  {
    cerr << "File: " << filename << " NOT exists!" << endl;
    return false;
  }

  H5SetStep(outFile, 0);
  H5PartSetNumParticles(outFile, numParticle);

  double scale = 0.01;
  double r_mean = 3 * scale;

  for(int i = 0; i < L; i++)
  {
    for(int j = 0; j < W; j++)
    {
      long int index = i * L + j;
      id_[index] = index;
      x_[index] = i * scale;
      y_[index] = j * scale;
      rx_[index] = (r_dist(gen) - 1) * scale * 0.2 + r_mean;
      ry_[index] = (r_dist(gen) - 1) * scale * 0.2 + r_mean;
    }
  }
  WriteFile(outFile);
  H5CloseFile(outFile);
  return true;
}

bool GenInput::GenerateUnifUnif(const char *filename,
                                int numParticle, int L, int W)
{
  h5_file_p outFile = H5OpenFile(filename, H5_O_WRONLY, 0 /* MPI_Comm */);

  if (H5CheckFile(outFile) != H5_SUCCESS) // In the implementation, SUCCESS returns 0 !
  {
    cerr << "File: " << filename << " NOT exists!" << endl;
    return false;
  }

  H5SetStep(outFile, 0);
  H5PartSetNumParticles(outFile, numParticle);

  double scale = 0.01;
  double r_mean = 3 * scale;
  long int index = 0;

  for(int i = 0; i < L; i++)
  {
    for(int j = 0; j < W; j++)
    {
      id_[index] = index;
      x_[index] = i * scale;
      y_[index] = j * scale;
      rx_[index++] = r_mean;
      ry_[index++] = r_mean;
    }
  }
  WriteFile(outFile);
  H5CloseFile(outFile);
  return true;
}

void GenInput::WriteFile(h5_file_t *file)
{
  H5PartWriteDataInt64(file, "id", id_);
  H5PartWriteDataFloat64(file, "x", x_);
  H5PartWriteDataFloat64(file, "y", y_);
  H5PartWriteDataFloat64(file, "rx", rx_);
  H5PartWriteDataFloat64(file, "ry", ry_);
}

GenInput::~GenInput()
{
  delete [] id_;
  delete [] x_;
  delete [] y_;
  delete [] rx_;
  delete [] ry_;
}


// Copyright (C) 2011-2014 by the BEM++ Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "discrete_hmat_boundary_operator.hpp"
#include "../fiber/explicit_instantiation.hpp"
#include <boost/numeric/conversion/converter.hpp>
#include "../hmat/compressed_matrix.hpp"

namespace Bempp {

template <typename ValueType>
DiscreteHMatBoundaryOperator<ValueType>::DiscreteHMatBoundaryOperator(
    const shared_ptr<hmat::CompressedMatrix<ValueType>> &compressedMatrix)
    : m_compressedMatrix(compressedMatrix),
      m_domainSpace(Thyra::defaultSpmdVectorSpace<ValueType>(
          compressedMatrix->columns())),
      m_rangeSpace(
          Thyra::defaultSpmdVectorSpace<ValueType>(compressedMatrix->rows())) {}

template <typename ValueType>
unsigned int DiscreteHMatBoundaryOperator<ValueType>::rowCount() const {

  return boost::numeric::converter<unsigned int, std::size_t>::convert(
      m_compressedMatrix->rows());
}

template <typename ValueType>
unsigned int DiscreteHMatBoundaryOperator<ValueType>::columnCount() const {

  return boost::numeric::converter<unsigned int, std::size_t>::convert(
      m_compressedMatrix->columns());
}

template <typename ValueType>
void DiscreteHMatBoundaryOperator<ValueType>::addBlock(
    const std::vector<int> &rows, const std::vector<int> &cols,
    const ValueType alpha, arma::Mat<ValueType> &block) const {}

template <typename ValueType>
void DiscreteHMatBoundaryOperator<ValueType>::applyBuiltInImpl(
    const TranspositionMode trans, const arma::Col<ValueType> &x_in,
    arma::Col<ValueType> &y_inout, const ValueType alpha,
    const ValueType beta) const {

  hmat::TransposeMode hmatTrans;
  if (trans == TranspositionMode::NO_TRANSPOSE)
    hmatTrans = hmat::NOTRANS;
  else if (trans == TranspositionMode::TRANSPOSE)
    hmatTrans = hmat::TRANS;
  else if (trans == TranspositionMode::CONJUGATE)
    hmatTrans = hmat::CONJ;
  else
    hmatTrans = hmat::CONJTRANS;
  m_compressedMatrix->apply(x_in, y_inout, hmatTrans, alpha, beta);
}

template <typename ValueType>
Teuchos::RCP<const Thyra::VectorSpaceBase<ValueType>>
DiscreteHMatBoundaryOperator<ValueType>::domain() const {
  return m_domainSpace;
}

template <typename ValueType>
Teuchos::RCP<const Thyra::VectorSpaceBase<ValueType>>
DiscreteHMatBoundaryOperator<ValueType>::range() const {
  return m_rangeSpace;
}

template <typename ValueType>
bool DiscreteHMatBoundaryOperator<ValueType>::opSupportedImpl(
    Thyra::EOpTransp M_trans) const {
  return (M_trans == Thyra::NOTRANS || M_trans == Thyra::TRANS ||
          M_trans == Thyra::CONJTRANS);
}

FIBER_INSTANTIATE_CLASS_TEMPLATED_ON_RESULT(DiscreteHMatBoundaryOperator);
}


#include <sparse.h>
#include <prox_math_policy.h>

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

BOOST_AUTO_TEST_SUITE(mass_block_jac);
BOOST_AUTO_TEST_CASE(mass_block_test_case)
{
    typedef prox::MathPolicy<float>       math_policy;
    typedef math_policy::mass_block_type	 Mass_block;
    typedef math_policy::value_traits     value_traits;
    typedef math_policy::real_type        real_type;

    Mass_block b(0); // zero-init
    // size checks
    BOOST_CHECK_EQUAL( b.nrows() , 6u);
    BOOST_CHECK_EQUAL( b.ncols() , 6u);
    BOOST_CHECK_EQUAL( b.size()  , 7u);

    // is data initialised to float(0)
    BOOST_CHECK_EQUAL(std::find_if(b.begin(), b.end(),bind2nd(std::not_equal_to<real_type>(), 0)) , b.end());

    b(0,0) = value_traits::half(); // should make m = b[0] == 0.5
    BOOST_CHECK_EQUAL(b[0] , value_traits::half());

    b(1,1) = value_traits::numeric_cast(1.5); // should make m = b[0] == 1.5
    BOOST_CHECK_EQUAL(b[0] , value_traits::numeric_cast(1.5));
    BOOST_CHECK_EQUAL(b(2,2) , b(0,0));//should be same as b(0,0) && b(1,1)
    BOOST_CHECK_EQUAL(b(2,2) , b(1,1));//should be same as b(0,0) && b(1,1)

    Mass_block b_copy(b);
    BOOST_CHECK_EQUAL(b[0] , b_copy[0]);
    BOOST_CHECK_EQUAL(b[1] , b_copy[1]);
    BOOST_CHECK_EQUAL(b[2] , b_copy[2]);
    BOOST_CHECK_EQUAL(b[3] , b_copy[3]);
    BOOST_CHECK_EQUAL(b[4] , b_copy[4]);
    BOOST_CHECK_EQUAL(b[5] , b_copy[5]);
    BOOST_CHECK_EQUAL(b[6] , b_copy[6]);

    b_copy(3,3) = value_traits::numeric_cast(0.5);
    b_copy(4,4) = value_traits::numeric_cast(2.5);
    b_copy(4,5) = value_traits::numeric_cast(3.5);
    b_copy(3,4) = value_traits::numeric_cast(4.5);
    b_copy(5,4) = value_traits::numeric_cast(5.5);
    b_copy(3,5) = value_traits::numeric_cast(6.5);
    b_copy(5,5) = value_traits::numeric_cast(7.5);

    BOOST_CHECK_EQUAL(b_copy(4,3), b_copy(3,4));// by symmetry
    BOOST_CHECK_EQUAL(b_copy(4,3), value_traits::numeric_cast(4.5));
    BOOST_CHECK_EQUAL(b_copy(4,5), b_copy(5,4)); // by symmetry
    BOOST_CHECK_EQUAL(b_copy(4,5), value_traits::numeric_cast(5.5));
    BOOST_CHECK_EQUAL(b_copy(5,3), b_copy(3,5)); // by symmetry
    BOOST_CHECK_EQUAL(b_copy(3,5), value_traits::numeric_cast(6.5));

    b = b_copy;

    BOOST_CHECK_EQUAL(b[0] , value_traits::numeric_cast(1.5));
    BOOST_CHECK_EQUAL(b[1] , value_traits::numeric_cast(0.5));
    BOOST_CHECK_EQUAL(b[2] , value_traits::numeric_cast(4.5));
    BOOST_CHECK_EQUAL(b[3] , value_traits::numeric_cast(6.5));
    BOOST_CHECK_EQUAL(b[4] , value_traits::numeric_cast(2.5));
    BOOST_CHECK_EQUAL(b[5] , value_traits::numeric_cast(5.5));
    BOOST_CHECK_EQUAL(b[6] , value_traits::numeric_cast(7.5));

}
BOOST_AUTO_TEST_SUITE_END();


/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include <boost/algorithm/string.hpp>
#include <ored/utilities/dategrid.hpp>
#include <ored/utilities/log.hpp>
#include <ored/utilities/parsers.hpp>
#include <ql/settings.hpp>
#include <ql/time/daycounters/actualactual.hpp>

using namespace QuantLib;
using namespace std;

namespace ore {
namespace data {

DateGrid::DateGrid()
    : dates_(1, Settings::instance().evaluationDate()), tenors_(1, 0 * Days), times_(1, 0.0),
      timeGrid_(times_.begin(), times_.end()), isValuationDate_(1, true), isCloseOutDate_(1, false) {}

DateGrid::DateGrid(const string& grid, const QuantLib::Calendar& gridCalendar, const QuantLib::DayCounter& dayCounter)
    : calendar_(gridCalendar), dayCounter_(dayCounter) {

    if (grid == "ALPHA") {
        // ALPHA is
        // quarterly up to 10Y,
        // annual up to 30Y,
        // quinquennial up to 100Y
        for (Size i = 1; i < 40; i++) { // 3M up to 39*3M = 117M = 9Y9M
            Period p(i * 3, Months);
            p.normalize();
            tenors_.push_back(p);
        }
        for (Size i = 10; i < 30; i++) // 10Y up to 29Y
            tenors_.push_back(Period(i, Years));
        for (Size i = 30; i < 105; i += 5) // 30Y up to 100Y
            tenors_.push_back(Period(i, Years));
    } else if (grid == "BETA") {
        // BETA is
        // monthly up to 10Y,
        // quarterly up to 20Y,
        // annually up to 50Y,
        // quinquennial up to 100Y
        for (Size i = 1; i < 119; i++) {
            Period p = i * Months;
            p.normalize();
            tenors_.push_back(p);
        }
        for (Size i = 40; i < 80; i++) {
            Period p = i * 3 * Months;
            p.normalize();
            tenors_.push_back(p);
        }
        for (Size i = 20; i < 50; i++)
            tenors_.push_back(i * Years);
        for (Size i = 50; i <= 100; i += 5)
            tenors_.push_back(i * Years);
    } else { // uniform grid of format "numPillars,spacing" (e.g. 40,1M)
        vector<string> tokens;
        boost::split(tokens, grid, boost::is_any_of(","));
        if (tokens.size() <= 2) {
            // uniform grid of format "numPillars,spacing" (e.g. 40,1M)
            Period gridTenor = 1 * Years; // default
            Size gridSize = atoi(tokens[0].c_str());
            QL_REQUIRE(gridSize > 0, "Invalid DateGrid string " << grid);
            if (tokens.size() == 2)
                gridTenor = data::parsePeriod(tokens[1]);
            if (gridTenor == Period(1, Days)) {
                // we have a daily grid. Period and Calendar are not consistant with
                // working & actual days, so we set the tenor grid
                Date today = Settings::instance().evaluationDate();
                Date d = today;
                for (Size i = 0; i < gridSize; i++) {
                    d = gridCalendar.advance(d, Period(1, Days), Following); // next working day
                    Size n = d - today;
                    tenors_.push_back(Period(n, Days));
                }
            } else {
                for (Size i = 0; i < gridSize; i++)
                    tenors_.push_back((i + 1) * gridTenor);
            }
        } else {
            // New style : 1D,2D,1W,2W,3Y,5Y,....
            for (Size i = 0; i < tokens.size(); i++)
                tenors_.push_back(data::parsePeriod(tokens[i]));
        }
    }
    buildDates(gridCalendar, dayCounter);
}

DateGrid::DateGrid(const vector<Period>& tenors, const QuantLib::Calendar& gridCalendar,
                   const QuantLib::DayCounter& dayCounter)
    : calendar_(gridCalendar), dayCounter_(dayCounter), tenors_(tenors) {
    QL_REQUIRE(!tenors_.empty(), "DateGrid requires a non-empty vector of tenors");
    QL_REQUIRE(is_sorted(tenors_.begin(), tenors_.end()),
               "Construction of DateGrid requires a sorted vector of unique tenors");
    buildDates(gridCalendar, dayCounter);
}

DateGrid::DateGrid(const vector<Date>& dates, const QuantLib::Calendar& cal, const DayCounter& dayCounter)
    : calendar_(cal), dayCounter_(dayCounter), dates_(dates) {
    QL_REQUIRE(!dates_.empty(), "Construction of DateGrid requires a non-empty vector of dates");
    QL_REQUIRE(is_sorted(dates_.begin(), dates_.end()),
               "Construction of DateGrid requires a sorted vector of unique dates");
    Date today = Settings::instance().evaluationDate();
    QL_REQUIRE(today < dates_.front(),
               "Construction of DateGrid requires first element to be strictly greater than today");

    // Populate the tenors, times and timegrid
    tenors_.resize(dates_.size());
    times_.resize(dates_.size());
    for (Size i = 0; i < dates_.size(); i++) {
        tenors_[i] = (dates_[i] - today) * Days;
        times_[i] = dayCounter.yearFraction(today, dates_[i]);
    }
    timeGrid_ = TimeGrid(times_.begin(), times_.end());
    isValuationDate_ = std::vector<bool>(dates_.size(), true);
    isCloseOutDate_ = std::vector<bool>(dates_.size(), false);

    // Log the date grid
    log();
}

void DateGrid::buildDates(const QuantLib::Calendar& cal, const QuantLib::DayCounter& dc) {
    // build dates from tenors
    // this is called by both constructors
    dates_.resize(tenors_.size());
    Date today = Settings::instance().evaluationDate();
    for (Size i = 0; i < tenors_.size(); i++) {
        if (tenors_[i].units() == Days)
            dates_[i] = cal.adjust(today + tenors_[i]);
        else
            dates_[i] = cal.advance(today, tenors_[i], Following, false);
        if (i > 0) {
            QL_REQUIRE(dates_[i] >= dates_[i - 1], "DateGrid::buildDates(): tenors must be monotonic");
            if (dates_[i] == dates_[i - 1]) {
                dates_.erase(std::next(dates_.begin(), i));
                tenors_.erase(std::next(tenors_.begin(), i));
                --i;
            }
        }
    }

    // Build times
    times_.resize(dates_.size());
    for (Size i = 0; i < dates_.size(); i++)
        times_[i] = dc.yearFraction(today, dates_[i]);

    timeGrid_ = TimeGrid(times_.begin(), times_.end());
    isValuationDate_ = std::vector<bool>(dates_.size(), true);
    isCloseOutDate_ = std::vector<bool>(dates_.size(), false);

    // Log the date grid
    log();
}

void DateGrid::log() {
    DLOG("DateGrid constructed, size = " << size());
    for (Size i = 0; i < tenors_.size(); i++)
        DLOG("[" << setw(2) << i << "] Tenor:" << tenors_[i] << ", Date:" << io::iso_date(dates_[i])
                 << ", Valuation:" << isValuationDate_[i] << ", CloseOut:" << isCloseOutDate_[i]);
}

void DateGrid::truncate(const Date& d, bool overrun) {
    if (d >= dates_.back())
        return; // no need for any truncation
    DLOG("Truncating DateGrid beyond " << QuantLib::io::iso_date(d));
    vector<Date>::iterator it = std::upper_bound(dates_.begin(), dates_.end(), d);
    if (overrun)
        ++it;
    dates_.erase(it, dates_.end());
    tenors_.resize(dates_.size());
    times_.resize(dates_.size());
    timeGrid_ = TimeGrid(times_.begin(), times_.end());
    DLOG("DateGrid size now " << dates_.size());
}

void DateGrid::truncate(Size len) {
    // Truncate grid up length len
    if (dates_.size() > len) {
        DLOG("Truncating DateGrid, removing elements " << dates_[len] << " to " << dates_.back());
        dates_.resize(len);
        tenors_.resize(len);
        times_.resize(len);
        timeGrid_ = TimeGrid(times_.begin(), times_.end());
        isValuationDate_.resize(len);
        isCloseOutDate_.resize(len);
        DLOG("DateGrid size now " << dates_.size());
    }
}

void DateGrid::addCloseOutDates(const QuantLib::Period& p) {
    if (p == QuantLib::Period(0, QuantLib::Days)) {
        for (Size i = 0; i < dates_.size(); ++i) {
            if (i == 0) {
                isCloseOutDate_.front() = false;
                isValuationDate_.front() = true;
            } else if (i == dates_.size() - 1) {
                isCloseOutDate_.back() = true;
                isValuationDate_.back() = false;
            } else {
                isCloseOutDate_[i] = true;
                isValuationDate_[i] = true;
            }
        }
    } else {
        std::vector<Date> tmpDates;
        std::vector<bool> tmpIsCloseOutDate, tmpIsValuationDate;
        for (Size i = 0; i < dates_.size(); ++i) {
            Date c;
            if (p.units() == Days)
                c = calendar_.adjust(dates_[i] + p);
            else
                c = calendar_.advance(dates_[i], p, Following, false);
            if (i < dates_.size() - 1) {
                // adjust the grid to ensure no overlap in valuation and closeout dates
                if (c >= dates_[i + 1]) {
                    dates_[i + 1] = calendar_.advance(c, QuantLib::Period(1, QuantLib::Days));
                    std::cout << QuantLib::io::iso_date(dates_[i + 1]) << std::endl;
                    // check that the grid is still monotonic
                    if ((i + 2) < dates_.size()) {
                        QL_REQUIRE(dates_[i + 1] < dates_[i + 2],
                                   "date grid is no longer monotonic: " << dates_[i + 1] << ", " << dates_[i + 2]);
                    }
                }
                QL_REQUIRE(c < dates_[i + 1],
                           "close out date " << c << " does not lie before next grid date " << dates_[i + 1]);
            }
            tmpDates.push_back(dates_[i]);
            tmpDates.push_back(c);
            tmpIsCloseOutDate.push_back(false);
            tmpIsCloseOutDate.push_back(true);
            tmpIsValuationDate.push_back(true);
            tmpIsValuationDate.push_back(false);
        }
        dates_ = tmpDates;
        isCloseOutDate_ = tmpIsCloseOutDate;
        isValuationDate_ = tmpIsValuationDate;
        // FIXME ... (is that needed anywhere ?)
        tenors_ = std::vector<QuantLib::Period>(dates_.size(), 0 * Days);
        times_.resize(dates_.size());
        Date today = Settings::instance().evaluationDate();
        for (Size i = 0; i < dates_.size(); i++)
            times_[i] = dayCounter_.yearFraction(today, dates_[i]);
        timeGrid_ = TimeGrid(times_.begin(), times_.end());
    }
    // Log Grid
    DLOG("Added Close Out Dates to DateGrid , size = " << size());
    log();
}

std::vector<QuantLib::Date> DateGrid::valuationDates() const {
    std::vector<Date> res;
    for (Size i = 0; i < dates_.size(); ++i) {
        if (isValuationDate_[i])
            res.push_back(dates_[i]);
    }
    return res;
}

std::vector<QuantLib::Date> DateGrid::closeOutDates() const {
    std::vector<Date> res;
    for (Size i = 0; i < dates_.size(); ++i) {
        if (isCloseOutDate_[i])
            res.push_back(dates_[i]);
    }
    return res;
}

QuantLib::TimeGrid DateGrid::valuationTimeGrid() const {
    std::vector<Real> times;
    Date today = Settings::instance().evaluationDate();
    for (Size i = 0; i < dates_.size(); ++i) {
        if (isValuationDate_[i])
            times.push_back(dayCounter_.yearFraction(today, dates_[i]));
    }
    return TimeGrid(times.begin(), times.end());
}

QuantLib::TimeGrid DateGrid::closeOutTimeGrid() const {
    std::vector<Real> times;
    Date today = Settings::instance().evaluationDate();
    for (Size i = 0; i < dates_.size(); ++i) {
        if (isCloseOutDate_[i])
            times.push_back(dayCounter_.yearFraction(today, dates_[i]));
    }
    return TimeGrid(times.begin(), times.end());
}

boost::shared_ptr<DateGrid> generateShiftedDateGrid(const boost::shared_ptr<DateGrid>& dg,
                                                    const QuantLib::Period& shift) {
    DLOG("Building shifted date grid with shift of " << shift);
    vector<Date> defaultDates = dg->dates();
    vector<Date> closeOutDates;
    for (auto d : defaultDates) {
        Date closeOut = dg->calendar().adjust(d + shift);
        closeOutDates.push_back(closeOut);
    }
    boost::shared_ptr<DateGrid> newDg = boost::make_shared<DateGrid>(closeOutDates, dg->calendar(), dg->dayCounter());
    return newDg;
}

boost::shared_ptr<DateGrid> combineDateGrids(const boost::shared_ptr<DateGrid>& dg1,
                                             const boost::shared_ptr<DateGrid>& dg2) {
    DLOG("Combining date grids");
    vector<Date> combinedVec;
    vector<Date> dates1 = dg1->dates();
    vector<Date> dates2 = dg2->dates();
    combinedVec.reserve(dates1.size() + dates2.size());
    combinedVec.insert(combinedVec.end(), dates1.begin(), dates1.end());
    combinedVec.insert(combinedVec.end(), dates2.begin(), dates2.end());
    std::sort(combinedVec.begin(), combinedVec.end());
    auto last = std::unique(combinedVec.begin(), combinedVec.end());
    combinedVec.erase(last, combinedVec.end());
    // FIXME: Check that grid calendars and day counters match?
    boost::shared_ptr<DateGrid> newDg = boost::make_shared<DateGrid>(combinedVec, dg1->calendar(), dg1->dayCounter());
    return newDg;
}

} // namespace data
} // namespace ore


//---------------------------------------------------------------------------//
// Copyright (c) 2018-2021 Mikhail Komarov <nemo@nil.foundation>
// Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//---------------------------------------------------------------------------//

#define BOOST_TEST_MODULE crypto3_marshalling_integral_non_fixed_size_container_test

#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <iostream>
#include <iomanip>

#include <nil/marshalling/types/integral.hpp>
#include <nil/marshalling/types/array_list.hpp>
#include <nil/marshalling/status_type.hpp>
#include <nil/marshalling/container/static_vector.hpp>
#include <nil/marshalling/field_type.hpp>
#include <nil/marshalling/endianness.hpp>

#include <nil/crypto3/multiprecision/cpp_int.hpp>
#include <nil/crypto3/multiprecision/number.hpp>

#include <nil/crypto3/marshalling/types/integral.hpp>

template<class T>
struct unchecked_type {
    typedef T type;
};

template<unsigned MinBits,
         unsigned MaxBits,
         nil::crypto3::multiprecision::cpp_integer_type SignType,
         nil::crypto3::multiprecision::cpp_int_check_type Checked,
         class Allocator,
         nil::crypto3::multiprecision::expression_template_option ExpressionTemplates>
struct unchecked_type<nil::crypto3::multiprecision::number<
    nil::crypto3::multiprecision::cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>,
    ExpressionTemplates>> {
    typedef nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::
            cpp_int_backend<MinBits, MaxBits, SignType, nil::crypto3::multiprecision::unchecked, Allocator>,
        ExpressionTemplates>
        type;
};

template<class T>
T generate_random() {
    typedef typename unchecked_type<T>::type unchecked_T;

    static const unsigned limbs = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_bounded ?
                                      std::numeric_limits<T>::digits / std::numeric_limits<unsigned>::digits + 3 :
                                      20;

    static boost::random::uniform_int_distribution<unsigned> ui(0, limbs);
    static boost::random::mt19937 gen;
    unchecked_T val = gen();
    unsigned lim = ui(gen);
    for (unsigned i = 0; i < lim; ++i) {
        val *= (gen.max)();
        val += gen();
    }
    return val;
}

template<typename TIter>
void print_byteblob(TIter iter_begin, TIter iter_end) {
    for (TIter it = iter_begin; it != iter_end; it++) {
        std::cout << std::hex << int(*it) << std::endl;
    }
}

template<typename Endianness, class T, std::size_t TSize>
void test_round_trip_non_fixed_size_container_fixed_precision(nil::marshalling::container::static_vector<T, TSize>
                                                                  val_container) {
    using namespace nil::crypto3::marshalling;
    std::size_t units_bits = 8;
    using unit_type = unsigned char;
    using integral_type = types::integral<nil::marshalling::field_type<Endianness>, T>;

    using container_type = nil::marshalling::types::array_list<
        nil::marshalling::field_type<Endianness>,
        integral_type,
        nil::marshalling::option::sequence_size_field_prefix<
            nil::marshalling::types::integral<nil::marshalling::field_type<Endianness>, std::size_t>>>;

    std::vector<T> val_vector(TSize);
    std::copy(val_container.begin(), val_container.end(), val_vector.begin());

    container_type filled_val = types::fill_integral_vector<T, Endianness>(val_vector);

    std::vector<T> constructed_val = types::make_integral_vector<T, Endianness>(filled_val);
    BOOST_CHECK(std::equal(val_container.begin(), val_container.end(), constructed_val.begin()));

    std::size_t unitblob_size =
        integral_type::bit_length() / units_bits + ((integral_type::bit_length() % units_bits) ? 1 : 0);

    std::vector<unit_type> cv;
    cv.resize(unitblob_size * TSize + sizeof(std::size_t), 0x00);

    std::vector<integral_type> container_data;

    for (std::size_t i = 0; i < TSize; i++) {
        container_data.push_back(integral_type(val_container[i]));
    }

    container_type test_val = container_type(container_data);

    auto write_iter = cv.begin();

    nil::marshalling::status_type status = test_val.write(write_iter, cv.size());

    container_type test_val_read;

    auto read_iter = cv.begin();
    status = test_val_read.read(read_iter, cv.size());

    BOOST_CHECK(std::equal(test_val.value().begin(), test_val.value().end(), test_val_read.value().begin()));
}

template<typename Endianness, class T, std::size_t TSize>
void test_round_trip_non_fixed_size_container_fixed_precision() {
    std::cout << std::hex;
    std::cerr << std::hex;
    for (unsigned i = 0; i < 1000; ++i) {
        if (!(i % 128) && i) {
            std::cout << std::dec << i << " tested" << std::endl;
        }
        nil::marshalling::container::static_vector<T, TSize> val_container;
        for (std::size_t i = 0; i < TSize; i++) {
            val_container.push_back(generate_random<T>());
        }
        test_round_trip_non_fixed_size_container_fixed_precision<Endianness, T, TSize>(val_container);
    }
}

BOOST_AUTO_TEST_SUITE(integral_non_fixed_test_suite)

BOOST_AUTO_TEST_CASE(integral_non_fixed_checked_int1024_be) {
    test_round_trip_non_fixed_size_container_fixed_precision<nil::marshalling::option::big_endian,
                                                             nil::crypto3::multiprecision::checked_int1024_t,
                                                             128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_checked_int1024_le) {
    test_round_trip_non_fixed_size_container_fixed_precision<nil::marshalling::option::little_endian,
                                                             nil::crypto3::multiprecision::checked_int1024_t,
                                                             128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_uint512_be) {
    test_round_trip_non_fixed_size_container_fixed_precision<nil::marshalling::option::big_endian,
                                                             nil::crypto3::multiprecision::checked_uint512_t,
                                                             128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_uint512_le) {
    test_round_trip_non_fixed_size_container_fixed_precision<nil::marshalling::option::little_endian,
                                                             nil::crypto3::multiprecision::checked_uint512_t,
                                                             128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_int_backend_64_be) {
    test_round_trip_non_fixed_size_container_fixed_precision<
        nil::marshalling::option::big_endian,
        nil::crypto3::multiprecision::number<
            nil::crypto3::multiprecision::cpp_int_backend<64,
                                                          64,
                                                          nil::crypto3::multiprecision::unsigned_magnitude,
                                                          nil::crypto3::multiprecision::checked,
                                                          void>>,
        128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_int_backend_64_le) {
    test_round_trip_non_fixed_size_container_fixed_precision<
        nil::marshalling::option::little_endian,
        nil::crypto3::multiprecision::number<
            nil::crypto3::multiprecision::cpp_int_backend<64,
                                                          64,
                                                          nil::crypto3::multiprecision::unsigned_magnitude,
                                                          nil::crypto3::multiprecision::checked,
                                                          void>>,
        128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_int_backend_23_be) {
    test_round_trip_non_fixed_size_container_fixed_precision<
        nil::marshalling::option::big_endian,
        nil::crypto3::multiprecision::number<
            nil::crypto3::multiprecision::cpp_int_backend<23,
                                                          23,
                                                          nil::crypto3::multiprecision::unsigned_magnitude,
                                                          nil::crypto3::multiprecision::checked,
                                                          void>>,
        128>();
}

BOOST_AUTO_TEST_CASE(integral_non_fixed_cpp_int_backend_23_le) {
    test_round_trip_non_fixed_size_container_fixed_precision<
        nil::marshalling::option::little_endian,
        nil::crypto3::multiprecision::number<
            nil::crypto3::multiprecision::cpp_int_backend<23,
                                                          23,
                                                          nil::crypto3::multiprecision::unsigned_magnitude,
                                                          nil::crypto3::multiprecision::checked,
                                                          void>>,
        128>();
}

BOOST_AUTO_TEST_SUITE_END()


/* Copyright Institute of Sound and Vibration Research - All rights reserved */

#include "vector_functions_reference_impl.hpp"

// #include <boost/preprocessor/seq/for_each.hpp>
// #include <boost/preprocessor/seq/enum.hpp>

namespace visr
{
namespace efl
{
  namespace reference
  {

#define FLOAT_TYPES (float)(double)
#define NUMERIC_TYPES (float)(double)(std::complex<float>)(std::complex<double>)

// using NumericTypesList = boost::mpl::vector<BOOST_PP_SEQ_ENUM(NUMERIC_TYPES)>;

/*
#define EXPLICIT_INSTANTIATION_FOR_TYPE_LIST( functionName, d, typeList ) \
  BOOST_PP_CAT( template ErrorCode, functionName);
   #define __FUNCTION_MACRO__( r, d, __type__ ) template ErrorCode  functionName; \
   BOOST_PP_SEQ_FOR_EACH( __FUNCTION_MACRO__, _, types )
   #undef __FUNCTION_MACRO__
*/

/*
//Here we should use our API macro
#define EXPLICIT_INSTANTIATION_VECTOR_ZERO(r, d, __type__) \
  template ErrorCode vectorZero<__type__>( __type__ * const, std::size_t, std::size_t );

#define EXPLICIT_INSTANTIATION_FUNCTION(r, d, __type__) \
  template ErrorCode vectorZero<__type__>( __type__ * const, std::size_t, std::size_t );
BOOST_PP_SEQ_FOR_EACH(EXPLICIT_INSTANTIATION_VECTOR_ZERO, _, NUMERIC_TYPES)
*/

template ErrorCode vectorFill<float>( float const, float * const, std::size_t, std::size_t );
template ErrorCode vectorFill<double>( double const, double * const, std::size_t, std::size_t );
template ErrorCode vectorFill<std::complex<float> >( std::complex<float> const, std::complex<float> * const, std::size_t, std::size_t );
template ErrorCode vectorFill<std::complex<double> >( std::complex<double> const, std::complex<double> * const, std::size_t, std::size_t );

// explicit instantiations
template ErrorCode vectorRamp( float * const, std::size_t, float, float, bool, bool, std::size_t );
template ErrorCode vectorRamp( double * const, std::size_t, double, double, bool, bool, std::size_t );

template ErrorCode vectorCopy<float>( float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorCopy<double>( double const * const, double * const, std::size_t, std::size_t );
template ErrorCode vectorCopy<std::complex<float> >( std::complex<float> const * const, std::complex<float> * const, std::size_t, std::size_t );
template ErrorCode vectorCopy<std::complex<double> >( std::complex<double> const * const, std::complex<double> * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorAdd<float>( float const * const, float const * const ,
               float * const, std::size_t, std::size_t );
template ErrorCode vectorAdd<double>( double const * const, double const * const ,
          double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorAddInplace<float>( float const * const,
                                            float * const, std::size_t, std::size_t);
template ErrorCode vectorAddInplace<double>( double const * const,
                                             double * const, std::size_t, std::size_t);

/** Explicit instantiation for types float and double */
template ErrorCode vectorAddConstant<float>( float, float const * const,
                               float * const, std::size_t, std::size_t);
template ErrorCode vectorAddConstant<double>( double, double const * const,
                                            double * const, std::size_t, std::size_t);

/** Explicit instantiation for types float and double */
template ErrorCode vectorAddConstantInplace<float>( float, float * const, std::size_t, std::size_t );
template ErrorCode vectorAddConstantInplace<double>( double, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorSubtract( float const * const, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorSubtract( double const * const, double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorSubtractInplace( float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorSubtractInplace( double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorSubtractConstant( float, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorSubtractConstant( double, double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorSubConstantInplace( float, float * const, std::size_t, std::size_t );
template ErrorCode vectorSubConstantInplace( double, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiply( float const * const, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiply( double const * const, double const * const, double * const, std::size_t, std::size_t );
template ErrorCode vectorMultiply( std::complex<double> const * const, std::complex<double> const * const, std::complex<double> * const, std::size_t, std::size_t );
template ErrorCode vectorMultiply( std::complex<float> const * const, std::complex<float> const * const, std::complex<float> * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyInplace( float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyInplace( double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyConstant( float, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstant( double, double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyConstantInplace( float, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstantInplace( double, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyAdd( float const * const, float const * const, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAdd( double const * const, double const * const, double const * const, double * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAdd( std::complex<float> const * const, std::complex<float> const * const, std::complex<float> const * const, std::complex<float> * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAdd( std::complex<double> const * const, std::complex<double> const * const, std::complex<double> const * const, std::complex<double> * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyAddInplace( float const * const, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAddInplace( double const * const, double const * const, double * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAddInplace( std::complex<float> const * const, std::complex<float> const * const, std::complex<float> * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyAddInplace( std::complex<double> const * const, std::complex<double> const * const, std::complex<double> * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyConstantAdd( float, float const * const, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstantAdd( double, double const * const, double const * const, double * const, std::size_t, std::size_t );

/** Explicit instantiation for types float and double */
template ErrorCode vectorMultiplyConstantAddInplace( float, float const * const, float * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstantAddInplace( double, double const * const, double * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstantAddInplace( std::complex<double>, std::complex<double> const * const, std::complex<double> * const, std::size_t, std::size_t );
template ErrorCode vectorMultiplyConstantAddInplace( std::complex<float>, std::complex<float> const * const, std::complex<float> * const, std::size_t, std::size_t );

} // namespace reference
} // namespace efl
} // namespace visr


/**
 * @file /ecl_linear_algebra/include/ecl/linear_algebra/eigen.hpp
 */
/*****************************************************************************
** Ifdefs
*****************************************************************************/

#ifndef ecl_linear_algebra_LINEAR_ALGEBRA_EIGEN_HPP_
#define ecl_linear_algebra_LINEAR_ALGEBRA_EIGEN_HPP_

/*****************************************************************************
** Includes
*****************************************************************************/

#include "eigen/formatters.hpp"

#ifndef EIGEN_MATRIXBASE_PLUGIN
  #define EIGEN_MATRIXBASE_PLUGIN <ecl/linear_algebra/eigen/plugin.hpp>
#endif

#include <Eigen/Cholesky>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <Eigen/Householder>
#include <Eigen/Jacobi>
// #include <Eigen/LeastSquares> // This is an eigen2 support module, forget it.
#include <Eigen/LU>
#include <Eigen/QR>
// This one is bad - it doesn't inline its headers (Eigen v3.01) - avoid it for now.
// #include <Eigen/QtAlignedMalloc>
#include <Eigen/Sparse>
#include <Eigen/StdDeque>
#include <Eigen/StdList>
#include <Eigen/StdVector>
#include <Eigen/SVD>

#endif /* ecl_linear_algebra_LINEAR_ALGEBRA_EIGEN_HPP_ */


/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */

/**
 * \file boost/numeric/ublasx/operation/arithmetic_ops.hpp
 *
 * \brief Collection of arithmetic operators for matrix and vector expressions.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 *
 * <hr/>
 *
 * Copyright (c) 2012, Marco Guazzone
 *
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_NUMERIC_UBLASX_OPERATION_ARITHMETIC_OPS_HPP
#define BOOST_NUMERIC_UBLASX_OPERATION_ARITHMETIC_OPS_HPP

#include <boost/numeric/ublas/expression_types.hpp>
#include <boost/numeric/ublas/matrix_expression.hpp>
#include <boost/numeric/ublas/vector_expression.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/utility/enable_if.hpp>

/// (t / v)[i] = t / v[i]
template <typename T1, typename E2>
BOOST_UBLAS_INLINE
typename ::boost::enable_if<
    ::boost::is_convertible<T1, typename E2::value_type>,
    typename ::boost::numeric::ublas::vector_binary_scalar1_traits<
                const T1,
                E2,
                ::boost::numeric::ublas::scalar_divides<T1, typename E2::value_type>
    >::result_type
>::type operator/(T1 const& e1, ::boost::numeric::ublas::vector_expression<E2> const& e2)
{
    typedef typename ::boost::numeric::ublas::vector_binary_scalar1_traits<
                const T1,
                E2,
                ::boost::numeric::ublas::scalar_divides<T1, typename E2::value_type>
        >::expression_type expression_type;

    return expression_type(e1, e2());
}

/// (t / A)(i,j) = t / A(i,j)
template <typename T1, typename E2>
BOOST_UBLAS_INLINE
typename ::boost::enable_if<
    ::boost::is_convertible<T1, typename E2::value_type>,
    typename ::boost::numeric::ublas::matrix_binary_scalar1_traits<
                const T1,
                E2,
                ::boost::numeric::ublas::scalar_divides<T1, typename E2::value_type>
    >::result_type
>::type operator/(T1 const& e1, ::boost::numeric::ublas::matrix_expression<E2> const& e2)
{
    typedef typename ::boost::numeric::ublas::matrix_binary_scalar1_traits<
                const T1,
                E2,
                ::boost::numeric::ublas::scalar_divides<T1, typename E2::value_type>
        >::expression_type expression_type;

    return expression_type(e1, e2());
}

#endif //  BOOST_NUMERIC_UBLASX_OPERATION_ARITHMETIC_OPS_HPP


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   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
//==============================================================================
#define NT2_UNIT_MODULE "nt2 complex.operator toolbox - log/simd Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of boost.simd.operator components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created  by jt the 18/02/2011
///
#include <nt2/include/functions/log.hpp>
#include <boost/simd/sdk/simd/native.hpp>
#include <nt2/include/functions/atan2.hpp>
#include <nt2/include/functions/extract.hpp>
#include <boost/simd/sdk/simd/logical.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/toolbox/constant/constant.hpp>
#include <nt2/sdk/complex/complex.hpp>
#include <nt2/sdk/complex/dry.hpp>
#include <nt2/sdk/complex/imaginary.hpp>
#include <nt2/sdk/complex/meta/as_complex.hpp>
#include <nt2/sdk/complex/meta/as_imaginary.hpp>
#include <nt2/sdk/complex/meta/as_dry.hpp>

NT2_TEST_CASE_TPL ( log_real__2_0,  (float))//BOOST_SIMD_SIMD_REAL_TYPES)
{
  using boost::simd::native;
  typedef NT2_SIMD_DEFAULT_EXTENSION  ext_t;
  typedef std::complex<T>                         cT;
  typedef native<T ,ext_t>                        vT;
  typedef native<cT ,ext_t>                      vcT;
  typedef typename nt2::meta::as_imaginary<T>::type   ciT;
  typedef native<ciT ,ext_t>                         vciT;
  typedef typename nt2::meta::as_dry<T>::type          dT;
  typedef native<dT ,ext_t>                           vdT;
  double ulpd;
  ulpd=0.0;

  typedef vcT r_t;
  // specific values tests
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf<vT>(), nt2::Zero<vT>()))[0], cT(nt2::Inf<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf<vT>(), nt2::Zero<vT>()))[0],cT(nt2::Inf<T>(), nt2::Pi<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Nan<vT>(), nt2::Zero<vT>()))[0], cT(nt2::Nan<cT>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::One<vT>(), nt2::Zero<vT>()))[0], cT(nt2::Zero<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Zero<vT>(), nt2::Zero<vT>()))[0],cT(nt2::Minf<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Zero<vT>(), nt2::One<vT>()))[0],  cT(nt2::Zero<T>(), nt2::Pio_2<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Zero<vT>(), nt2::Mone<vT>()))[0], cT(nt2::Zero<T>(), -nt2::Pio_2<T>()),0.75);

  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::One  <vT>(), nt2::Inf <vT>()))[0], cT(nt2::Inf<T>(), nt2::Pio_2<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::One  <vT>(), nt2::Nan <vT>()))[0], cT(nt2::Nan<T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf <vT>(), nt2::One <vT>()))[0], cT(nt2::Inf<T>(), nt2::Pi<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf <vT>(), nt2::Mone<vT>()))[0], cT(nt2::Inf<T>(), -nt2::Pi<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf  <vT>(), nt2::One <vT>()))[0], cT(nt2::Inf<T>(), nt2::Zero<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf  <vT>(), nt2::Mone<vT>()))[0], cT(nt2::Inf<T>(), nt2::Zero<T>()),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf <vT>(), nt2::Inf<vT>()))[0],  cT(nt2::Inf<T>(), 3*nt2::Pi<T>()/4),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf  <vT>(), nt2::Inf<vT>()))[0],  cT(nt2::Inf<T>(), nt2::Pi<T>()/4),0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf <vT>(), nt2::Nan<vT>()))[0],  cT(nt2::Inf<T>(), nt2::Nan <T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf  <vT>(), nt2::Nan<vT>()))[0],  cT(nt2::Inf <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Nan  <vT>(), nt2::One<vT>()))[0],  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Nan  <vT>(), nt2::Nan<vT>()))[0],  cT(nt2::Nan <T>(), nt2::Nan<T>()), 0.75);

  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::One  <vT>(), -nt2::Inf <vT>()))[0], cT(nt2::Inf<T>(), -nt2::Pio_2<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::One  <vT>(), -nt2::Nan <vT>()))[0], cT(nt2::Nan<T>(), nt2::Nan<T>()), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Minf <vT>(),  nt2::Minf<vT>()))[0],  cT(nt2::Inf<T>(), -3*nt2::Pi<T>()/4), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Inf  <vT>(),  nt2::Minf<vT>()))[0],  cT(nt2::Inf<T>(), -nt2::Pi<T>()/4), 0.75);
  NT2_TEST_ULP_EQUAL(nt2::log(vcT(nt2::Nan  <vT>(), -nt2::One<vT>()))[0],  cT(nt2::Nan <T>(), -nt2::Nan<T>()), 0.75);
} // end of test for floating_


#pragma once

#include <mtao/geometry/volume.h>
#include <Eigen/Sparse>
#include <mtao/geometry/mesh/compactify.hpp>
#include <mtao/eigen/stack.h>
#include <vector>
#include "mandoline/cutface.hpp"
#include "cutmesh.pb.h"
namespace mandoline {
struct CutCell : public std::map<int, bool> {

    using coord_type = std::array<int, 3>;
    int index = -1;
    int region = -1;
    coord_type grid_cell;

    operator std::string() const;
    void serialize(protobuf::CutCell &) const;
    static CutCell from_proto(const protobuf::CutCell &);

    std::vector<Eigen::Triplet<double>> boundary_triplets() const;
    mtao::ColVecs3i triangulated(const std::vector<CutFace<3>> &Fs) const;
    std::tuple<mtao::ColVecs3d, mtao::ColVecs3i> triangulated_with_additional_vertices(const std::vector<CutFace<3>> &Fs, int vertex_offset) const;

    /*
           coord_type grid_cell(const std::vector<CutFace<3>>& F) const;
           */

    template<typename Derived>
    double volume(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const;
    double volume(const mtao::VecXd &face_brep_vols) const;
    template<typename Derived>
    mtao::Vec3d centroid(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const;
    mtao::Vec3d moment(const mtao::ColVecs3d &face_brep_cents) const;
    template<typename Derived>
    std::tuple<mtao::ColVecs3d, mtao::ColVecs3i> get_mesh(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const;

    template<typename Derived, typename VecType>
    bool contains(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs, const Eigen::MatrixBase<VecType> &v) const;

    template<typename Derived, typename VecType>
    double solid_angle(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs, const Eigen::MatrixBase<VecType> &v) const;

    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
};

template<typename Derived>
double CutCell::volume(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const {

    double vol = 0;

    for (auto &&[f, b] : *this) {
        auto &&F = Fs[f];
        double sign = b ? 1 : -1;
        vol += sign * Fs[f].brep_volume(V);
    }
    return vol;
}
template<typename Derived>
mtao::Vec3d CutCell::centroid(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const {

    double vol = 0;
    mtao::Vec3d mom = mtao::Vec3d::Zero();

    for (auto &&[f, b] : *this) {
        auto &&F = Fs[f];
        double sign = b ? 1 : -1;
        vol += sign * Fs[f].brep_volume(V);
        mom += sign * Fs[f].brep_centroid(V);
    }
    mom /= vol;
    return mom;
}
template<typename Derived>
std::tuple<mtao::ColVecs3d, mtao::ColVecs3i> CutCell::get_mesh(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs) const {
    std::vector<mtao::ColVecs3i> FF;
    for (auto &&[fidx, s] : *this) {
        auto &&f = Fs[fidx];
        assert(bool(f.triangulation));
        FF.push_back(*f.triangulation);
    }
    auto F = mtao::eigen::hstack_iter(FF.begin(), FF.end());
    return mtao::geometry::mesh::compactify(V, F);
}

template<typename Derived, typename VecType>
bool CutCell::contains(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs, const Eigen::MatrixBase<VecType> &v) const {
    //> 4 * M_PI, but with some slack
    return solid_angle(V, Fs, v) > .5;
}
template<typename Derived, typename VecType>
double CutCell::solid_angle(const Eigen::MatrixBase<Derived> &V, const mtao::vector<CutFace<3>> &Fs, const Eigen::MatrixBase<VecType> &v) const {
    double sa = 0;
    for (auto &&[fid, sgn] : *this) {
        sa += (sgn ? -1 : 1) * Fs[fid].solid_angle(V, v);
    }
    return sa;
}
}// namespace mandoline


/*===================================================================

MSI applications for interactive analysis in MITK (M2aia)

Copyright (c) Jonas Cordes

All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt for details.

===================================================================*/

#include "mitkIOUtil.h"
#include <algorithm>
#include <signal/m2Normalization.h>
#include <m2FsmSpectrumImage.h>
#include <m2TestingConfig.h>
#include <mitkTestFixture.h>
#include <mitkTestingMacros.h>
#include <numeric>
#include <random>

//#include <boost/algorithm/string.hpp>

class m2FSMImageIOTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(m2FSMImageIOTestSuite);
  MITK_TEST(LoadTestData_shouldReturnTrue);
  MITK_TEST(InitializeImageAccess_shouldReturnTrue);

  CPPUNIT_TEST_SUITE_END();

private:
  std::vector<double> ReadDoubleVector(const std::string &fileNameInM2aiaDir, char delim = '\n')
  {
    std::vector<double> signal;
    std::ifstream f(GetTestDataFilePath(fileNameInM2aiaDir, M2AIA_DATA_DIR));
    std::string line;
    while (std::getline(f, line, delim))
    {
      signal.push_back(std::stod(line));
    }
    return signal;
  }

  template <class T>
  void WriteVector(
    const std::vector<T> &vec,
    const std::string &fileNameInM2aiaDir,
    char delim = '\n')
  {
    std::ofstream f(GetTestDataFilePath(fileNameInM2aiaDir, M2AIA_DATA_DIR));

    for (int i = 0; i < vec.size(); i++)
    {
      f << std::setprecision(128) << vec[i];
      if (i < vec.size() - 1)
        f << delim;
    }
  }

public:
  void LoadTestData_shouldReturnTrue()
  {
    auto v = mitk::IOUtil::Load(GetTestDataFilePath("Markierung.fsm", M2AIA_DATA_DIR));
    m2::FsmSpectrumImage::Pointer fsmImage = dynamic_cast<m2::FsmSpectrumImage *>(v.back().GetPointer());
    CPPUNIT_ASSERT_ASSERTION_PASS(CPPUNIT_ASSERT(fsmImage != nullptr));
  }

  void InitializeImageAccess_shouldReturnTrue()
  {
    auto v = mitk::IOUtil::Load(GetTestDataFilePath("Markierung.fsm", M2AIA_DATA_DIR));
    m2::FsmSpectrumImage::Pointer fsmImage = dynamic_cast<m2::FsmSpectrumImage *>(v.back().GetPointer());
    fsmImage->SetNormalizationStrategy(m2::NormalizationStrategyType::None);
    fsmImage->SetBaselineCorrectionStrategy(m2::BaselineCorrectionType::None);
    fsmImage->SetSmoothingStrategy(m2::SmoothingType::None);
    fsmImage->InitializeImageAccess();
    CPPUNIT_ASSERT_ASSERTION_PASS(CPPUNIT_ASSERT(fsmImage != nullptr));

    std::vector<float> ints, mzs;
    fsmImage->GetSpectrum(0, mzs, ints, 0);
    //WriteVector(ints, "FSMSpectrum.data");
    auto reference = ReadDoubleVector("FSMSpectrum.data");

    using namespace std;
    CPPUNIT_ASSERT_EQUAL(true, equal(begin(ints), end(ints), begin(reference)));

  }
};

MITK_TEST_SUITE_REGISTRATION(m2FSMImageIO)


#include <boost/test/auto_unit_test.hpp>

#include <CompositeDiscretizer.h>
#include <EqualSizeDiscretizer.h>
#include <EqualFrequencyDiscretizer.h>

struct DiscretizerFixture
{
	DiscretizerFixture()
	{
		{
			ClassDescription a{ { 1, 1, 1 }, { 1, 2, 4 }, { 2, 2, 2 } };
			b.insert(std::make_pair("a", a));
		}
		{
			ClassDescription a{ { 6, 6, 5 }, { 6, 5, 8 }, { 5, 7, 8 } };
			b.insert(std::make_pair("b", a));
    	}
		{
			ClassDescription a{ { 2, 10, 16 }, { 1, 21, 14 }, { 0, 12, 32 } };
			b.insert(std::make_pair("c", a));
		}
	}

	ClassDescriptionBase b;
};

BOOST_FIXTURE_TEST_SUITE(Discretizers, DiscretizerFixture)

BOOST_AUTO_TEST_CASE(EqualSizeDiscretizerDiscretizesToEqualSizes)
{
	EqualSizeDiscretizer attr_0(3, b, 0);
	attr_0.teach();

	BOOST_CHECK_EQUAL(attr_0.discretize(0), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(1), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(1.9), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(2.1), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(3.9), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(4.1), 2);
	BOOST_CHECK_EQUAL(attr_0.discretize(4.5), 2);
	BOOST_CHECK_EQUAL(attr_0.discretize(5.9), 2);
	BOOST_CHECK_EQUAL(attr_0.discretize(59), 2);

	EqualSizeDiscretizer attr_1(10, b, 1);
	attr_1.teach();

	BOOST_CHECK_EQUAL(0, attr_1.discretize(1));
	BOOST_CHECK_EQUAL(2, attr_1.discretize(6));
	BOOST_CHECK_EQUAL(4, attr_1.discretize(10));
	BOOST_CHECK_EQUAL(9, attr_1.discretize(200));																																																														BOOST_CHECK_EQUAL(0, attr_1.discretize(1));
}

BOOST_AUTO_TEST_CASE(EqualFrequencyDiscretizerDiscretizesToEqualFrequencies)
{
	EqualFrequencyDiscretizer attr_0(3, b, 0);
	attr_0.teach();

	BOOST_CHECK_EQUAL(attr_0.discretize(0), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(1), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(1.45), 0);
	BOOST_CHECK_EQUAL(attr_0.discretize(1.55), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(2), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(2.5), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(3.9), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(4.1), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(4.5), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(5), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(5.45), 1);
	BOOST_CHECK_EQUAL(attr_0.discretize(5.55), 2);
	BOOST_CHECK_EQUAL(attr_0.discretize(5.9), 2);
	BOOST_CHECK_EQUAL(attr_0.discretize(59), 2);

	EqualFrequencyDiscretizer attr_1(10, b, 1);
	attr_1.teach();

	BOOST_CHECK_EQUAL(0, attr_1.discretize(1));
	BOOST_CHECK_EQUAL(1, attr_1.discretize(2));
	BOOST_CHECK_EQUAL(4, attr_1.discretize(10));
	BOOST_CHECK_EQUAL(7, attr_1.discretize(200));
}

BOOST_AUTO_TEST_CASE(CompositeDistretizerCanDistretizeInMultipleWays)
{
}

BOOST_AUTO_TEST_SUITE_END()


#include <vector>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <sstream>
#include "CorruptionChecksumSolver.h"

int CorruptionChecksumSolver::solve(const std::string &matrix) const {
    int result{0};

    std::vector<std::string> tokens;
    std::vector<int> values;

    std::string line;
    std::istringstream iss(matrix);
    while(std::getline(iss, line)) {
        if (line.find('\t') == std::string::npos)
            break;

        values.clear(); tokens.clear();
        boost::split(tokens, line, boost::is_any_of("\t"));

        std::transform(tokens.begin(), tokens.end(), std::back_inserter(values),
                       [](const std::string& str) { return std::stoi(str); });

        auto minmax = std::minmax_element(values.begin(), values.end());
        result += *minmax.second - *minmax.first;
    }

    return result;
}