/*
 *  Face manager 0.1
 *
 *  Copyright (c) 2018 David Snowdon. All rights reserved.
 *
 *  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)
 */

#include "facedetector.h"
#include "imagelogger.h"

#include <dlib/matrix.h>
#include <dlib/dnn.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_transforms.h>

// From dnn_face_recognition_ex.cpp
// ----------------------------------------------------------------------------------------

// The next bit of code defines a ResNet network.  It's basically copied
// and pasted from the dnn_imagenet_ex.cpp example, except we replaced the loss
// layer with loss_metric and made the network somewhat smaller.  Go read the introductory
// dlib DNN examples to learn what all this stuff means.
//
// Also, the dnn_metric_learning_on_images_ex.cpp example shows how to train this network.
// The dlib_face_recognition_resnet_model_v1 model used by this example was trained using
// essentially the code shown in dnn_metric_learning_on_images_ex.cpp except the
// mini-batches were made larger (35x15 instead of 5x5), the iterations without progress
// was set to 10000, and the training dataset consisted of about 3 million images instead of
// 55.  Also, the input layer was locked to images of size 150.
template<template<int, template<typename> class, int, typename> class block, int N,
        template<typename> class BN, typename SUBNET>
using residual = dlib::add_prev1<block<N, BN, 1, dlib::tag1<SUBNET>>>;

template<template<int, template<typename> class, int, typename> class block, int N,
        template<typename> class BN, typename SUBNET>
using residual_down = dlib::add_prev2<dlib::avg_pool<2, 2, 2, 2, dlib::skip1<dlib::tag2<block<N, BN, 2, dlib::tag1<SUBNET>>>>>>;

template<int N, template<typename> class BN, int stride, typename SUBNET>
using block  = BN<dlib::con<N, 3, 3, 1, 1, dlib::relu<BN<dlib::con<N, 3, 3, stride, stride, SUBNET>>>>>;

template<int N, typename SUBNET> using ares      = dlib::relu<residual<block, N, dlib::affine, SUBNET>>;
template<int N, typename SUBNET> using ares_down = dlib::relu<residual_down<block, N, dlib::affine, SUBNET>>;

template<typename SUBNET> using alevel0 = ares_down<256, SUBNET>;
template<typename SUBNET> using alevel1 = ares<256, ares<256, ares_down<256, SUBNET>>>;
template<typename SUBNET> using alevel2 = ares<128, ares<128, ares_down<128, SUBNET>>>;
template<typename SUBNET> using alevel3 = ares<64, ares<64, ares<64, ares_down<64, SUBNET>>>>;
template<typename SUBNET> using alevel4 = ares<32, ares<32, ares<32, SUBNET>>>;

using anet_type = dlib::loss_metric<dlib::fc_no_bias<128, dlib::avg_pool_everything<
        alevel0<alevel1<alevel2<alevel3<alevel4<dlib::max_pool<3, 3, 2, 2, dlib::relu<dlib::affine<dlib::con<32, 7, 7, 2, 2,
                dlib::input_rgb_image_sized<150>
        >>>>>>>>>>>>;

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

class FaceDetectorImpl {
public:
    FaceDetectorImpl(const std::string &model_dir);

    // TODO generalise the input image type
    std::vector<dlib::rectangle> detectFaces(const dlib::cv_image<dlib::bgr_pixel> &image);

    std::vector<dlib::rectangle> detectFaces(const dlib::array2d<dlib::rgb_pixel> &image);

    // TODO generalise the returned image type
    std::vector<dlib::matrix<dlib::rgb_pixel>> extractFaceImages(const dlib::cv_image<dlib::bgr_pixel> &image,
                                                                 const std::vector<dlib::rectangle> &face_bounds) const;

    dlib::matrix<dlib::rgb_pixel> extractFaceImage(const dlib::cv_image<dlib::bgr_pixel> &image,
                                                   const dlib::rectangle &face_bounds) const;

    dlib::matrix<dlib::rgb_pixel> extractFaceImage(const dlib::array2d<dlib::rgb_pixel> &image,
                                                   const dlib::rectangle &face_bounds) const;

    std::vector<FaceDescriptor> getFaceDescriptors(std::vector<dlib::matrix<dlib::rgb_pixel>> face_images);

    FaceDescriptor getFaceDescriptor(const dlib::matrix<dlib::rgb_pixel> &face_image, bool use_jitter);

private:
    // Get the face detector
    dlib::frontal_face_detector face_detector = dlib::get_frontal_face_detector();

    // facial landmark detector
    dlib::shape_predictor landmark_detector;

    // DNN used for face recognition
    anet_type face_metrics_net;
};

FaceDetectorImpl::FaceDetectorImpl(const std::string &model_dir) {
    // Get the face detector
    face_detector = dlib::get_frontal_face_detector();

    // facial landmark detector
    dlib::deserialize(model_dir + "/shape_predictor_5_face_landmarks.dat") >> landmark_detector;

    // DNN used for face recognition
    dlib::deserialize(model_dir + "/dlib_face_recognition_resnet_model_v1.dat") >> face_metrics_net;
}

std::vector<dlib::rectangle>
FaceDetectorImpl::detectFaces(const dlib::cv_image<dlib::bgr_pixel> &image) {
    return face_detector(image);
}

std::vector<dlib::rectangle>
FaceDetectorImpl::detectFaces(const dlib::array2d<dlib::rgb_pixel> &image) {
    return face_detector(image);
}

std::vector<dlib::matrix<dlib::rgb_pixel>>
FaceDetectorImpl::extractFaceImages(const dlib::cv_image<dlib::bgr_pixel> &image,
                                    const std::vector<dlib::rectangle> &face_bounds) const {
    // These are the transformed and extracted faces
    std::vector<dlib::matrix<dlib::rgb_pixel>> faces;

    // Loop over all detected face rectangles
    for (const auto &face_bound : face_bounds) {
        faces.push_back(std::move(extractFaceImage(image, face_bound)));
    }
    return faces;
}

// TODO fix duplication
dlib::matrix<dlib::rgb_pixel>
FaceDetectorImpl::extractFaceImage(const dlib::cv_image<dlib::bgr_pixel> &image,
                                   const dlib::rectangle &face_bounds) const {
    // Find the face landmarks
    dlib::full_object_detection landmarks = landmark_detector(image, face_bounds);

    // use the landmarks to normalise the face image and extract
    dlib::matrix<dlib::rgb_pixel> face_chip;
    dlib::extract_image_chip(image, dlib::get_face_chip_details(landmarks, 150, 0.25), face_chip);
    logger.debug("face-chip", face_chip);
    return face_chip;
}

dlib::matrix<dlib::rgb_pixel>
FaceDetectorImpl::extractFaceImage(const dlib::array2d<dlib::rgb_pixel> &image,
                                   const dlib::rectangle &face_bounds) const {
    // Find the face landmarks
    dlib::full_object_detection landmarks = landmark_detector(image, face_bounds);

    // use the landmarks to normalise the face image and extract
    dlib::matrix<dlib::rgb_pixel> face_chip;
    dlib::extract_image_chip(image, dlib::get_face_chip_details(landmarks, 150, 0.25), face_chip);
    logger.debug("face-chip", face_chip);
    return face_chip;
}

std::vector<FaceDescriptor>
FaceDetectorImpl::getFaceDescriptors(std::vector<dlib::matrix<dlib::rgb_pixel>> face_images) {
    return face_metrics_net(face_images);
}

// From dnn_face_recognition_ex.cpp
std::vector<dlib::matrix<dlib::rgb_pixel>>
jitter_image(const dlib::matrix<dlib::rgb_pixel> &img) {
    // All this function does is make 100 copies of img, all slightly jittered by being
    // zoomed, rotated, and translated a little bit differently. They are also randomly
    // mirrored left to right.
    thread_local dlib::rand rnd;

    std::vector<dlib::matrix<dlib::rgb_pixel>> crops;
    for (int i = 0; i < 100; ++i)
        crops.push_back(dlib::jitter_image(img, rnd));

    return crops;
}

FaceDescriptor
FaceDetectorImpl::getFaceDescriptor(const dlib::matrix<dlib::rgb_pixel> &face_image, bool use_jitter) {
    if (use_jitter) {
        return dlib::mean(dlib::mat(face_metrics_net(jitter_image(face_image))));
    } else {
        std::vector<dlib::matrix<dlib::rgb_pixel>> face_images{face_image};
        auto descriptors = face_metrics_net(face_images);
        return descriptors[0];
    }
}

FaceDetector::FaceDetector(const std::string &model_dir) {
    impl = new FaceDetectorImpl(model_dir);
}

FaceDetector::~FaceDetector() {
    delete impl;
}

std::vector<dlib::rectangle>
FaceDetector::detectFaces(const dlib::cv_image<dlib::bgr_pixel> &image) {
    ++counters_.detect_count_;
    return impl->detectFaces(image);
}

std::vector<dlib::rectangle>
FaceDetector::detectFaces(const dlib::array2d<dlib::rgb_pixel> &image) {
    ++counters_.detect_count_;
    return impl->detectFaces(image);
}

std::vector<dlib::matrix<dlib::rgb_pixel>>
FaceDetector::extractFaceImages(const dlib::cv_image<dlib::bgr_pixel> &image,
                                const std::vector<dlib::rectangle> &face_bounds) {
    counters_.extract_face_image_count_ += face_bounds.size();
    return impl->extractFaceImages(image, face_bounds);
}

dlib::matrix<dlib::rgb_pixel>
FaceDetector::extractFaceImage(const dlib::cv_image<dlib::bgr_pixel> &image,
                               const dlib::rectangle &face_bounds) {
    ++counters_.extract_face_image_count_;
    return impl->extractFaceImage(image, face_bounds);
}

dlib::matrix<dlib::rgb_pixel>
FaceDetector::extractFaceImage(const dlib::array2d<dlib::rgb_pixel> &image,
                               const dlib::rectangle &face_bounds) {
    ++counters_.extract_face_image_count_;
    return impl->extractFaceImage(image, face_bounds);
}

std::vector<FaceDescriptor>
FaceDetector::getFaceDescriptors(std::vector<dlib::matrix<dlib::rgb_pixel>> face_images) {
    counters_.face_descriptor_count_ += face_images.size();
    return impl->getFaceDescriptors(face_images);
}

FaceDescriptor
FaceDetector::getFaceDescriptor(const dlib::matrix<dlib::rgb_pixel> face_image, bool use_jitter) {
    ++counters_.face_descriptor_count_;
    return impl->getFaceDescriptor(face_image, use_jitter);
}


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

// Copyright (c) 2017-2018, Oracle and/or its affiliates.

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

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

#ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_BOX_BOX_HPP
#define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_BOX_BOX_HPP

#include <boost/config.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_void.hpp>

#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tags.hpp>

#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/concepts/distance_concept.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
#include <boost/geometry/strategies/spherical/distance_cross_track_box_box.hpp>

#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>

namespace boost { namespace geometry
{

namespace strategy { namespace distance
{

/*!
\brief Strategy functor for distance point to box calculation
\ingroup strategies
\details Class which calculates the distance of a point to a box, for
points and boxes on a sphere or globe
\tparam CalculationType \tparam_calculation
\tparam Strategy underlying point-segment distance strategy, defaults
to cross track
\qbk{
[heading See also]
[link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
}
*/
template
<
    typename FormulaPolicy = strategy::andoyer,
    typename Spheroid = srs::spheroid<double>,
    typename CalculationType = void
>
class geographic_cross_track_box_box
{
public:
    typedef geographic_cross_track<FormulaPolicy, Spheroid, CalculationType> Strategy;

