#include <boost/test/unit_test.hpp>
#include "cadata_fc8_data.h"
#include "space_ga_fc6_data.h"
#include "../src/svm_impl/svm_model.h"
#include "../src/svm_impl/regressions_generator.h"
#include "utils/algorithms.hpp"

BOOST_AUTO_TEST_CASE(test_prediction_svm_regression_space)
{
    // for these models we would be using default parameters and
    // the default kernel and type
    using namespace mlmodels;

    auto model = svm::regression::create_model(svm::regression::nu_rbf_train{
                                            svm::regression::nu_rbf_train::base_1 {
                                                    svm::rbf_args{},
                                                    svm::base_train_params{
                                                        10, 1e-4, true, false
                                                    }},
                                            svm::regression::nu_rbf_train::base_2{}
                                        },
                                        space_ga_fc6_train_features, space_ga_fc6_labels
                                    );
    BOOST_TEST_REQUIRE((model.get() != nullptr), "this should not fail - these are valid paramters to train a model");
   auto predictions = svm::predict(model, space_ga_fc6_test_features);
   BOOST_TEST_REQUIRE(not predictions.empty(), "we should be getting a valid list of prediction here");
   BOOST_TEST_REQUIRE(predictions.size() == space_ga_fc6_predictions.size());
    auto expted_begin = std::begin(space_ga_fc6_predictions);
    unsigned int at = 0;
    auto count = 0;
    for (auto our_results : predictions) {
        if (not round_cmp(our_results, static_cast<value_type>(*expted_begin), 0.01f)) {
            BOOST_TEST(false, "["<<at<<"] our results "<<our_results<<" do not match expected results "<<*expted_begin);
            ++count;
        }
        ++expted_begin;
        ++at;
    }
    BOOST_TEST(count == 0, "we have some mismatches between our results and expeected results");
}

BOOST_AUTO_TEST_CASE(test_prediction_svm_regression_cadata)
{
    // for these models we would be using default parameters and
    // the default kernel and type
    using namespace mlmodels;

    auto model = svm::regression::create_model(svm::regression::nu_rbf_train{
                                            svm::regression::nu_rbf_train::base_1 {
                                                    svm::rbf_args{},
                                                    svm::base_train_params{
                                                        10, 1e-4, true, false
                                                    }},
                                                svm::regression::nu_rbf_train::base_2{}
                                        },
                                        cadata_fc8_train_features, cadata_fc8_labels
                                    );
    BOOST_TEST_REQUIRE((model.get() != nullptr), "this should not fail - these are valid paramters to train a model");
   auto predictions = svm::predict(model, cadata_fc8_test_features);
   BOOST_TEST_REQUIRE(not predictions.empty(), "we should be getting a valid list of prediction here");
   BOOST_TEST_REQUIRE(predictions.size() == cadata_fc8_predictions.size());
    auto expted_begin = std::begin(cadata_fc8_predictions);
    unsigned int at = 0;
    auto count = 0;
    for (auto our_results : predictions) {
        if (static_cast<int>(our_results - *expted_begin) != 0) {
            BOOST_TEST(false, "["<<at<<"] our results "<<our_results<<" do not match expected results "<<*expted_begin
                    <<" delta: "<< static_cast<int>(our_results - *expted_begin));
            ++count;
        }
        ++expted_begin;
        ++at;
    }
    BOOST_TEST(count == 0, "we have some mismatches between our results and expeected results");
}


//
// Copyright (c) 2018 Sho Hirose
//
// Distributed under the MIT License. (See accompanying file LICENSE.txt or copy
// at https://opensource.org/licenses/MIT)
//
#ifndef SPARSE_SOLVER_INTERFACE_HPP
#define SPARSE_SOLVER_INTERFACE_HPP

#include <Eigen/SparseCore>
#include "solver_interface.hpp"

struct sparse_solver_interface : solver_interface<Eigen::SparseMatrix<double>> {
  using SparseMatrix = Eigen::SparseMatrix<double>;

  virtual ~sparse_solver_interface() override = default;
  virtual void analyze_pattern(const Eigen::Ref<const SparseMatrix>& A) = 0;
  virtual void factorize(const Eigen::Ref<const SparseMatrix>& A)       = 0;
  virtual bool fail() const                                             = 0;
};

#endif


// https://qiita.com/benikabocha/items/5ec6b471de0d10aaf2df

// cppからpythonへEigenの配列を参照渡しするサンプル

#include <pybind11/eval.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/eigen.h>

#include <Eigen/Dense>

#include <iostream>

namespace py = pybind11;

template <typename T>
using RMatrix = Eigen::Matrix<T, -1, -1, Eigen::RowMajor>;

int main(int argc, char** argv) {
	RMatrix<double> m(2,2);
	m << 2,3,4,6;

//	py::EigenDRef<Eigen::MatrixXd> k();

	wchar_t* program = Py_DecodeLocale(argv[0], nullptr);
	if (program == nullptr) {
		fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
		exit(1);
	}

	Py_SetProgramName(program);
	Py_Initialize();

	try {
		auto global = py::dict(py::module::import("__main__").attr("__dict__"));
		auto local = py::dict();
		// ここにコードを記述していく
		Eigen::Ref<RMatrix<double>> mm = m;
		global["val"] = mm;
		py::eval_file("script.py", global);

	} catch (py::error_already_set& e) {
		std::cout << "Python error.\n" << e.what() << "\n";
	}

	Py_Finalize();
	PyMem_RawFree(program);

	std::cout << m << std::endl;

	return 0;
}


//==================================================================================================
/**
  EVE - Expressive Vector Engine
  Copyright : EVE Contributors & Maintainers
  SPDX-License-Identifier: MIT
**/
//==================================================================================================
#include <eve/function/pedantic/rising_factorial.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <eve/constant/eps.hpp>

#include <type_traits>
#include <eve/constant/inf.hpp>
#include <eve/constant/minf.hpp>
#include <eve/constant/nan.hpp>

TTS_CASE_TPL("Check eve::rising_factorial return type", EVE_TYPE)
{
  TTS_EXPR_IS(eve::pedantic(eve::rising_factorial)(int(), T()), T);
  TTS_EXPR_IS(eve::pedantic(eve::rising_factorial)( T (), T()), T);
}

TTS_CASE_TPL("Check eve::rising_factorial behavior", EVE_TYPE)
{
  if constexpr( eve::platform::supports_invalids )
  {
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(eve::nan(eve::as<T>()), T(2.5))    , eve::nan(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(4.9), eve::nan(eve::as<T>()))  , eve::nan(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(eve::inf(eve::as<T>()), T(2.5))   , eve::nan(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(4.9),eve::inf(eve::as<T>()))      , eve::inf(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(eve::minf(eve::as<T>()), T(2.5))   , eve::nan(eve::as<T>()), 0);
    TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(4.9),eve::minf(eve::as<T>()))     , eve::nan(eve::as<T>()), 0);
  }

  auto ulp = 70.0;
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T( 20),   T(2.0))   , T(420), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(10, T(0.1))         , T(1.253198719801548e+00), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(5,  T(0.1))         , T(1.163823072432015e+00) , ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(0,  T(0.1))         , T(0) , ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(2,  T(0.1))         , T(1.046485846853560e+00) , ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(20.3), T(10.2))   , T(1.622459238800527e+14), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20),  T(-2.0))   , T(2.164502164502165e-03), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(20),  T(-20))     , T(eve::tgamma(T(21))), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20),  T(20))     , eve::inf(eve::as<T>()), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20),  T(10.3))   , eve::zero(eve::as<T>()), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20.2),  T(-10.3)), T(1.780471883652420e-15), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20.2),  T( 10.3)), T(-2.953299835634237e+12), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20.2),  T( 30.4)), T(-4.755869905739260e+23), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(5), 10*eve::eps(eve::as<T>())), T(1.000000000000003e+00), ulp);
  TTS_ULP_EQUAL(eve::pedantic(eve::rising_factorial)(T(-20.5),  T(-1.0))   , T(-4.651162790697673e-02), ulp);
}


#include <iostream>
#include <vector>
#include "jefflib.h"
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

using namespace std;
using namespace boost;

int main()
{
    vector<string> vect;
    if(GetStringInput(vect)){
        cout << "Got data!" << endl;
        cout << endl;
    }
    else {
        cout << "Failed to read input :( " << cout;
        return -1;
    }

    // Create a 1000x1000 piece of cloth
    int cloth[1000][1000] = {0};

    // Accumulate claims
    for (const string line : vect)
    {
        char_separator<char> sep(" @,:x");
        tokenizer< char_separator<char> > tokens(line, sep);
        // num col row width height
        vector<string> s_tmp(tokens.begin(), tokens.end());
        int col_offset = stoi(s_tmp[1]);
        int row_offset = stoi(s_tmp[2]);
        int width = stoi(s_tmp[3]);
        int height = stoi(s_tmp[4]);

        for(int col = col_offset; col < col_offset+width; col++){
            for(int row = row_offset; row<row_offset+height; row++){
                cloth[row][col] += 1;
            }
        }
    }

    // Count squares with >1 claim
    int count = 0;
    for (int i = 0; i<1000; i++){
        for(int j=0; j<1000;j++){
            if (cloth[i][j] > 1){
                count++;
            }
        }
    }

    cout << "Count: " << count << endl;
}


//          Copyright Carl Philipp Reh 2009 - 2016.
// 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 <fcppt/bit/shift_count.hpp>
#include <fcppt/bit/shifted_mask.hpp>
#include <fcppt/bit/test.hpp>
#include <fcppt/cast/enum_to_int.hpp>
#include <fcppt/container/bitfield/object.hpp>
#include <fcppt/container/bitfield/object_from_enum.hpp>
#include <fcppt/container/bitfield/underlying_value.hpp>
#include <fcppt/preprocessor/disable_gcc_warning.hpp>
#include <fcppt/preprocessor/pop_warning.hpp>
#include <fcppt/preprocessor/push_warning.hpp>
#include <fcppt/config/external_begin.hpp>
#include <boost/test/unit_test.hpp>
#include <fcppt/config/external_end.hpp>

FCPPT_PP_PUSH_WARNING
FCPPT_PP_DISABLE_GCC_WARNING(-Weffc++)

BOOST_AUTO_TEST_CASE(
	container_bitfield_underlying_value
)
{
FCPPT_PP_POP_WARNING

	enum class test_enum
	{
		test1,
		test2,
		test3,
		fcppt_maximum = test3
	};

	typedef
	fcppt::container::bitfield::object_from_enum<
		test_enum
	>
	bitfield;

	auto const check_bit(
		[](
			bitfield::internal_type const _value,
			test_enum const _enum
		)
		-> bool
		{
			return
				fcppt::bit::test(
					_value,
					fcppt::bit::shifted_mask<
						bitfield::internal_type
					>(
						fcppt::cast::enum_to_int<
							fcppt::bit::shift_count
						>(
							_enum
						)
					)
				);
		}
	);

	bitfield field1(
		bitfield::null()
	);

	field1[
		test_enum::test2
	] = true;

	bitfield::internal_type const value(
		fcppt::container::bitfield::underlying_value(
			field1
		)
	);

	BOOST_CHECK(
		!check_bit(
			value,
			test_enum::test1
		)
	);

	BOOST_CHECK(
		check_bit(
			value,
			test_enum::test2
		)
	);

	BOOST_CHECK(
		!check_bit(
			value,
			test_enum::test3
		)
	);
}


#ifndef RIGIDREGISTRATION_HPP
#define RIGIDREGISTRATION_HPP

#include <Eigen/Dense>
#include <stdio.h>
#include <memory.h>
#include <time.h>
#include "../global.hpp"
#include "CorrespondenceFilter.hpp"
#include "SymmetricCorrespondenceFilter.hpp"
#include "InlierDetector.hpp"
#include "RigidTransformer.hpp"

typedef Eigen::VectorXf VecDynFloat;
typedef Eigen::Matrix< float, Eigen::Dynamic, registration::NUM_FEATURES> FeatureMat; //matrix Mx6 of type float
typedef Eigen::Matrix4f Mat4Float;

namespace registration{

class RigidRegistration
{
    /*
    # GOAL
    This class performs icp-based rigid registration between two oriented pointclouds.

    # INPUTS
    -ioFloatingFeatures
    -inTargetFeatures
    -inFloatingFlags
    -inTargetFlags

    # PARAMETERS
    -numNeighbours(=3):
    number of nearest neighbours

    # OUTPUT
    -outCorrespondingFeatures
    -outCorrespondingFlags
    */

    public:

        void set_input(FeatureMat * const ioFloatingFeatures,
                       const FeatureMat * const inTargetFeatures,
                       const VecDynFloat * const inFloatingFlags,
                       const VecDynFloat * const inTargetFlags);
        void set_parameters(bool symmetric, size_t numNeighbours,
                            float flagThreshold, bool equalizePushPull,
                            float kappaa, bool inlierUseOrientation,
                            size_t numIterations, bool useScaling);
        Mat4Float get_transformation() const {return _transformationMatrix;}

        void update();

    protected:

    private:
        //# Inputs/Outputs
        FeatureMat * _ioFloatingFeatures = NULL;
        const FeatureMat * _inTargetFeatures = NULL;
        const VecDynFloat * _inFloatingFlags = NULL;
        const VecDynFloat * _inTargetFlags = NULL;