    template <typename Box1, typename Box2>
    struct return_type
        : services::return_type<Strategy, typename point_type<Box1>::type, typename point_type<Box2>::type>
    {};

    inline geographic_cross_track_box_box()
    {}

    template <typename Box1, typename Box2>
    inline typename return_type<Box1, Box2>::type
    apply(Box1 const& box1, Box2 const& box2) const
    {
/*
#if !defined(BOOST_MSVC)
        BOOST_CONCEPT_ASSERT
            (
                (concepts::PointSegmentDistanceStrategy
                    <
                        Strategy,
                        typename point_type<Box1>::type,
                        typename point_type<Box2>::type
                    >)
            );
#endif
*/
        typedef typename return_type<Box1, Box2>::type return_type;
        return details::cross_track_box_box_generic
                                       <return_type>::apply(box1, box2, Strategy());
    }
};

#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{

template <typename Strategy, typename Spheroid, typename CalculationType>
struct tag<geographic_cross_track_box_box<Strategy, Spheroid, CalculationType> >
{
    typedef strategy_tag_distance_box_box type;
};

template <typename Strategy, typename Spheroid, typename CalculationType, typename Box1, typename Box2>
struct return_type<geographic_cross_track_box_box<Strategy, Spheroid, CalculationType>, Box1, Box2>
    : geographic_cross_track_box_box
        <
            Strategy, Spheroid, CalculationType
        >::template return_type<Box1, Box2>
{};

template <typename Strategy, typename Spheroid, typename Box1, typename Box2>
struct return_type<geographic_cross_track_box_box<Strategy, Spheroid>, Box1, Box2>
    : geographic_cross_track_box_box
        <
            Strategy, Spheroid
        >::template return_type<Box1, Box2>
{};

template <typename Strategy, typename Box1, typename Box2>
struct return_type<geographic_cross_track_box_box<Strategy>, Box1, Box2>
    : geographic_cross_track_box_box
        <
            Strategy
        >::template return_type<Box1, Box2>
{};

template <typename Strategy, typename Spheroid, typename CalculationType>
struct comparable_type<geographic_cross_track_box_box<Strategy, Spheroid, CalculationType> >
{
    typedef geographic_cross_track_box_box
        <
            typename comparable_type<Strategy>::type, Spheroid, CalculationType
        > type;
};

template <typename Strategy, typename Spheroid, typename CalculationType>
struct get_comparable<geographic_cross_track_box_box<Strategy, Spheroid, CalculationType> >
{
    typedef geographic_cross_track_box_box<Strategy, Spheroid, CalculationType> this_strategy;
    typedef typename comparable_type<this_strategy>::type comparable_type;

public:
    static inline comparable_type apply(this_strategy const& /*strategy*/)
    {
        return comparable_type();
    }
};

template <typename Strategy, typename Spheroid, typename CalculationType, typename Box1, typename Box2>
struct result_from_distance
    <
        geographic_cross_track_box_box<Strategy, Spheroid, CalculationType>, Box1, Box2
    >
{
private:
    typedef geographic_cross_track_box_box<Strategy, Spheroid, CalculationType> this_strategy;

    typedef typename this_strategy::template return_type
        <
            Box1, Box2
        >::type return_type;

public:
    template <typename T>
    static inline return_type apply(this_strategy const& strategy,
                                    T const& distance)
    {
        result_from_distance
            <
                Strategy,
                typename point_type<Box1>::type,
                typename point_type<Box2>::type
            >::apply(strategy, distance);
    }
};

template <typename Box1, typename Box2>
struct default_strategy
    <
        box_tag, box_tag, Box1, Box2,
        geographic_tag, geographic_tag
    >
{
    typedef geographic_cross_track_box_box<> type;
};

} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

}} // namespace strategy::distance

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_DISTANCE_CROSS_TRACK_BOX_BOX_HPP


#pragma once

#include "gtest.h"

#include <mpreal.h>
#include <Eigen/Core>
#include <Eigen/CXX11/Tensor>

#include <irlib/basis.hpp>

using mpfr::mpreal;

//extern template class irlib::basis_set<mpfr::mpreal>;
//extern template class irlib::piecewise_polynomial<double,mpfr::mpreal>;


/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/configuration.h"

#include <cassert>
#include <cmath>
#include <cstring>
#include <regex>

#include <boost/uuid/uuid_io.hpp>

#include "gui/document.h"
#include "gui/label.h"

namespace flint {
namespace gui {

const char *Configuration::GetKisaoId() const
{
	if (method == "ARK")
		return "9999999";
	if (method == "Euler")
		return "0000030";
	if (method == kLabelEulerMaruyama)
		return "0000286";
	return "0000032";
}

namespace {

/*
 * Return the scalar value of time length in the initial step unit
 */
double Convert(double d, int i, const Document *doc)
{
	int k = doc->initial_config().step_unit;
	d *= doc->GetNumerator(i) * doc->GetDenominator(k);
	d /= doc->GetDenominator(i) * doc->GetNumerator(k);
	return d;
}

double Convert(const wxString &s, int i, const Document *doc)
{
	double d;
	auto b = s.ToCDouble(&d);
	assert(b);
	return Convert(d, i, doc);
}

}

double Configuration::GetOutputStartTime(const Document *doc) const
{
	return Convert(start, start_unit, doc);
}

double Configuration::GetOutputEndTime(const Document *doc) const
{
	return Convert(length, length_unit, doc);
}

int Configuration::GetNumberOfPoints(const Document *doc) const
{
	auto l = Convert(length, length_unit, doc);
	auto s = Convert(step, step_unit, doc);
	return std::floor(l/s);
}

namespace {

const std::string &GetTargetString(const lo::Column &column, int filter_column)
{
	return (filter_column == 0) ? column.name() : column.track_name();
}

std::string GetKey(const lo::Column &column)
{
	boost::uuids::uuid uuid;
	std::memcpy(&uuid, column.uuid().c_str(), 16);
	return boost::uuids::to_string(uuid) + ":" + column.name();
}

}

void Configuration::GetOutputVariables(const Document *doc,
									   std::vector<lo::Column> *v) const
{
	if (filter_pattern == "Regular expression") {
		try {
			std::regex r(filter_value);
			for (auto &column : doc->var()) {
				if (std::regex_search(GetTargetString(column, filter_column), r))
					v->push_back(column);
			}
		} catch (const std::regex_error &e) {
			// ignore columns if given regexp is invalid
		}
	} else { // Fixed string
		for (auto &column : doc->var()) {
			auto found = GetTargetString(column, filter_column).find(filter_value);
			if (found != std::string::npos)
				v->push_back(column);
		}
	}
}

void Configuration::GetOutputVariables(const Document *doc,
									   std::vector<std::string> *v) const
{
	std::vector<lo::Column> columns;
	GetOutputVariables(doc, &columns);
	for (auto &column : columns)
		v->push_back(GetKey(column));
}

std::vector<std::pair<lo::Column, std::string> > Configuration::GetTargets(const Document *doc) const
{
	std::vector<std::pair<lo::Column, std::string> > v;
	int i = 0;
	for (const auto &column : doc->param()) {
		auto it = parameters.find(i++);
		if (it != parameters.end())
			v.emplace_back(column, it->second);
	}
	return v;
}

}
}


/*
 *  Copyright (c), 2017, Adrien Devresse
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 *
 */
#include <iostream>

#undef H5_USE_BOOST
#define H5_USE_BOOST

#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <highfive/H5File.hpp>

using namespace HighFive;

const std::string FILE_NAME("boost_ublas_double.h5");
const std::string DATASET_NAME("dset");

const size_t size_x = 10;
const size_t size_y = 10;

int main(void) {

    try {
        typedef typename boost::numeric::ublas::matrix<double> Matrix;

        // create a 10x10 matrix
        Matrix mat(size_x, size_y);

        // fill it
        for (std::size_t i = 0; i < size_x; ++i) {
            mat(i, i) = i;
        }

        // Create a new HDF5 file
        File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

        // create a new dataset with the 10x10 Matrix dimension
        DataSet dataset =
            file.createDataSet<double>(DATASET_NAME, DataSpace::From(mat));

        // write it
        dataset.write(mat);

        // now, let read it back
        Matrix result;
        dataset.read(result);

        // print what we read
        std::cout << "Matrix result:\n" << result << std::endl;

    } catch (Exception& err) {
        // catch and print any HDF5 error
        std::cerr << err.what() << std::endl;
    }

    return 0; // successfully terminated
}


#include <chrono>
#include <iostream>
#include <ratio>
#include <sstream>
#include <locale>
#include <iomanip>
#include <cassert>
#include <boost/date_time/posix_time/posix_time.hpp>

namespace pt = boost::posix_time;
using date = boost::gregorian::date;

/**
 * Transparent implementation of joaDateTime core functionality conserning OADate (OLE Automation)
 * for fun, see: https://social.msdn.microsoft.com/Forums/office/en-US/f1eef5fe-ef5e-4ab6-9d92-0998d3fa6e14/what-is-story-behind-december-30-1899-as-base-date
 */
struct DateTime {
	// Number of 100ns ticks per time unit
	static const long TicksPerMillisecond = 10000;
	static const long TicksPerSecond = TicksPerMillisecond * 1000;
	static const long TicksPerMinute = TicksPerSecond * 60;
	static const long TicksPerHour = TicksPerMinute * 60;
	static const long TicksPerDay = TicksPerHour * 24;

	// Number of milliseconds per time unit
	static const int MillisPerSecond = 1000;
	static const int MillisPerMinute = MillisPerSecond * 60;
	static const int MillisPerHour = MillisPerMinute * 60;
	static const int MillisPerDay = MillisPerHour * 24;

	// Number of days in a non-leap year
	static const int DaysPerYear = 365;
	// Number of days in 4 years
	static const int DaysPer4Years = DaysPerYear * 4 + 1;       // 1461
	// Number of days in 100 years
	static const int DaysPer100Years = DaysPer4Years * 25 - 1;  // 36524
	// Number of days in 400 years
	static const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097

	// Number of days from 1/1/0001 to 12/31/1600
	static const int DaysTo1601 = DaysPer400Years * 4;          // 584388
	// Number of days from 1/1/0001 to 12/30/1899
	static const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
	// Number of days from 1/1/0001 to 12/31/1969
	static const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162
	// Number of days from 1/1/0001 to 12/31/9999
	static const int DaysTo10000 = DaysPer400Years * 25 - 366;  // 3652059

	static const long MinTicks = 0;
	static const long MaxTicks = DaysTo10000 * TicksPerDay - 1;
	static const long MaxMillis = (long)DaysTo10000 * MillisPerDay;

	static const long FileTimeOffset = DaysTo1601 * TicksPerDay;
	static const long DoubleDateOffset = DaysTo1899 * TicksPerDay;
	// The minimum OA date is 0100/01/01 (Note it's year 100).
	// The maximum OA date is 9999/12/31
	static const long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;
	// All OA dates must be greater than (not >=) OADateMinAsDouble
	constexpr static const double OADateMinAsDouble = -657435.0;
	// All OA dates must be less than (not <=) OADateMaxAsDouble
	constexpr static const double OADateMaxAsDouble = 2958466.0;

	// Converts an OLE Date to a tick count.
	// This function is duplicated in COMDateTime.cpp
	static long OADateToTicks(double value) {
		// The check done this way will take care of NaN
		if (!(value < OADateMaxAsDouble) || !(value > OADateMinAsDouble))
			throw std::runtime_error("OADateToTicks(): Arg_OleAutDateInvalid");

		// Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble
		long millis = (long)(value * MillisPerDay + (value >= 0 ? 0.5: -0.5));
		// The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899
		// However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative
		// This line below fixes up the millis in the negative case
		if (millis < 0) {
			millis -= (millis % MillisPerDay) * 2;
		}

		millis += DoubleDateOffset / TicksPerMillisecond;

		if (millis < 0 || millis >= MaxMillis) throw std::runtime_error("OADateToTicks(): Arg_OleAutDateScale");
		return millis * TicksPerMillisecond;
	}

	// This function is duplicated in COMDateTime.cpp
	static double TicksToOADate(long value) {
		if (value == 0)
			return 0.0;  // Returns OleAut's zero'ed date value.
		if (value < TicksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899.
			value += DoubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check.
		if (value < OADateMinAsTicks)
			throw std::out_of_range("TicksToOADate(): Arg_OleAutDateInvalid");
		// Currently, our max date == OA's max date (12/31/9999), so we don't
		// need an overflow check in that direction.
		long millis = (value  - DoubleDateOffset) / TicksPerMillisecond;
		if (millis < 0) {
			long frac = millis % MillisPerDay;
			if (frac != 0) millis -= (MillisPerDay + frac) * 2;
		}
		return (double)millis / MillisPerDay;
	}

	static long EpochToTicks(long sec) {
        auto t0 = DaysTo1970 * TicksPerDay;
        auto t1 = sec * TicksPerSecond;
        return t0 + t1;

    }

    static long TicksToEpoch(long ticks) {
        constexpr auto t0 = (DaysTo1970 * TicksPerDay) / TicksPerSecond;
        auto t1 = ticks / TicksPerSecond;
        return (t1 - t0);
    }

    static std::string EpochToString(long epoch) {
        std::time_t temp = epoch;
        std::tm* t = std::gmtime(&temp);
        std::stringstream ss; // or if you're going to print, just input directly into the output stream
        ss << std::put_time(t, "%Y-%m-%d %I:%M:%S %p");
        return ss.str();
    }

    static int64_t PosixTimeToEpoch(const pt::ptime& t) {
        static const auto epoch = pt::ptime(date {1970, 1, 1});
        return (t - epoch).total_seconds();
    }

    static pt::ptime EpochToPosixTime(int64_t value) {
        static const auto epoch = pt::ptime(date {1970, 1, 1});
        return epoch + pt::seconds(value);
    }

    /**
     * An OLE Automation date is implemented as a floating-point number whose integral component
     * is the number of days before or after midnight, 30 December 1899, and whose fractional component
     * represents the time on that day divided by 24.
     * For example,
     * midnight, 31 December 1899 is represented by 1.0;
     * 6 A.M., 1 January 1900 is represented by 2.25;
     * midnight, 29 December 1899 is represented by -1.0; and
     * 6 A.M., 29 December 1899 is represented by -1.25.
     */
    static pt::ptime OADateToPosixTime(double value) {
        return EpochToPosixTime(TicksToEpoch(OADateToTicks(value)));
    }

    static double PosixTimeToOADate(const pt::ptime& value) {
        return TicksToOADate(EpochToTicks(PosixTimeToEpoch(value)));
    }
};

void test_fixed_timepoints() {
    /**
     * https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tooadate?view=netframework-4.8
     */
    pt::ptime de = pt::ptime(date { 1899, 12, 30 }); //ticks: 599264352000000000
    pt::ptime ue = pt::ptime(date { 1970, 1, 1 });
    assert(DateTime::PosixTimeToEpoch(ue) == 0);
    assert(DateTime::PosixTimeToOADate(de) == 0.0);

    //midnight, 31 December 1899 is represented by 1.0;
    pt::ptime _1899_12_31_00_00_00 = pt::ptime(date { 1899, 12, 31 } );
    assert(DateTime::PosixTimeToOADate(_1899_12_31_00_00_00) == 1.0);
    // 6 A.M., 1 January 1900 is represented by 2.25;
    pt::ptime _1900_01_01_06_00_00 = pt::ptime(pt::from_iso_string("19000101T060000"));
    assert(DateTime::PosixTimeToOADate(_1900_01_01_06_00_00) == 2.25);
    //midnight, 29 December 1899 is represented by -1.0; and
    pt::ptime _1899_12_29_00_00_00 = pt::ptime(date { 1899, 12, 29 } );
    assert(DateTime::PosixTimeToOADate(_1899_12_29_00_00_00) == -1.0);
    //6 A.M., 29 December 1899 is represented by -1.25.
    pt::ptime _1899_12_29_06_00_00 = pt::ptime(pt::from_iso_string("18991229T060000"));
    assert(DateTime::PosixTimeToOADate(_1899_12_29_06_00_00) == -1.25);

}

int main(int argc, char* argv[]) {
    test_fixed_timepoints();

    //pt::ptime t = pt::ptime(date { 1970, 1, 1 });
    pt::ptime t = pt::ptime(date { 1899, 12, 30 });
    pt::ptime t1 = pt::ptime(date { 1970, 1, 1 });

    std::cout << DateTime::PosixTimeToEpoch(t1) << std::endl;
    std::cout << DateTime::PosixTimeToOADate(t1) << std::endl;

    auto epoch = DateTime::PosixTimeToEpoch(t);

    auto ticks = DateTime::EpochToTicks(epoch);
    auto oadate = DateTime::TicksToOADate(ticks);

    std::cout << "date:   " << DateTime::EpochToString(epoch) << std::endl;
    std::cout << "epoch:  " << epoch << std::endl;
    std::cout << "ticks:  " << ticks << std::endl;
    std::cout << "oadate: " << std::fixed << oadate << std::endl;

    auto test_oadate = DateTime::OADateToTicks(oadate);
    auto test_epoch = DateTime::TicksToEpoch(test_oadate);

    std::cout << "ticks:  " << std::fixed << test_oadate << std::endl;
    std::cout << "epoch:  " << test_epoch << std::endl;

    assert(test_oadate == ticks);
    assert(test_epoch == epoch);

    return 0;
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012 - 2014 NUMSCALE SAS
//
//          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_ARITHMETIC_FUNCTIONS_SIMD_COMMON_SQRS_HPP_INCLUDED
#define BOOST_SIMD_ARITHMETIC_FUNCTIONS_SIMD_COMMON_SQRS_HPP_INCLUDED

#include <boost/simd/arithmetic/functions/sqrs.hpp>
#include <boost/simd/include/functions/simd/sqr.hpp>
#include <boost/simd/include/functions/simd/abss.hpp>
#include <boost/simd/include/functions/simd/is_greater.hpp>
#include <boost/simd/include/functions/simd/if_else.hpp>
#include <boost/simd/include/constants/valmax.hpp>
#include <boost/simd/include/constants/sqrtvalmax.hpp>
#include <boost/dispatch/attributes.hpp>

#ifdef USE_UBSAN
#include <boost/simd/include/functions/simd/bitwise_cast.hpp>
#include <boost/dispatch/meta/as_unsigned.hpp>
#endif

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT          ( sqrs_, tag::cpu_
                                    , (A0)(X)
                                    , ((simd_< int_<A0>, X >))
                                    )
  {
    typedef A0 result_type;
    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL(1)
    {
// workaround for UBSan
#ifdef USE_UBSAN
      typedef typename boost::dispatch::meta::as_unsigned<A0>::type utype;
      return if_else(gt(abss(a0), boost::simd::Sqrtvalmax<result_type>()),
        boost::simd::Valmax<result_type>(), bitwise_cast<A0>(sqr(bitwise_cast<utype>(a0))));
#else
      return if_else(gt(abss(a0), boost::simd::Sqrtvalmax<result_type>()),
                     boost::simd::Valmax<result_type>(), sqr(a0));
#endif
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( sqrs_, tag::cpu_
                                    , (A0)(X)
                                    , ((simd_< uint_<A0>, X >))
                                    )
  {
    typedef A0 result_type;
    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL(1)
    {
      return if_else(gt(a0, boost::simd::Sqrtvalmax<result_type>()),
                     boost::simd::Valmax<result_type>(), sqr(a0));
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( sqrs_, tag::cpu_
                                    , (A0)(X)
                                    , ((simd_< floating_<A0>, X >))
                                    )
  {
    typedef A0 result_type;
    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL(1)
    {
      return sqr(a0);
    }
  };
} } }

#endif


#include "Lib/spin_system.h"
#include "Lib/log_trace.h"
#include "Lib/simulate.h"
#include "Lib/grid.h"
#include "Lib/constants.h"
#include "Lib/load_parameters.h"

#include <omp.h>

#include <iostream>
#include <filesystem>
#include <unsupported/Eigen/MatrixFunctions>
#include <Eigen/Eigenvalues>
#include <vector>
#include <fstream>
#include <string>
#include <vector>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/ref.hpp>

namespace fs = std::experimental::filesystem;

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

	try {
		if (argc < 4)
		{
			throw std::runtime_error("Not enough arguments given");
		}
	}
	catch (std::runtime_error &er) {
		std::cout << er.what() << "\n";
	}

	std::vector<double> phi;
	std::vector<double> theta;
	std::vector<double> weights;

	std::vector<double> B;
	double t_step;

	Spin_System_Doublet spin_time;
	Spin_System_Doublet spin_pulse;
	std::vector<double> t;
	auto temp = boost::make_tuple(boost::ref(spin_time), boost::ref(spin_pulse), boost::ref(t_step), boost::ref(B), boost::ref(t));
	temp=load_parameters_doublet(argv[1]);

	auto temp2 = boost::make_tuple(boost::ref(phi), boost::ref(theta), boost::ref(weights));
	temp2 = grid(argv[3],spin_time.symmetrie, spin_time.knots);

	double const t0 = t[0];
	double const t1 = t[1];
	double const t2 = t[2];
	double const t3 = t[3];
	double const t4 = t[4];
	double const t5 = t[5];

	Log_stream log_stream (argv[2], "integral", t_step);

	for (auto B_temp : B) {

		spin_time.change_B(B_temp);
		spin_pulse.change_B(B_temp);

		Spin_System_Doublet::operator_type rho_eq = spin_time.get_rho_equ();
		Spin_System_Doublet::operator_type rho;

		log_stream.save_x(B_temp);

		for (int i = 0; i < phi.size(); ++i) {

			std::vector<double> angles = { 0,theta[i],phi[i],weights[i] };
			rho = simulate(spin_pulse, t0, t1, angles, rho_eq, Log_trace_none{});
			rho = simulate(spin_time, t1, t2, angles, rho, Log_trace_none{});
			rho = simulate(spin_pulse, t2, t3, angles, rho, Log_trace_none{});
			rho = simulate(spin_time, t3, t4, angles, rho, Log_trace_none{});
			rho = simulate(spin_time, t4, t5, angles, rho, log_stream);
		}

		log_stream.next();

	}

	log_stream.save_data();

}


#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>
#include <fstream>
#include <string>
#include <regex>
#include <iterator>
#include <filesystem>
#include <python3.7m/Python.h>
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>

#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>

#include "boost/filesystem.hpp"
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"

namespace fs = boost::filesystem;
namespace p = boost::python;
namespace np = boost::python::numpy;

struct VectorObj
{
    _Float32 x;
    _Float32 y;
    _Float32 z;
    _Float32 mag;

    VectorObj() : x(0.0), y(0.0), z(0.0), mag(0.0) {}
    VectorObj(_Float32 x, _Float32 y, _Float32 z)
    {
        VectorObj::mag = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
        if (mag != 0)
        {
            VectorObj::x = x / mag;
            VectorObj::y = y / mag;
            VectorObj::z = z / mag;
        }
    }

    void setX(_Float32 val) { this->x = val; }
    void setY(_Float32 val) { this->y = val; }
    void setZ(_Float32 val) { this->z = val; }
    void setMag(_Float32 val) { this->mag = val; }

    _Float32 getX() { return x; }
    _Float32 getY() { return y; }
    _Float32 getZ() { return z; }
    _Float32 getMag() { return mag; }

    bool operator==(VectorObj const &val) const
    {
        return (x == val.x) && (y == val.y) && (z == val.z);
    }
    bool operator!=(VectorObj const &val) const
    {
        return (x != val.x) || (y != val.y) || (z != val.z);
    }

    std::string repr() const
    {
        return std::to_string(x) + " " + std::to_string(y) + " " + std::to_string(z);
    }
};

struct Parser
{
    std::vector<std::vector<VectorObj>> fileList;
    bool checkBase = true;
    bool checkNodes = true;
    int xnodes, ynodes, znodes;
    double xbase, ybase, zbase;
    std::string def_ext;

    Parser()
    {
        xnodes = 0;
        ynodes = 0;
        znodes = 0;

        xbase = 0.0;
        ybase = 0.0;
        zbase = 0.0;

        def_ext = ".omf";
    };

    void setXnodes(int val) { this->xnodes = val; }
    void setYnodes(int val) { this->ynodes = val; }
    void setZnodes(int val) { this->znodes = val; }
    void setXbase(int val) { this->xbase = val; }
    void setYbase(int val) { this->ybase = val; }
    void setZbase(int val) { this->zbase = val; }
    int getXnodes() { return xnodes; }
    int getYnodes() { return ynodes; }
    int getZnodes() { return znodes; }
    double getXbase() { return xbase; }
    double getYbase() { return ybase; }
    double getZbase() { return zbase; }

    std::vector<std::vector<VectorObj>> getVectors()
    {
        return fileList;
    }

    np::ndarray getOmfToList(std::string path)
    {
        // is a text file
        std::ifstream miffile;
        miffile.open(path, std::ios::out);
        int buffer_size = getMifHeader(miffile);

        int num_vectors = xnodes * ynodes * znodes;
        double *fut_ndarray = (double *)(malloc(sizeof(double) * num_vectors * 3));
        int i = 0;
        if (miffile.is_open())
        {
            std::string line;
            while (std::getline(miffile, line))
            {
                std::istringstream iss(line);
                if (line[0] == '#')
                    continue;
                else
                {
                    double x, y, z;
                    if (!(iss >> x >> y >> z))
                        break;
                    fut_ndarray[i + 0] = x;
                    fut_ndarray[i + 1] = y;
                    fut_ndarray[i + 2] = z;
                    i += 3;
                }
            }
        }
        miffile.close();
        boost::python::numpy::dtype dt1 = boost::python::numpy::dtype::get_builtin<double>();
        boost::python::tuple shape = boost::python::make_tuple(num_vectors, 3);
        boost::python::tuple stride = boost::python::make_tuple(3 * sizeof(double), sizeof(double));
        boost::python::numpy::ndarray vectorData = boost::python::numpy::from_data(fut_ndarray,
                                                                                dt1,
                                                                                shape,
                                                                                stride,
                                                                                boost::python::object());
        // last entry is object owner
        return vectorData;
    }

    int listFiles(std::string dirpath)
    {
        if (!fs::exists(dirpath))
        {
            std::cout << "\nNot found: " << dirpath << std::endl;
            return 1;
        }
        if (fs::is_directory(dirpath))
        {
            fs::directory_iterator end_iter;
            for (fs::directory_iterator dir_it(dirpath); dir_it != end_iter; dir_it++)
            {
                if (fs::is_regular_file(dir_it->status()) && dir_it->path().extension() == this->def_ext)
                {
                    std::cout << dir_it->path().string() << std::endl;
                }
            }
        }
        else
        {
            std::cout << "\nNot a directory: " << dirpath << std::endl;
        }
        return 0;
    }

    int getMifHeader(std::ifstream &miffile)
    {
        std::string line;
        int buffer_size = 0;

        std::string node_reg("# xnodes:");
        std::string base_reg("# xbase:");

        // we have to change strategy here
        std::string data_text("# Begin: Data Text");
        if (miffile.is_open())
        {
            while (std::getline(miffile, line))
            {
                if (line.at(0) == '#')
                {
                    if (line == "# Begin: Data Binary 8")
                    {
                        buffer_size = 8;
                        break;
                    }
                    else if (line == "# Begin: Data Binary 4")
                    {
                        buffer_size = 4;
                        break;
                    }
                    else if (data_text.compare(line.substr(0, data_text.length())) == 0)
                    {
                        buffer_size = 1;
                        break;
                    }

                    if (checkNodes && line.substr(0, node_reg.length()) == node_reg)
                    {

                        if (node_reg.at(2) == 'x')
                        {
                            xnodes = std::stoi(line.substr(node_reg.length(), line.length()));
                            node_reg.at(2) = 'y';
                        }
                        else if (node_reg.at(2) == 'y')
                        {
                            ynodes = std::stoi(line.substr(node_reg.length(), line.length()));
                            node_reg.at(2) = 'z';
                        }
                        else
                        {
                            znodes = std::stoi(line.substr(node_reg.length(), line.length()));
                            checkNodes = false;
                        }
                    }
                    if (checkBase && line.substr(0, base_reg.length()) == base_reg)
                    {

                        if (base_reg.at(2) == 'x')
                        {
                            xbase = std::stod(line.substr(base_reg.length(), line.length()));
                            base_reg.at(2) = 'y';
                        }
                        else if (base_reg.at(2) == 'y')
                        {
                            ybase = std::stod(line.substr(base_reg.length(), line.length()));
                            base_reg.at(2) = 'z';
                        }
                        else
                        {
                            zbase = std::stod(line.substr(base_reg.length(), line.length()));
                            checkBase = false;
                        }
                    }
                }
                else
                    break;
            }
            if (buffer_size <= 0)
            {
                throw std::runtime_error("Invalid buffer size");
            }
            char IEEE_BUF[buffer_size + 1];

            miffile.read(IEEE_BUF, buffer_size);
            if (buffer_size == 4)
            {
                float IEEE_val;
                float IEEE_VALIDATION = 1234567.0;

                std::memcpy(&IEEE_val, IEEE_BUF, sizeof(float));
                if (IEEE_val != IEEE_VALIDATION)
                {
                    printf("%f\n", IEEE_val);
                    throw std::runtime_error("IEEE value not consistent");
                }
            }
            else if (buffer_size == 8)
            {
                double IEEE_val;
                double IEEE_VALIDATION = 123456789012345.0;
                std::memcpy(&IEEE_val, IEEE_BUF, sizeof(double));

                if (IEEE_val != IEEE_VALIDATION)
                {
                    printf("%f\n", IEEE_val);
                    throw std::runtime_error("IEEE value not consistent");
                }
            }
            else if (buffer_size == 1)
            {
                // actaully I don't know what I should do here
            }
            else
            {
                throw std::runtime_error("Unspecified or invalid buffer size for binary input data");
            }

            return buffer_size;
        }
        else
        {
            throw std::runtime_error("Invalid mif file");
        }
        return 0;
    }

    std::vector<VectorObj> getMifAsVectorObj(std::string path)
    {
        std::vector<VectorObj> vectors;
        std::ifstream miffile;
        miffile.open(path, std::ios::out | std::ios_base::binary);

        int buffer_size = getMifHeader(miffile);
        if (buffer_size == 0)
        {
            miffile.close();
            throw std::runtime_error("Invalid mif file");
        }
        int lines = znodes * xnodes * ynodes;
        char buffer[buffer_size * lines * 3];
        miffile.read(buffer, buffer_size * lines * 3);
        double *vals = (double *)buffer;

        for (int i = 0; i < lines; i += 3)
        {
            vectors.push_back(VectorObj(vals[i + 0], vals[i + 1], vals[i + 2]));
        }

        miffile.close();
        return vectors;
    }

    std::vector<std::vector<double>> getMifAsDblObj(std::string path)
    {
        std::vector<std::vector<double>> vectors;

        std::ifstream miffile;
        miffile.open(path, std::ios::out | std::ios_base::binary);
        int buffer_size = getMifHeader(miffile);
        if (buffer_size == 0)
        {
            miffile.close();
            throw std::runtime_error("Invalid mif file");
        }
        int lines = znodes * xnodes * ynodes;
        char buffer[buffer_size * lines * 3];
        miffile.read(buffer, buffer_size * lines * 3);
        double *vals = (double *)buffer;
        for (int i = 0; i < lines * 3; i += 3)
        {
            std::vector<double> tmp = {vals[i + 0], vals[i + 1], vals[i + 2]};
            vectors.push_back(tmp);
        }

        miffile.close();
        return vectors;
    }

    void getArrowVectors(double *vbo,
                         double pos[3],
                         double col[3],
                         int resolution,
                         int height,
                         int radius,
                         int offset)
    {
        for (int i = 0; i < resolution - 1; i++)
        {
            // vbo[*offset + i + 0] = math.sin(
        }
    }

    np::ndarray getMifAsNdarray(std::string path)
    {

        std::ifstream miffile;
        miffile.open(path, std::ios::out | std::ios_base::binary);
        int buffer_size = getMifHeader(miffile);
        if (buffer_size == 0)
        {
            miffile.close();
            throw std::runtime_error("Invalid mif file");
        }

        int lines = znodes * xnodes * ynodes;
        char buffer[buffer_size * lines * 3];
        miffile.read(buffer, buffer_size * lines * 3);
        double *vals = (double *)buffer;
        double *fut_ndarray = (double *)(malloc(sizeof(double) * lines * 3));
        double mag;
        for (int i = 0; i < lines * 3; i += 3)
        {
            mag = sqrt(pow(vals[i + 0], 2) + pow(vals[i + 1], 2) + pow(vals[i + 2], 2));
            if (mag == 0.0)
                mag = 1.0;
            fut_ndarray[i + 0] = vals[i + 0] / mag;
            fut_ndarray[i + 1] = vals[i + 1] / mag;
            fut_ndarray[i + 2] = vals[i + 2] / mag;
        }
        miffile.close();
        // use explicit namespace here to make sure it does not mix the functions
        boost::python::numpy::dtype dt1 = boost::python::numpy::dtype::get_builtin<double>();
        boost::python::tuple shape = boost::python::make_tuple(lines, 3);
        boost::python::tuple stride = boost::python::make_tuple(3 * sizeof(double), sizeof(double));
        boost::python::numpy::ndarray vectorData = boost::python::numpy::from_data(fut_ndarray,
                                                                                dt1,
                                                                                shape,
                                                                                stride,
                                                                                boost::python::object());
        // last entry is object owner
        return vectorData;
    }
};

BOOST_PYTHON_MODULE(Parser)
{
    // avoids the SIGSEV on dtype in numpy initialization
    boost::python::numpy::initialize();

    using namespace boost::python;

    class_<VectorObj>("VectorObj", init<double, double, double>())
        .def("__repr__", &VectorObj::repr)
        .add_property("x", &VectorObj::getX, &VectorObj::setX)
        .add_property("y", &VectorObj::getY, &VectorObj::setY)
        .add_property("z", &VectorObj::getZ, &VectorObj::setZ)
        .add_property("mag", &VectorObj::getMag, &VectorObj::setMag);

    class_<std::vector<VectorObj>>("MifObj")
        .def(vector_indexing_suite<std::vector<VectorObj>>());

    class_<std::vector<double>>("DblObj")
        .def(vector_indexing_suite<std::vector<double>>());

    class_<std::vector<std::vector<double>>>("VecDblObj")
        .def(vector_indexing_suite<std::vector<std::vector<double>>>());

    class_<Parser>("Parser")
        .def(init<>())
        .def(init<Parser>())
        .def("getMifAsVectorObj", &Parser::getMifAsVectorObj)
        .def("getMifAsDblObj", &Parser::getMifAsDblObj)
        .def("getMifAsNdarray", &Parser::getMifAsNdarray)
        .def("getFileList", &Parser::listFiles)
        .def("getOmfToList", &Parser::getOmfToList)
        .def("getMifHeader", &Parser::getMifHeader)

        .add_property("xnodes", &Parser::getXnodes, &Parser::setXnodes)
        .add_property("ynodes", &Parser::getYnodes, &Parser::setYnodes)
        .add_property("znodes", &Parser::getZnodes, &Parser::setZnodes)

        .add_property("xbase", &Parser::getXbase, &Parser::setXbase)
        .add_property("ybase", &Parser::getYbase, &Parser::setYbase)
        .add_property("zbase", &Parser::getZbase, &Parser::setZbase);
}


#pragma once

/*
   Quick analysis to collect the set of variables and constants that might
   define array segment boundaries.
*/

#include <crab/cfg/cfg.hpp>
#include <crab/domains/discrete_domains.hpp>
#include <crab/iterators/killgen_fixpoint_iterator.hpp>
#include <crab/support/debug.hpp>
#include <crab/support/stats.hpp>

#include <boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>

namespace crab {

namespace analyzer {

template <class CFG>
class array_segment_ops
    : public crab::iterators::killgen_operations_api<
      CFG, ikos::discrete_domain<typename CFG::variable_t>> {

  using killgen_operations_api_t = crab::iterators::killgen_operations_api<
      CFG, ikos::discrete_domain<typename CFG::variable_t>>;

public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using N = typename CFG::number_t;
  using V = typename CFG::varname_t;
  using variable_t = typename CFG::variable_t;
  using array_segment_domain_t =
      typename killgen_operations_api_t::killgen_domain_t;

private:
  class array_segment_visitor
      : public crab::cfg::statement_visitor<basic_block_label_t, N, V> {
    using bin_op_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                           N, V>::bin_op_t;
    using assign_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                           N, V>::assign_t;
    using assume_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                           N, V>::assume_t;
    using select_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                           N, V>::select_t;
    using assert_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                           N, V>::assert_t;

    using havoc_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                          N, V>::havoc_t;
    using unreach_t = typename crab::cfg::statement_visitor<basic_block_label_t,
                                                            N, V>::unreach_t;
    using callsite_t =
        typename crab::cfg::statement_visitor<basic_block_label_t, N,
                                              V>::callsite_t;

    using arr_init_t =
        typename crab::cfg::statement_visitor<basic_block_label_t, N,
                                              V>::arr_init_t;
    using arr_load_t =
        typename crab::cfg::statement_visitor<basic_block_label_t, N,
                                              V>::arr_load_t;
    typedef typename crab::cfg::statement_visitor<basic_block_label_t, N,
                                                  V>::arr_store_t arr_store_t;

    // assume all statements have the same type expression_t;
    using linear_expression_t = typename bin_op_t::linear_expression_t;
    using linear_constraint_t = typename assume_t::linear_constraint_t;

    array_segment_domain_t get_variables(const linear_expression_t &e) const {
      array_segment_domain_t res;
      for (auto const &v : e.variables())
        res += v;
      return res;
    }

    array_segment_domain_t get_variables(const linear_constraint_t &c) const {
      array_segment_domain_t res;
      for (auto const &v : c.variables())
        res += v;
      return res;
    }

  public:
    array_segment_domain_t m_indexes;

    array_segment_visitor(array_segment_domain_t inv) : m_indexes(inv) {}

    void visit(bin_op_t &s) {
      if (!(m_indexes & s.lhs()).is_bottom()) {
        m_indexes += get_variables(s.left());
        m_indexes += get_variables(s.right());
      }
    }

    void visit(assign_t &s) {
      if (!(m_indexes & s.lhs()).is_bottom()) {
        m_indexes += get_variables(s.rhs());
      }
    }

    void visit(assume_t &s) {
      auto vars = get_variables(s.constraint());
      if (!(m_indexes & vars).is_bottom())
        m_indexes += vars;
    }

    void visit(arr_init_t &s) {
      m_indexes += get_variables(s.lb_index());
      m_indexes += get_variables(s.ub_index());
    }

    void visit(arr_load_t &s) { m_indexes += get_variables(s.index()); }

    void visit(arr_store_t &s) {
      m_indexes += get_variables(s.lb_index());
      m_indexes += get_variables(s.ub_index());
    }

    void visit(unreach_t &) {}

    // FIXME: implement these
    void visit(select_t &) {}
    void visit(callsite_t &) {}
    void visit(havoc_t &) {}
    void visit(assert_t &) {}
  };

public:
  array_segment_ops(CFG cfg) : killgen_operations_api_t(cfg) {}

  virtual bool is_forward() override { return false; }

  virtual std::string name() override { return "array_segment"; }

  virtual void init_fixpoint() override {}

  virtual array_segment_domain_t entry() override {
    return array_segment_domain_t::bottom();
  }

  virtual array_segment_domain_t merge(array_segment_domain_t d1,
                                       array_segment_domain_t d2) override {
    return d1 | d2;
  }

  virtual array_segment_domain_t analyze(const basic_block_label_t &bb_id,
                                         array_segment_domain_t in) override {
    auto &bb = this->m_cfg.get_node(bb_id);
    array_segment_visitor vis(in);
    for (auto &s : bb) {
      s.accept(&vis);
    }
    return vis.m_indexes;
  }
};

template<class CFG>
class array_segmentation : public crab::iterators::killgen_fixpoint_iterator<
                               CFG, array_segment_ops<CFG>> {
public:
  using array_segment_ops_t = array_segment_ops<CFG>;
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using statement_t = typename CFG::statement_t;
  using varname_t = typename CFG::varname_t;
  using array_segment_domain_t =
      typename array_segment_ops_t::array_segment_domain_t;

private:
  using killgen_fixpoint_iterator_t =
      crab::iterators::killgen_fixpoint_iterator<CFG, array_segment_ops_t>;
  using segment_map_t =
      boost::unordered_map<basic_block_label_t, array_segment_domain_t>;

  segment_map_t m_segment_map;
  array_segment_ops_t m_array_segment_ops;

public:
  array_segmentation(CFG cfg)
    : killgen_fixpoint_iterator_t(cfg, m_array_segment_ops),
      m_array_segment_ops(cfg) {}

  array_segmentation(const array_segmentation<CFG> &o) = delete;
  array_segmentation<CFG> &operator=(const array_segmentation<CFG> &o) = delete;

  void exec() {
    this->run();

    CRAB_LOG("array-segment",
             crab::outs()
                 << "Array segment variables alive at the block entries\n";);

    for (auto p :
         boost::make_iterator_range(this->in_begin(), this->in_end())) {
      CRAB_LOG("array-segment", crab::outs()
                                    << p.first << ":" << p.second << "\n";);
      m_segment_map.insert(std::make_pair(p.first, p.second));
    }
    this->release_memory();
  }

  array_segment_domain_t get_variables(const basic_block_label_t &bb) const {
    auto it = m_segment_map.find(bb);
    if (it == m_segment_map.end())
      return array_segment_domain_t();
    else
      return it->second;
  }

  void write(crab_os &o) const {}
};

// Visitor for finding constants that might appear as array
// segment boundaries.
template <class CFG, class ArraySegmentDom>
class array_constant_segment_visitor
    : public crab::cfg::statement_visitor<typename CFG::basic_block_label_t,
                                          typename CFG::number_t,
                                          typename CFG::varname_t> {

  using BBL = typename CFG::basic_block_label_t;
  using N = typename CFG::number_t;
  using V = typename CFG::varname_t;
  using bin_op_t = typename crab::cfg::statement_visitor<BBL, N, V>::bin_op_t;
  using assign_t = typename crab::cfg::statement_visitor<BBL, N, V>::assign_t;
  using assume_t = typename crab::cfg::statement_visitor<BBL, N, V>::assume_t;
  using havoc_t = typename crab::cfg::statement_visitor<BBL, N, V>::havoc_t;
  using unreach_t = typename crab::cfg::statement_visitor<BBL, N, V>::unreach_t;
  using select_t = typename crab::cfg::statement_visitor<BBL, N, V>::select_t;
  using callsite_t =
      typename crab::cfg::statement_visitor<BBL, N, V>::callsite_t;
  using assert_t = typename crab::cfg::statement_visitor<BBL, N, V>::assert_t;

  using arr_init_t =
      typename crab::cfg::statement_visitor<BBL, N, V>::arr_init_t;
  using arr_load_t =
      typename crab::cfg::statement_visitor<BBL, N, V>::arr_load_t;
  using arr_store_t =
      typename crab::cfg::statement_visitor<BBL, N, V>::arr_store_t;

  using linear_expression_t = typename bin_op_t::linear_expression_t;
  using number_t = typename linear_expression_t::number_t;

public:
  using constant_set_t = std::vector<number_t>;

private:
  ArraySegmentDom m_dom;
  constant_set_t m_csts;

public:
  array_constant_segment_visitor(ArraySegmentDom dom) : m_dom(dom) {}

  constant_set_t get_constants() { return m_csts; }

  /// XXX: we focus for now only on assignments
  void visit(assign_t &s) {
    if (!(m_dom & s.lhs()).is_bottom()) {
      if (s.rhs().is_constant() && s.rhs().constant() >= 0 &&
          std::find(m_csts.begin(), m_csts.end(), s.rhs().constant()) ==
              m_csts.end()) {
        m_csts.push_back(s.rhs().constant());
        // for decrementing loops we need to include the upper bound index i and
        // i+1
        m_csts.push_back(s.rhs().constant() + 1);
      }
    }
  }

  void visit(bin_op_t &s) {}
  void visit(assume_t &s) {}
  void visit(arr_init_t &s) {}
  void visit(arr_load_t &s) {}
  void visit(arr_store_t &s) {}
  void visit(select_t &) {}
  void visit(callsite_t &) {}
  void visit(havoc_t &) {}
  void visit(assert_t &) {}
  void visit(unreach_t &) {}
};

} // end namespace analyzer
} // end namespace crab


#ifndef GUNEROTRANSACTIONRECEIVECIRCUIT_H_
#define GUNEROTRANSACTIONRECEIVECIRCUIT_H_

#include <deque>
#include <boost/optional.hpp>
#include <boost/static_assert.hpp>
#include <libff/common/utils.hpp>
#include <libsnark/common/default_types/r1cs_gg_ppzksnark_pp.hpp>
#include <libsnark/common/default_types/r1cs_gg_ppzksnark_pp.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/r1cs_gg_ppzksnark.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/uscs_ppzksnark.hpp>
#include <libff/algebra/fields/field_utils.hpp>
#include <libff/algebra/scalar_multiplication/multiexp.hpp>
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libff/algebra/curves/edwards/edwards_pp.hpp>
#include <libff/algebra/curves/mnt/mnt4/mnt4_pp.hpp>
#include <libff/algebra/curves/mnt/mnt6/mnt6_pp.hpp>
#include <libff/common/utils.hpp>

#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp>

#include "gunerotransactionreceive_gadget.hpp"
#include "GuneroProof.hpp"

using namespace libsnark;

namespace gunero {

class GuneroTransactionReceiveWitness{
public:
    uint256 W;
    uint256 T;
    uint256 V_S;
    uint256 V_R;
    uint256 L;

    GuneroTransactionReceiveWitness() {}
    GuneroTransactionReceiveWitness(
        const uint256& pW,
        const uint256& pT,
        const uint256& pV_S,
        const uint256& pV_R,
        const uint256& pL
    ) : W(pW),
        T(pT),
        V_S(pV_S),
        V_R(pV_R),
        L(pL)
    {
    }
    ~GuneroTransactionReceiveWitness() {}

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
        READWRITE(W);
        READWRITE(T);
        READWRITE(V_S);
        READWRITE(V_R);
        READWRITE(L);
    }

    friend std::ostream& operator<<(std::ostream &out, const GuneroTransactionReceiveWitness &witness)
    {
        ::Serialize(out, witness, 1, 1);

        return out;
    }

    friend std::istream& operator>>(std::istream &in, GuneroTransactionReceiveWitness &witness)
    {
        ::Unserialize(in, witness, 1, 1);

        return in;
    }
};

///// TRANSACTION RECEIVE PROOF /////
// Public Parameters:
// Authorization Root Hash (W)
// Token UID (T)
// Sender Account View Hash (V_S)
// Receiver Account View Hash (V_R)
// Current Transaction Hash (L)

// Private Parameters:
// Receiver Account Secret Key (s_R)
// Receiver Account View Randomizer (r_R)
// Sender Account Address (A_S)
// Sender Account View Randomizer (r_S)
// Firearm Serial Number (F)
// Firearm View Randomizer (j)
// alt: Receiver Account (A_R)
// alt: Sender Proof Public Key (P_proof_S)

//1) Obtain A_R from s_R through EDCSA operations
//1 alt) Obtain P_proof_R from s_R through PRF operations
//2) Validate V_S == hash(A_S, hash(W, r_S)) (View Hash is consistent for Sender)
//2 alt) Validate V_S == hash(P_proof_S, hash(W, r_S)) (View Hash is consistent for Sender)
//3) Validate V_R == hash(A_R, hash(W, r_R) (View Hash is consistent for Receiver)
//3 alt) Validate V_R == hash(P_proof_R, hash(W, r_R)) (View Hash is consistent for Receiver)
//4) Validate T == hash(F, j) (Both parties know the serial number)
//5) Validate L == hash(A_S, hash(s_R, hash(T, W)) (The send proof is consistent, not forged)
template<typename FieldT, typename BaseT, typename HashT>
class GuneroTransactionReceiveCircuit
{
public:
    GuneroTransactionReceiveCircuit()
    {}
    ~GuneroTransactionReceiveCircuit() {}

    void generate(
        const std::string& r1csPath,
        const std::string& pkPath,
        const std::string& vkPath
    ) {
        protoboard<FieldT> pb;
        gunerotransactionreceive_gadget<FieldT, BaseT, HashT> gunero(pb);

        gunero.generate_r1cs_constraints(r1csPath, pkPath, vkPath);
    }

    bool prove(
        const uint256& pW,
        const uint256& pT,
        const uint256& pV_S,
        const uint256& pV_R,
        const uint256& pL,
        const uint252& ps_R,
        const uint256& pr_R,
        const uint160& pA_S,
        const uint256& pr_S,
        const uint256& pF,
        const uint256& pj,
        const uint160& pA_R,
        const uint256& pP_proof_S,
        const r1cs_ppzksnark_proving_key<BaseT>& pk,
        const r1cs_ppzksnark_verification_key<BaseT>& vk,
        GuneroProof& proof
    )
    {
#ifdef DEBUG
        libff::print_header("Gunero witness (proof)");
#endif

        {
            r1cs_primary_input<FieldT> primary_input;
            r1cs_auxiliary_input<FieldT> aux_input;
            {
                protoboard<FieldT> pb;
                {
#ifdef DEBUG
                    libff::print_header("Gunero gunerotransactionreceive_gadget.load_r1cs_constraints()");
#endif

                    gunerotransactionreceive_gadget<FieldT, BaseT, HashT> gunero(pb);

                    gunero.generate_r1cs_witness(
                        pW,
                        pT,
                        pV_S,
                        pV_R,
                        pL,
                        ps_R,
                        pr_R,
                        pA_S,
                        pr_S,
                        pF,
                        pj,
                        pA_R,
                        pP_proof_S
                    );

#ifdef DEBUG
                    printf("\n"); libff::print_indent(); libff::print_mem("after gunerotransactionreceive_gadget.load_r1cs_constraints()"); libff::print_time("after gunerotransactionreceive_gadget.load_r1cs_constraints()");
#endif
                }

                // The constraint system must be satisfied or there is an unimplemented
                // or incorrect sanity check above. Or the constraint system is broken!
                assert(pb.is_satisfied());

                // TODO: These are copies, which is not strictly necessary.
                primary_input = pb.primary_input();
                aux_input = pb.auxiliary_input();

                // Swap A and B if it's beneficial (less arithmetic in G2)
                // In our circuit, we already know that it's beneficial
                // to swap, but it takes so little time to perform this
                // estimate that it doesn't matter if we check every time.
                // pb.constraint_system.swap_AB_if_beneficial();

                //Test witness_map()
                {
                    r1cs_primary_input<FieldT> primary_input_test = gunerotransactionreceive_gadget<FieldT, BaseT, HashT>::witness_map(
                        pW,
                        pT,
                        pV_S,
                        pV_R,
                        pL
                    );
                    assert(primary_input == primary_input_test);
                }
            }

            r1cs_ppzksnark_proof<BaseT> r1cs_proof = r1cs_ppzksnark_prover<BaseT>(
                pk,
                primary_input,
                aux_input
            );

            proof = GuneroProof(r1cs_proof);

#ifdef DEBUG
            printf("\n"); libff::print_indent(); libff::print_mem("after witness (proof)"); libff::print_time("after witness (proof)");
#endif
        }

        //Verify
        {
            r1cs_primary_input<FieldT> primary_input = gunerotransactionreceive_gadget<FieldT, BaseT, HashT>::witness_map(
                pW,
                pT,
                pV_S,
                pV_R,
                pL
            );

            return r1cs_ppzksnark_verifier_strong_IC<BaseT>(vk, primary_input, proof.to_libsnark_proof<r1cs_ppzksnark_proof<BaseT>>());
        }
    }

    bool verify(
        const uint256& pW,
        const uint256& pT,
        const uint256& pV_S,
        const uint256& pV_R,
        const uint256& pL,
        const GuneroProof& proof,
        const r1cs_ppzksnark_verification_key<BaseT>& vk,
        const r1cs_ppzksnark_processed_verification_key<BaseT>& vk_precomp
        )
    {
        try
        {
            r1cs_primary_input<FieldT> primary_input = gunerotransactionreceive_gadget<FieldT, BaseT, HashT>::witness_map(
                pW,
                pT,
                pV_S,
                pV_R,
                pL
            );

            r1cs_ppzksnark_proof<BaseT> r1cs_proof = proof.to_libsnark_proof<r1cs_ppzksnark_proof<BaseT>>();

            ProofVerifier<BaseT> verifierEnabled = ProofVerifier<BaseT>::Strict();

            bool verified = verifierEnabled.check(
                vk,
                vk_precomp,
                primary_input,
                r1cs_proof
            );

#ifdef DEBUG
            printf("\n"); libff::print_indent(); libff::print_mem("after verify"); libff::print_time("after verify");
#endif

            if (verified)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (...)
        {
            return false;
        }
    }
};

} // end namespace `gunero`

#endif /* GUNEROTRANSACTIONRECEIVECIRCUIT_H_ */


/*
==== Author:

Relja Arandjelovic (relja@robots.ox.ac.uk)
Visual Geometry Group,
Department of Engineering Science
University of Oxford

==== Copyright:

The library belongs to Relja Arandjelovic and the University of Oxford.
No usage or redistribution is allowed without explicit permission.
*/

#include <iostream>
#include <string.h>

#include <boost/format.hpp>

#include <fastann/fastann.hpp>

#include "feat_standard.h"
#include "hamming.h"
#include "hamming_embedder.h"
#include "tfidf_v2.h"
#include "util.h"

int main(){

    std::string clstFn= "~/Relja/Data/tmp/indexing_v2/ox5k/clst_paris_hesrootsift3_100k.e3bin";
    std::string wghtFn= util::expandUser("~/Relja/Data/tmp/indexing_v2/ox5k/hamm/train_paris_hesrootsift3_100k_hamm64.v2bin");

    // feature getter
    featGetter_standard featGetter_obj( "hesaff-rootsift-scale3" );

    // clusters
    std::cout<<"oxGQ::main: Loading cluster centres\n";
    double t0= timing::tic();
    clstCentres clstCentres_obj( util::expandUser(clstFn).c_str(), true );
    std::cout<<"oxGQ::main: Loading cluster centres - DONE ("<< timing::toc(t0) <<" ms)\n";

    std::cout<<"oxGQ::main: Constructing NN search object\n";
    t0= timing::tic();

    fastann::nn_obj<float> *nn= fastann::nn_obj_build_kdtree(
            clstCentres_obj.clstC_flat,
            clstCentres_obj.numClst,
            clstCentres_obj.numDims, 8, 1024);

    std::cout<<"oxGQ::main: Constructing NN search object - DONE ("<< timing::toc(t0) << " ms)\n";

    // embedder

    uint32_t const hammEmbBits= 64;
    uint32_t const vocSize= 100000;
    std::string const trainFilesPrefix= util::expandUser("~/Relja/Data/tmp/indexing_v2/ox5k/hamm/train_paris_hesrootsift3_" );
    std::string const trainHammFn= trainFilesPrefix + util::uintToShortStr(vocSize) + "_hamm" + boost::lexical_cast<std::string>(hammEmbBits) + ".v2bin";

    hammingEmbedderFactory embFactory(trainHammFn, hammEmbBits);

    // create retrievers

    tfidfV2 tfidfObj(
        NULL, NULL, wghtFn);

    hamming hammingObj(
            tfidfObj,
            NULL,
            embFactory,
            NULL,
            &featGetter_obj, nn, &clstCentres_obj);

    // extract

    for (uint32_t queryID= 0; queryID<11; ++queryID){
        std::cout<< queryID <<"\n";
        for (uint32_t imageID= 0; imageID<8; ++imageID){
            std::string queryImage= (boost::format("/home/relja/Relja/Databases/MultiQuery/%02d/%02d.jpg") % queryID % imageID).str();
            std::string outData= (boost::format("/home/relja/Relja/Data/Temp/MultiQuery/hamm_ox5k_HA/%02d/%02d.v2bin") % queryID % imageID).str();
            query queryObj(0, false, outData );
            hammingObj.externalQuery_computeData( queryImage, queryObj );
        }
    }
}


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

// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands.

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

#ifndef BOOST_GEOMETRY_POLICIES_COMPARE_HPP
#define BOOST_GEOMETRY_POLICIES_COMPARE_HPP

#include <cstddef>

#include <boost/geometry/strategies/compare.hpp>
#include <boost/geometry/util/math.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace compare
{

template
<
    int Direction,
    typename Point,
    typename Strategy,
    std::size_t Dimension,
    std::size_t DimensionCount
>
struct compare_loop
{
    typedef typename strategy::compare::detail::select_strategy
        <
            Strategy, Direction, Point, Dimension
        >::type compare_type;

    typedef typename geometry::coordinate_type<Point>::type coordinate_type;

    static inline bool apply(Point const& left, Point const& right)
    {
        coordinate_type const& cleft = geometry::get<Dimension>(left);
        coordinate_type const& cright = geometry::get<Dimension>(right);

        if (geometry::math::equals(cleft, cright))
        {
            return compare_loop
                <
                    Direction, Point, Strategy,
                    Dimension + 1, DimensionCount
                >::apply(left, right);
        }
        else
        {
            compare_type compare;
            return compare(cleft, cright);
        }
    }
};

template
<
    int Direction,
    typename Point,
    typename Strategy,
    std::size_t DimensionCount
>
struct compare_loop<Direction, Point, Strategy, DimensionCount, DimensionCount>
{
    static inline bool apply(Point const&, Point const&)
    {
        // On coming here, points are equal. Return true if
        // direction = 0 (equal), false if -1/1 (greater/less)
        return Direction == 0;
    }
};

template <int Direction, typename Point, typename Strategy>
struct compare_in_all_dimensions
{
    inline bool operator()(Point const& left, Point const& right) const
    {
        return detail::compare::compare_loop
            <
                Direction, Point, Strategy,
                0, geometry::dimension<Point>::type::value
            >::apply(left, right);
    }
};

template <typename Point, typename Strategy, std::size_t Dimension>
class compare_in_one_dimension
{
    Strategy compare;

public :
    inline bool operator()(Point const& left, Point const& right) const
    {
        typedef typename geometry::coordinate_type<Point>::type coordinate_type;

        coordinate_type const& cleft = get<Dimension>(left);
        coordinate_type const& cright = get<Dimension>(right);
        return compare(cleft, cright);
    }
};

}} // namespace detail::compare

#endif

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    int Direction,
    typename Point,
    typename Strategy,
    int Dimension
>
struct compare_geometries
    : detail::compare::compare_in_one_dimension
        <
            Point,
            typename strategy::compare::detail::select_strategy
                <
                    Strategy, Direction, Point, Dimension
                >::type,
            Dimension
        >
{};

// Specialization with -1: compare in all dimensions
template <int Direction, typename Point, typename Strategy>
struct compare_geometries<Direction, Point, Strategy, -1>
    : detail::compare::compare_in_all_dimensions<Direction, Point, Strategy>
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

/*!
\brief Less functor, to sort points in ascending order.
\ingroup compare
\details This functor compares points and orders them on x,
    then on y, then on z coordinate.
\tparam Geometry the geometry
\tparam Dimension the dimension to sort on, defaults to -1,
    indicating ALL dimensions. That's to say, first on x,
    on equal x-es then on y, etc.
    If a dimension is specified, only that dimension is considered
\tparam Strategy underlying coordinate comparing functor,
    defaults to the default comparison strategies
    related to the point coordinate system. If specified, the specified
    strategy is used. This can e.g. be std::less<double>.
*/
template
<
    typename Point,
    int Dimension = -1,
    typename Strategy = strategy::compare::default_strategy
>
struct less
    : dispatch::compare_geometries
        <
            1, // indicates ascending
            Point,
            Strategy,
            Dimension
        >
{
    typedef Point first_argument_type;
    typedef Point second_argument_type;
    typedef bool result_type;
};

/*!
\brief Greater functor
\ingroup compare
\details Can be used to sort points in reverse order
\see Less functor
*/
template
<
    typename Point,
    int Dimension = -1,
    typename Strategy = strategy::compare::default_strategy
>
struct greater
    : dispatch::compare_geometries
        <
            -1,  // indicates descending
            Point,
            Strategy,
            Dimension
        >
{};

/*!
\brief Equal To functor, to compare if points are equal
\ingroup compare
\tparam Geometry the geometry
\tparam Dimension the dimension to compare on, defaults to -1,
    indicating ALL dimensions.
    If a dimension is specified, only that dimension is considered
\tparam Strategy underlying coordinate comparing functor
*/
template
<
    typename Point,
    int Dimension = -1,
    typename Strategy = strategy::compare::default_strategy
>
struct equal_to
    : dispatch::compare_geometries
        <
            0,
            Point,
            Strategy,
            Dimension
        >
{};

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_POLICIES_COMPARE_HPP


#include "Demos/Utils/Config.h"
#include "Demos/Visualization/MiniGL.h"
#include "Demos/Visualization/Selection.h"
#include "GL/glut.h"
#include "Demos/Simulation/TimeManager.h"
#include <Eigen/Dense>
#include "Demos/Simulation/SimulationModel.h"
#include "Demos/Simulation/TimeStepController.h"
#include <iostream>

#define _USE_MATH_DEFINES
#include "math.h"

// Enable memory leak detection
#ifdef _DEBUG
	#define new DEBUG_NEW
#endif

using namespace PBD;
using namespace Eigen;
using namespace std;

void timeStep ();
void buildModel ();
void createBodyModel();
void render ();
void reset();
void cleanup();
void selection(const Eigen::Vector2i &start, const Eigen::Vector2i &end);
void TW_CALL setTimeStep(const void *value, void *clientData);
void TW_CALL getTimeStep(void *value, void *clientData);
void TW_CALL setVelocityUpdateMethod(const void *value, void *clientData);
void TW_CALL getVelocityUpdateMethod(void *value, void *clientData);

SimulationModel model;
TimeStepController sim;

const int numberOfBodies = 10;
const float width = 1.0f;
const float height = 0.1f;
const float depth = 0.1f;
bool doPause = true;
std::vector<unsigned int> selectedBodies;
Eigen::Vector3f oldMousePos;

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