        //# User Parameters
        //## Correspondences
        bool _symmetric = true;
        size_t _numNeighbours = 3;
        float _flagThreshold = 0.9f;
        bool _equalizePushPull = false;
        //## Inliers
        float _kappaa = 3.0;
        bool _inlierUseOrientation = true;
        //## Transformation
        size_t _numIterations = 10;
        bool _useScaling = false;

        //# Internal Data structures
        Mat4Float _transformationMatrix = Mat4Float::Identity();

        //# Internal Parameters

        //# Internal functions
};

}//namespace registration

#endif // RIGIDREGISTRATION_HPP


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG, www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also tools/license/license.mtl.txt in the distribution.
//
// Author Marc Hartung

#ifndef MTL_MATRIX_EIGENVALUE_INCLUDE
#define MTL_MATRIX_EIGENVALUE_INCLUDE

#include <cmath>
#include <complex>
#include <utility>

#include <boost/numeric/mtl/concept/collection.hpp>
#include <boost/numeric/mtl/operation/qr_givens.hpp>
#include <boost/numeric/mtl/operation/misc.hpp>
#include <boost/numeric/linear_algebra/identity.hpp>
#include <boost/numeric/mtl/utility/irange.hpp>
#include <boost/numeric/mtl/vector/dense_vector.hpp>

namespace mtl { namespace mat {

/// Solver class for general eigenvalues
/** Not yet tested for complex matrices. **/
template <typename Matrix>
class eigenvalue_solver {

    typedef typename Collection<Matrix>::value_type   value_type;
    typedef typename Collection<Matrix>::size_type    size_type;

public:

    /** \brief Constructor needs a sqare-matrix as input
     * \param MTL-Matrix type
     *
     */
    eigenvalue_solver(const Matrix& IN) : ncols(num_cols(IN)), nrows(num_rows(IN)) {
	zero= math::zero(IN[0][0]);
	one= math::one(IN[0][0]);
	R = hessenberg(IN);
	I = Matrix(ncols,nrows);
	I = one;

	//Standartwert Initialisierung:

	maxIteration = 20*ncols*ncols;
	eps = 1.0e-8;
    }

    /** \brief Changes the zero-tolerance
     *  \param value_type of allowed distance to zero
     */
    void setTolerance(value_type in) {
	eps = in;
    }

    /** \brief Changes the number of allowed iterations
     * \param size_type variable of maximum allowed iterations
     */
    void setMaxIteration(size_type in) {
	maxIteration = in;
    }

    /** \brief Starts the calculation of eigenvalues.
     */
    void calc() {
	value_type singleCont;
	std::complex<value_type> compCont;
	size_type size, allIt = 0;
	for(size_type i=ncols-1;i>0 && i<ncols && allIt<=maxIteration;i--) {
	    size = i+1; // verkleinert die Matrix-Dimensionen
	    irange r(0,size);
	    singleCont = std::abs(R[i][i-1])+1;
	    compCont = getComplex2x2EW(i) + 1;
	    while( allIt < maxIteration  && std::abs(R[i][i-1])>eps) {
		if(isRealEW(i)) {
		    if(std::abs(R[i][i-1])<singleCont) { //SingleShift
			singleCont = std::abs(R[i][i-1]);
			singleShift(r);
		    }
		    else { //DoubleShift
			singleCont = std::abs(R[i][i-1]);
			doubleShift(r);
		    }
		    allIt++;
		}
		else {
		    if(std::abs(compCont-getComplex2x2EW(i))>eps) {
			compCont = getComplex2x2EW(i);
			doubleShift(r);
			allIt++;
		    }
		    else {
			i--;
			break;
		    }
		}
 	    }
	}
    }

    /** \brief Returner for the calculated eigenvalues
     *
     * Before using get_eigenvalues() you have to use calc()!
     * \param dense_vector<complex<value_type>> of eigenvalues
     */
    dense_vector<std::complex<value_type> > get_eigenvalues()
    {
	using mtl::conj;
	dense_vector<std::complex<double> > res(ncols, 0.0);
	size_type i;
	for(i=ncols-1;i>0 && i<ncols;i--) {
	    if(std::abs(R[i][i-1])<eps || isRealEW(i)) { // wenn ein reeller EW
		res[i] = R[i][i];
	    }
	    else { // wenn zwei konjungiert komplexe EW

		std::complex<value_type> ews = getComplex2x2EW(i);
		res[i-1] = ews;
		res[i] = conj(ews);
		i--;
	    }
	}
	if(i==0) { // zur Vermeidung von Zugriffsfehler
	    res[0] = R[0][0];
	}
	return res;
    }

private:
    Matrix R, I;
    size_type ncols, nrows, maxIteration;
    value_type zero, one, eps;

    bool isRealEW(size_type k) {
	if(std::abs(sqrt(square(R[k-1][k-1]+R[k][k])/4.0+R[k-1][k]*R[k][k-1]-R[k-1][k-1]*R[k][k])) >= 0.0) {
	    return true;
	}
	return false;
    }

    /** \brief Calculates real eigenvalues of a 2x2-matrix defined by col/row k arround the diagonal of the input-matrix
     *
     * First entry of the pair is the eigenvalue closer to the (kxk)-entry (Wilkinson-shift for single shifting)
     */
    std::pair<value_type, value_type> get2x2EW(const size_type k) {
	std::pair<value_type, value_type> res;
	value_type front, back, comparator;

	front = (R[k-1][k-1]+R[k][k])/2.0;
	back = sqrt(square(R[k-1][k-1]+R[k][k])/4.0+R[k-1][k]*R[k][k-1]-R[k-1][k-1]*R[k][k]);
	comparator = R[k][k]-front;

	if( std::abs(comparator-back) < std::abs(comparator+back) ) {
	    res.first = front+back;
	    res.second = front-back;
	}
	else {
	    res.first = front-back;
	    res.second = front+back;
	}
	return res;
    }

    /** \brief Calculates a complex eigenvalue of a 2x2-matrix defined by col/row k arround the diagonal of the input-matrix
     *
     */
    std::complex<value_type> getComplex2x2EW(const size_type k) {
	std::complex<value_type> res;
	res = square(R[k-1][k-1]+R[k][k])/4.0+R[k-1][k]*R[k][k-1]-R[k-1][k-1]*R[k][k];
	res = sqrt(res);
	res += (R[k-1][k-1]+R[k][k])/2.0;
	return res;
    }

    /** \brief Performes a double shift for submatrix defined by range r
     */

    void doubleShift(irange r)
    {
	using mtl::conj;
	value_type s,t;

	if(isRealEW(r.finish()-1)) {
	    std::pair<value_type, value_type> ews = get2x2EW(r.finish()-1);
	    s = ews.first+ews.second;
	    t = ews.first*ews.second;
	}
	else {
	    std::complex<value_type> ew = getComplex2x2EW(r.finish()-1);
	    s = 2.0*ew.real();
	    t = std::abs(ew*conj(ew));
	}

	Matrix RIter(R[r][r]*R[r][r] - s*R[r][r] + t*I[r][r]);

	qr_givens_solver<Matrix> QR(RIter);
	QR.setTolerance(eps);
	QR.calc();

	RIter = R[r][r];
	R[r][r] = (QR.getQ()) * RIter * trans(QR.getQ());

    }

     /** \brief Performes a single shift for submatrix defined by range r
     */
    void singleShift(irange r) {
	value_type sh = get2x2EW(r.finish()-1).first;
	if(!(std::abs(sh) >= 0.0)) {
	    sh = R[r.finish()-1][r.finish()-1];
	}
	Matrix RIter(R[r][r] - sh*I[r][r]);		//Shift wird abgezogen

	qr_givens_solver<Matrix> QR(RIter);		//QR-Zerlegung
	QR.setTolerance(eps);
	QR.calc();

	R[r][r] = ((QR.getR())*trans(QR.getQ())) + sh*I[r][r];	//QR-Iteration mit dem Rückshift

    }

};

/// Calculation of eigenvalues of general matrix A
/** Not yet tested for complex matrices. **/
template <typename Matrix>
dense_vector<std::complex<typename Collection<Matrix>::value_type> >
inline eigenvalues(const Matrix& A)
{
    eigenvalue_solver<Matrix> s(A);
    s.calc();
    return s.get_eigenvalues();
}

}} // namespace mtl::matrix

#endif // MTL_MATRIX_EIGENVALUE_INCLUDE


// DeepBasic.cpp : Defines the entry point for the console application.
//

#include <dlib/dnn.h>
#include <iostream>
#include <dlib/data_io.h>

int main()
{
    // load the data
    std::vector<dlib::matrix<unsigned char>> train_images;
    std::vector<unsigned long> train_labels;
    std::vector<dlib::matrix<unsigned char>> test_images;
    std::vector<unsigned long> test_labels;
    dlib::load_mnist_dataset("../data/mnistImages", train_images, train_labels,
        test_images, test_labels);

    // define leNet
    using net_type = dlib::loss_multiclass_log <
        dlib::fc < 10,   // fully-connected 10 output
        dlib::relu < dlib::fc < 84,  // fully-connected 84 output -> relu
        dlib::relu < dlib::fc < 120,  // fully-connected 120 output->relu
        dlib::max_pool<2, 2, 2, 2, dlib::relu<dlib::con<16, 5, 5, 1, 1, // convolute 5x5x16 ->relu-> maxpool
        dlib::max_pool<2, 2, 2, 2, dlib::relu<dlib::con<6, 5, 5, 1, 1, // convolute 5x5x6 -> relu->maxpool
        dlib::input<dlib::matrix<unsigned char>>  // input 28x28 image
        >>>>>>>>>>>>;
    net_type net;

    // train the net
    dlib::dnn_trainer<net_type> trainer(net);
    trainer.set_learning_rate(0.01);
    trainer.set_min_learning_rate(0.00001);
    trainer.set_mini_batch_size(128);
    trainer.set_max_num_epochs(5);
    trainer.be_verbose();

    // save results every 20 second
    trainer.set_synchronization_file("./DeepBasic.dir/mnist_sync", std::chrono::seconds(20));

    // start training
    trainer.train(train_images, train_labels);

    // save the trained model
    net.clean();
    dlib::serialize("./DeepBasic.dir/mnist_network.dat") << net;

    // now run train images through net
    std::vector<unsigned long> predicted_labels = net(train_images);
    int num_right = 0;
    int num_wrong = 0;
    for (size_t i =0; i< train_images.size(); ++i)
    {
        if (predicted_labels[i] == train_labels[i])
            ++num_right;
        else
            ++num_wrong;
    }
    std::cout << "training number right= " << num_right << std::endl;
    std::cout << "training number wrong= " << num_wrong << std::endl;
    std::cout << "training accuracy= " << num_right / double(num_right + num_wrong) << std::endl;

    // now run on test images
    predicted_labels.clear();
    predicted_labels = net(test_images);
    num_right = 0; num_wrong = 0;
    for (size_t i=0; i< predicted_labels.size(); ++i)
    {
        if (predicted_labels[i] == test_labels[i])
        {
            ++num_right;
        }
        else
        {
            ++num_wrong;
        }
    }
    std::cout << "test number right= " << num_right << "\n";
    std::cout << "test number wrong= " << num_wrong << "\n";
    std::cout << "test accuracy= " << num_right / double(num_right + num_wrong) << "\n";

    std::system("pause");

    return 0;
}


/**
 * @file sdirk.cc
 * @brief NPDE homework SDIRK code
 * @author Unknown, Oliver Rietmann
 * @date 31.03.2021
 * @copyright Developed at ETH Zurich
 */

#include "sdirk.h"

#include <Eigen/Dense>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>

#include "polyfit.h"

namespace SDIRK {

/* SAM_LISTING_BEGIN_0 */
Eigen::Vector2d sdirkStep(const Eigen::Vector2d &z0, double h, double gamma) {
  Eigen::Vector2d res;
  // TO DO (13-3.f): compute one timestep of the ODE
  //====================
  // Your code goes here
  //====================
  return res;
}
/* SAM_LISTING_END_0 */

/* SAM_LISTING_BEGIN_1 */
std::vector<Eigen::Vector2d> sdirkSolve(const Eigen::Vector2d &z0,
                                        unsigned int N, double T,
                                        double gamma) {
  // Solution vector
  std::vector<Eigen::Vector2d> res(N + 1);
  // TO DO (13-3.g): solve the ODE with uniform timesteps using the SDIRK method
  //====================
  // Your code goes here
  //====================
  return res;
}
/* SAM_LISTING_END_1 */

/* SAM_LISTING_BEGIN_2 */
double cvgSDIRK() {
  double conv_rate;
  // TO DO (13-3.g) study the convergence rate of the method.
  //====================
  // Your code goes here
  //====================
  return conv_rate;
}
/* SAM_LISTING_END_2 */

}  // namespace SDIRK


//---------------------------------------------------------------------------//
//  MIT License
//
//  Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
//  Copyright (c) 2020-2021 Nikita Kaskov <nemo@nil.foundation>

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

#ifndef FILECOIN_STORAGE_PROOFS_CORE_PIECES_HPP
#define FILECOIN_STORAGE_PROOFS_CORE_PIECES_HPP

#include <cstdint>
#include <cmath>

#include <boost/assert.hpp>

#include <nil/filecoin/storage/proofs/core/fr32.hpp>
#include <nil/filecoin/storage/proofs/core/utilities.hpp>