	// OpenGL
	MiniGL::init (argc, argv, 1024, 768, 0, 0, "Rigid body demo");
	MiniGL::initLights ();
	MiniGL::setClientIdleFunc (50, timeStep);
	MiniGL::setKeyFunc(0, 'r', reset);
	MiniGL::setSelectionFunc(selection);

	buildModel ();

	MiniGL::setClientSceneFunc(render);
	MiniGL::setViewport (40.0f, 0.1f, 500.0f, Vector3f (5.0, -10.0, 30.0), Vector3f (5.0, 0.0, 0.0));

	TwAddVarRW(MiniGL::getTweakBar(), "Pause", TW_TYPE_BOOLCPP, &doPause, " label='Pause' group=Simulation key=SPACE ");
	TwAddVarCB(MiniGL::getTweakBar(), "TimeStepSize", TW_TYPE_FLOAT, setTimeStep, getTimeStep, &model, " label='Time step size'  min=0.0 max = 0.1 step=0.001 precision=4 group=Simulation ");
	TwType enumType = TwDefineEnum("VelocityUpdateMethodType", NULL, 0);
	TwAddVarCB(MiniGL::getTweakBar(), "VelocityUpdateMethod", enumType, setVelocityUpdateMethod, getVelocityUpdateMethod, &sim, " label='Velocity update method' enum='0 {First Order Update}, 1 {Second Order Update}' group=Simulation");

	glutMainLoop ();

	cleanup ();

	return 0;
}

void cleanup()
{
	delete TimeManager::getCurrent();
}

void reset()
{
	model.reset();
	sim.reset();
	TimeManager::getCurrent()->setTime(0.0);
}

void mouseMove(int x, int y)
{
	Eigen::Vector3f mousePos;
	MiniGL::unproject(x, y, mousePos);
	const Eigen::Vector3f diff = mousePos - oldMousePos;

	TimeManager *tm = TimeManager::getCurrent();
	const float h = tm->getTimeStepSize();

	SimulationModel::RigidBodyVector &rb = model.getRigidBodies();
	for (size_t j = 0; j < selectedBodies.size(); j++)
	{
		rb[selectedBodies[j]]->getVelocity() += 1.0f / h * diff;
	}
	oldMousePos = mousePos;
}

void selection(const Eigen::Vector2i &start, const Eigen::Vector2i &end)
{
 	std::vector<unsigned int> hits;
 	selectedBodies.clear();

	SimulationModel::RigidBodyVector &rb = model.getRigidBodies();
	std::vector<Eigen::Vector3f, Eigen::aligned_allocator<Eigen::Vector3f> > x;
	x.resize(rb.size());
 	for (unsigned int i = 0; i < rb.size(); i++)
 	{
 		x[i] = rb[i]->getPosition();
 	}

 	Selection::selectRect(start, end, &x[0], &x[rb.size() - 1], selectedBodies);
 	if (selectedBodies.size() > 0)
 		MiniGL::setMouseMoveFunc(GLUT_MIDDLE_BUTTON, mouseMove);
 	else
 		MiniGL::setMouseMoveFunc(-1, NULL);

 	MiniGL::unproject(end[0], end[1], oldMousePos);
}

void timeStep ()
{
	if (doPause)
		return;

	// Simulation code
	for (unsigned int i = 0; i < 8; i++)
		sim.step(model);
}

void buildModel ()
{
	TimeManager::getCurrent ()->setTimeStepSize (0.005f);

	createBodyModel();
}

void renderBallJoint(BallJoint &bj)
{
	float jointColor[4] = { 0.0f, 0.6f, 0.2f, 1 };
	MiniGL::drawSphere(bj.m_jointInfo.col(2), 1.25f*height, jointColor);
}

void render ()
{
	MiniGL::coordinateSystem();

	// Draw sim model

	SimulationModel::RigidBodyVector &rb = model.getRigidBodies();
	SimulationModel::ConstraintVector &constraints = model.getConstraints();

	float selectionColor[4] = { 0.8f, 0.0f, 0.0f, 1 };
	float surfaceColor[4] = { 0.1f, 0.4f, 0.8f, 1 };

	for (size_t i = 0; i < rb.size(); i++)
	{
		bool selected = false;
		for (unsigned int j = 0; j < selectedBodies.size(); j++)
		{
			if (selectedBodies[j] == i)
				selected = true;
		}

		if (!selected)
			MiniGL::drawCube(rb[i]->getPosition(), rb[i]->getRotationMatrix().transpose(), width, height, depth, surfaceColor);
		else
			MiniGL::drawCube(rb[i]->getPosition(), rb[i]->getRotationMatrix().transpose(), width, height, depth, selectionColor);
	}

	for (size_t i = 0; i < constraints.size(); i++)
	{
		if (constraints[i]->getTypeId() == BallJoint::TYPE_ID)
		{
			renderBallJoint(*(BallJoint*)constraints[i]);
		}
	}

	MiniGL::drawTime( TimeManager::getCurrent ()->getTime ());
}

/** Create the rigid body model
*/
void createBodyModel()
{
	SimulationModel::RigidBodyVector &rb = model.getRigidBodies();
	SimulationModel::ConstraintVector &constraints = model.getConstraints();

	rb.resize(numberOfBodies);
	const float mass = 1.0f;
	for (unsigned int i = 0; i < numberOfBodies; i++)
	{
		// Compute diagonal inertia tensor
		const float Ix = (mass / 12.0f) * (height*height + depth*depth);
		const float Iy = (mass / 12.0f) * (width*width + depth*depth);
		const float Iz = (mass / 12.0f) * (width*width + height*height);

		rb[i] = new RigidBody();
		rb[i]->initBody(1.0f,
			Eigen::Vector3f((float)i*width, 0.0f, 0.0f),
			Eigen::Vector3f(Ix, Iy, Iz),
			Eigen::Quaternionf(1.0f, 0.0f, 0.0f, 0.0f));
	}
	// Make first body static
	rb[0]->setMass(0.0f);

	constraints.reserve(numberOfBodies - 1);
	for (unsigned int i = 0; i < numberOfBodies-1; i++)
	{
		model.addBallJoint(i, i + 1, Eigen::Vector3f((float)i*width + 0.5f*width, 0.0f, 0.0f));
	}
}

void TW_CALL setTimeStep(const void *value, void *clientData)
{
	const float val = *(const float *)(value);
	TimeManager::getCurrent()->setTimeStepSize(val);
}

void TW_CALL getTimeStep(void *value, void *clientData)
{
	*(float *)(value) = TimeManager::getCurrent()->getTimeStepSize();
}

void TW_CALL setVelocityUpdateMethod(const void *value, void *clientData)
{
	const short val = *(const short *)(value);
	((TimeStepController*)clientData)->setVelocityUpdateMethod((unsigned int)val);
}

void TW_CALL getVelocityUpdateMethod(void *value, void *clientData)
{
	*(short *)(value) = (short)((TimeStepController*)clientData)->getVelocityUpdateMethod();
}


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

#include "chainparams.h"
#include "main.h"

#include "test/test_bitcoin.h"

#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)

const CAmount INITIAL_SUBSIDY = 12.5 * COIN;

static int GetTotalHalvings(const Consensus::Params& consensusParams) {
    // This assumes that BLOSSOM_POW_TARGET_SPACING_RATIO == 2
    // and treats blossom activation as a halving event
    return consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT ? 64 : 65;
}

static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
    bool blossomActive = false;
    int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
    int nHeight = consensusParams.nSubsidySlowStartInterval;
    BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), INITIAL_SUBSIDY);
    CAmount nPreviousSubsidy = INITIAL_SUBSIDY;
    for (int nHalvings = 1; nHalvings < GetTotalHalvings(consensusParams); nHalvings++) {
        if (blossomActive) {
            if (nHeight == blossomActivationHeight) {
                int preBlossomHeight = (nHalvings - 1) * consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift();
                nHeight += (preBlossomHeight - blossomActivationHeight) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO;
            } else {
                nHeight += consensusParams.nPostBlossomSubsidyHalvingInterval;
            }
        } else {
            nHeight = nHalvings * consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift();
            if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) {
                nHeight = blossomActivationHeight;
                blossomActive = true;
            }
        }
        BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight - 1, consensusParams), nPreviousSubsidy);
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY);
        BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
        nPreviousSubsidy = nSubsidy;
    }
    BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), 0);
}