namespace nil {
    namespace filecoin {
        namespace detail {
            std::size_t subtree_capacity(std::size_t pos, std::size_t total) {
                BOOST_ASSERT_MSG(pos < total, "position must be less than tree capacity");

                std::size_t capacity = 1;
                // If tree is not 'full', then pos 0 will have subtree_capacity greater than size of tree.
                std::size_t cursor = pos + std::ceil(std::log2(total));

                while ((cursor & 1) == 0) {
                    capacity *= 2;
                    cursor >>= 1;
                }
                return capacity;
            }

            bool piece_is_aligned(std::size_t position, std::size_t length, std::size_t tree_len) {
                std::size_t capacity_at_pos = subtree_capacity(position, tree_len);

                return (capacity_at_pos & (capacity_at_pos - 1)) == 0 && capacity_at_pos >= length;
            }

            std::size_t height_for_length(std::size_t n) {
                return n == 0 ? 0 : std::ceil(std::log2(n));
            }
        }    // namespace detail

        struct PieceSpec {
            std::size_t height() {
                return detail::height_for_length(number_of_leaves);
            }

            // `proof_length` is length of proof that comm_p is in the containing root, excluding comm_p and root, which
            // aren't needed for the proof itself.
            std::size_t proof_length(std::size_t tree_len) {
                return detail::height_for_length(tree_len) - height();
            }

            /// `compute_packing` returns a packing list and a proof size.
            /// A packing list is a pair of (start, length) pairs, relative to the beginning of the piece,
            /// in leaf units.
            /// Proof size is a number of elements (size same as one leaf) provided in the variable part of a
            /// PieceInclusionProof.
            std::tuple<std::vector<std::tuple<std::size_t, std::size_t>>, std::size_t>
                compute_packing(std::size_t tree_len) {
                BOOST_ASSERT(is_aligned(tree_len));

                std::vector<std::tuple<std::size_t, std::size_t>> packing_list {{0, number_of_leaves}};
                return std::make_tuple(packing_list, proof_length(tree_len));
            }

            bool is_aligned(std::size_t tree_len) const {
                return detail::piece_is_aligned(position, number_of_leaves, tree_len);
            }

            fr32_array comm_p;
            std::size_t position;
            std::size_t number_of_leaves;
        };

        /// Generate `comm_p` from a source and return it as bytes.
        template<typename Hash, typename Read, template<typename> class BinaryMerkleTree>
        fr32_array generate_piece_commitment_bytes_from_source(Read &source, std::size_t padded_piece_size) {
            BOOST_ASSERT_MSG(padded_piece_size > 32, "piece is too small");
            BOOST_ASSERT_MSG(padded_piece_size % 32 == 0, "piece is not valid size");

            std::array<std::uint32_t, NODE_SIZE> buf;
            buf.fill(0);

            std::size_t parts = std::ceil(static_cast<double>(padded_piece_size) / static_cast<double>(NODE_SIZE));

            BinaryMerkleTree<Hash> tree = BinaryMerkleTree<Hash>::try_from_iter((0..parts).map(| _ | {
                source.read_exact(buf);
                H::digest_type::try_from_bytes(&buf)
            }));

            std::array<std::uint32_t, NODE_SIZE> comm_p_bytes;
            comm_p_bytes.fill(0);
            const auto comm_p = tree.root();
            comm_p.write_bytes(comm_p_bytes);

            return comm_p_bytes;
        }
    }    // namespace filecoin
}    // namespace nil

#endif


/**
 * @file    euler500.cpp
 * @author  Marvin Smith
 * @date    5/10/2015
 *
 * Notes: http://mathschallenge.net/index.php?section=faq&ref=number/number_of_divisors
*/

// C++ Standard Libraries
#include <cinttypes>

// Boost Libraries
#include <boost/multiprecision/cpp_int.hpp>

using namespace std;
using namespace boost::multiprecision;

/**
 * @brief Main Function
 */
int main( int argc, char* argv[] )
{
    // Create a huge integer
    cpp_int large_number = 2;
    cpp_int result = pow(large_number,500500);

    // Exit Program
    return 0;
}


/* Copyright (c) 2017, Julian Straub <jstraub@csail.mit.edu>
 * Licensed under the MIT license. See the license file LICENSE.
 */
// g++ -Wall -std=c++1z -I /usr/include/eigen3/ main.cpp -o test
#include <random>
#include <cmath>
#include <iostream>
#include <Eigen/Dense>
#include "vmf.hpp"
#include "vmfPrior.hpp"
#include "sample.hpp"

int main() {

  std::mt19937 rnd(1);

  vMF<float,3> vmfA(Eigen::Vector3f(0,0,1), 100);
  vMF<float,3> vmfB(Eigen::Vector3f(0,1,0), 100);
  vMF<float,3> vmfC(Eigen::Vector3f(1,0,0), 100);
  vMF<float,3> vmfD(Eigen::Vector3f(-1,0,0),100);
  vMF<float,3> vmfO(Eigen::Vector3f(1,0,0),10);

  size_t N=30;
  std::vector<std::vector<Eigen::Vector3f>> x;
  for (size_t i=0; i<N; ++i) {
    x.push_back(std::vector<Eigen::Vector3f>());
    for (size_t j=0; j<N; ++j) {
      if (i<N/2 && j<N/2)
        x[i].push_back(vmfA.sample(rnd));
      if (i>=N/2 && j<N/2)
        x[i].push_back(vmfB.sample(rnd));
      if (i>=N/2 && j>=N/2)
        x[i].push_back(vmfC.sample(rnd));
      if (i<N/2 && j>=N/2)
        x[i].push_back(vmfD.sample(rnd));
      if (N/3 < i && i< 2*N/3 && N/3 < j && j < 2*N/3)
        x[i].back() = vmfO.sample(rnd);
    }
  }
  std::cout << "have " << x.size() << " input data" << std::endl;

  std::vector<Eigen::Vector3f> xSum(1, Eigen::Vector3f::Zero());
  std::vector<std::vector<uint32_t>> z(x.size());
  for (size_t i=0; i<x.size(); ++i)
    for (size_t j=0; j<x[i].size(); ++j)  {
      xSum[0] += x[i][j];
      z[i].push_back(0);
    }
  std::vector<float> counts(1, x.size()*x.size());
  std::vector<vMF<float,3>> vmfs;
  vMFprior<float> base(Eigen::Vector3f(0,0,1), .1, 0.0);
  float logAlpha = log(10.);
  float lambda = .1;

  vmfs.push_back(base.sample(rnd));
  for (size_t it=0; it<10000; ++it) {
    // sample labels | parameters
    size_t K = vmfs.size();
    for (size_t i=0; i<x.size(); ++i) {
      for (size_t j=0; j<x[i].size(); ++j) {
        Eigen::VectorXf logPdfs(K+1);
        Eigen::VectorXf pdfs(K+1);

        Eigen::VectorXf neighNs = Eigen::VectorXf::Zero(K);
        if (i+1<N) neighNs[z[i+1][j]] ++;
        if (i>=1)  neighNs[z[i-1][j]] ++;
        if (j+1<N) neighNs[z[i][j+1]] ++;
        if (j>=1)  neighNs[z[i][j-1]] ++;

//        if (i+1<N) neighNs[z[i+1][j]] += x[i+1][j].dot(x[i][j]);
//        if (i>=1)  neighNs[z[i-1][j]] += x[i-1][j].dot(x[i][j]);
//        if (j+1<N) neighNs[z[i][j+1]] += x[i][j+1].dot(x[i][j]);
//        if (j>=1)  neighNs[z[i][j-1]] += x[i][j-1].dot(x[i][j]);

//        if (i+1<N) neighNs[z[i+1][j]] += vmfs[z[i+1][j]].mu_.dot(x[i][j]);
//        if (i>=1)  neighNs[z[i-1][j]] += vmfs[z[i-1][j]].mu_.dot(x[i][j]);
//        if (j+1<N) neighNs[z[i][j+1]] += vmfs[z[i][j+1]].mu_.dot(x[i][j]);
//        if (j>=1)  neighNs[z[i][j-1]] += vmfs[z[i][j-1]].mu_.dot(x[i][j]);

//        if (i+1<N) neighNs[z[i+1][j]] += vmfs[z[i+1][j]].mu_.dot(vmfs[z[i][j]].mu_);
//        if (i>=1)  neighNs[z[i-1][j]] += vmfs[z[i-1][j]].mu_.dot(vmfs[z[i][j]].mu_);
//        if (j+1<N) neighNs[z[i][j+1]] += vmfs[z[i][j+1]].mu_.dot(vmfs[z[i][j]].mu_);
//        if (j>=1)  neighNs[z[i][j-1]] += vmfs[z[i][j-1]].mu_.dot(vmfs[z[i][j]].mu_);

        for (size_t k=0; k<K; ++k) {
          logPdfs[k] = lambda*(neighNs[k]-4);
          if (z[i][j] == k) {
            // TODO what if last in cluster
            logPdfs[k] += log(counts[k]-1)+vmfs[k].logPdf(x[i][j]);
          } else {
            logPdfs[k] += log(counts[k])+vmfs[k].logPdf(x[i][j]);
          }
        }
        logPdfs[K] = logAlpha + base.logMarginal(x[i][j]);
        logPdfs = logPdfs.array() - logSumExp<float>(logPdfs);
        pdfs = logPdfs.array().exp();
        size_t zPrev = z[i][j];
        z[i][j] = sampleDisc(pdfs, rnd);
        //      std::cout << z[i] << " " << K << ": " << pdfs.transpose() << std::endl;
        if (z[i][j] == K) {
          vmfs.push_back(base.posterior(x[i][j],1).sample(rnd));
          counts.push_back(0);
          xSum.push_back(Eigen::Vector3f::Zero());
          K++;
        }
        if (zPrev != z[i][j]) {
          counts[zPrev] --;
          counts[z[i][j]] ++;
          xSum[zPrev] -= x[i][j];
          xSum[z[i][j]] += x[i][j];
        }
      }
    }
//    std::cout << "sample parameters" << std::endl;
    // sample parameters | labels
//    for (size_t i=0; i<x.size(); ++i) {
//      xSum[z[i]] += x[i]; // TODO: can fold in above as well
//    }
    for (size_t k=0; k<K; ++k) {
      if (counts[k] > 0) {
        vmfs[k] = base.posterior(xSum[k],counts[k]).sample(rnd);
      }
    }
    std::cout << "counts " << K << ": ";
    for (size_t k=0; k<K; ++k) if (counts[k] > 0) std::cout << counts[k] << " ";
    std::cout << "\ttaus: " ;
    for (size_t k=0; k<K; ++k) if (counts[k] > 0) std::cout << vmfs[k].tau_ << " ";
    std::cout << std::endl;
  }
  return 0;
}


#include "NoiseModel2.h"
#include <iostream>
#include <DNest4/code/Distributions/Cauchy.h>
#include <DNest4/code/Utils.h>
#include <Eigen/Sparse>