static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nPreBlossomSubsidyHalvingInterval, int blossomActivationHeight)
{
    Consensus::Params consensusParams;
    consensusParams.nSubsidySlowStartInterval = nSubsidySlowStartInterval;
    consensusParams.nPreBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval;
    consensusParams.nPostBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO;
    consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = blossomActivationHeight;
    TestBlockSubsidyHalvings(consensusParams);
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
    TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
    TestBlockSubsidyHalvings(20000, Consensus::PRE_BLOSSOM_HALVING_INTERVAL, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); // Pre-Blossom
    TestBlockSubsidyHalvings(50, 150, 80); // As in regtest
    TestBlockSubsidyHalvings(500, 1000, 900); // Just another interval
    TestBlockSubsidyHalvings(500, 1000, 3000); // Multiple halvings before Blossom activation
}

BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
    const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();

    CAmount nSum = 0;
    int nHeight = 0;
    // Mining slow start
    for (; nHeight < consensusParams.nSubsidySlowStartInterval; nHeight++) {
        CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY);
        nSum += nSubsidy;
        BOOST_CHECK(MoneyRange(nSum));
    }
    BOOST_CHECK_EQUAL(nSum, 12500000000000ULL);

    // Regular mining
    CAmount nSubsidy;
    do {
        nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
        BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY);
        nSum += nSubsidy;
        BOOST_ASSERT(MoneyRange(nSum));
        ++nHeight;
    } while (nSubsidy > 0);

    // Changing the block interval from 10 to 2.5 minutes causes truncation
    // effects to occur earlier (from the 9th halving interval instead of the
    // 11th), decreasing the total monetary supply by 0.0693 ARK.
    // BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL);
    // Reducing the interval further to 1.25 minutes has a similar effect,
    // decreasing the total monetary supply by another 0.09240 ARK.
    // BOOST_CHECK_EQUAL(nSum, 2099999990760000ULL);
    BOOST_CHECK_EQUAL(nSum, 2099999981520000LL);
}

bool ReturnFalse() { return false; }
bool ReturnTrue() { return true; }

BOOST_AUTO_TEST_CASE(test_combiner_all)
{
    boost::signals2::signal<bool (), CombinerAll> Test;
    BOOST_CHECK(Test());
    Test.connect(&ReturnFalse);
    BOOST_CHECK(!Test());
    Test.connect(&ReturnTrue);
    BOOST_CHECK(!Test());
    Test.disconnect(&ReturnFalse);
    BOOST_CHECK(Test());
    Test.disconnect(&ReturnTrue);
    BOOST_CHECK(Test());
}

BOOST_AUTO_TEST_SUITE_END()


/*******************************************************************************
 * Copyright (c) 2018 UT-Battelle, LLC.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompanies this
 * distribution. The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
 *License is available at https://eclipse.org/org/documents/edl-v10.php
 *
 * Contributors:
 *   Tyler Kharazi - initial implementation
 *******************************************************************************/
#ifndef XACC_ASSIGNMENTERRORKERNELDECORATOR_HPP_
#define XACC_ASSIGNMENTERRORKERNELDECORATOR_HPP_

#include "AcceleratorDecorator.hpp"
#include <Eigen/Dense>
#include "xacc.hpp"

namespace xacc {

namespace quantum {

class AssignmentErrorKernelDecorator : public AcceleratorDecorator {
protected:
  bool gen_kernel;
  Eigen::MatrixXd errorKernel;
  std::vector<std::string> permutations = {""};
  bool multiplex;
  std::vector<std::size_t> layout;