namespace CorrelatedNoise
{

NoiseModel2::NoiseModel2(int _ny, int _nx)
:ny(_ny)
,nx(_nx)
,n(ny*nx)
{

}

void NoiseModel2::from_prior(DNest4::RNG& rng)
{
    DNest4::Cauchy cauchy(0.0, 5.0);

    // Fairly generic priors
    do
    {
        coeff0 = cauchy.generate(rng);
    }while(std::abs(coeff0) >= 100.0);
    coeff0 = exp(coeff0);

    do
    {
        coeff1 = cauchy.generate(rng);
    }while(std::abs(coeff1) >= 100.0);
    coeff1 = exp(coeff1);

    correlation_logit = 5.0*rng.randn();
}

double NoiseModel2::perturb(DNest4::RNG& rng)
{
    double logH = 0.0;

    DNest4::Cauchy cauchy(0.0, 5.0);

    int which = rng.rand_int(3);

    if(which == 0)
    {
        coeff0 = log(coeff0);
        logH += cauchy.perturb(coeff0, rng);
        if(std::abs(coeff0) >= 100.0)
        {
            coeff0 = 1.0;
            return -1E300;
        }
        coeff0 = exp(coeff0);
    }
    else if(which == 1)
    {
        coeff1 = log(coeff1);
        logH += cauchy.perturb(coeff1, rng);
        if(std::abs(coeff1) >= 100.0)
        {
            coeff1 = 1.0;
            return -1E300;
        }
        coeff1 = exp(coeff1);
    }
    else
    {
        logH -= -0.5*pow(correlation_logit/5.0, 2);
        correlation_logit += 5.0*rng.randh();
        logH += -0.5*pow(correlation_logit/5.0, 2);
    }

    return logH;
}

// More complete log likelihood
double NoiseModel2::log_likelihood(const Eigen::MatrixXd& data,
                                   const Eigen::MatrixXd& model,
                                   const Eigen::MatrixXd& sigma_map) const
{
    // Convert from logit
    double alpha = 0.25*exp(correlation_logit)/(1.0 + exp(correlation_logit));

    // Find min of model
    double min = 1E300;
    for(int i=0; i<ny; ++i)
        for(int j=0; j<nx; ++j)
            if(model(i, j) < min)
                min = model(i, j);

    // Flatten data and turn it into standardised residuals
    Eigen::VectorXd ys(n);
    int k = 0;
    double extra_log_determinant = 0.0;
    double sd;
    int num_non_masked = 0;
    for(int i=0; i<ny; ++i)
    {
        for(int j=0; j<nx; ++j)
        {
            sd = sqrt(coeff0*coeff0 + coeff1*(model(i, j) - min)
                                    + pow(sigma_map(i, j), 2));
            if(sigma_map(i, j) < 1E100)
            {
                ys(k++) = (data(i, j) - model(i, j))/sd;
                extra_log_determinant += 2*log(sd);
                ++num_non_masked;
            }
            else
            {
                // Masked pixels
                ys(k++) = 0.0;
            }
        }
    }

    double logL = -0.5*num_non_masked*log(2.0*M_PI) - 0.5*extra_log_determinant;

    std::vector<Eigen::Triplet<double>> triplets;
    int k1, k2;
    for(int i=0; i<ny; ++i)
    {
        for(int j=0; j<nx; ++j)
        {
            // Here
            k1 = j + i*nx;
            triplets.emplace_back(k1, k1, 1.0);

            // Pixel up
            if(i > 0)
            {
                k2 = j + (i-1)*nx;
//                std::cout << k1 << ' ' << k2 << std::endl;
                triplets.emplace_back(k1, k2, -alpha);
            }

            // Pixel down
            if(i < ny - 1)
            {
                k2 = j + (i+1)*nx;
//                std::cout << k1 << ' ' << k2 << std::endl;
                triplets.emplace_back(k1, k2, -alpha);
            }

            // Pixel left
            if(j > 0)
            {
                k2 = (j-1) + i*nx;
//                std::cout << k1 << ' ' << k2 << std::endl;
                triplets.emplace_back(k1, k2, -alpha);
            }

            // Pixel right
            if(j < nx - 1)
            {
                k2 = (j+1) + i*nx;
//                std::cout << k1 << ' ' << k2 << std::endl;
                triplets.emplace_back(k1, k2, -alpha);
            }

        }
    }

    // Make the sparse precision matrix
    Eigen::SparseMatrix<double> sparse_mat(n, n);
    sparse_mat.setFromTriplets(triplets.begin(), triplets.end());

    // Term in the exponential
    logL += -0.5*ys.transpose()*sparse_mat*ys;

    // Use LDLT for log determinant
    Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> ldlt;
    ldlt.compute(sparse_mat);
    Eigen::VectorXd D = ldlt.vectorD();

    // log det of C, not of anything else!!!
    double log_det = 0.0;
    for(int i=0; i<n; ++i)
        log_det += -log(D(i));
    logL += -0.5*log_det;

    if(std::isnan(logL) || std::isinf(logL))
        logL = -1E300;

    return logL;
}

void NoiseModel2::print(std::ostream& out) const
{
    out << coeff0 << ' ' << coeff1 << ' ' << correlation_logit;
}

std::string NoiseModel2::description()
{
    return "coeff0, coeff1, correlation_logit, ";
}

std::ostream& operator << (std::ostream& out, const NoiseModel2& m)
{
    m.print(out);
    return out;
}

} // namespace CorrelatedNoise


#include "../factorial.hxx"
#include "../../../../sdp_read.hxx"
#include "../../../../Timers.hxx"

#include <boost/math/tools/polynomial.hpp>

Boost_Float integral(const Boost_Float &prefactor, const Boost_Float &b,
                     const Boost_Float &x, const int64_t &k);

Boost_Float
rest(const int64_t &m, const Boost_Float &p,
     const std::vector<Boost_Float> &sorted_poles,
     const std::pair<std::vector<Boost_Float>::const_iterator,
                     std::vector<Boost_Float>::const_iterator> &equal_range,
     const int64_t &k);

Boost_Float bilinear_form(
  const Damped_Rational &damped_rational,
  const std::vector<Boost_Float> &sorted_poles,
  const std::vector<std::pair<std::vector<Boost_Float>::const_iterator,
                              std::vector<Boost_Float>::const_iterator>>
    &equal_ranges,
  const std::vector<int64_t> &lengths,
  const std::vector<Boost_Float> &products,
  const std::vector<std::vector<Boost_Float>> &integral_matrix,
  const int64_t &m)
{
  Boost_Float result(0);

  size_t index(0);
  for(auto pole(sorted_poles.begin()); pole != sorted_poles.end();)
    {
      const Boost_Float &p(*pole);
      auto &equal_range(equal_ranges.at(index));
      auto &l(lengths.at(index));
      auto &product(products.at(index));

      Boost_Float integral_sum(0);
      auto &integrals(integral_matrix.at(index));
      for(int64_t k = 0; k < l; ++k)
        {
          integral_sum
            += integrals.at(k) * rest(m, p, sorted_poles, equal_range, k);
        }
      result += (pow(p, m) * product) * integral_sum;

      std::advance(pole, l);
      ++index;
    }

  boost::math::tools::polynomial<Boost_Float> numerator(
    pow(boost::math::tools::polynomial<Boost_Float>({0, 1}), m)),
    divisor({1});
  for(auto &pole : sorted_poles)
    {
      divisor *= boost::math::tools::polynomial<Boost_Float>({-pole, 1});
    }
  boost::math::tools::polynomial<Boost_Float> quotient(
    boost::math::tools::quotient_remainder(numerator, divisor).first);

  for(int64_t n = 0; n < int64_t(quotient.size()); ++n)
    {
      result += quotient[n] * factorial(n)
                * pow(-log(damped_rational.base), -1 - n);
    }
  return result * damped_rational.constant;
}


/*
==============================================================================
KratosStructuralApplication
A library based on:
Kratos
A General Purpose Software for Multi-Physics Finite Element Analysis
Version 1.0 (Released on march 05, 2007).

Copyright 2007
Pooyan Dadvand, Riccardo Rossi, Janosch Stascheit, Felix Nagel
pooyan@cimne.upc.edu
rrossi@cimne.upc.edu
janosch.stascheit@rub.de
nagel@sd.rub.de
- CIMNE (International Center for Numerical Methods in Engineering),
Gran Capita' s/n, 08034 Barcelona, Spain
- Ruhr-University Bochum, Institute for Structural Mechanics, Germany

Permission is hereby granted, free  of charge, to any person obtaining
a  copy  of this  software  and  associated  documentation files  (the
"Software"), to  deal in  the Software without  restriction, including
without limitation  the rights to  use, copy, modify,  merge, publish,
distribute,  sublicense and/or  sell copies  of the  Software,  and to
permit persons to whom the Software  is furnished to do so, subject to
the following condition:

Distribution of this code for  any  commercial purpose  is permissible
ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNERS.

The  above  copyright  notice  and  this permission  notice  shall  be
included in all copies or substantial portions of the Software.

THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT  SHALL THE AUTHORS OR COPYRIGHT HOLDERS  BE LIABLE FOR ANY
CLAIM, DAMAGES OR  OTHER LIABILITY, WHETHER IN AN  ACTION OF CONTRACT,
TORT  OR OTHERWISE, ARISING  FROM, OUT  OF OR  IN CONNECTION  WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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

//
//   Project Name:        Kratos
//   Last Modified by:    $Author: hurga $
//   Date:                $Date: 2009-02-02 14:03:23 $
//   Revision:            $Revision: 1.5 $
//
//

#if !defined(KRATOS_ADD_CONSTITUTIVE_LAWS_TO_PYTHON_H_INCLUDED )
#define  KRATOS_ADD_CONSTITUTIVE_LAWS_TO_PYTHON_H_INCLUDED

// System includes
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

// External includes
#include "boost/smart_ptr.hpp"

// Project includes
#include "custom_python/add_constitutive_laws_to_python.h"
#include "includes/define.h"
#include "includes/constitutive_law.h"
#include "constitutive_laws/dummy_constitutive_law.h"
#include "constitutive_laws/tutorial_damage_model.h"
#include "constitutive_laws/isotropic_2d.h"
#include "constitutive_laws/isotropic_3d.h"
#include "constitutive_laws/neo_hookean_3d.h"
#include "constitutive_laws/hyperelastic_3d.h"
#include "constitutive_laws/hyperelastic_2d.h"
// #include "constitutive_laws/viscoelastic_2d.h" // new VISCOELASTICITY
// #include "constitutive_laws/viscofibers_2d.h" // new VISCOELASTIC Fibers
// #include "constitutive_laws/viscofibers_hypermatrix_2d.h" // new VISCOELASTIC Fibers and Hyperelastic Matrix
#include "constitutive_laws/von_mises_3d.h"
#include "constitutive_laws/hypoelastic_2d.h"
#include "constitutive_laws/plane_strain.h"
#include "constitutive_laws/plane_stress.h"
#include "constitutive_laws/fluid_2d.h"
#include "constitutive_laws/external_isotropic_3d.h"
#include "constitutive_laws/drucker_prager.h"
#include "constitutive_laws/cam_clay_3d.h"
//#include "constitutive_laws/isotropic_elastic_large_strain.h"
#include "constitutive_laws/hooks_law.h"
#include "constitutive_laws/isotropic_planestress_wrinkling.h"
#include "constitutive_laws/isotropic_damage_2d.h"
#include "constitutive_laws/isotropic_rankine_damage_2d.h"
#include "constitutive_laws/isotropic_rankine_damage_3d.h"
#include "constitutive_laws/isotropic_damage_3d.h"
#include "constitutive_laws/isotropic_damage_implex.h"
#include "constitutive_laws/plasticity_2d.h"
#include "constitutive_laws/plane_stress_J2.h"
#include "constitutive_laws/brittle_material_2d.h"
#include "constitutive_laws/orthotropic_3d.h"
#include "includes/node.h"
#include "includes/variables.h"
#include "includes/mesh.h"
#include "includes/element.h"
#include "includes/condition.h"
#include "includes/properties.h"
#include "python/add_mesh_to_python.h"
#include "python/pointer_vector_set_python_interface.h"
#include "python/variable_indexing_python.h"
#include "fluency_criteria/fluency_criteria.h"
#include "constitutive_laws/mohr_coulomb_plane_strain.h"

#include "constitutive_laws/von_mises_3d.h"

namespace Kratos
{

namespace Python
{

using namespace boost::python;

typedef ConstitutiveLaw ConstitutiveLawBaseType;
typedef Mesh<Node<3>, Properties, Element, Condition> MeshType;
typedef FluencyCriteria::Pointer FluencyCriteriaPointer;
typedef SofteningHardeningCriteria::Pointer SofteningHardeningCriteriaPointer;
typedef Properties::Pointer PropertiesPointer;

typedef std::vector<ConstitutiveLaw::Pointer> MaterialsContainer;
typedef ConstitutiveLaw::Pointer  ConstitutiveLawPointer;

void Push_Back_Constitutive_Laws( MaterialsContainer& ThisMaterialsContainer,
                                  ConstitutiveLawPointer ThisConstitutiveLaw )
{
    ThisMaterialsContainer.push_back( ThisConstitutiveLaw );
}

void  AddConstitutiveLawsToPython()
{
    class_< MaterialsContainer >( "MaterialsContainer", init<>() )
    .def( "PushBack", Push_Back_Constitutive_Laws )
    ;

    class_< DummyConstitutiveLaw, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "DummyConstitutiveLaw",
      init<>() )
    ;

    class_< TutorialDamageModel, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "TutorialDamageModel",
      init<>() )
    ;

    class_< Isotropic2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Isotropic2D",
      init<>() )
    // .def("Clone",              &Isotropic2D::Clone)
    ;

    class_< PlaneStrain, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "PlaneStrain",
      init<>() )
    ;

    class_< PlaneStress, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "PlaneStress",
      init<>() )
    ;

    class_< MohrCoulombPlaneStrain, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "MohrCoulombPlaneStrain",
      init<>() )
    ;

    class_< Isotropic3D, bases< ConstitutiveLawBaseType >,  boost::noncopyable >
    ( "Isotropic3D",
      init<>() )
    ;

    class_< DruckerPrager, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "DruckerPrager",
      init<>() )
    ;

    class_< Orthotropic3D, bases< ConstitutiveLawBaseType >,  boost::noncopyable >
    ( "Orthotropic3D",
      init<>() )
    ;

    class_< Isotropic_Damage_2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicDamage2D",
      init<>() )
    .def( init<FluencyCriteriaPointer, SofteningHardeningCriteriaPointer, PropertiesPointer>() )
    ;

    class_< Isotropic_Damage_3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicDamage3D",
      init<>() )
    .def( init<FluencyCriteriaPointer, SofteningHardeningCriteriaPointer, PropertiesPointer>() )
    ;

    class_< IsotropicDamageIMPLEX, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicDamageIMPLEX",
      init<>() )
    .def( init<>() )
    ;

    class_<Plasticity2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Plasticity2D",
      init<>() )
    .def( init<FluencyCriteriaPointer, PropertiesPointer>() )
    ;

    class_<PlaneStressJ2, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "PlaneStressJ2",
      init<>() )
    ;

//             class_<Plasticity3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
//             ("Plasticity3D",
//             init<>() )
//                 .def(init<FluencyCriteriaPointer,SofteningHardeningCriteriaPointer, PropertiesPointer>())
//                  ;

    class_<BrittleMaterial2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "BrittleMaterial2D",
      init<>() )
    .def( init<FluencyCriteriaPointer, PropertiesPointer>() )
    ;

    class_<IsotropicRankineDamage2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicRankineDamage2D",
      init<>() )
    .def( init<>() )
    ;

    class_<IsotropicRankineDamage3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicRankineDamage3D",
      init<>() )
    .def( init<>() )
    ;

    class_< VonMises3D, bases< ConstitutiveLawBaseType >,  boost::noncopyable >
    ( "VonMises3D",
      init<>() )
    ;

    class_< Hypoelastic2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Hypoelastic2D",
      init<>() )
    ;

    class_< Fluid2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Fluid2D",
      init<>() )
    ;

    class_< ExternalIsotropic3D, bases< ConstitutiveLawBaseType >,  boost::noncopyable >
    ( "ExternalIsotropic3D",
      init<>() )
    ;

    class_< HooksLaw, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "HooksLaw",
      init<>() )
    ;

    class_< IsotropicPlaneStressWrinkling, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "IsotropicPlaneStressWrinkling",
      init<>() )
    ;

    class_< Hyperelastic3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Hyperelastic3D",
      init<>() )
    ;

    class_< Hyperelastic2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "Hyperelastic2D",
      init<>() )
    ;

    class_< CamClay3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "CamClay3D",
      init<>() )
    ;

    class_< NeoHookean3D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
    ( "NeoHookean3D",
      init<>() )
    ;

    /*
           class_< Viscofibers2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
                   ("Viscofibers2D",
                    init<>() )
                   ;

           class_< Viscoelastic2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
                   ("Viscoelastic2D",
                    init<>() )
                   ;

    class_< Viscofibers_Hypermatrix2D, bases< ConstitutiveLawBaseType >, boost::noncopyable >
                   ("Viscofibers_Hypermatrix2D",
                    init<>() )
                   ;
     */