  std::vector<std::string> generatePermutations(int num_bits) {
    int pow_bits = std::pow(2, num_bits);
    std::vector<std::string> bitstring(pow_bits);
    std::string str = "";
    std::string curr;
    int counter = 0;
    int j = num_bits;
    while (j--) {
      str.push_back('0');
    }
    for (int k = 0; k <= num_bits; k++) {
      str[num_bits - k] = '1';
      curr = str;
      do {
        bitstring[counter] = curr;
        counter++;
      } while (next_permutation(curr.begin(), curr.end()));
    }
    return bitstring;
  }

  void generateKernel(std::shared_ptr<AcceleratorBuffer> buffer) {
    // pow(2, num_bits) gets used a lot, so I figured I should just define it
    // here

    int num_bits = buffer->size();
    int pow_bits = std::pow(2, num_bits);
    this->permutations = generatePermutations(num_bits);

    // permutations contains all possible permutationss to generate circuits,
    // there is direct mapping from permutations to circuit as follows:
    // permutations: 10 => X gate on zeroth qubit and nothing on first qubit and
    // measure both permutations: 11 => X gate on both qubits and measure both
    // etc...

    std::shared_ptr<AcceleratorBuffer> tmpBuffer = xacc::qalloc(buffer->size());
    // generating list of circuits to evaluate
    std::vector<std::shared_ptr<CompositeInstruction>> circuits;
    auto provider = xacc::getIRProvider("quantum");
    for (int i = 0; i < pow_bits; i++) {
      auto circuit = provider->createComposite(permutations[i]);
      int j = num_bits-1;
      for (char c : permutations[i]) {
        if (c == '1') {
          // std::cout<<"1 found at position: "<<j<<std::endl;
          auto x = provider->createInstruction("X", j);
          circuit->addInstruction(x);
        }
        j = (j-1)%num_bits;
      }
      for(int i = 0; i < num_bits; i++){
        circuit->addInstruction(provider->createInstruction("Measure", i));
        //std::cout<<"added instruction"<<std::endl;
      }
      if (!layout.empty()){
        circuit->mapBits(layout);
      }
      //std::cout<<circuit->toString()<<std::endl;
      //decoratedAccelerator->execute(tmpBuffer, circuit);
      circuits.push_back(circuit);
    }
    //std::cout<<tmpBuffer->size()<<std::endl;
    decoratedAccelerator->execute(tmpBuffer, circuits);
    auto buffers = tmpBuffer->getChildren();
    int shots = 0;
    // compute num shots;
    //std::cout<<tmpBuffer->nChildren()<<std::endl;
    for (auto &x : buffers[0]->getMeasurementCounts()) {
      shots += x.second;
    }
    // initializing vector of vector of counts to size 2^num_bits x 2^num_bits
    std::vector<std::vector<int>> counts(std::pow(2, num_bits),
                                         std::vector<int>(pow_bits));

    int row = 0;
    Eigen::MatrixXd K(pow_bits, pow_bits);
    K.setZero();
    for (auto &b : buffers) {
      //b->print();
      int col = 0;
      for (auto &x : permutations) {
        auto temp = b->computeMeasurementProbability(x);
        K(row, col) = temp;
        col++;
      }
      row++;
    }
    //std::cout << "MATRIX:\n" << K << "\n";
    errorKernel = K.inverse();
    //std::cout << "INVERSE:\n" << errorKernel << "\n";
    std::vector<double> vec(errorKernel.data(), errorKernel.data() + errorKernel.rows()*errorKernel.cols());
    buffer->addExtraInfo("error-kernel", vec);

    gen_kernel = false;
  }

public:
  AssignmentErrorKernelDecorator() = default;

  const std::vector<std::string> configurationKeys() override {
    return {"gen-kernel"};
  }

  void initialize(const HeterogeneousMap &params = {}) override;

  void execute(std::shared_ptr<AcceleratorBuffer> buffer,
               const std::shared_ptr<CompositeInstruction> function) override;
  void execute(std::shared_ptr<AcceleratorBuffer> buffer,
               const std::vector<std::shared_ptr<CompositeInstruction>>
                   functions) override;

  const std::string name() const override { return "assignment-error-kernel"; }
  const std::string description() const override { return ""; }

  ~AssignmentErrorKernelDecorator() override {}
};

} // namespace quantum
} // namespace xacc
#endif


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

/*
 Copyright (C) 2006 Giorgio Facchinetti

 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.
*/

#if defined(HAVE_CONFIG_H)
    #include <qlo/config.hpp>
#endif

#include <qlo/cmsmarketcalibration.hpp>
#include <qlo/cmsmarket.hpp>
#include <qlo/swaptionvolstructure.hpp>

#include <boost/timer.hpp>

using boost::shared_ptr;
using ObjectHandler::LibraryObject;
using QuantLib::EndCriteria;
using QuantLib::OptimizationMethod;

namespace QuantLibAddin {

     CmsMarketCalibration::CmsMarketCalibration(
        const shared_ptr<ObjectHandler::ValueObject>& properties,
        QuantLib::Handle<QuantLib::SwaptionVolatilityStructure>& volCube,
        shared_ptr<QuantLib::CmsMarket>& cmsMarket,
        const QuantLib::Matrix& weights,
        QuantLib::CmsMarketCalibration::CalibrationType calibrationType,
        bool permanent)
    : LibraryObject<QuantLib::CmsMarketCalibration>(properties, permanent) {

        libraryObject_ = shared_ptr<QuantLib::CmsMarketCalibration>(new
            QuantLib::CmsMarketCalibration(volCube,
                                           cmsMarket,
                                           weights,
                                           calibrationType));
     }

    std::vector<std::vector<ObjectHandler::property_t> >
    CmsMarketCalibration::getSparseSabrParameters() {
        return getSabrParameters(libraryObject_->sparseSabrParameters_);
    }

    std::vector<std::vector<ObjectHandler::property_t> >
    CmsMarketCalibration::getDenseSabrParameters() {
        return getSabrParameters(libraryObject_->denseSabrParameters_);
    }

    std::vector<std::vector<ObjectHandler::property_t> >
    CmsMarketCalibration::getCmsMarket() {
       return browseCmsMarket(libraryObject_->browseCmsMarket_);
    }

   QuantLib::Array
   CmsMarketCalibration::compute(const shared_ptr<EndCriteria>& endCriteria,
                                 const shared_ptr<OptimizationMethod>& method,
                                 const QuantLib::Array& guess,
                                 bool isMeanReversionFixed) {
        boost::timer t;
        t.restart();
        QuantLib::Array result = libraryObject_->compute(endCriteria,
                                method,
                                guess,
                                isMeanReversionFixed);
        elapsed_ = t.elapsed();
        return result;
   }

}