//    class_<Plane_Stress_Damage_Orthotropic_2D  , bases< ConstitutiveLawBaseType >, boost::noncopyable >
//    ("PlaneStressDamageOrthotropic2D",
//    init<>() )
//    //.def(init<FluencyCriteriaType const&>())
//                         .def(init<FluencyCriteriaPointer>())
//    ;
    /*
       class_<ComposeMaterial , bases< ConstitutiveLawBaseType >, boost::noncopyable >
       ("ComposeMaterial",
       init<>() )
                            .def(init<MaterialsContainer>())
       ;*/

}
}  // namespace Python.
}  // namespace Kratos.
#endif // KRATOS_ADD_CONSTITUTIVE_LAWS_TO_PYTHON_H_INCLUDED defined


#include <iostream>
#include <Eigen/Core>
#include <bench/BenchTimer.h>
using namespace Eigen;

#ifndef SIZE
#define SIZE 50
#endif

#ifndef REPEAT
#define REPEAT 10000
#endif

typedef float Scalar;

__attribute__ ((noinline)) void benchVec(Scalar* a, Scalar* b, Scalar* c, int size);
__attribute__ ((noinline)) void benchVec(MatrixXf& a, MatrixXf& b, MatrixXf& c);
__attribute__ ((noinline)) void benchVec(VectorXf& a, VectorXf& b, VectorXf& c);

int main(int argc, char* argv[])
{
    int size = SIZE * 8;
    int size2 = size * size;
    Scalar* a = ei_aligned_new<Scalar>(size2);
    Scalar* b = ei_aligned_new<Scalar>(size2+4)+1;
    Scalar* c = ei_aligned_new<Scalar>(size2);

    for (int i=0; i<size; ++i)
    {
        a[i] = b[i] = c[i] = 0;
    }

    BenchTimer timer;

    timer.reset();
    for (int k=0; k<10; ++k)
    {
        timer.start();
        benchVec(a, b, c, size2);
        timer.stop();
    }
    std::cout << timer.value() << "s  " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";
    return 0;
    for (int innersize = size; innersize>2 ; --innersize)
    {
        if (size2%innersize==0)
        {
            int outersize = size2/innersize;
            MatrixXf ma = Map<MatrixXf>(a, innersize, outersize );
            MatrixXf mb = Map<MatrixXf>(b, innersize, outersize );
            MatrixXf mc = Map<MatrixXf>(c, innersize, outersize );
            timer.reset();
            for (int k=0; k<3; ++k)
            {
                timer.start();
                benchVec(ma, mb, mc);
                timer.stop();
            }
            std::cout << innersize << " x " << outersize << "  " << timer.value() << "s   " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";
        }
    }

    VectorXf va = Map<VectorXf>(a, size2);
    VectorXf vb = Map<VectorXf>(b, size2);
    VectorXf vc = Map<VectorXf>(c, size2);
    timer.reset();
    for (int k=0; k<3; ++k)
    {
        timer.start();
        benchVec(va, vb, vc);
        timer.stop();
    }
    std::cout << timer.value() << "s   " << (double(size2*REPEAT)/timer.value())/(1024.*1024.*1024.) << " GFlops\n";

    return 0;
}

void benchVec(MatrixXf& a, MatrixXf& b, MatrixXf& c)
{
    for (int k=0; k<REPEAT; ++k)
        a = a + b;
}

void benchVec(VectorXf& a, VectorXf& b, VectorXf& c)
{
    for (int k=0; k<REPEAT; ++k)
        a = a + b;
}

void benchVec(Scalar* a, Scalar* b, Scalar* c, int size)
{
    typedef ei_packet_traits<Scalar>::type PacketScalar;
    const int PacketSize = ei_packet_traits<Scalar>::size;
    PacketScalar a0, a1, a2, a3, b0, b1, b2, b3;
    for (int k=0; k<REPEAT; ++k)
        for (int i=0; i<size; i+=PacketSize*8)
        {
//             a0 = ei_pload(&a[i]);
//             b0 = ei_pload(&b[i]);
//             a1 = ei_pload(&a[i+1*PacketSize]);
//             b1 = ei_pload(&b[i+1*PacketSize]);
//             a2 = ei_pload(&a[i+2*PacketSize]);
//             b2 = ei_pload(&b[i+2*PacketSize]);
//             a3 = ei_pload(&a[i+3*PacketSize]);
//             b3 = ei_pload(&b[i+3*PacketSize]);
//             ei_pstore(&a[i], ei_padd(a0, b0));
//             a0 = ei_pload(&a[i+4*PacketSize]);
//             b0 = ei_pload(&b[i+4*PacketSize]);
//
//             ei_pstore(&a[i+1*PacketSize], ei_padd(a1, b1));
//             a1 = ei_pload(&a[i+5*PacketSize]);
//             b1 = ei_pload(&b[i+5*PacketSize]);
//
//             ei_pstore(&a[i+2*PacketSize], ei_padd(a2, b2));
//             a2 = ei_pload(&a[i+6*PacketSize]);
//             b2 = ei_pload(&b[i+6*PacketSize]);
//
//             ei_pstore(&a[i+3*PacketSize], ei_padd(a3, b3));
//             a3 = ei_pload(&a[i+7*PacketSize]);
//             b3 = ei_pload(&b[i+7*PacketSize]);
//
//             ei_pstore(&a[i+4*PacketSize], ei_padd(a0, b0));
//             ei_pstore(&a[i+5*PacketSize], ei_padd(a1, b1));
//             ei_pstore(&a[i+6*PacketSize], ei_padd(a2, b2));
//             ei_pstore(&a[i+7*PacketSize], ei_padd(a3, b3));

            ei_pstore(&a[i+2*PacketSize], ei_padd(ei_ploadu(&a[i+2*PacketSize]), ei_ploadu(&b[i+2*PacketSize])));
            ei_pstore(&a[i+3*PacketSize], ei_padd(ei_ploadu(&a[i+3*PacketSize]), ei_ploadu(&b[i+3*PacketSize])));
            ei_pstore(&a[i+4*PacketSize], ei_padd(ei_ploadu(&a[i+4*PacketSize]), ei_ploadu(&b[i+4*PacketSize])));
            ei_pstore(&a[i+5*PacketSize], ei_padd(ei_ploadu(&a[i+5*PacketSize]), ei_ploadu(&b[i+5*PacketSize])));
            ei_pstore(&a[i+6*PacketSize], ei_padd(ei_ploadu(&a[i+6*PacketSize]), ei_ploadu(&b[i+6*PacketSize])));
            ei_pstore(&a[i+7*PacketSize], ei_padd(ei_ploadu(&a[i+7*PacketSize]), ei_ploadu(&b[i+7*PacketSize])));
        }
}


// Copyright 2015-2018 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/core/lightweight_test.hpp>
#include <boost/histogram/algorithm/project.hpp>
#include <boost/histogram/algorithm/sum.hpp>
#include <boost/histogram/axis/integer.hpp>
#include <boost/histogram/axis/ostream.hpp>
#include <boost/histogram/literals.hpp>
#include <boost/histogram/ostream.hpp>
#include <vector>
#include "throw_exception.hpp"
#include "utility_histogram.hpp"

using namespace boost::histogram;
using namespace boost::histogram::literals; // to get _c suffix
using namespace boost::histogram::algorithm;

template <typename Tag>
void run_tests() {
  {
    auto h = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3));
    h(0, 0);
    h(0, 1);
    h(1, 0);
    h(1, 1);
    h(1, 2);
    h(1, 2);

    /*
      matrix layout:

      x ->
    y 1 1
    | 1 1
    v 0 2
    */

    auto hx = project(h, 0_c);
    BOOST_TEST_EQ(hx.rank(), 1);
    BOOST_TEST_EQ(sum(hx), 6);
    BOOST_TEST_EQ(hx.axis(), h.axis(0_c));
    BOOST_TEST_EQ(hx.at(0), 2);
    BOOST_TEST_EQ(hx.at(1), 4);

    auto hy = project(h, 1_c);
    BOOST_TEST_EQ(hy.rank(), 1);
    BOOST_TEST_EQ(sum(hy), 6);
    BOOST_TEST_EQ(hy.axis(), h.axis(1_c));
    BOOST_TEST_EQ(hy.at(0), 2);
    BOOST_TEST_EQ(hy.at(1), 2);
    BOOST_TEST_EQ(hy.at(2), 2);

    auto hyx = project(h, 1_c, 0_c);
    BOOST_TEST_EQ(hyx.rank(), 2);
    BOOST_TEST_EQ(sum(hyx), 6);
    BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c));
    BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c));
    BOOST_TEST_EQ(hyx.at(0, 0), 1);
    BOOST_TEST_EQ(hyx.at(1, 0), 1);
    BOOST_TEST_EQ(hyx.at(2, 0), 0);
    BOOST_TEST_EQ(hyx.at(0, 1), 1);
    BOOST_TEST_EQ(hyx.at(1, 1), 1);
    BOOST_TEST_EQ(hyx.at(2, 1), 2);
  }

  {
    auto h =
        make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3), axis::integer<>(0, 4));
    h(0, 0, 0);
    h(0, 1, 0);
    h(0, 1, 1);
    h(0, 0, 2);
    h(1, 0, 2);

    auto h_0 = project(h, 0_c);
    BOOST_TEST_EQ(h_0.rank(), 1);
    BOOST_TEST_EQ(sum(h_0), 5);
    BOOST_TEST_EQ(h_0.at(0), 4);
    BOOST_TEST_EQ(h_0.at(1), 1);
    BOOST_TEST_EQ(h_0.axis(), axis::integer<>(0, 2));

    auto h_1 = project(h, 1_c);
    BOOST_TEST_EQ(h_1.rank(), 1);
    BOOST_TEST_EQ(sum(h_1), 5);
    BOOST_TEST_EQ(h_1.at(0), 3);
    BOOST_TEST_EQ(h_1.at(1), 2);
    BOOST_TEST_EQ(h_1.axis(), axis::integer<>(0, 3));

    auto h_2 = project(h, 2_c);
    BOOST_TEST_EQ(h_2.rank(), 1);
    BOOST_TEST_EQ(sum(h_2), 5);
    BOOST_TEST_EQ(h_2.at(0), 2);
    BOOST_TEST_EQ(h_2.at(1), 1);
    BOOST_TEST_EQ(h_2.at(2), 2);
    BOOST_TEST_EQ(h_2.axis(), axis::integer<>(0, 4));

    auto h_01 = project(h, 0_c, 1_c);
    BOOST_TEST_EQ(h_01.rank(), 2);
    BOOST_TEST_EQ(sum(h_01), 5);
    BOOST_TEST_EQ(h_01.at(0, 0), 2);
    BOOST_TEST_EQ(h_01.at(0, 1), 2);
    BOOST_TEST_EQ(h_01.at(1, 0), 1);
    BOOST_TEST_EQ(h_01.axis(0_c), axis::integer<>(0, 2));
    BOOST_TEST_EQ(h_01.axis(1_c), axis::integer<>(0, 3));

    auto h_02 = project(h, 0_c, 2_c);
    BOOST_TEST_EQ(h_02.rank(), 2);
    BOOST_TEST_EQ(sum(h_02), 5);
    BOOST_TEST_EQ(h_02.at(0, 0), 2);
    BOOST_TEST_EQ(h_02.at(0, 1), 1);
    BOOST_TEST_EQ(h_02.at(0, 2), 1);
    BOOST_TEST_EQ(h_02.at(1, 2), 1);
    BOOST_TEST_EQ(h_02.axis(0_c), axis::integer<>(0, 2));
    BOOST_TEST_EQ(h_02.axis(1_c), axis::integer<>(0, 4));

    auto h_12 = project(h, 1_c, 2_c);
    BOOST_TEST_EQ(h_12.rank(), 2);
    BOOST_TEST_EQ(sum(h_12), 5);
    BOOST_TEST_EQ(h_12.at(0, 0), 1);
    BOOST_TEST_EQ(h_12.at(1, 0), 1);
    BOOST_TEST_EQ(h_12.at(1, 1), 1);
    BOOST_TEST_EQ(h_12.at(0, 2), 2);
    BOOST_TEST_EQ(h_12.axis(0_c), axis::integer<>(0, 3));
    BOOST_TEST_EQ(h_12.axis(1_c), axis::integer<>(0, 4));

    auto h_210 = project(h, 2_c, 1_c, 0_c);
    BOOST_TEST_EQ(h_210.at(0, 0, 0), 1);
    BOOST_TEST_EQ(h_210.at(0, 1, 0), 1);
    BOOST_TEST_EQ(h_210.at(1, 1, 0), 1);
    BOOST_TEST_EQ(h_210.at(2, 0, 0), 1);
    BOOST_TEST_EQ(h_210.at(2, 0, 1), 1);
  }

  {
    auto h = make(dynamic_tag(), axis::integer<>(0, 2), axis::integer<>(0, 3));
    h(0, 0);
    h(0, 1);
    h(1, 0);
    h(1, 1);
    h(1, 2);
    h(1, 2);

    std::vector<int> x;

    x = {0};
    auto hx = project(h, x);
    BOOST_TEST_EQ(hx.rank(), 1);
    BOOST_TEST_EQ(sum(hx), 6);
    BOOST_TEST_EQ(hx.at(0), 2);
    BOOST_TEST_EQ(hx.at(1), 4);
    BOOST_TEST(hx.axis() == h.axis(0_c));

    x = {1};
    auto hy = project(h, x);
    BOOST_TEST_EQ(hy.rank(), 1);
    BOOST_TEST_EQ(sum(hy), 6);
    BOOST_TEST_EQ(hy.at(0), 2);
    BOOST_TEST_EQ(hy.at(1), 2);
    BOOST_TEST_EQ(hy.at(2), 2);
    BOOST_TEST(hy.axis() == h.axis(1_c));

    x = {1, 0};
    auto hyx = project(h, x);
    BOOST_TEST_EQ(hyx.rank(), 2);
    BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c));
    BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c));
    BOOST_TEST_EQ(sum(hyx), 6);
    BOOST_TEST_EQ(hyx.at(0, 0), 1);
    BOOST_TEST_EQ(hyx.at(1, 0), 1);
    BOOST_TEST_EQ(hyx.at(0, 1), 1);
    BOOST_TEST_EQ(hyx.at(1, 1), 1);
    BOOST_TEST_EQ(hyx.at(2, 1), 2);

    // indices must be unique
    x = {0, 0};
    BOOST_TEST_THROWS((void)project(h, x), std::invalid_argument);

    // indices must be valid
    x = {2, 1};
    BOOST_TEST_THROWS((void)project(h, x), std::invalid_argument);
  }
}

int main() {
  run_tests<static_tag>();
  run_tests<dynamic_tag>();

  return boost::report_errors();
}


#include <limits>
#include <boost/test/unit_test.hpp>
#include "algorithms/math/int_to_roman.hpp"

BOOST_AUTO_TEST_SUITE(ConversionOfIntegerToRomanNumber)

BOOST_AUTO_TEST_CASE(invalid_numbers)
{
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(
                    std::numeric_limits<int>::min()).empty());

    BOOST_CHECK(Algo::Math::IntToRoman::Convert(-12).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(-1).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(0).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(4000).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(4001).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::Convert(15000).empty());

    BOOST_CHECK(Algo::Math::IntToRoman::Convert(
                    std::numeric_limits<int>::max()).empty());

    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(
                    std::numeric_limits<int>::min()).empty());

    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(-12).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(-1).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(0).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(4000).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(4001).empty());
    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(15000).empty());

    BOOST_CHECK(Algo::Math::IntToRoman::ConvertSimple(
                    std::numeric_limits<int>::max()).empty());
}

BOOST_AUTO_TEST_CASE(main_numbers)
{
    BOOST_CHECK(std::string("I") == Algo::Math::IntToRoman::Convert(1));
    BOOST_CHECK(std::string("V") == Algo::Math::IntToRoman::Convert(5));
    BOOST_CHECK(std::string("X") == Algo::Math::IntToRoman::Convert(10));
    BOOST_CHECK(std::string("L") == Algo::Math::IntToRoman::Convert(50));
    BOOST_CHECK(std::string("C") == Algo::Math::IntToRoman::Convert(100));
    BOOST_CHECK(std::string("D") == Algo::Math::IntToRoman::Convert(500));
    BOOST_CHECK(std::string("M") == Algo::Math::IntToRoman::Convert(1000));

    BOOST_CHECK(std::string("I") == Algo::Math::IntToRoman::ConvertSimple(1));
    BOOST_CHECK(std::string("V") == Algo::Math::IntToRoman::ConvertSimple(5));
    BOOST_CHECK(std::string("X") == Algo::Math::IntToRoman::ConvertSimple(10));
    BOOST_CHECK(std::string("L") == Algo::Math::IntToRoman::ConvertSimple(50));
    BOOST_CHECK(std::string("C") == Algo::Math::IntToRoman::ConvertSimple(100));
    BOOST_CHECK(std::string("D") == Algo::Math::IntToRoman::ConvertSimple(500));
    BOOST_CHECK(std::string("M") == Algo::Math::IntToRoman::ConvertSimple(1000));
}

BOOST_AUTO_TEST_CASE(main_susbstract_numbers)
{
    BOOST_CHECK(std::string("IV") == Algo::Math::IntToRoman::Convert(4));
    BOOST_CHECK(std::string("IX") == Algo::Math::IntToRoman::Convert(9));
    BOOST_CHECK(std::string("XL") == Algo::Math::IntToRoman::Convert(40));
    BOOST_CHECK(std::string("XC") == Algo::Math::IntToRoman::Convert(90));
    BOOST_CHECK(std::string("CD") == Algo::Math::IntToRoman::Convert(400));
    BOOST_CHECK(std::string("CM") == Algo::Math::IntToRoman::Convert(900));

    BOOST_CHECK(std::string("IV") == Algo::Math::IntToRoman::ConvertSimple(4));
    BOOST_CHECK(std::string("IX") == Algo::Math::IntToRoman::ConvertSimple(9));
    BOOST_CHECK(std::string("XL") == Algo::Math::IntToRoman::ConvertSimple(40));
    BOOST_CHECK(std::string("XC") == Algo::Math::IntToRoman::ConvertSimple(90));
    BOOST_CHECK(std::string("CD") == Algo::Math::IntToRoman::ConvertSimple(400));
    BOOST_CHECK(std::string("CM") == Algo::Math::IntToRoman::ConvertSimple(900));
}

BOOST_AUTO_TEST_CASE(main_valid_numbers)
{
    BOOST_CHECK(std::string("II") == Algo::Math::IntToRoman::Convert(2));
    BOOST_CHECK(std::string("III") == Algo::Math::IntToRoman::Convert(3));
    BOOST_CHECK(std::string("VIII") == Algo::Math::IntToRoman::Convert(8));
    BOOST_CHECK(std::string("XIV") == Algo::Math::IntToRoman::Convert(14));
    BOOST_CHECK(std::string("XXXIX") == Algo::Math::IntToRoman::Convert(39));
    BOOST_CHECK(std::string("XLIV") == Algo::Math::IntToRoman::Convert(44));
    BOOST_CHECK(std::string("LVIII") == Algo::Math::IntToRoman::Convert(58));
    BOOST_CHECK(std::string("LXXXII") == Algo::Math::IntToRoman::Convert(82));
    BOOST_CHECK(std::string("MMMCMXCIV") ==
                Algo::Math::IntToRoman::Convert(3994));

    BOOST_CHECK(std::string("II") == Algo::Math::IntToRoman::ConvertSimple(2));
    BOOST_CHECK(std::string("III") == Algo::Math::IntToRoman::ConvertSimple(3));
    BOOST_CHECK(std::string("VIII") == Algo::Math::IntToRoman::ConvertSimple(8));
    BOOST_CHECK(std::string("XIV") == Algo::Math::IntToRoman::ConvertSimple(14));
    BOOST_CHECK(std::string("XXXIX") ==
                Algo::Math::IntToRoman::ConvertSimple(39));

    BOOST_CHECK(std::string("XLIV") ==
                Algo::Math::IntToRoman::ConvertSimple(44));

    BOOST_CHECK(std::string("LVIII") ==
                Algo::Math::IntToRoman::ConvertSimple(58));

    BOOST_CHECK(std::string("LXXXII") ==
                Algo::Math::IntToRoman::ConvertSimple(82));

    BOOST_CHECK(std::string("MMMCMXCIV") ==
                Algo::Math::IntToRoman::ConvertSimple(3994));
}

BOOST_AUTO_TEST_SUITE_END()


/* Siconos-Kernel, Copyright INRIA 2005-2012.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */

#ifndef __determinant__
#define __determinant__

#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/numeric/ublas/lu.hpp>

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

namespace ublas = boost::numeric::ublas;

template<class matrix_T>
double determinant(ublas::matrix_expression<matrix_T> const& mat_r)
{
  double det = 1.0;

  matrix_T mLu(mat_r());
  ublas::permutation_matrix<std::size_t> pivots(mat_r().size1());

  int is_singular = lu_factorize(mLu, pivots);

  if (!is_singular)
  {
    for (std::size_t i=0; i < pivots.size(); ++i)
    {
      if (pivots(i) != i)
        det *= -1.0;

      det *= mLu(i,i);
    }
  }
  else
    det = 0.0;

  return det;
}

#endif


// Copyright (c) 2015
// Author: Chrono Law
#include <std.hpp>
using namespace std;

#include <boost/date_time/gregorian/gregorian.hpp>
using namespace boost::gregorian;

//////////////////////////////////////////
void case1()
{
    date_period dp(date(2014,1,1), days(20));

    dp.shift(days(3));
    assert(dp.begin().day() == 4);
    assert(dp.length().days() == 20);

    dp.expand(days(3));
    assert(dp.begin().day() == 1);
    assert(dp.length().days() == 26);

}

//////////////////////////////////////////

void case2()
{
    date_period dp(date(2010,1,1), days(20));

    assert(dp.is_after(date(2009,12,1)));
    assert(dp.is_before(date(2010,2,1)));
    assert(dp.contains(date(2010,1,10)));

    date_period dp2(date(2010,1,5), days(10));
    assert(dp.contains(dp2));

    assert(dp.intersects(dp2));
    assert(dp.intersection(dp2) == dp2);

    date_period dp3(date(2010,1,21), days(5));
    assert(!dp3.intersects(dp2));
    assert(dp3.intersection(dp2).is_null());

    assert(dp.is_adjacent(dp3));
    assert(!dp.intersects(dp3));

}

//////////////////////////////////////////
void case3()
{
    date_period dp1(date(2010,1,1), days(20));
    date_period dp2(date(2010,1,5), days(10));
    date_period dp3(date(2010,2,1), days(5));
    date_period dp4(date(2010,1,15), days(10));

    assert( dp1.contains(dp2) && dp1.merge(dp2) == dp1);
    assert(!dp1.intersects(dp3) && dp1.merge(dp3).is_null());
    assert( dp1.intersects(dp2) && dp1.merge(dp4).end() == dp4.end());
    assert( dp1.span(dp3).end() == dp3.end());
}

//////////////////////////////////////////
void case4()
{
    date d(2006,11,26);
    day_iterator d_iter(d);

    assert(d_iter == d);
    ++d_iter;
    assert(d_iter == date(2006,11,27));

    year_iterator y_iter(*d_iter, 8);
    assert(y_iter == d + days(1));
    ++y_iter;
    assert(y_iter->year() == 2014);

    day_iterator iter(day_clock::local_day());
    ++iter;

    //iter += 5;
    //std::advance(iter, 5);
}

//////////////////////////////////////////
void case5()
{
    typedef gregorian_calendar gre_cal;
    cout << "Y2014 is "
        << (gre_cal::is_leap_year(2014)?"":"not")
        << " a leap year." << endl;
    assert(gre_cal::end_of_month_day(2014, 2) == 28);
}

//////////////////////////////////////////
void case6()
{
    date d(2008,11,20);

    date d_start(d.year(), d.month(), 1);
    date d_end = d.end_of_month();

    for(day_iterator d_iter(d_start);
        d_iter <= d_end; ++d_iter)
    {
            cout << *d_iter << " " <<
                    d_iter->day_of_week()<< endl;
    }

}

//////////////////////////////////////////
void case7()
{
    date d(2008,11,20);

    date d18years = d + years(18);
    cout << d18years << " is "
        << d18years.day_of_week()<< endl;

    int count = 0;
    for (day_iterator d_iter(date(d18years.year(),11,1));
            d_iter <= d18years.end_of_month(); ++d_iter)
    {
        if (d_iter->day_of_week() == Sunday)
        {
            ++count;
        }
    }
    cout << "total " << count << " Sundays." << endl;

    count = 0;
    for (month_iterator m_iter(date(d18years.year(),1,1));
            m_iter < date(d18years.year() + 1 ,1, 1); ++m_iter)
    {
        count += m_iter->end_of_month().day();
    }
    cout << "total " << count << " days of year." << endl;

}

//////////////////////////////////////////
class credit_card
{
public:
    string bank_name;
    int bill_day_no;

    credit_card(const char* bname, int no):
        bank_name(bname), bill_day_no(no){}

    int calc_free_days(date consume_day = day_clock::local_day()) const
    {
        date bill_day(consume_day.year(), consume_day.month(), bill_day_no);
        if (consume_day > bill_day)
        {
            bill_day += months(1);
        }

        return (bill_day - consume_day).days() + 20;
    }

    friend bool operator<(const credit_card& l, const credit_card& r)
    {

        return l.calc_free_days() < r.calc_free_days();
    }
};

void case8()
{
    credit_card a("A bank", 25);
    credit_card b("B bank", 12);

    credit_card tmp = std::max(a, b);
    cout << "You should use " << tmp.bank_name
        << ", free days = " << tmp.calc_free_days() << endl;
}

//////////////////////////////////////////

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
    case8();
}


#ifndef _MAIN_HPP_
#define _MAIN_HPP_
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <boost/math/distributions.hpp>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
#include <random>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/Core>
#include <unsupported/Eigen/MatrixFunctions>
#include <cmath>
#include <chrono>
#include <omp.h>
#include <Eigen/StdVector>
#include <boost/numeric/odeint/external/openmp/openmp.hpp>
#include <experimental/filesystem>
#include "rr/rrRoadRunner.h"
#include "rr/rrExecutableModel.h"
#include "rr/rrException.h"
#include "rr/rrUtils.h"
#include "rr/rrLogger.h"
#include "rr/rrConfig.h"
using Eigen::MatrixXd;
using Eigen::VectorXd;
using namespace std;
using namespace boost;
using namespace boost::math;
using namespace boost::numeric::odeint;
using namespace rr;
using namespace ls;
namespace fs = std::experimental::filesystem;
#endif


#include "loadLibrary.hpp"
#include <cstdlib>
#include <cmath>
#include<deque>
#include<vector>
#include <random>
#include <cmath>
#include <boost/program_options.hpp>

int N = 100;
int get_power(int ix)
{
    int fade = N / 5;
    if (ix < fade) {
        return ix * 255 / fade;
    }
    else if (ix < N - fade) {
        return 255;
    }
    else {
        return (N - ix) * 255 / fade;
    }
}

template< typename t >
t max3(t const & a, t const & b, t const & c)
{
    auto ab = a < b ? b : a;
    return ab < c ? c : ab;
}

template< typename proc_t >
void concentric(proc_t const & proc)
{
    for (int ix = 0; ix<N; ++ix) {
        int cx = LED_WIDTH / 2;
        int cy = LED_HEIGHT / 2;
        int cz = LED_DEPTH / 2;
        Clear();
        int power = get_power(ix);
        for (int x = 0; x < LED_WIDTH; ++x) {
            for (int y = 0; y < LED_HEIGHT; ++y) {
                for (int z = 0; z < LED_DEPTH; ++z) {
                    double d = proc(x - cx, y - cy, z - cz, ix*1.0 / N);
                    int col0 = static_cast<int>(std::round(ix - d)) % 64;
                    int col = (col0 % 6) == 0 ? col0 % 7 + 1 : 0;
                    int r = (col & 1) ? power : 0;
                    int g = (col & 2) ? power : 0;
                    int b = (col & 4) ? power : 0;
                    int rgb = (r << 16) + (g << 8) + b;
                    SetLed(x, y, z, rgb);
                }
            }
        }
        Show();
        Wait(50);
    }
}

struct xyz_t{
    double x, y, z;
    double len() const { return std::sqrt(x*x + y*y + z*z); }
};

xyz_t xyz(double x, double y, double z)
{
    return{ x, y, z };
}

struct xyzc_t{
    xyz_t p;
    int color;
};

xyz_t operator*(xyz_t const & a, double t)
{
    return{ a.x*t, a.y*t, a.z*t };
}

xyz_t operator+(xyz_t const & a, xyz_t const & b)
{
    return{ a.x + b.x, a.y + b.y, a.z + b.z };
}

xyz_t operator-(xyz_t const & a, xyz_t const & b)
{
    return{ a.x - b.x, a.y - b.y, a.z - b.z };
}

xyz_t & operator+=(xyz_t & a, xyz_t const & b)
{
    a = a + b;
    return a;
}

xyz_t & operator-=(xyz_t & a, xyz_t const & b)
{
    a = a - b;
    return a;
}

double ip(xyz_t const & a, xyz_t const & b)
{
    return a.x*b.x + a.y*b.y + a.z*b.z;
}

xyz_t op(xyz_t const & a, xyz_t const & b)
{
    return{
        a.y*b.z - a.z*b.y,
        a.z*b.x - a.x*b.z,
        a.x*b.y - a.y*b.x
    };
}

xyz_t sphere_face(std::mt19937 & rng)
{
    std::uniform_real_distribution<double> dist(-1, 1);
    for (;;) {
        xyz_t pos = { dist(rng), dist(rng), dist(rng) };
        double d2 = pos.x*pos.x + pos.y*pos.y + pos.z*pos.z;
        if (0.1<d2 && d2 < 1) {
            double d = 0.5;
            return{ pos.x * d, pos.y * d + 0.1, pos.z * d };
        }
    }
}

bool can_show(xyz_t const & p)
{
    return 0 <= p.x && p.x < LED_WIDTH
        && 0 <= p.y && p.y < LED_HEIGHT
        && 0 <= p.z && p.z < LED_DEPTH;
}

void color_cube()
{
    using namespace std;
    const int N = 200;
    std::vector<xyzc_t> points;
    auto rgb = [](double x, double y, double z)->int {
        auto c = [](double v)->int {
            return std::round((v + 1) * 127);
        };
        return c(x) * 0x10000 + c(y) * 0x100 + c(z) * 0x1;
    };
    const int P = 90 * 10;
#if 1
    for (int i = 0; i < P; ++i) {
        double k = 0.8;
        double x = ((rand() % 101) / 50.0 - 1);
        double y = ((rand() % 101) / 50.0 - 1);
        double z = ((rand() % 101) / 50.0 - 1);
        points.push_back({ { k*x, k*y, k*z }, rgb(x, y, z) });
    }
#else
    for (int i = 0; i < P; ++i) {
        double k = 0.5;
        double t = k*(2 * i / (P - 1.0) - 1);
        for (int sig = 0; sig < 4; ++sig) {
            double s0 = sig & 1 ? -k : k;
            double s1 = sig & 2 ? -k : k;
            points.push_back({ { s0, s1, t }, rgb(i) });
            points.push_back({ { s0, t, s1 }, rgb(i) });
            points.push_back({ { t, s0, s1 }, rgb(i) });
        }
    }
#endif
    for (int i = 0; i < N; ++i) {
        Clear();
        for (auto p0 : points) {
            double t = cos(6.28*i / N * 2)*3.14;
            double t1 = sin(6.28*i / N * 2)*3.14;
            xyz_t p1 = {
                p0.p.x * cos(t) + p0.p.z * sin(t),
                p0.p.y,
                -p0.p.x * sin(t) + p0.p.z * cos(t),
            };
            double zo = sin(6.28*i / N * 2)*0.3 + 1;
            if (N - 30 < i) {
                zo *= (N - i)*1.0 / 30;
            }
            if (i < 30) {
                zo *= i*1.0 / 30;
            }
            xyz_t p = {
                zo*(p1.x * cos(t1) + p1.y * sin(t1)),
                zo*(-p1.x * sin(t1) + p1.y * cos(t1)),
                zo*p1.z,
            };
            double x = (p.x / 2 + 0.5)* (LED_WIDTH - 1);
            double y = (p.y / 2 + 0.5)* (LED_HEIGHT - 1);
            double z = (p.z / 2 + 0.5)* (LED_DEPTH - 1);
            if (can_show({ x, y, z })) {
                SetLed(x, y, z, p0.color);
            }
        }
        Show();
        Wait(50);
    }
}

void fireworks()
{
    const int N = 200;
    std::vector<xyzc_t> poss;
    std::vector<xyz_t> vs(poss.size());
    std::mt19937 rng;
    const int PS = 1000;
    auto rgb = [](double x)->int {
        auto red = [](int ix)->int {
            int i = ix % 90;
            if (i < 30) {
                return i * 255 / 30;
            }
            else if (i < 60) {
                return (60 - i) * 255 / 30;
            }
            else {
                return 0;
            }
        };
        int n = std::floor(x * 1 * 90);
        return red(n) * 0x10000 + red(n + 30) * 0x100 + red(n + 60) * 0x1;
    };
    auto darken = [](int x)->int
    {
        int r = ((x & 0xff0000) * 49 / 50) & 0xff0000;
        int g = ((x & 0xff00) * 49 / 50) & 0xff00;
        int b = ((x & 0xff) * 49 / 50) & 0xff;
        return r + g + b;
    };
    std::uniform_real_distribution<double> dist(0, 1);
    for (int ix = 0; ix < N; ++ix) {
        Clear();
        if (ix % 20 == 0 && 20<N - ix) {
            double cx = LED_WIDTH * dist(rng);
            double cy = LED_HEIGHT * dist(rng);
            double cz = LED_DEPTH * dist(rng);
            for (int i = 0; i < PS; ++i) {
                vs.push_back(sphere_face(rng));
                poss.push_back({ { cx, cy, cz }, rgb(vs.back().len()) });
            }
        }
        for (size_t i = 0; i<poss.size(); ++i){
            auto & p = poss[i];
            auto & v = vs[i];
            if (can_show(p.p)) {
                SetLed(p.p.x, p.p.y, p.p.z, p.color);
            }
            else {

            }
            p.p = p.p + v;
            p.color = darken(p.color);
        }
        Show();
        Wait(50);
    }
}

void repbang()
{
    std::vector<xyzc_t> ps;
    std::mt19937 rng;
    auto newp = [&rng]()->xyzc_t{
        std::uniform_real_distribution<double> dist(-1, 1);
        double x = dist(rng);
        double y = dist(rng);
        double z = dist(rng);
        double r = dist(rng) / sqrt(x*x + y*y + z*z + 1e-5);
        return{
            { x*r, y*r, z*r },
            static_cast<int>(rng() % 0x1000000) };
    };
    for (int i = 0; i < 4000; ++i){
        ps.push_back(newp());
    }
    int N = 216;
    for (int i = 0; i < N; ++i){
        Clear();
        double r = 1 - std::cos(i*3.1416 / N * 8);
        double t = i*3.1416 / N * 16;
        for (auto & p : ps){
            xyz_t q = {
                std::cos(t)*p.p.x - std::sin(t)*p.p.z,
                p.p.y,
                std::sin(t)*p.p.x + std::cos(t)*p.p.z,
            };
            xyz_t pos = q * r * LED_HEIGHT + xyz(LED_WIDTH, LED_HEIGHT, LED_DEPTH)*0.5;

            if (can_show(pos)){
                SetLed(pos.x, pos.y, pos.z, p.color);
            }
        }
        Show();
        Wait(50);
    }
}

void spiral()
{
    struct rty_t{ double r, t, y; };
    struct rtyc_t { rty_t p; int c; };
    std::vector<rtyc_t> pcs;
    std::mt19937 rng;

    for (int i = 0; i < 1000; ++i){
        double r = ((rng() % 1000) / 1000.0) * 0.8 + 0.2;
        double y = (rng() % 1000) / 1000.0;
        double t = y*3.1416 * 16;// rng() % 1000;
        double t0 = 3.1416 * 2 / 3;
        auto c = [t0](double t)->int {
            double v = std::sin(t * 2 / 3);
            return v < 0 ? 0 : v * 255;
        };
        int col = c(t) + c(t + t0) * 256 + c(t + t0 * 2) * 65536;
        pcs.push_back({ { r, t, y }, col });
    }
    const int N = 200;
    const double T = 0.125;
    const double U = 0.25;
    const int D = 20;
    auto darken = [D](int x, int d)->int
    {
        int r = ((x & 0xff0000) * d / D) & 0xff0000;
        int g = ((x & 0xff00) * d / D) & 0xff00;
        int b = ((x & 0xff) * d / D) & 0xff;
        return r + g + b;
    };
    for (int i = 0; i < N; ++i){
        Clear();
        int d = i < D ? i : N < i + D ? N - i : D;
        for (auto & pc : pcs){
            double y = int((pc.p.y) * LED_HEIGHT + N - i*U) % LED_HEIGHT;
            double x = (pc.p.r * std::cos(pc.p.t + i*T)) * LED_WIDTH / 2 + LED_WIDTH / 2;
            double z = (pc.p.r * std::sin(pc.p.t + i*T)) * LED_WIDTH / 2 + LED_DEPTH / 2;
            if (can_show({ x, y, z })){
                SetLed(x, y, z, darken(pc.c, d));
            }
        }
        Show();
        Wait(50);
    }
}

void brown()
{
    int len = N * 2;
    struct pos_t{ int x, y, z; };
    std::deque<pos_t> poses[3]{
        {{ LED_WIDTH / 2, LED_HEIGHT / 4, LED_DEPTH / 2 }},
        { { LED_WIDTH / 2, LED_HEIGHT / 2, LED_DEPTH / 2 } },
        { { LED_WIDTH / 2, LED_HEIGHT * 3 / 4, LED_DEPTH / 2 } }
    };

    auto normalize = [](pos_t const & s) -> pos_t {
        return{
            (s.x + LED_WIDTH) % LED_WIDTH,
            (s.y + LED_HEIGHT) % LED_HEIGHT,
            (s.z + LED_DEPTH) % LED_DEPTH
        };
    };
    auto move = [](pos_t const & s) -> pos_t {
        switch (rand() % 12) {
        default:
        case 0: return{ s.x + 1, s.y, s.z };
        case 1: return{ s.x - 1, s.y, s.z };
        case 2:
        case 3:
        case 4:
        case 5:
            return{ s.x, s.y + 1, s.z };
        case 6:
        case 7:
        case 8:
        case 9:
            return{ s.x, s.y - 1, s.z };
        case 10: return{ s.x, s.y, s.z + 1 };
        case 11: return{ s.x, s.y, s.z - 1 };
        }
    };
    auto red = [](int ix)->int {
        int i = ix % 90;
        if (i < 30) {
            return i * 255 / 30;
        }
        else if (i < 60) {
            return (60 - i) * 255 / 30;
        }
        else {
            return 0;
        }
    };
    for (int i = 0; i < len; ++i) {
        Clear();
        for (int i = 0; i < 3; ++i) {
            auto & pos = poses[i];
            for (int j = 0; j < 3; ++j) {
                pos.push_back(normalize(move(pos.back())));
            }
            int power = i < len - 20 ? 255 : (len - i) * 255 / 20;
            while (150 < pos.size()) {
                pos.pop_front();
            }
            int ix = 0;
            for (auto it = pos.begin(); it != pos.end(); ++it, ++ix) {
                int r = red(ix) * power / 255;
                int g = red(ix + 30)* power / 255;
                int b = red(ix + 60)* power / 255;
                int rgb = (r << 16) + (g << 8) + b;
                SetLed(it->x, it->y, it->z, rgb);
            }
        }
        Show();
        Wait(50);
    }
}

void cube()
{
    concentric([](int dx, int dy, int dz, double t)->double {
        return max3(std::abs(dx), std::abs(dy), std::abs(dz));
    });
}

void sphere()
{
    concentric([](int dx, int dy, int dz, double t)->double {
        return std::sqrt(dx*dx + dy*dy + dz*dz);
    });
}

void skewed_sphere()
{
    concentric([](int dx0, int dy, int dz0, double t)->double {
        double T = 4;
        double s = std::sin(t*3.14*T);
        double c = std::cos(t*3.14*T);
        double dx = (dx0*c + dz0*s)*0.5;
        double dz = (-dx0*s + dz0*c) * 2;
        return std::sqrt(dx*dx + dy*dy + dz*dz);
    });
}

void gala()
{
    struct rtyc_t{ double r, t, y; int c; };
    std::mt19937 rng;
    std::uniform_real_distribution<> tdist(0, 3.1416 * 2);
    std::uniform_real_distribution<> one(-1, 1);
    std::vector<rtyc_t> stars;
    for (int i = 0; i < 2000; ++i){
        if (rng() % 2){
            double r = std::abs(one(rng));
            double y = one(rng);
            double rr = 0.3*std::abs(one(rng)) / sqrt(r*r + y*y + 1e-5);
            stars.push_back({ r * rr, tdist(rng), y * rr, static_cast<int>(rng() % 0x1000000) });
        }
        else {
            double r = 0.3 + 4 * std::abs(one(rng));
            double y = one(rng)*0.1;
            stars.push_back({ r, tdist(rng), y, static_cast<int>(rng() % 0x1000000) });
        }
    }
    const int D = 20;
    auto darken = [D](int x, int d)->int
    {
        int r = ((x & 0xff0000) * d / D) & 0xff0000;
        int g = ((x & 0xff00) * d / D) & 0xff00;
        int b = ((x & 0xff) * d / D) & 0xff;
        return r + g + b;
    };
    const int N = 200;
    for (int i = 0; i < N; ++i){
        Clear();
        int d = i < D ? i : N < i + D ? N - i : D;
        for (auto & star : stars){
            star.t += 0.005 / (std::abs(star.r) + 0.1);
            xyz_t q{
                star.r * std::cos(star.t),
                star.y,
                star.r * std::sin(star.t) };
            double T = 2, U = -4;
            double x = std::cos(T)*q.x - std::sin(T)*q.y;
            double y = std::sin(T)*q.x + std::cos(T)*q.y;
            double z = q.z;
            xyz_t p{
                std::cos(U)*x - std::sin(U)*z,
                y,
                std::sin(U)*x + std::cos(U)*z,
            };
            xyz_t pos{
                p.x * LED_WIDTH / 2 + LED_WIDTH / 2,
                p.y * LED_WIDTH / 2 + LED_HEIGHT / 2,
                p.z * LED_WIDTH / 2 + LED_DEPTH / 2 };
            if (can_show(pos)){
                SetLed(pos.x, pos.y, pos.z, darken(star.c, d));
            }
        }
        Show();
        Wait(50);
    }
}

void balls()
{
    struct p_t { xyz_t p, v; int c; };
    std::vector<p_t> ps;
    std::mt19937 rng;
    for (int i = 1; i < 7; ++i){
        ps.push_back({
            { static_cast<double>(i & 1 ? 0 : LED_WIDTH),
            static_cast<double>(i & 2 ? 0 : LED_HEIGHT),
            static_cast<double>(i & 4 ? 0 : LED_DEPTH) },
            { 0, 0, 0 },
            (i & 1 ? 0xff0000 : 0) + (i & 2 ? 0xff00 : 0) + (i & 4 ? 0xff : 0)
        });
    }
    int N = 200;
    for (int ix = 0;; ++ix){
        Clear();
        bool shown = false;
        for (auto & p : ps){
            if (ix<N && (!can_show(p.p) || p.v.len() == 0)){
                xyz_t dir;
                for (;;){
                    xyz_t dest{ static_cast<double>(rng() % LED_WIDTH), static_cast<double>(rng() % LED_HEIGHT), static_cast<double>(rng() % LED_DEPTH) };
                    dir = dest - p.p;
                    if (dir.len() != 0){
                        break;
                    }
                }
                p.v = dir *(1.0 / dir.len() * 2);
            }
            p.p += p.v;
            for (int i = 0; i < 125; ++i){
                xyz_t delta{
                    static_cast<double>(i % 5 - 2),
                    static_cast<double>((i / 5) % 5 - 2),
                    static_cast<double>((i / 25) % 5 - 2) };
                if (delta.len() < 2.5){
                    xyz_t pos = p.p + delta;
                    if (can_show(pos)){
                        shown = true;
                        SetLed(pos.x, pos.y, pos.z, p.c);
                    }
                }
            }
        }
        Show();
        Wait(50);
        if (!shown){
            break;
        }
    }
}

void threed()
{
    char m0[] =
        "00000000"/*0*/
        "01111110"/*1*/
        "01111110"/*2*/
        "00000110"/*3*/
        "00000110"/*4*/
        "00000110"/*5*/
        "00000110"/*6*/
        "00111110"/*7*/
        "00111110"/*8*/
        "00000110"/*9*/
        "00000110"/*a*/
        "00000110"/*b*/
        "00000110"/*c*/
        "01111110"/*d*/
        "01111110"/*e*/
        "00000000"/*f*/;
    char m1[] =
        "00000000"/*0*/
        "01111000"/*1*/
        "01111100"/*2*/
        "01101110"/*3*/
        "01100110"/*4*/
        "01100110"/*5*/
        "01100110"/*6*/
        "01100110"/*7*/
        "01100110"/*8*/
        "01100110"/*9*/
        "01100110"/*a*/
        "01100110"/*b*/
        "01101110"/*c*/
        "01111100"/*d*/
        "01111000"/*e*/
        "00000000"/*f*/;
    std::mt19937 rng;
    auto col_at = [&m0, &m1, &rng](int x, int y, int c)->int {
        char const * m = c == 0 ? m0 : m1;
        return m[x / 2 + (y / 2) * 8] == '0' ? 0 :
            c == 0 ? x * 0x100000 + (16 - x) * 0x1000
            : y * 0x8 + (31 - y) * 0x80000;
    };
    auto col_at2 = [&col_at](xyz_t const & p, int c)->int {
        return col_at(p.x, p.y, c);
    };
    struct pp_t{
        xyz_t p[2];
    };
    std::vector<pp_t> pps;
    while (pps.size()<2000){
        xyz_t a{
            static_cast<double>(rng() % LED_WIDTH),
            static_cast<double>(rng() % LED_HEIGHT),
            static_cast<double>(rng() % LED_DEPTH) };
        xyz_t b{
            static_cast<double>(rng() % LED_WIDTH),
            static_cast<double>(rng() % LED_HEIGHT),
            static_cast<double>(rng() % LED_DEPTH) };
        if (col_at2(a, 0) && col_at2(b, 1)) {
            pps.push_back({ { a, b } });
        }
    }
    int N0 = 20;
    int N1 = 20;
    auto show = [&col_at2, &pps, N0](double c, double d)->void {
        Clear();
        for (auto & pp : pps) {
            xyz_t p = pp.p[0] * (1 - c) + pp.p[1] * c;
            int c0 = col_at2(pp.p[0], 0);
            int c1 = col_at2(pp.p[1], 1);
            auto mean = [&](int mask, double d) {
                int v = ((c0 & mask)*(1 - c) + (c1 & mask)*c)*d;
                return v & mask;
            };
            int col = mean(0xff0000, d) + mean(0xff00, d) + mean(0xff, d);
            if (can_show(p)) {
                SetLed(p.x, p.y, p.z, col);
            }
        }
        Show();
        Wait(50);
    };
    for (int ix = 0; ix < N0; ++ix) {
        show(0, ix*1.0 / N0);
    }
    for (int ix = 0; ix < N1; ++ix) {
        show(ix*1.0 / N1, 1);
    }
    for (int ix = 0; ix < N0 / 2; ++ix) {
        show(1, 1);
    }
    for (int ix = 0; ix < N0; ++ix) {
        show(1, (N0 - ix)*1.0 / N0);
    }
}

template< typename t >
t max_(t const & a, t const & b){
    return a < b ? b : a;
}

template< typename t >
t max_(t const & a, t const & b, t const & c){
    return max_(a, max_(b, c));
}

void wave()
{
    const int N0 = 300;
    for (int i = 0; i < N0; ++i){
        Clear();
        double it = 3.14 * 10 / N0;
        double xt = 3.14 * 2;
        double yt = 3.14 * 2 * 1.41;
        double LT = 20.0;
        double light = i < LT ? i / LT : N0 - i<LT ? (N0 - i) / LT : 1;
        for (int iy = 0; iy < LED_HEIGHT; ++iy){
            for (int ix = 0; ix < LED_WIDTH; ++ix){
                double x = xt*(ix - LED_WIDTH / 2) / LED_WIDTH * 2;
                double y = yt*(iy - LED_HEIGHT / 2) / LED_HEIGHT * 2;
                double iz = static_cast<int>(sin(x)*sin(y)*sin(i*it)*LED_DEPTH / 2 + LED_DEPTH / 2);
                auto col = [&](double t)->int{
                    double dx = (ix - LED_WIDTH / 2);
                    double dy = (iy - LED_HEIGHT / 2);
                    double d = std::pow(dx*dx + dy*dy, 0.7) / 10.0 + t + i*it;
                    double W = sin(3.1416 * 7 / 6);
                    double v = sin(d) < W ? 0 : (sin(d) - W) / (1 - W);
                    return 255 & int(v * 255 * light);
                };
                const double T = 3.1416 * 2 / 3;
                int c = col(T) * 1 + col(T * 2) * 0x100 + col(T * 3) * 0x10000;
                for (int dz : { -1, 0, 1 }){
                    if (can_show({ static_cast<double>(ix), static_cast<double>(iy), iz + dz })){
                        SetLed(ix, iy, iz + dz, c);
                    }
                }
            }
        }
        Show();
        Wait(50);
    }
}

struct yz_t
{
    double y, z;
};

int main(int argc, const char* argv[])
{
    namespace po = boost::program_options;
    po::options_description desc("3D LED DEMO PROGRAM");
    desc.add_options()	//
        ("help,h", "produce help message")	//
        ("version,v", "produce version information")	//
        ("url,u", po::value<std::string>(), "3D LED URL")	//
        ("port,p", po::value<int>(), "3D LED PORT")	//
        ;
    po::variables_map vm;
    try
    {
#if defined(WIN32)
        loadLibrary("ledLib32.dll");
#elif defined(WIN64)
        loadLibrary("ledLib64.dll");
#endif
        po::store(po::parse_command_line(argc, argv, desc), vm);
        if (vm.count("version"))
        {
            std::cout << "version 1. 2018. 0" << std::endl;
            return 0;
        }
        if (vm.count("help"))
        {
            std::cout << desc << std::endl;
            return 0;
        }
        po::notify(vm);
        if (0 < vm.count("url") && 0 < vm.count("port")){
            std::string const url = vm["url"].as<std::string>();
            int const port = vm["port"].as<int>();
            std::cout << "URL : " << url << "\n" "PORT : " << port << std::endl;
            SetUrl(url.c_str());
            SetPort(port);
        }
    }
    catch (std::exception const & e) {
        std::cerr << e.what() << std::endl;
        return 1;
    }
    for (;;) {
        ShowMotioningText1("MAKERFAIRE2018");
        wave();
        balls();
        gala();
        skewed_sphere();
        threed();
        repbang();
        color_cube();
        spiral();
        cube();
        fireworks();
        brown();
        sphere();
    }
    return 0; // unreachable
}