// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2007-2008 Steven Watanabe
//
// 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/type_traits/is_same.hpp>
#include <boost/mpl/assert.hpp>

#include <boost/units/base_unit.hpp>
#include <boost/units/derived_dimension.hpp>
#include <boost/units/make_system.hpp>
#include <boost/units/operators.hpp>
#include <boost/units/reduce_unit.hpp>
#include <boost/units/unit.hpp>

#include <boost/units/physical_dimensions/current.hpp>
#include <boost/units/physical_dimensions/electric_potential.hpp>
#include <boost/units/physical_dimensions/energy.hpp>
#include <boost/units/physical_dimensions/force.hpp>
#include <boost/units/physical_dimensions/length.hpp>
#include <boost/units/physical_dimensions/mass.hpp>
#include <boost/units/physical_dimensions/time.hpp>

namespace test_system1 {

// the base units in the system will be:
//
// volts  = m^2 kg s^-2 C^-1
// newtons = m kg s^-2
// joules = m^2 kg s^-2

// we will find the representation of m^-1 C^-1 = V N J^-2 = m^-1 C^-1

// reducing the system should generate the matrix equation
//   2   1   2
//   1   1   1  x  = c
//  -2  -2  -2
//  -1   0   0

struct volt : boost::units::base_unit<volt, boost::units::electric_potential_dimension, 1> {};
struct newton : boost::units::base_unit<newton, boost::units::force_dimension, 2> {};
struct joule : boost::units::base_unit<joule, boost::units::energy_dimension, 3> {};

typedef boost::units::make_system<volt, newton, joule>::type complicated_system;

typedef boost::units::derived_dimension<
    boost::units::length_base_dimension, -1,
    boost::units::time_base_dimension, -1,
    boost::units::current_base_dimension, -1
>::type dimension;

typedef boost::units::reduce_unit<boost::units::unit<dimension, complicated_system> >::type reduced;

typedef boost::units::divide_typeof_helper<
    boost::units::multiply_typeof_helper<volt::unit_type, newton::unit_type>::type,
    boost::units::power_typeof_helper<joule::unit_type, boost::units::static_rational<2> >::type
>::type expected;

void test() {
    BOOST_MPL_ASSERT((boost::is_same<reduced, expected>));
}

}

namespace test_system2 {

// the base units in the system will be:
//
// kilograms  = kg
// meters = m

// we will find the representation of m and kg

// reducing the system should generate the matrix equation
//   0   1
//   1   0  x  = c

struct kilogram : boost::units::base_unit<kilogram, boost::units::mass_dimension, 4> {};
struct meter : boost::units::base_unit<meter, boost::units::length_dimension, 5> {};

typedef boost::units::make_system<meter, kilogram>::type mk_system;

typedef boost::units::reduce_unit<boost::units::unit<boost::units::mass_dimension, mk_system> >::type mass_unit;
typedef boost::units::reduce_unit<boost::units::unit<boost::units::length_dimension, mk_system> >::type length_unit;

void test() {
    BOOST_MPL_ASSERT((boost::is_same<mass_unit, kilogram::unit_type>));
    BOOST_MPL_ASSERT((boost::is_same<length_unit, meter::unit_type>));
}

}


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

using namespace xacc::vqe;

TEST(PauliOperatorTester,checkEasy) {

//	CURRENT: (0.25,0) X1 Z2 X3 + (0,0.25) X1 Z2 Y3 + (0.25,0) Y1 Z2 Y3 + (0,-0.25) Y1 Z2 X3
//	SUM: (0,-0.5) Z0 Y1 + (0.5,0) Z0 X1

	PauliOperator op({{1, "X"}, {2, "Z"}, {3,"X"}}, .25);
	op += PauliOperator({{1,"X"}, {2, "Z"}, {3,"Y"}}, std::complex<double>(0,.25));
	op += PauliOperator({{1,"Y"}, {2, "Z"}, {3,"Y"}}, .25);
	op += PauliOperator({{1,"Y"}, {2, "Z"}, {3,"X"}}, std::complex<double>(0,-.25));

	PauliOperator sum({{0,"Z"}, {1, "Y"}}, std::complex<double>(0,-.5));
	sum += PauliOperator({{0, "Z"}, {1,"X"}}, .5);

	std::cout << "PRINT: " << op.toString() << "\n";
	std::cout << "SUM: " << sum.toString() << "\n";

	op *= sum;

	std::cout << "CURRENTMULT: " << op.toString() << "\n";
}
TEST(PauliOperatorTester,checkConstruction) {

	PauliOperator inst({ { 4, "X" },
			{ 3, "Z" }, { 9, "Y" }, { 1, "Z" } });

	std::cout << "PRINT: " << inst.toString() << "\n";

	PauliOperator i2({ { 4, "X" },
			{ 3, "Z" } });
	auto sumInst = inst + i2;
	std::cout << "PRINT: " << sumInst.toString() << "\n";

	PauliOperator expected({{3,"Z"}, {4,"X"}});
	expected += PauliOperator({{1,"Z"}, {3,"Z"},{4,"X"}, {9,"Y"}});
	std::cout << "EXPECTED: " << expected.toString() << "\n";
	EXPECT_TRUE(expected == sumInst);
	EXPECT_TRUE(sumInst == sumInst);

	PauliOperator i3({ { 3, "X" } });
	auto testPauliProducts = i2 * i3;
	std::cout << testPauliProducts.toString() << "\n";

	expected.clear();
	expected += PauliOperator({{3,"Y"},{4,"X"}}, std::complex<double>(0,1));
//	expected.addTerm({{3,"Y"},{4,"X"}}, std::complex<double>(0,1));

	std::cout << "NEWEXPECTED: " << expected.toString() << "\n";
	EXPECT_TRUE(expected == testPauliProducts);

	PauliOperator testEqual({ { 4, "X" },
			{ 3, "Z" } }, std::complex<double>(33.3,0.0));
	EXPECT_TRUE(i2 == testEqual);
	EXPECT_TRUE(i2 != inst);

	// Term * scalar multiple
	auto multScalar = testPauliProducts * 3.3;
	EXPECT_TRUE("(0,3.3) Y3 X4" == multScalar.toString());
	EXPECT_TRUE(PauliOperator( { {3,"Y"}, {4,"X"}}, std::complex<double>(0,3.3)) == multScalar);

	testPauliProducts*=3.3;
	EXPECT_TRUE(testPauliProducts == multScalar);

	// Plus with same terms
	sumInst = inst + 2.2 * inst;
	std::cout << inst.toString() << ", " << (2.2*inst).toString() << ", " << sumInst.toString() << "\n";
	EXPECT_TRUE(PauliOperator( { {1,"Z"}, {3,"Z"}, {4,"X"}, {9,"Y"}}, std::complex<double>(3.2,0)) == sumInst);

	PauliOperator i4( { { 0, "Z" } });
	PauliOperator i6( { { 1, "Y" } }, std::complex<double>(0,1));
	i6 += PauliOperator({{1,"X"}});
	PauliOperator i7( { { 1, "Z" } });

	expected.clear();
	expected += PauliOperator({{0, "Z"}, {1, "Y"}}, std::complex<double>(0,1));
	expected += PauliOperator({{0, "Z"}, {1, "X"}});
//	expected.addTerm({{0, "Z"}, {1, "Y"}}, std::complex<double>(0,1));
//	expected.addTerm({{0, "Z"}, {1, "X"}});

	std::cout << i4.toString() << ", " << i6.toString() << "\nSTARTING:\n";
	auto newMultByComp = i4 * i6;
	std::cout << "ENDED:\nHI: " << newMultByComp.toString() << "\n";
	EXPECT_TRUE(expected == newMultByComp);

	std::cout << "MADE IT HERE\n";
	// Z1 * X1 + i * Z1 * Y1 = i * Y1 + i * (-i * X1)
	newMultByComp = i7 * i6;
	expected.clear();
	expected += PauliOperator({{1,"X"}}) + PauliOperator({{1,"Y"}},std::complex<double>(0,1) );
//	expected.addTerm({{1,"X"}}).addTerm({{1,"Y"}}, std::complex<double>(0,1));

	EXPECT_TRUE(expected == newMultByComp);

}

TEST(PauliOperatorTester,checkVariableCoefficient) {
	// make a4dag a3dag a9 a1
	PauliOperator inst({ { 4, "X" },
			{ 3, "Z" }, }, "theta");
	auto three = 3*inst;
	auto sum = ((inst+inst) + three);
	std::cout << "SUMSTR: " << sum.toString() << "\n";
	EXPECT_TRUE(sum.toString() == "(5,0) theta Z3 X4");

	PauliOperator i2({ { 4, "X" },
			{ 3, "Z" } }, "theta2");

	EXPECT_TRUE(i2 != inst);
	auto sumInst = inst + i2;
	std::cout << "SUMSTR: " << sumInst.toString() << "\n";
	EXPECT_TRUE("(1,0) theta2 Z3 X4 + (1,0) theta Z3 X4" == sumInst.toString());
}

TEST(PauliOperatorTester,checkBinaryVector) {
//	SpinInstruction inst( { { 4, "X" },
//				{ 3, "Z" }, { 9, "Y" }, { 1, "Z" } });
//
//	// This is Z1 Z3 X4 Y9
//
//	auto bv = inst.toBinaryVector(10);
//
//	EXPECT_TRUE(bv.size() == 20);
//
//	std::vector<int> expected(20);
//	expected[4] = 1;
//	expected[9] = 1;
//	expected[19] = 1;
//	expected[13] = 1;
//	expected[11] = 1;
//
//	EXPECT_TRUE(expected == bv);
//
//	SpinInstruction i;
//	std::vector<int> zeros(20);
//	EXPECT_TRUE(zeros == i.toBinaryVector(10));
//
//	i.fromBinaryVector(expected, std::complex<double>(1.0,0.0));
//
//	EXPECT_TRUE(inst.toString() == i.toString());
}

TEST(PauliOperatorTester,checkAction) {

	PauliOperator inst({ { 0, "X" },
					{ 1, "Z" }, { 2, "Y" }, { 3, "Z" } }, std::complex<double>(2.2,0));

	auto result = inst.computeActionOnKet("0110");

	EXPECT_TRUE(result[0].first == "1100");
	EXPECT_TRUE(result[0].second == std::complex<double>(0,2.2));

	std::cout << "HELLO:\n" << result[0].first << ", " << result[0].second << "\n";

	PauliOperator inst2({ { 0, "X" },
					{ 1, "Z" }, { 2, "Y" }, { 3, "Y" } }, std::complex<double>(2.2,0));

	auto result2 = inst2.computeActionOnKet("0110");

	std::cout << "HELLO:\n" << result2[0].first << ", " << result2[0].second << "\n";

	EXPECT_TRUE(result2[0].first == "1101");
	EXPECT_TRUE(result2[0].second == std::complex<double>(-2.2,0));

}

TEST(PauliOperatorTester,checkComplexTerms) {
//	SpinInstruction inst({{1,"X"}, {3,"Y"}, {8,"Z"}}, std::complex<double>(0.5,0.0)),
//			inst2({{1,"Z"}, {3,"X"}, {8,"Z"}}, std::complex<double>(1.2,0.0)),
//			inst3({{1,"Z"}, {3,"Y"}, {9,"Z"}}, std::complex<double>(0.0,1.4)),
//			c({}, std::complex<double>(.25+1.2*1.2, 0.0)
//					+ std::complex<double>(0,1.4)*std::complex<double>(0,1.4)),
//			c2({{1,"Y"},{3,"Z"}}, std::complex<double>(0,2)*std::complex<double>(0,1)*std::complex<double>(.5,0)*std::complex<double>(1.2,0));
//
//	auto op = inst+inst2+inst3;
//
//	auto res = op*op;
//	std::cout << "RES: " << res.toString("") << "\n";
//	res.simplify();
//	std::cout << "Simplified: " << res.toString("") << "\n";
//
//	auto t = c + c2;
//	t.simplify();
//	std::cout << "TSimp: " << t.toString("") << "\n";
//
//	EXPECT_TRUE(t == res);

}

TEST(PauliOperatorTester,checkHelpMe) {

	PauliOperator sum1({ { 0, "X" } },
				std::complex<double>(.5, 0));
	PauliOperator sum2({ { 0, "Y" } },
					std::complex<double>(0, 0.5));
	PauliOperator current1({ { 0, "X" } },
				std::complex<double>(-.62215, 0));
	PauliOperator current2({ { 0, "Y" } },
					std::complex<double>(0, 0.62215));

	PauliOperator sum, current;
	sum += sum1 + sum2;
	current += current1 + current2;

//	UM: (0.5,0) * X0 + (0,0.5) * Y0
//	Current: (-0.62215,0) * X0 + (0,0.62215) * Y0

	std::cout << "SUM: " << sum.toString() << "\n";
	std::cout << "Current: " << current.toString() << "\n";
	auto x = current * sum;

	std::cout << "RESULT: " << x.toString() << "\n";

	std::cout << (std::complex<double>(1,0) * std::complex<double>(0,1)) << "\n";
}

TEST(PauliOperatorTester,checkIdentity) {
	PauliOperator i1(
			std::complex<double>(3.3, 0));
	PauliOperator i2(
			std::complex<double>(5.3, 0));
	PauliOperator compInst;
	compInst += i1;

	compInst = compInst + i2;

	std::cout << "HI: " << compInst.toString() << "\n";
	EXPECT_TRUE("(8.6,0)" == compInst.toString());
	EXPECT_TRUE(PauliOperator(std::complex<double>(8.6,0)) == compInst);
}

TEST(PauliOperatorTester,checkComposition) {
	PauliOperator i1({ { 0, "Z" } });
	PauliOperator i2({ { 1, "X" } });
	PauliOperator i3({ { 1, "Y" } }, std::complex<double>(0,1));
	PauliOperator i4({ { 1, "Z" } });
	PauliOperator i5({ { 1, "Y" } }, std::complex<double>(0,-1));

	PauliOperator compInst, compInst2, compInst3;
	compInst += i2 + i3;

	compInst3 += i2 + i1;

	compInst2 += i2;

	std::complex<double> i(0,1);
	EXPECT_TRUE(compInst == compInst);
	EXPECT_TRUE(compInst != compInst2);
	EXPECT_TRUE(compInst2 == i2);
	EXPECT_TRUE(compInst2 != i1);

	auto multBySpinInst = compInst * i4;
	PauliOperator expected({{1,"X"}}, -1);
	expected += PauliOperator({{1,"Y"}}, -i);
	EXPECT_TRUE(expected == multBySpinInst);

	multBySpinInst = compInst * i1;
	std::cout << "HOWDY: " << multBySpinInst.toString() << "\n";
	expected.clear();
	expected += PauliOperator({{0,"Z"}, {1,"Y"}}, i);
	expected += PauliOperator({{0,"Z"}, {1,"X"}});
	EXPECT_TRUE(expected == multBySpinInst);

	auto multByComposite = compInst * compInst;
	std::cout << "ZERO: " << multByComposite.toString() << "\n";
	EXPECT_TRUE(PauliOperator() == multByComposite);

	auto t = compInst3 * compInst3;
	expected.clear();
	expected += PauliOperator({{0,"Z"}, {1,"X"}}, 2);
	expected += PauliOperator(2);
	EXPECT_TRUE(expected
					== t);

	auto test = compInst * 4.4;
	expected.clear();
	expected += PauliOperator({{1,"X"}}, 4.4);
	expected += PauliOperator({{1,"Y"}}, 4.4*i);
	EXPECT_TRUE(expected == test);

	EXPECT_TRUE(expected == (4.4 * compInst));

	test = compInst * std::complex<double>(4.4, 0);
	EXPECT_TRUE(expected == test);
	EXPECT_TRUE(expected
					== (std::complex<double>(4.4, 0) * compInst));

	// Test Addition now

	auto added = compInst + compInst3;
	expected.clear();
	expected += PauliOperator({{0, "Z"}});
	expected += PauliOperator({{1,"X"}}, 2);
	expected += PauliOperator({{1,"Y"}}, i);

	EXPECT_TRUE(expected == added);
}

TEST(PauliOperatorTester,checkMatrixElements) {
	PauliOperator op({{0, "X"}, {1, "Y"}, {2, "Z"}});
	auto elements = op.getSparseMatrixElements();
}

TEST(PauliOperatorTester,checkFromXACCIR) {

	using namespace xacc;

	xacc::Initialize();
	auto gateRegistry = xacc::getService<IRProvider>("gate");
	auto f = gateRegistry->createFunction("f", {}, {});
	auto f2 = gateRegistry->createFunction("f2", {}, {});

	auto h1 = gateRegistry->createInstruction("H", std::vector<int>{0});
	auto h2 = gateRegistry->createInstruction("H", std::vector<int>{1});
	auto m1 = gateRegistry->createInstruction("Measure", std::vector<int>{0});
	InstructionParameter p(0), p1(1), p2(2);
	m1->setParameter(0, p);
	auto m2 = gateRegistry->createInstruction("Measure", std::vector<int>{1});
	m2->setParameter(0,p1);

	auto m3 = gateRegistry->createInstruction("Measure", std::vector<int>{2});
	m3->setParameter(0,p2);

	f->addInstruction(h1);
	f->addInstruction(h2);
	f->addInstruction(m1);
	f->addInstruction(m2);
	f->addInstruction(m3);

	auto h3 = gateRegistry->createInstruction("H", std::vector<int>{0});
	auto rx = gateRegistry->createInstruction("Rx", std::vector<int>{1});
	InstructionParameter q(3.1415/2.0);
	rx->setParameter(0,q);

	auto m4 = gateRegistry->createInstruction("Measure", std::vector<int>{0});
	InstructionParameter p3(0), p4(1), p5(2);
	m4->setParameter(0, p3);
	auto m5 = gateRegistry->createInstruction("Measure", std::vector<int>{1});
	m5->setParameter(0,p4);

	auto m6 = gateRegistry->createInstruction("Measure", std::vector<int>{2});
	m6->setParameter(0,p5);

	f2->addInstruction(h3);
	f2->addInstruction(rx);
	f2->addInstruction(m4);
	f2->addInstruction(m5);
	f2->addInstruction(m6);

	auto ir = gateRegistry->createIR();
	ir->addKernel(f);
	ir->addKernel(f2);

	PauliOperator op;

	op.fromXACCIR(ir);

	std::cout << "HEY: " << op.toString() << "\n";

	xacc::Finalize();
}

int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
}


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// This file is part of the Boost Graph Library
//
// You should have received a copy of the License Agreement for the
// Boost Graph Library along with the software; see the file LICENSE.
// If not, contact Office of Research, University of Notre Dame, Notre
// Dame, IN 46556.
//
// Permission to modify the code and to distribute modified code is
// granted, provided the text of this NOTICE is retained, a notice that
// the code was modified is included with the above COPYRIGHT NOTICE and
// with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
// file is distributed with the modified code.
//
// LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
// By way of example, but not limitation, Licensor MAKES NO
// REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
// PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
// OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
// OR OTHER RIGHTS.
//=======================================================================
#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <boost/graph/adjacency_list.hpp>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/graph/incremental_components.hpp>

/*

  This example shows how to use the disjoint set data structure
  to compute the connected components of an undirected, changing
  graph.

  Sample output:

  An undirected graph:
  0 <--> 1 4
  1 <--> 0 4
  2 <--> 5
  3 <-->
  4 <--> 1 0
  5 <--> 2

  representative[0] = 1
  representative[1] = 1
  representative[2] = 5
  representative[3] = 3
  representative[4] = 1
  representative[5] = 5

  component 0 contains: 4 1 0
  component 1 contains: 3
  component 2 contains: 5 2

 */

using namespace std;

int main(int , char* [])
{
  using namespace boost;
  typedef adjacency_list <vecS, vecS, undirectedS> Graph;
  typedef graph_traits<Graph>::vertex_descriptor Vertex;
  typedef graph_traits<Graph>::vertices_size_type size_type;

  const int N = 6;
  Graph G(N);

  std::vector<Vertex> rank(num_vertices(G));
  std::vector<Vertex> parent(num_vertices(G));
  // VC++ version of std::vector has no ::pointer, so
  // I use ::value_type* instead.
  typedef std::vector<size_type>::value_type* Rank;
  typedef std::vector<Vertex>::value_type* Parent;
  disjoint_sets<Rank, Parent>  ds(&rank[0], &parent[0]);

  initialize_incremental_components(G, ds);
  incremental_components(G, ds);

  graph_traits<Graph>::edge_descriptor e;
  bool flag;
  boost::tie(e,flag) = add_edge(0, 1, G);
  ds.union_set(0,1);

  boost::tie(e,flag) = add_edge(1, 4, G);
  ds.union_set(1,4);

  boost::tie(e,flag) = add_edge(4, 0, G);
  ds.union_set(4,0);

  boost::tie(e,flag) = add_edge(2, 5, G);
  ds.union_set(2,5);

  cout << "An undirected graph:" << endl;
  print_graph(G, get(vertex_index, G));
  cout << endl;

  graph_traits<Graph>::vertex_iterator i,end;
  for (boost::tie(i, end) = vertices(G); i != end; ++i)
    cout << "representative[" << *i << "] = " <<
      ds.find_set(*i) << endl;;
  cout << endl;

  typedef component_index<unsigned int> Components;
  Components components(&parent[0], &parent[0] + parent.size());

  for (Components::size_type c = 0; c < components.size(); ++c) {
    cout << "component " << c << " contains: ";
    Components::value_type::iterator
      j = components[c].begin(),
      jend = components[c].end();
    for ( ; j != jend; ++j)
      cout << *j << " ";
    cout << endl;
  }

  return 0;
}


//
// Created by asem on 10/02/19.
//

#ifndef MARKOVIAN_FEATURES_RANDOMFORESTMODEL_HPP
#define MARKOVIAN_FEATURES_RANDOMFORESTMODEL_HPP

// STL
#include <variant>

// dlib
#include <dlib/random_forest.h>
#include <dlib/svm.h>
#include <dlib/statistics.h>
#include <dlib/svm_threaded.h>

// local
#include "common.hpp"
#include "SimilarityMetrics.hpp"

struct RandomForestConfiguration
{
    size_t nTrees = 1000;
};

class RandomForestModel
{
    using SampleType = dlib::matrix<double, 0, 1>;
    using Label = double;
    using FeatureExtractor = dlib::dense_feature_extractor;
    using RFTrainer = dlib::random_forest_regression_trainer<FeatureExtractor>;
    using SVMOneVsAllTrainer =  dlib::one_vs_all_trainer<dlib::any_trainer<SampleType>, Label>;
    using DecisionFunction = SVMOneVsAllTrainer::trained_function_type;

public:
    explicit RandomForestModel( RandomForestConfiguration config );

    virtual ~RandomForestModel() = default;

    void fit(
            std::vector<std::string_view> &&labels,
            std::vector<std::vector<double >> &&featuresVector
    );

    ScoredLabels predict( std::vector<double> &&features ) const;

private:
    DecisionFunction _fit(
            std::vector<Label> &&labels,
            std::vector<SampleType> &&samples,
            const RandomForestConfiguration &configuration,
            const std::map<std::string_view, Label> &label2Index
    );

    static SampleType _dlibFeatures( std::vector<double> &&features );

    static std::vector<SampleType> _dlibSamples( std::vector<std::vector<double >> &&features );

    std::vector<Label> _registerLabels( std::vector<std::string_view> &&labels );

private:
    RandomForestConfiguration _config;
    std::set<std::string_view> _labels;
    std::map<std::string_view, Label> _label2Index;
    std::unordered_map<Label, std::string_view> _index2Label;
    DecisionFunction _decisionFunction;
};

#endif //MARKOVIAN_FEATURES_RANDOMFORESTMODEL_HPP


//! \file examples/Arrangement_on_surface_2/overlay_unbounded.cpp
// A face overlay of two arrangements with unbounded faces.

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

#include <CGAL/basic.h>
#include <CGAL/Arr_extended_dcel.h>
#include <CGAL/Arr_overlay_2.h>
#include <CGAL/Arr_default_overlay_traits.h>

#include "arr_linear.h"

// Define a functor for creating a label from a characer and an integer.
struct Overlay_label {
  std::string operator()(char c, unsigned int i) const
  { return c + boost::lexical_cast<std::string>(i); }
};

typedef CGAL::Arr_face_extended_dcel<Traits, char>         Dcel_dlue;
typedef CGAL::Arrangement_2<Traits, Dcel_dlue>             Arrangement_blue;
typedef CGAL::Arr_face_extended_dcel<Traits, unsigned int> Dcel_red;
typedef CGAL::Arrangement_2<Traits, Dcel_red>              Arrangement_red;
typedef CGAL::Arr_face_extended_dcel<Traits, std::string>  Dcel_res;
typedef CGAL::Arrangement_2<Traits, Dcel_res>              Arrangement_res;
typedef CGAL::Arr_face_overlay_traits<Arrangement_blue, Arrangement_red,
                                      Arrangement_res, Overlay_label>
                                                           Overlay_traits;

int main() {
  // Construct the first arrangement, induced by two lines y = x and y = -x.
  Arrangement_blue arr1;
  insert(arr1, Line(Point(0, 0), Point(1, 1)));
  insert(arr1, Line(Point(0, 0), Point(1, -1)));

  // Label the four (unbounded) faces of the arrangement as 'A' to 'D' by
  // traversing the faces incident to the halfedges around the single
  // arrangement vertex (0, 0).
  char clabel = 'A';
  auto first = arr1.vertices_begin()->incident_halfedges();
  auto curr = first;
  do curr->face()->set_data(clabel++);
  while (++curr != first);

  // Construct the second arrangement, containing a single square-shaped face.
  Arrangement_red arr2;
  insert_non_intersecting_curve(arr2, Segment(Point(-3, -3), Point(3, -3)));
  insert_non_intersecting_curve(arr2, Segment(Point(3, -3), Point(3, 3)));
  insert_non_intersecting_curve(arr2, Segment(Point(3, 3), Point(-3, 3)));
  insert_non_intersecting_curve(arr2, Segment(Point(-3, 3), Point(-3, -3)));

  // Give the unbounded face the index 1, and the bounded face the index 2.
  for (auto fit = arr2.faces_begin(); fit != arr2.faces_end(); ++fit)
    fit->set_data((fit == arr2.unbounded_face()) ? 1 : 2);

  // Compute the overlay of the two arrangements.
  Arrangement_res overlay_arr;
  Overlay_traits overlay_traits;
  CGAL::overlay(arr1, arr2, overlay_arr, overlay_traits);

  // Go over the faces of the overlay arrangement and print their labels.
  std::cout << "The overlay faces are:\n";
  for (auto res_fit = overlay_arr.faces_begin();
       res_fit != overlay_arr.faces_end(); ++res_fit)
  {
    std::cout << "  " << res_fit->data().c_str() << " ("
              << (res_fit->is_unbounded() ? "unbounded" : "bounded") << ").\n";
  }
  return 0;
}


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

/*
    Copyright (c) 2020, Klaus Spanderen
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    3. Neither the names of the copyright holders nor the names of the QuantLib
    Group and its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* The class MP_TqrEigenDecomposition is derived from
 * QuantLib's TqrEigenDecomposition class. MPHestonVanillaEngine and HestonCvChF
 * share some code with AnalyticHestonEngine.
 *
 * see http://quantlib.org/license.shtml
 */

/*! \file mphestonengine.cpp
*/

#include <ql/pricingengines/vanilla/mphestonvanillaengine.hpp>
#include <boost/math/distributions/normal.hpp>

namespace QuantLib {

    namespace {
        typedef MPHestonVanillaEngine::MP_Real MP_Real;

        const MP_Real MP_Real_MPI = 1.0/boost::math::constants::pi<MP_Real>();

        class MP_TqrEigenDecomposition {
          public:

            MP_TqrEigenDecomposition(const std::vector<MP_Real>& diag,
                                     const std::vector<MP_Real>& sub)
            : iter_(0),
              d_(diag),
              ev_(d_.size(), 0.0) {
                Size n = diag.size();

                QL_REQUIRE(n == sub.size()+1, "Wrong dimensions");

                std::vector<MP_Real> e(n, 0.0);
                std::copy(sub.begin(),sub.end(),e.begin()+1);

                ev_[0] = 1.0;

                for (Size k=n-1; k >=1; --k) {
                    while (!offDiagIsZero(k, e)) {
                        Size l = k;
                        while (--l > 0 && !offDiagIsZero(l,e));
                        iter_++;

                        MP_Real q = d_[l];
                        // calculated eigenvalue of 2x2 sub matrix of
                        // [ d_[k-1] e_[k] ]
                        // [  e_[k]  d_[k] ]
                        // which is closer to d_[k+1].
                        const MP_Real t1 = sqrt(
                                              0.25*(d_[k]*d_[k] + d_[k-1]*d_[k-1])
                                              - 0.5*d_[k-1]*d_[k] + e[k]*e[k]);
                        const MP_Real t2 = 0.5*(d_[k]+d_[k-1]);

                        const MP_Real lambda =
                            (abs(t2+t1 - d_[k]) < abs(t2-t1 - d_[k]))?
                            MP_Real(t2+t1) : MP_Real(t2-t1);

                        q-=((k==n-1)? 1.25 : 1.0)*lambda;

                        // the QR transformation
                        MP_Real sine = 1.0;
                        MP_Real cosine = 1.0;
                        MP_Real u = 0.0;

                        bool recoverUnderflow = false;
                        for (Size i=l+1; i <= k && !recoverUnderflow; ++i) {
                            const MP_Real h = cosine*e[i];
                            const MP_Real p = sine*e[i];

                            e[i-1] = sqrt(p*p+q*q);
                            if (e[i-1] != MP_Real(0.0)) {
                                sine = p/e[i-1];
                                cosine = q/e[i-1];

                                const MP_Real g = d_[i-1]-u;
                                const MP_Real t = (d_[i]-g)*sine+2*cosine*h;

                                u = sine*t;
                                d_[i-1] = g + u;
                                q = cosine*t - h;

                                const MP_Real tmp = ev_[i-1];
                                ev_[i-1] = sine*ev_[i] + cosine*tmp;
                                ev_[i] = cosine*ev_[i] - sine*tmp;
                            } else {
                                // recover from underflow
                                d_[i-1] -= u;
                                e[l] = 0.0;
                                recoverUnderflow = true;
                            }
                        }

                        if (!recoverUnderflow) {
                            d_[k] -= u;
                            e[k] = q;
                            e[l] = 0.0;
                        }
                    }
                }

                // sort (eigenvalues, eigenvectors),
                // code taken from symmetricSchureDecomposition.cpp
                std::vector<std::pair<MP_Real, MP_Real> > temp(n);
                for (Size i=0; i<n; i++) {
                    temp[i] = std::make_pair(d_[i], ev_[i]);
                }
                std::sort(temp.begin(), temp.end(),
                          std::greater<std::pair<MP_Real, MP_Real> >());
                // first element is positive
                for (Size i=0; i<n; i++) {
                    d_[i] = temp[i].first;
                    if (temp[i].second < MP_Real(0.0))
                        ev_[i] = - temp[i].second;
                    else
                        ev_[i] = temp[i].second;
                }
            }

            const std::vector<MP_Real>& eigenvalues()  const {
                return d_;
            }
            const std::vector<MP_Real>& eigenvectors() const {
                return ev_;
            }

            Size iterations() const { return iter_; }

          private:

            // see NR for abort assumption as it is
            // not part of the original Wilkinson algorithm
            bool offDiagIsZero(Size k, const std::vector<MP_Real>& e) const {
                return abs(d_[k-1])+abs(d_[k])
                    == abs(d_[k-1])+abs(d_[k])+abs(e[k]);
            }

            Size iter_;
            std::vector<MP_Real> d_;
            std::vector<MP_Real> ev_;
        };

        class MP_GausLaguerreQuadrature {
          public:
            MP_GausLaguerreQuadrature(Size n)
            : x_(n), w_(n) {
                std::vector<MP_Real> e(n-1);

                for (Size i=1; i < n; ++i) {
                    e[i-1] = MP_Real(i);
                    x_[i] = 2*e[i-1]+1;
                }
                x_[0] = MP_Real(1.0);

                MP_TqrEigenDecomposition tqr(x_, e);

                x_ = tqr.eigenvalues();
                const std::vector<MP_Real>& ev = tqr.eigenvectors();

                for (Size i=0; i<n; ++i)
                    w_[i] = ev[i]*ev[i] * exp(x_[i]);
            }

            const std::vector<MP_Real>& weights() const { return w_; }
            const std::vector<MP_Real>& x()       const { return x_; }

          protected:
            std::vector<MP_Real> x_, w_;
        };

        class HestonCvChF {
          public:
            HestonCvChF(MP_Real kappa, MP_Real sigma, MP_Real theta,
                        MP_Real rho, MP_Real v0, MP_Real t,
                        MP_Real freq, MP_Real sigmaBS)
            : kappa_(kappa),
              sigma_(sigma), sigma2_(sigma*sigma), invSigma2_(1.0/sigma2_),
              theta_(theta), rho_(rho), v0_(v0), t_(t), freq_(freq),
              sigmaBS_(sigmaBS) {}

            MP_Real operator()(MP_Real u) const {

                const std::complex<MP_Real> z(u, -0.5);
                const std::complex<MP_Real> f(0.0, u*freq_);

                const std::complex<MP_Real> phiBS =
                        std::complex<MP_Real>(-0.5*sigmaBS_*sigmaBS_*t_, 0.0)
                    *(z*z + std::complex<MP_Real>(-z.imag(), z.real()));

                return ((exp(phiBS + f)-exp(lnChF(z) + f))).real()
                        / (u*u + 0.25);
            }

          private:
            std::complex<MP_Real> lnChF(const std::complex<MP_Real>& z) const {
                const std::complex<MP_Real> g
                    (kappa_+std::complex<MP_Real>(rho_*sigma_, 0.0)
                        *std::complex<MP_Real>(z.imag(), -z.real()));

                const std::complex<MP_Real> D( sqrt(
                    g*g + (z*z +
                        std::complex<MP_Real>(-z.imag(), z.real()))*sigma2_));

                const std::complex<MP_Real> G( (g-D)/(g+D) );

                const MP_Real e1(1.0);

                return std::complex<MP_Real>(v0_*invSigma2_, 0.0)
                        *(e1-exp(-D*t_))/(e1-G*exp(-D*t_))*(g-D)
                        + std::complex<MP_Real>(kappa_*theta_*invSigma2_, 0.0)
                            *((g-D)*t_-MP_Real(2.0)*log((e1-G*exp(-D*t_))/(e1-G)));
            }

            const MP_Real kappa_, sigma_, sigma2_, invSigma2_;
            const MP_Real theta_, rho_, v0_, t_, freq_, sigmaBS_;
        };
    }

    MPHestonVanillaEngine::MPHestonVanillaEngine(
          const ext::shared_ptr<HestonModel>& model,Size n)
      : n_(n), model_(model) {
        const MP_GausLaguerreQuadrature q(n_);

        x_ = q.x();
        w_ = q.weights();
    }

    void MPHestonVanillaEngine::calculate() const {
        QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
                   "not an European option");

        const Date maturityDate = arguments_.exercise->lastDate();

        const ext::shared_ptr<PlainVanillaPayoff> payoff =
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
        QL_REQUIRE(payoff, "non plain vanilla payoff given");

        const MP_Real strike = payoff->strike();

        const ext::shared_ptr<HestonProcess> process = model_->process();

        const MP_Real t = process->time(maturityDate);

        const MP_Real rd = process->riskFreeRate()->discount(maturityDate);
        const MP_Real dd = process->dividendYield()->discount(maturityDate);

        const MP_Real spot = process->s0()->value();
        QL_REQUIRE(spot > 0.0, "negative or null underlying given");

        const MP_Real freq = log(spot) - log(rd/dd) - log(strike);

        const MP_Real fwd = spot * dd / rd;

        const MP_Real kappa = model_->kappa();
        const MP_Real sigma = model_->sigma();
        const MP_Real theta = model_->theta();
        const MP_Real rho   = model_->rho();
        const MP_Real v0    = model_->v0();

        const MP_Real vAvg = (1-exp(-kappa*t))*(v0-theta)/(kappa*t) + theta;
        const MP_Real var = vAvg*t;
        const MP_Real sqVar = sqrt(var);

        const MP_Real d1 = (log(fwd/strike) + 0.5*var)/sqVar;
        const MP_Real d2 = d1 - sqVar;

        const boost::math::normal_distribution<MP_Real> n(0.0, 1.0);
        const MP_Real bsPrice =
            rd*(fwd*boost::math::cdf(n, d1)    - strike*boost::math::cdf(n, d2));

        const HestonCvChF helper(
            kappa, sigma, theta, rho, v0, t, freq, sqrt(vAvg));

        MP_Real s = 0.0;
        for (Integer i = x_.size()-1; i >= 0; --i)
            s += w_[i] * helper(x_[i]);

        const MP_Real h_cv = s * sqrt(strike * fwd)*rd * MP_Real_MPI;

        switch (payoff->optionType())
        {
          case Option::Call:
              results_.value = (bsPrice + h_cv).convert_to<Real>();
            break;
          case Option::Put:
              results_.value = (bsPrice + h_cv - rd*(fwd - strike))
                    .convert_to<Real>();
            break;
          default:
            QL_FAIL("unknown option type");
        }
    }
}


/********************************************************************************
*  This file is part of CinoLib                                                 *
*  Copyright(C) 2016: Marco Livesu                                              *
*                                                                               *
*  The MIT License                                                              *
*                                                                               *
*  Permission is hereby granted, free of charge, to any person obtaining a      *
*  copy of this software and associated documentation files (the "Software"),   *
*  to deal in the Software without restriction, including without limitation    *
*  the rights to use, copy, modify, merge, publish, distribute, sublicense,     *
*  and/or sell copies of the Software, and to permit persons to whom the        *
*  Software is furnished to do so, subject to the following conditions:         *
*                                                                               *
*  The above copyright notice and this permission notice shall be included in   *
*  all copies or substantial portions of the Software.                          *
*                                                                               *
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   *
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     *
*  FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. 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.                                                             *
*                                                                               *
*  Author(s):                                                                   *
*                                                                               *
*     Marco Livesu (marco.livesu@gmail.com)                                     *
*     http://pers.ge.imati.cnr.it/livesu/                                       *
*                                                                               *
*     Italian National Research Council (CNR)                                   *
*     Institute for Applied Mathematics and Information Technologies (IMATI)    *
*     Via de Marini, 6                                                          *
*     16149 Genoa,                                                              *
*     Italy                                                                     *
*********************************************************************************/
#include <cinolib/geometry/tetrahedron.h>
#include <cinolib/standard_elements_tables.h>
#include <cinolib/geometry/vec3.h>
#include <cinolib/geometry/segment.h>

#include <Eigen/Dense>
#include <set>

namespace cinolib
{

// http://steve.hollasch.net/cgindex/geometry/ptintet.html
//
CINO_INLINE
bool tet_barycentric_coords(const vec3d & A,
                            const vec3d & B,
                            const vec3d & C,
                            const vec3d & D,
                            const vec3d & P,
                            std::vector<double> & wgts,
                            const double  tol)
{
    wgts = std::vector<double>(4, 0.0);

    //Eigen::Matrix<double,4,4> M;
    //M(0,0) = A[0]; M(0,1) = A[1]; M(0,2) = A[2]; M(0,3) = 1;
    //M(1,0) = B[0]; M(1,1) = B[1]; M(1,2) = B[2]; M(1,3) = 1;
    //M(2,0) = C[0]; M(2,1) = C[1]; M(2,2) = C[2]; M(2,3) = 1;
    //M(3,0) = D[0]; M(3,1) = D[1]; M(3,2) = D[2]; M(3,3) = 1;

    Eigen::Matrix<double,4,4> M0;
    M0(0,0) = P[0]; M0(0,1) = P[1]; M0(0,2) = P[2]; M0(0,3) = 1;
    M0(1,0) = B[0]; M0(1,1) = B[1]; M0(1,2) = B[2]; M0(1,3) = 1;
    M0(2,0) = C[0]; M0(2,1) = C[1]; M0(2,2) = C[2]; M0(2,3) = 1;
    M0(3,0) = D[0]; M0(3,1) = D[1]; M0(3,2) = D[2]; M0(3,3) = 1;

    Eigen::Matrix<double,4,4> M1;
    M1(0,0) = A[0]; M1(0,1) = A[1]; M1(0,2) = A[2]; M1(0,3) = 1;
    M1(1,0) = P[0]; M1(1,1) = P[1]; M1(1,2) = P[2]; M1(1,3) = 1;
    M1(2,0) = C[0]; M1(2,1) = C[1]; M1(2,2) = C[2]; M1(2,3) = 1;
    M1(3,0) = D[0]; M1(3,1) = D[1]; M1(3,2) = D[2]; M1(3,3) = 1;

    Eigen::Matrix<double,4,4> M2;
    M2(0,0) = A[0]; M2(0,1) = A[1]; M2(0,2) = A[2]; M2(0,3) = 1;
    M2(1,0) = B[0]; M2(1,1) = B[1]; M2(1,2) = B[2]; M2(1,3) = 1;
    M2(2,0) = P[0]; M2(2,1) = P[1]; M2(2,2) = P[2]; M2(2,3) = 1;
    M2(3,0) = D[0]; M2(3,1) = D[1]; M2(3,2) = D[2]; M2(3,3) = 1;

    Eigen::Matrix<double,4,4> M3;
    M3(0,0) = A[0]; M3(0,1) = A[1]; M3(0,2) = A[2]; M3(0,3) = 1;
    M3(1,0) = B[0]; M3(1,1) = B[1]; M3(1,2) = B[2]; M3(1,3) = 1;
    M3(2,0) = C[0]; M3(2,1) = C[1]; M3(2,2) = C[2]; M3(2,3) = 1;
    M3(3,0) = P[0]; M3(3,1) = P[1]; M3(3,2) = P[2]; M3(3,3) = 1;

    //double det_M  = M.determinant();
    double det_M0 = M0.determinant();
    double det_M1 = M1.determinant();
    double det_M2 = M2.determinant();
    double det_M3 = M3.determinant();
    double sum    = det_M0 + det_M1 + det_M2 + det_M3;

    if (sum==0) return false; // degenerate

    wgts[0] = det_M0/sum; assert(!std::isnan(wgts[0]));
    wgts[1] = det_M1/sum; assert(!std::isnan(wgts[1]));
    wgts[2] = det_M2/sum; assert(!std::isnan(wgts[2]));
    wgts[3] = det_M3/sum; assert(!std::isnan(wgts[3]));

    for(double w : wgts) if (w < -tol || w > 1.0+tol) return false; // outside
    return true; // inside
}

CINO_INLINE
void tet_closest_vertex(const vec3d  & A,
                        const vec3d  & B,
                        const vec3d  & C,
                        const vec3d  & D,
                        const vec3d  & query,
                              uint   & id,
                              double & dist)
{
    vec3d tet[4] = { A, B, C, D };

    std::set< std::pair<double,int> > sorted_verts;
    for(uint i=0; i<4; ++i)
    {
        sorted_verts.insert(std::make_pair(tet[i].dist(query),i));
    }

    dist = (*sorted_verts.begin()).first;
    id   = (*sorted_verts.begin()).second;
}

CINO_INLINE
void tet_closest_edge(const vec3d  & A,
                      const vec3d  & B,
                      const vec3d  & C,
                      const vec3d  & D,
                      const vec3d  & query,
                            uint   & id,
                            double & dist)
{
    vec3d tet[4] = { A, B, C, D };

    std::set< std::pair<double,uint>> sorted_segs;
    for(uint i=0; i<6; ++i)
    {
        Segment s(tet[TET_EDGES[i][0]], tet[TET_EDGES[i][1]]);
        sorted_segs.insert(std::make_pair(s.dist_to_point(query),i));
    }

    dist = (*sorted_segs.begin()).first;
    id   = (*sorted_segs.begin()).second;
}

}


#include <iostream>
#include <fstream>
#include <ostream>
#include <Eigen/Eigen>
#include "ColorWriter.h"
#include "Ray.h"
#include "HittableList.h"
#include "Sphere.h"
#include "rtUtility.h"
#include "Camera.h"
#include "Material.h"
#include "Lambertian.h"
#include "Metal.h"
#include "Dielectric.h"
#include "Scene.h"

using namespace std;

int main()
{
	// Image
	const auto aspect_ratio = 16.0 / 9.0;
	const int image_width = 1920;
	const int image_height = static_cast<int>(image_width / aspect_ratio);
	const int samplesPerPixel = 50;//多重采样次数
	const int maxDepth = 100;//限制光线着色函数递归次数

	// Open File
	ofstream outfile;
	outfile.open("image.ppm");
	if (outfile)
	{
		cout << "open file success!" << endl;
	}
	else
	{
		cout << "open file failed" << endl;
	}

	//World
	HittableList world;
	world = RandomScene();
 	/*world.add(make_shared<Sphere>(point3(0, 0, -1), 0.5));
 	world.add(make_shared<Sphere>(point3(0, -100.5, -1), 100));*/
	//auto R = cos(PI / 4);

	//Camera
	point3 lookfrom(13, 2, 3);
	point3 lookat(0, 0, 0);
	vec3 vup(0, 1, 0);
	auto dist_to_focus = 10.0;
	auto aperture = 0.1;

	Camera camera(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus);

	//Materials
	//auto materialGround = make_shared<Lambertian>(color3(0.8, 0.8, 0.0));
	//auto materialCenter = make_shared<Lambertian>(color3(0.1, 0.2, 0.5));
	//auto materialLeft = make_shared<Dielectric>(1.5);
	//auto materialRight = make_shared<Metal>(color3(0.8, 0.6, 0.2), 0.0);

	//world.add(make_shared<Sphere>(point3( 0.0, -100.5, -1.0), 100.0, materialGround));
	//world.add(make_shared<Sphere>(point3( 0.0,	  0.0, -1.0),   0.5, materialCenter));
	//world.add(make_shared<Sphere>(point3(-1.0,    0.0, -1.0),   0.5, materialLeft));
	//world.add(make_shared<Sphere>(point3(-1.0,    0.0, -1.0),  -0.4, materialLeft));
	//world.add(make_shared<Sphere>(point3( 1.0,    0.0, -1.0),   0.5, materialRight));

	//auto materialLeft = make_shared<Lambertian>(color3(0, 0, 1));
	//auto materialRight = make_shared<Lambertian>(color3(1, 0, 0));

	//world.add(make_shared<Sphere>(point3(-R, 0, -1), R, materialLeft));
	//world.add(make_shared<Sphere>(point3( R, 0, -1), R, materialRight));

	// Render
	outfile << "P3\n" << image_width << ' ' << image_height << "\n255\n";
	for (int j = image_height - 1; j >= 0; --j)
	{
		cerr << "\rScanlines remaining: " << j << ' ' << flush;
		for (int i = 0; i < image_width; ++i)
		{
			color3 pixel_color(0.0, 0.0, 0.0);
			for (int s = 0; s < samplesPerPixel; ++s)
			{
				auto u = (i + RandomDouble()) / (double(image_width) - 1);
				auto v = (j + RandomDouble()) / (double(image_height) - 1);
				u = Clamp(u, 0.0, 1.0);
				v = Clamp(v, 0.0, 1.0);
				Ray ray = camera.GetRay(u,v);
				pixel_color += ColorWriter::RayColor2(ray, world, maxDepth);
			}
			ColorWriter::WriteColor(outfile, pixel_color, samplesPerPixel);
		}
	}
	cerr << "\nDone.\n";
	system("pause");
	return 0;
}


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

//<include> please don't modify between these tags
#include <boost/simd/toolbox/arithmetic/include/functions/fast_toint.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/negs.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/divround.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/divfloor.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/divfix.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/divceil.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/random.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/logical_xor.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/ifloor.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/fast_hypot.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/iround.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/arg.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/sqrt1pm1.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/remainder.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/rem.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/mod.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/remquo.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/minmod.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/iceil.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/trunc.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/ceil.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/round.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/floor.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/two_split.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/two_prod.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/two_add.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/rsqrt.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/sqrt.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/sqr.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/rec.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/rdivide.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/oneplus.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/oneminus.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/minusone.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/min.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/max.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/madd.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/ldivide.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/ldiv.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/idivround.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/idivfloor.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/idivfix.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/idivceil.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/hypot.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/fma.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/fam.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/dist.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/correct_fma.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/average.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/amul.hpp>
#include <boost/simd/toolbox/arithmetic/include/functions/abs.hpp>
//<\include>

#endif


#include "../sigma.h"
#include "../sigmadb.h"
#include "../sigmaprimitives.h"

#include "../../test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

#include <stddef.h>
#include <vector>

namespace exodus {
namespace {

struct SigmaDatabaseFixture : TestingSetup
{
    SigmaDatabaseFixture()
    {
        sigmaDb = new SigmaDatabase(pathTemp / "exodus-sigmadb", true, 10);
    }

    ~SigmaDatabaseFixture()
    {
        delete sigmaDb; sigmaDb = nullptr;
    }
};

SigmaPublicKey CreateMint()
{
    SigmaPrivateKey key;
    key.Generate();
    return SigmaPublicKey(key, DefaultSigmaParams);
}

std::vector<SigmaPublicKey> CreateMints(size_t n)
{
    std::vector<SigmaPublicKey> mints;

    while (n--) {
        mints.push_back(CreateMint());
    }

    return mints;
}

} // unnamed namespace

BOOST_AUTO_TEST_SUITE(exodus_sigma_tests)

BOOST_FIXTURE_TEST_CASE(verify_spend, SigmaDatabaseFixture)
{
    auto& params = DefaultSigmaParams;
    SigmaPrivateKey key;
    SigmaProof proof(params);
    std::vector<SigmaPublicKey> anonimitySet;
    bool increaseBlock = false;
    int block = 100;

    // Create set of mint that contains our spendable mint.
    key.Generate();

    anonimitySet.push_back(SigmaPublicKey(key, params));

    for (auto& mint : CreateMints(sigmaDb->groupSize - 2)) { // -2 to make anonimitySet not a full group.
        anonimitySet.push_back(mint);
    }

    proof.Generate(key, anonimitySet.begin(), anonimitySet.end(), false);

    // Generate spendable group.
    for (unsigned i = 0; i < sigmaDb->groupSize; i++) {
        if (i < anonimitySet.size()) {
            sigmaDb->RecordMint(3, 0, anonimitySet[i], block);
        } else {
            sigmaDb->RecordMint(3, 0, CreateMint(), block);
        }

        sigmaDb->RecordMint(3, 1, CreateMint(), block);
        sigmaDb->RecordMint(4, 0, CreateMint(), block);

        if (increaseBlock) {
            block++;
            increaseBlock = false;
        } else {
            increaseBlock = true;
        }
    }

    // Generate non-spendable group.
    for (auto& mint : CreateMints(sigmaDb->groupSize)) {
        sigmaDb->RecordMint(3, 0, mint, block);
    }

    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size(), proof, false), true);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() - 1, proof, false), false);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() + 1, proof, false), false);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, sigmaDb->groupSize + 1, proof, false), false);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 1, 0, sigmaDb->groupSize, proof, false), false);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(4, 0, 0, sigmaDb->groupSize, proof, false), false);
    BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 1, sigmaDb->groupSize, proof, false), false);
}

BOOST_AUTO_TEST_SUITE_END()

} // namespace exodus


#pragma once
#include<cstddef>

/** @file GaussKronrod.hpp
 * @brief
 * @author C.D. Clark III
 * @date 05/25/20
 */

#include <boost/math/quadrature/gauss_kronrod.hpp>

namespace _1D
{
namespace Boost
{
  /**
   * A wrapper around the Boost.Math gauss_kronrob function
   */
template<typename T, std::size_t Order>
class GaussKronrodQuadrature{
  public:

    template<typename F>
    auto operator()(F f, T a, T b, unsigned max_depth, T tol, T* error, T* pL1) const -> T
    {
      return boost::math::quadrature::gauss_kronrod<T,Order>::integrate(f,a,b,max_depth,tol,error,pL1);
    }

    template<typename F>
    auto operator()(F f, T a, T b) const -> T
    {
      return boost::math::quadrature::gauss_kronrod<T,Order>::integrate(f,a,b);
    }

};
}  // namespace boost
}  // namespace _1D


/**
 * \brief Test the gradient of shape functions via the numerical volume
 *        integration.
 *
 * \copyright
 * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 *  \file
 *  Created on July 14, 2017, 10:08 AM
 */

#include <gtest/gtest.h>

#include <Eigen/Eigen>
#include <cmath>
#include <vector>

#include "FeTestData/TestFeHEX20.h"
#include "FeTestData/TestFeHEX8.h"
#include "FeTestData/TestFeLINE2.h"
#include "FeTestData/TestFeLINE2Y.h"
#include "FeTestData/TestFeLINE3.h"
#include "FeTestData/TestFePRISM15.h"
#include "FeTestData/TestFePRISM6.h"
#include "FeTestData/TestFePYRA13.h"
#include "FeTestData/TestFePYRA5.h"
#include "FeTestData/TestFeQUAD4.h"
#include "FeTestData/TestFeQUAD8.h"
#include "FeTestData/TestFeQUAD9.h"
#include "FeTestData/TestFeTET10.h"
#include "FeTestData/TestFeTET4.h"
#include "FeTestData/TestFeTRI3.h"
#include "FeTestData/TestFeTRI6.h"
#include "MeshLib/CoordinateSystem.h"
#include "MeshLib/ElementCoordinatesMappingLocal.h"
#include "NumLib/Fem/CoordinatesMapping/ShapeMatrices.h"
#include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h"
#include "NumLib/Fem/InitShapeMatrices.h"
#include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h"
#include "NumLib/Fem/ShapeMatrixPolicy.h"
#include "Tests/TestTools.h"

using namespace NumLib;
using namespace FeTestData;

namespace
{
// test cases
template <class TestFeType_, template <typename, int> class ShapeMatrixPolicy_>
struct TestCase
{
    using TestFeType = TestFeType_;
    static const int GlobalDim = TestFeType::global_dim;
    using ShapeMatrixTypes =
        ShapeMatrixPolicy_<typename TestFeType::ShapeFunction, GlobalDim>;
    template <typename X>
    using ShapeMatrixPolicy = ShapeMatrixPolicy_<X, GlobalDim>;
};

using TestTypes =
    ::testing::Types<TestCase<TestFeHEX8, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeHEX20, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeLINE2, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeLINE2Y, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeLINE3, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFePRISM6, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFePRISM15, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFePYRA5, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFePYRA13, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeQUAD4, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeQUAD8, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeQUAD9, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeTET4, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeTET10, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeTRI3, EigenDynamicShapeMatrixPolicy>,
                     TestCase<TestFeTRI6, EigenDynamicShapeMatrixPolicy>,

                     TestCase<TestFeHEX8, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeHEX20, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeLINE2, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeLINE2Y, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeLINE3, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFePRISM6, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFePRISM15, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFePYRA5, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFePYRA13, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeQUAD4, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeQUAD8, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeQUAD9, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeTET4, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeTET10, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeTRI3, EigenFixedShapeMatrixPolicy>,
                     TestCase<TestFeTRI6, EigenFixedShapeMatrixPolicy>>;
}  // namespace

template <class T>
class GradShapeFunctionTest : public ::testing::Test, public T::TestFeType
{
public:
    using ShapeMatrixTypes = typename T::ShapeMatrixTypes;
    using TestFeType = typename T::TestFeType;

    // Finite element type
    template <typename X>
    using ShapeMatrixPolicy = typename T::template ShapeMatrixPolicy<X>;
    using MeshElementType = typename TestFeType::MeshElementType;

    static const int dim = TestFeType::dim;
    static const unsigned e_nnodes = TestFeType::e_nnodes;
    static const unsigned n_sample_pt_order2 = TestFeType::n_sample_pt_order2;
    static const unsigned n_sample_pt_order3 = TestFeType::n_sample_pt_order3;

    using IntegrationMethod = typename NumLib::GaussLegendreIntegrationPolicy<
        MeshElementType>::IntegrationMethod;

public:
    GradShapeFunctionTest()
        : integration_method(3),
          element_volume(this->getVolume()),
          mesh_element(this->createMeshElement())
    {
        // only for destructor because class element has nodes in pointer type.
        vec_eles.push_back(mesh_element);
        for (auto e : vec_eles)
        {
            for (unsigned i = 0; i < e->getNumberOfNodes(); i++)
            {
                vec_nodes.push_back(e->getNode(i));
            }
        }
    }

    ~GradShapeFunctionTest() override
    {
        for (auto itr = vec_nodes.begin(); itr != vec_nodes.end(); ++itr)
        {
            delete *itr;
        }
        for (auto itr = vec_eles.begin(); itr != vec_eles.end(); ++itr)
        {
            delete *itr;
        }
    }

    IntegrationMethod integration_method;

    const double element_volume;
    MeshElementType* mesh_element;

    std::vector<const MeshLib::Node*> vec_nodes;
    std::vector<const MeshElementType*> vec_eles;

    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
};  // NumLibFemIsoTest

template <class T>
const int GradShapeFunctionTest<T>::dim;

template <class T>
const unsigned GradShapeFunctionTest<T>::e_nnodes;

template <class T>
const unsigned GradShapeFunctionTest<T>::n_sample_pt_order2;

template <class T>
const unsigned GradShapeFunctionTest<T>::n_sample_pt_order3;

TYPED_TEST_SUITE(GradShapeFunctionTest, TestTypes);

TYPED_TEST(GradShapeFunctionTest,
           CheckGradShapeFunctionByComputingElementVolume)
{
    auto const shape_matrices =
        NumLib::initShapeMatrices<typename TestFixture::ShapeFunction,
                                  typename TestFixture::ShapeMatrixTypes,
                                  TestFixture::global_dim,
                                  ShapeMatrixType::N_J>(
            *this->mesh_element, false /*is_axially_symmetric*/,
            this->integration_method);

    // Compute element volume numerically as V_e = int {1}dA_e
    double computed_element_volume = 0.;
    for (std::size_t i = 0; i < this->integration_method.getNumberOfPoints();
         i++)
    {
        auto const& shape = shape_matrices[i];
        auto wp = this->integration_method.getWeightedPoint(i);
        computed_element_volume += shape.detJ * wp.getWeight();
    }

    ASSERT_NEAR(this->element_volume, computed_element_volume, 1.e-11);
}


/*
 * Copyright (c) 2021, Tetsuro Nagai
 */

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <cstring>
#include <cassert>
#include <string>
#include <iomanip>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <prettyprint.hpp>
#include "time_string.hpp"

constexpr double kB=1.380649e-23  ;
constexpr double NA=6.02214076e23 ;
constexpr double kB_kJ_per_mol=kB*NA/1000 ;
constexpr int BUF_MAX=100000;

constexpr int DIM_HIST=3 ;

using std::string;
using std::vector;
using std::array;
using std::cout;
using std::cerr;
using std::endl;
namespace po=boost::program_options;

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

  string starting_date;
  misc::put_string_of_time(starting_date);
  cout << "Execution start at " << starting_date <<endl;

  //get command line argments
  double min[DIM_HIST],max[DIM_HIST],dx[DIM_HIST], T;
  string fout_prefix;
  bool bStrict;

  // making command line options
  po::options_description opt("generic histogram and free energy. Data should be supplemented from the standard input; the first and second columns will be analysed.");
  opt.add_options()
    ("help,h" ,                                                   "show help")
    ("dx"     ,      po::value<double>()->default_value(0.1),    "dx, width of histogram")
    ("minx"     ,    po::value<double>()->default_value(-10),    "minx of histogram")
    ("maxx"     ,    po::value<double>()->default_value(10),     "maxx of histogram")
    ("dy"     ,      po::value<double>()->default_value(0.1),    "dy, width of histogram")
    ("miny"     ,    po::value<double>()->default_value(-10),    "miny of histogram")
    ("maxy"     ,    po::value<double>()->default_value(10),     "maxy of histogram")
    ("dz"     ,      po::value<double>()->default_value(0.1),    "dz, width of histogram")
    ("minz"     ,    po::value<double>()->default_value(-10),    "minz of histogram")
    ("maxz"     ,    po::value<double>()->default_value(10),     "maxz of histogram")
    ("T"     ,       po::value<double>()->default_value(300),     "temperature for free energy convertion")
    ("bStrictOutOfRange"   , po::value<bool>()->default_value(false),     "if true, abort when a sample out of min and max is found")
    ("fout_prefix",  po::value<string>(),                         "fout_prefix, a number of files will be made with this prefix");

  // analyze argc and argv and results are stored in vm
  try{
    po::variables_map vm;
    store(parse_command_line(argc, argv, opt), vm);
    notify(vm);
    if(vm.count("help")){
      cout << opt << endl; // show help
      exit(1);
    }
    else if(!vm.count("fout_prefix")){
      cerr << vm.count("fout_prefix") << endl;
      cerr << "fout_prefix is mandatory " << endl;
      cerr << "exit!!" << endl;
      exit(1);
    }
    else
    {
      dx[0]  = vm["dx"].as<double>();
      min[0] = vm["minx"].as<double>();
      max[0] = vm["maxx"].as<double>();
      dx[1]  = vm["dy"].as<double>();
      min[1] = vm["miny"].as<double>();
      max[1] = vm["maxy"].as<double>();
      dx[2]  = vm["dz"].as<double>();
      min[2] = vm["minz"].as<double>();
      max[2] = vm["maxz"].as<double>();
      T = vm["T"].as<double>();
      bStrict = vm["bStrictOutOfRange"].as<bool>();
      fout_prefix = vm["fout_prefix"].as<string>();
		}
	}
  catch (boost::bad_any_cast &e) {
    cout << e.what() << endl;
  	cout <<"something wrong and buggy happend!!"  << endl;
  	cout <<"exit!!"  << endl;
  	exit(1);
  }
  catch (std::exception  &e) {
    cout << e.what() << endl;
    cout <<"exit!!"  << endl;
    exit(2);
  }

  cout << "**** Input parameters ****"  << endl;
  cout << "dx: " << dx[0] << endl;
  cout << "minx: " << min[0] << endl;
  cout << "maxx: " << max[0] << endl;
  cout << "dy: " << dx[1] << endl;
  cout << "miny: " << min[1] << endl;
  cout << "maxy: " << max[1] << endl;
  cout << "dz: " << dx[2] << endl;
  cout << "minz: " << min[2] << endl;
  cout << "maxz: " << max[2] << endl;
  cout << "T: " << T << endl;
  cout << "bStrictOutOfRange: " << bStrict << endl;
  cout << "fout_prefix: " << fout_prefix << endl;
  cout << "*************************\n"  << endl;

	const string fname_hist = fout_prefix+"_hist.dat";
	const string fname_FE   = fout_prefix+"_free_energy.dat";

  cout << "Files to be created: " << fname_hist << endl;
  cout << "Files to be created: " << fname_FE  << endl;

  std::ofstream ofs_hist(fname_hist.c_str());
  std::ofstream ofs_FE(fname_FE.c_str());

  if(!ofs_hist){
    cerr << "cannot open " << fname_hist << endl;
    return -1;
  }
  if(!ofs_FE){
    cerr << "cannot open " << fname_FE << endl;
    return -1;
  }

  for(int i=0; i<DIM_HIST; i++){
    if(max[i]<=min[i]){
      cout << boost::format("ERROR: max < min for %2d-th dimenstion") % i <<endl;
      cerr << boost::format("ERROR: max < min for %2d-th dimenstion") % i <<endl;
      cout << boost::format("I am exitting.") % i <<endl;
      cerr << boost::format("I am exitting.") % i <<endl;
      return -1;
    }
  }

  const int  nbins[DIM_HIST] = {(int)std::ceil((max[0]-min[0])/dx[0]), (int)std::ceil((max[1]-min[1])/dx[1]), (int)std::ceil((max[2]-min[2])/dx[2])};
  vector<vector<double> >  edges;
  vector< vector< vector<int>>>  counts(nbins[0],vector<vector<int>>(nbins[1],vector<int>(nbins[2],0)));
  vector< vector<vector<double>>> pdf(nbins[0],vector<vector<double>>(nbins[1],vector<double>(nbins[2], 0.0)));
  vector<vector<vector<double>>> free_energy(nbins[0],vector<vector<double>>(nbins[1],vector<double>(nbins[2], 0.0)));

  edges.push_back(vector<double>(nbins[0],0));
  edges.push_back(vector<double>(nbins[1],0));
  edges.push_back(vector<double>(nbins[2],0));
  for (int i = 0 ; i < DIM_HIST; i++){
    for (int j = 0 ; j < nbins[i]+1; j++){
      edges[i][j] = min[i] + dx[i]*j ;
    }
  }

  cout << "**** parameters determined ****"  << endl;
  cout << "nbins_x: " << nbins[0] <<endl;
  cout << "nbins_y: " << nbins[1] <<endl;
  cout << "nbins_z: " << nbins[2] <<endl;
  cout << "edges_x: " << edges[0] <<endl;
  cout << "edges_y: " << edges[1] <<endl;
  cout << "edges_z: " << edges[2] <<endl;
  cout << "*******************************"  << endl;

  double val[DIM_HIST];
  string buf;
  char tmp[DIM_HIST][BUF_MAX/3];
  char* err[DIM_HIST];

  auto get_ibin = [](double val,double min, double dx){return std::floor((val-min)/dx);};
  int ibin[DIM_HIST];

  while (std::getline(std::cin, buf))
  {
    auto bsscanf = std::sscanf(buf.c_str(), "%s %s %s" , tmp[0],tmp[1] ,tmp[2] );
    if(bsscanf != DIM_HIST){
        cout << "ERROR: not enough columns\n" << "Exit!!" <<endl;
        cerr << "ERROR: not enough columns\n" << "Exit!!" <<endl;
        return -1;
    }

    for(int i=0; i<DIM_HIST; i++){
      val[i]=std::strtod(tmp[i], &err[i]);
      if(*err[i]!='\0'){
        cout << "error to convert: " << tmp[i] << "in line "<<buf <<"\nExit!!" <<endl;
        cerr << "error to convert: " << tmp[i] << "in line "<<buf <<"\nExit!!" <<endl;
        return -1;
      }
    }

    for(int i=0; i<DIM_HIST; i++){
      ibin[i] = get_ibin(val[i],min[i],dx[i]);
      if(val[i] < min[i]){
        cout << "min is too large: set min < " << val[i] << endl;
        cerr << "min is too large: set min < " << val[i] << endl;
        ibin[i] = 0;
        if(bStrict){
          cout << "As bStrictOutOfRange is on, abort at parsing: " << buf << endl;
          cerr << "As bStrictOutOfRange is on, abort at parsing: " << buf << endl;
          return -1;
        }
      }
      if(val[i] >= max[i]){
        cout << "max is too small: set max > " << val[i] << endl;
        cerr << "max is too small: set max > " << val[i] << endl;
        ibin[i] = nbins[i]-1;
        if(bStrict){
          cout << "As bStrictOutOfRange is on, abort at parsing: " << buf << endl;
          cerr << "As bStrictOutOfRange is on, abort at parsing: " << buf << endl;
          return -1;
        }
      }
    }
    counts[ibin[0]][ibin[1]][ibin[2]]++;
  }

  int ncounts = 0;
  for(const auto  &v1: counts){
    for(const auto &v2: v1){
      for(const auto &v3: v2){
        ncounts+=v3;
      }
    }
  }

  cout << boost::format("In total, %d samples have been considered.") % ncounts << endl;

  for(int i=0; i < nbins[0]; i++){
    for(int j=0; j < nbins[1]; j++){
      for(int k=0; k < nbins[2]; k++){
        pdf[i][j][k] = counts[i][j][k]/double(ncounts)/(dx[0]*dx[1]*dx[2]);
        free_energy[i][j][k] = -kB_kJ_per_mol*T*std::log(pdf[i][j][k]);
      }
    }
  }

  double min_free_energy = free_energy[0][0][0];
  for(const auto  &v1: free_energy){
    for(const auto &v2: v1){
      for(const auto &v3: v2){
        min_free_energy=std::min(min_free_energy, v3);
      }
    }
  }

  for(auto  &v1: free_energy){
    for(auto &v2: v1){
      for(auto &v3: v2){
        v3 -= min_free_energy;
      }
    }
  }

  cout << counts << endl;
  cout << free_energy << endl;

  for(int i= 0; i<nbins[0];i++){
    for(int j= 0; j<nbins[1];j++){
      for(int k= 0; k<nbins[2];k++){
        ofs_hist << boost::format("%10.5f %10.5f %10.5f %12.6g %12d\n") % (edges[0][i]+0.5*dx[0]) % (edges[1][j]+0.5*dx[1]) % (edges[2][k]+0.5*dx[2]) % pdf[i][j][k]  %counts[i][j][k] ;
        ofs_FE   << boost::format("%10.5f %10.5f %10.5f %12.6g\n")      % (edges[0][i]+0.5*dx[0]) % (edges[1][j]+0.5*dx[1]) % (edges[2][k]+0.5*dx[2]) % free_energy[i][j][k] ;
      }
    }
  }
  ofs_hist.close();
  ofs_FE.close();

  return EXIT_SUCCESS ;
}


// Copyright 2018 The Simons Foundation, Inc. - All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef NETKET_HEISENBERG_HPP
#define NETKET_HEISENBERG_HPP

#include <mpi.h>
#include <Eigen/Dense>
#include <iostream>
#include <vector>
#include "abstract_hamiltonian.hpp"

namespace netket {

// Heisenberg model on an arbitrary graph
template <class G>
class Heisenberg : public AbstractHamiltonian {
  const int nspins_;
  double offdiag_;

  const G &graph_;

  // list of bonds for the interaction part
  std::vector<std::vector<int>> bonds_;

  int mynode_;

  /**
    Hilbert space descriptor for this hamiltonian.
  */
  Hilbert hilbert_;

 public:
  explicit Heisenberg(const G &graph) : graph_(graph), nspins_(graph.Nsites()) {
    Init();
  }

  // Json constructor
  explicit Heisenberg(const G &graph, const json &pars)
      : nspins_(graph.Nsites()), graph_(graph) {
    Init();

    if (FieldExists(pars["Hamiltonian"], "TotalSz")) {
      double totalsz = pars["Hamiltonian"]["TotalSz"];
      SetTotalSz(totalsz);
    }
  }

  void Init() {
    if (graph_.IsBipartite()) {
      offdiag_ = -2;
    } else {
      offdiag_ = 2;
    }

    GenerateBonds();

    // Specifying the hilbert space
    json hil;
    hil["Hilbert"]["Name"] = "Spin";
    hil["Hilbert"]["Nspins"] = nspins_;
    hil["Hilbert"]["S"] = 0.5;

    hilbert_.Init(hil);

    MPI_Comm_rank(MPI_COMM_WORLD, &mynode_);

    if (mynode_ == 0) {
      std::cout << "# Heisenberg model created " << std::endl;
    }
  }

  void SetTotalSz(double totalSz) {
    json hil;
    hil["Hilbert"]["Name"] = "Spin";
    hil["Hilbert"]["Nspins"] = nspins_;
    hil["Hilbert"]["S"] = 0.5;
    hil["Hilbert"]["TotalSz"] = totalSz;

    hilbert_.Init(hil);
  }

  void GenerateBonds() {
    auto adj = graph_.AdjacencyList();

    bonds_.resize(nspins_);

    for (int i = 0; i < nspins_; i++) {
      for (auto s : adj[i]) {
        if (s > i) {
          bonds_[i].push_back(s);
        }
      }
    }
  }

  void FindConn(const Eigen::VectorXd &v,
                std::vector<std::complex<double>> &mel,
                std::vector<std::vector<int>> &connectors,
                std::vector<std::vector<double>> &newconfs) const override {
    connectors.clear();
    connectors.resize(1);
    newconfs.clear();
    newconfs.resize(1);
    mel.resize(1);

    // computing interaction part Sz*Sz
    mel[0] = 0.;
    connectors[0].resize(0);
    newconfs[0].resize(0);

    for (int i = 0; i < nspins_; i++) {
      for (auto bond : bonds_[i]) {
        // interaction part
        mel[0] += v(i) * v(bond);

        // spin flips
        if (v(i) != v(bond)) {
          connectors.push_back(std::vector<int>({i, bond}));
          newconfs.push_back(std::vector<double>({v(bond), v(i)}));
          mel.push_back(offdiag_);
        }
      }
    }
  }

  const Hilbert &GetHilbert() const override { return hilbert_; }
};

}  // namespace netket

#endif


#include "zinfandel.h"

#include "parse_args.h"
#include "tensorOps.h"
#include "threads.h"

#include <Eigen/SVD>
#include <complex>

// Helper Functions
Eigen::MatrixXcf GrabSources(
    Cx3 const &ks,
    float const scale,
    long const n_src,
    long const s_read,
    long const n_read,
    std::vector<long> const &spokes)
{
  assert((s_read + n_read + n_src) < ks.dimension(1));
  long const n_chan = ks.dimension(0);
  long const n_spoke = spokes.size();
  Eigen::MatrixXcf S(n_chan * n_src, n_read * n_spoke);
  S.setZero();
  for (long i_spoke = 0; i_spoke < n_spoke; i_spoke++) {
    long const col_spoke = i_spoke * n_read;
    long const ind_spoke = spokes[i_spoke];
    assert(ind_spoke < ks.dimension(2));
    for (long i_read = 0; i_read < n_read; i_read++) {
      long const col = col_spoke + i_read;
      for (long i_coil = 0; i_coil < n_chan; i_coil++) {
        long const row_coil = i_coil * n_src;
        for (long i_src = 0; i_src < n_src; i_src++) {
          long const row = row_coil + i_src;
          S(row, col) = ks(i_coil, s_read + i_read + i_src, ind_spoke) / scale;
        }
      }
    }
  }
  return S;
}

Eigen::MatrixXcf GrabTargets(
    Cx3 const &ks,
    float const scale,
    long const s_read,
    long const n_read,
    std::vector<long> const &spokes)
{
  long const n_chan = ks.dimension(0);
  long const n_spoke = spokes.size();
  Eigen::MatrixXcf T(n_chan, n_read * n_spoke);
  T.setZero();
  for (long i_spoke = 0; i_spoke < n_spoke; i_spoke++) {
    long const col_spoke = i_spoke * n_read;
    long const ind_spoke = spokes[i_spoke];
    for (long i_read = 0; i_read < n_read; i_read++) {
      long const col = col_spoke + i_read;
      for (long i_coil = 0; i_coil < n_chan; i_coil++) {
        T(i_coil, col) = ks(i_coil, s_read + i_read, ind_spoke) / scale;
      }
    }
  }
  return T;
}

Eigen::MatrixXcf
CalcWeights(Eigen::MatrixXcf const &src, Eigen::MatrixXcf const tgt, float const lambda)
{
  if (lambda > 0.f) {
    auto const reg = lambda * src.norm() * Eigen::MatrixXcf::Identity(src.rows(), src.rows());
    auto const rhs = src * src.adjoint() + reg;
    Eigen::MatrixXcf pinv = rhs.completeOrthogonalDecomposition().pseudoInverse();
    return tgt * src.adjoint() * pinv;
  } else {
    Eigen::MatrixXcf const pinv = src.completeOrthogonalDecomposition().pseudoInverse();
    return tgt * pinv;
  }
}

std::vector<long>
FindClosest(R3 const &traj, long const &tgt, long const &n_spoke, std::vector<long> &all_spokes)
{
  std::vector<long> spokes(n_spoke);
  R1 const end_is = traj.chip(tgt, 2).chip(traj.dimension(1) - 1, 1);
  std::partial_sort(
      all_spokes.begin(),
      all_spokes.begin() + n_spoke,
      all_spokes.end(),
      [&traj, end_is](long const a, long const b) {
        auto const &end_a = traj.chip(a, 2).chip(traj.dimension(1) - 1, 1);
        auto const &end_b = traj.chip(b, 2).chip(traj.dimension(1) - 1, 1);
        return Norm(end_a - end_is) < Norm(end_b - end_is);
      });
  std::copy_n(all_spokes.begin(), n_spoke, spokes.begin());
  return spokes;
}

// Actual calculation
void zinfandel(
    long const gap_sz,
    long const n_src,
    long const n_spoke,
    long const n_read1,
    float const lambda,
    R3 const &traj,
    Cx3 &ks,
    Log &log)
{
  long const n_read = n_read1 < 1 ? ks.dimension(1) - (gap_sz + n_src) : n_read1;

  log.info(
      FMT_STRING("ZINFANDEL Gap {} Sources {} Cal Spokes/Read {}/{} "),
      gap_sz,
      n_src,
      n_spoke,
      n_read);

  for (long ig = gap_sz; ig > 0; ig--) {
    auto spoke_task = [&](long const spoke_lo, long const spoke_hi) {
      std::vector<long> all_spokes(ks.dimension(2)); // Need a thread-local copy of the indices
      std::iota(all_spokes.begin(), all_spokes.end(), 0L);
      for (auto is = spoke_lo; is < spoke_hi; is++) {
        float const scale = R0(ks.chip(is, 2).abs().maximum())();
        auto const spokes = FindClosest(traj, is, n_spoke, all_spokes);
        auto const calS = GrabSources(ks, scale, n_src, ig + 1, n_read, spokes);
        auto const calT = GrabTargets(ks, scale, ig, n_read, spokes);
        auto const W = CalcWeights(calS, calT, lambda);
        auto const S = GrabSources(ks, scale, n_src, ig, 1, {is});
        auto const T = W * S;
        for (long icoil = 0; icoil < ks.dimension(0); icoil++) {
          ks(icoil, ig - 1, is) = T(icoil) * scale;
        }
      }
    };
    Threads::RangeFor(spoke_task, 0, ks.dimension(2));
  }
}


#ifndef INTEGRATOR_CHAINS_PROBLEM_H
#define INTEGRATOR_CHAINS_PROBLEM_H

#include <vector>
#include <list>
#include <sstream>
#include <iomanip>
#include <string>
#include <cstdlib>

#include <Eigen/Dense>

#include "polytope.hpp"

namespace integrator_chains {

/** Representation of problem instances.

    \ingroup integrator_chains */
class Problem {
public:
    Eigen::VectorXd Xinit;
    Polytope *Y;
    Polytope *U;
    std::vector<LabeledPolytope *> goals;
    std::vector<LabeledPolytope *> obstacles;

    double period;

    Problem();
    ~Problem();

    bool is_consistent() const;

    /** Create formula using SPIN LTL syntax <http://spinroot.com/spin/Man/ltl.html>.
       Support for other syntax is coming soon. */
    void to_formula( std::ostream &out ) const;

    /* Change the number of dimensions of output or the order of the
       differential operator (i.e., the number of integrators). Return True on
       success, False otherwise, such as if one of the numbers is negative.

       This method only changes the internal values corresponding to
       numdim_output and highest_order_deriv but not any of the other parts of
       this problem instance. As such, it is possible to have an inconsistent
       instance after this call. (Try is_consistent() to check.) */
    bool change_order( int new_numdim_output , int new_highest_order_deriv );

    /** Output description of problem in JSON to a stream */
    friend std::ostream & operator<<( std::ostream &out, const Problem &prob );

    /** Get description of problem in JSON. */
    std::string dumpJSON() const;

    /** Generate a random problem instance.

       \param numdim_output_bounds range of integers from which the dimension of
       the output space will be chosen.

       \param highest_order_deriv_bounds range of integers from which the order
       of derivation (i.e., the number of integrators in the ODE defining the
       system) will be chosen.

       \param Y_box the compact subset of the output space in which the
       trajectory must remain, defined using the same format as for
       Polytope::box(). Unlike most other parameters of this method, \p Y_box is
       not a definition of the support of  a probability density
       function. However, the number of elements in it that are actually used
       depends on the randomly chosen number of dimensions of the output space.

       \param U_box analogous to \p Y_box but for the input space.

       \param number_goals_bounds range of integers from which the number of
       goal polytopes in the output space will be chosen.

       \param number_obstacles_bounds analogous to \p number_goals_bounds but
       for obstacles.

       \param period_bounds range from which is uniformly randomly chosen the
       constant period by which the original system is discretized.

       \param Xinit_bounds (optional) the box from which the initial state will
       be chosen. It is assumed to be consistent with \p Y_box. Bounds for
       missing dimensions are assumed to be [0,0], i.e., Xinit is assigned 0.0
       at the corresponding indices. E.g., if Xinit_bounds has size 0 or is not
       given, then Xinit is the origin of the state space.

       N.B., several parameters depend on each other in terms of consistency.
       E.g., if \p numdim_output_bounds = [2, 3], then Y_box must have length of
       at least 6 (cf. documentation for Polytope::box()).

       This method relies on rand() for pseudo-randomness and assumes that
       something else has seeded the RNG. */
    static Problem * random( const Eigen::Vector2i &numdim_output_bounds,
                             const Eigen::Vector2i &highest_order_deriv_bounds,
                             const Eigen::VectorXd &Y_box,
                             const Eigen::VectorXd &U_box,
                             const Eigen::Vector2i &number_goals_bounds,
                             const Eigen::Vector2i &number_obstacles_bounds,
                             const Eigen::Vector2d &period_bounds,
                             const Eigen::VectorXd &Xinit_bounds = Eigen::VectorXd() );

    int get_numdim_output() const
    { return numdim_output; }
    int get_highest_order_deriv() const
    { return highest_order_deriv; }

private:
    int numdim_output;
    int highest_order_deriv;
    static std::string int_to_str( int x, int zero_padding=0 );
};

std::string Problem::int_to_str( int x, int zero_padding )
{
    std::ostringstream out;
    if (zero_padding > 0)
        out << std::setfill('0') << std::setw( zero_padding );
    out << x;
    return out.str();
}

Problem::Problem()
    : numdim_output(0), highest_order_deriv(0), Y(nullptr), U(nullptr)
{ }

Problem::~Problem()
{
    if (Y)
        delete Y;
    if (U)
        delete U;
    for (int i = 0; i < goals.size(); i++)
        delete goals[i];
    for (int i = 0; i < obstacles.size(); i++)
        delete obstacles[i];
}

bool Problem::change_order( int new_numdim_output , int new_highest_order_deriv )
{
    if (new_numdim_output < 0 || new_highest_order_deriv < 0)
        return false;

    numdim_output = new_numdim_output;
    highest_order_deriv = new_highest_order_deriv;

    return true;
}

std::ostream & operator<<( std::ostream &out, const Problem &prob )
{
    out << "{" << std::endl << "\"version\": " << 0 << "," << std::endl;
    out << "\"Xinit\": [";
    for (int i = 0; i < prob.Xinit.size(); i++) {
        if (i > 0)
            out << ", ";
        out << prob.Xinit(i);
    }
    out << "]," << std::endl;
    out << "\"goals\": [" << std::endl;
    for (int i = 0; i < prob.goals.size(); i++) {
        if (i > 0)
            out << ", ";
        out << *prob.goals[i];
        out << std::endl;
    }
    out << "]," << std::endl;
    out << "\"obstacles\": [";
    for (int i = 0; i < prob.obstacles.size(); i++) {
        if (i > 0)
            out << ", ";
        out << *prob.obstacles[i];
        out << std::endl;
    }
    out << "]," << std::endl;
    out << "\"Y\": ";
    if (prob.Y) {
        out << *prob.Y;
    } else {
        out << "null";
    }
    out << "," << std::endl;
    out << "\"U\": ";
    if (prob.U) {
        out << *prob.U;
    } else {
        out << "null";
    }
    out << "," << std::endl;
    out << "\"period\": " << prob.period;
    out << std::endl << " }";
    return out;
}

std::string Problem::dumpJSON() const
{
    std::ostringstream out;
    out << *this;
    return out.str();
}

Problem * Problem::random( const Eigen::Vector2i &numdim_output_bounds,
                           const Eigen::Vector2i &highest_order_deriv_bounds,
                           const Eigen::VectorXd &Y_box,
                           const Eigen::VectorXd &U_box,
                           const Eigen::Vector2i &number_goals_bounds,
                           const Eigen::Vector2i &number_obstacles_bounds,
                           const Eigen::Vector2d &period_bounds,
                           const Eigen::VectorXd &Xinit_bounds )
{
    assert( numdim_output_bounds(0) >= 1
            && numdim_output_bounds(0) <= numdim_output_bounds(1)
            && highest_order_deriv_bounds(0) >= 1
            && highest_order_deriv_bounds(0) <= highest_order_deriv_bounds(1)
            && number_goals_bounds(0) >= 0
            && number_goals_bounds(0) <= number_goals_bounds(1)
            && number_obstacles_bounds(0) >= 0
            && number_obstacles_bounds(0) <= number_obstacles_bounds(1)
            && Y_box.size() >= 2*numdim_output_bounds(1)
            && U_box.size() >= 2*numdim_output_bounds(1)
            && period_bounds(0) >= 0 && period_bounds(1) >= period_bounds(0) );

    int i, j;
    Problem *prob = new Problem;

    prob->numdim_output = numdim_output_bounds(0);
    if (numdim_output_bounds(1) != numdim_output_bounds(0))
        prob->numdim_output += (std::rand()
                                % (1+numdim_output_bounds(1)
                                   - numdim_output_bounds(0)));

    prob->highest_order_deriv = highest_order_deriv_bounds(0);
    if (highest_order_deriv_bounds(1) != highest_order_deriv_bounds(0))
        prob->highest_order_deriv += (std::rand()
                                      % (1+highest_order_deriv_bounds(1)
                                         - highest_order_deriv_bounds(0)));

    int number_goals = number_goals_bounds(0);
    if (number_goals_bounds(1) != number_goals_bounds(0))
        number_goals += (std::rand()
                         % (1+number_goals_bounds(1)
                            - number_goals_bounds(0)));

    int number_obstacles = number_obstacles_bounds(0);
    if (number_obstacles_bounds(1) != number_obstacles_bounds(0))
        number_obstacles += (std::rand()
                         % (1+number_obstacles_bounds(1)
                            - number_obstacles_bounds(0)));

    prob->Y = Polytope::box( Y_box.head( 2*prob->numdim_output ) );
    prob->U = Polytope::box( U_box.head( 2*prob->numdim_output ) );

    prob->Xinit.setZero( prob->numdim_output*prob->highest_order_deriv );
    int largest_dim = prob->numdim_output*prob->highest_order_deriv;
    if (largest_dim > Xinit_bounds.size()/2)
        largest_dim = Xinit_bounds.size()/2;
    for (i = 0; i < largest_dim; i++) {
        assert( Xinit_bounds(2*i+1) >= Xinit_bounds(2*i) );
        prob->Xinit(i) = Xinit_bounds(2*i);
        if (Xinit_bounds(2*i+1) != Xinit_bounds(2*i))
            prob->Xinit(i) += (double(std::rand())/RAND_MAX)*(Xinit_bounds(2*i+1) - Xinit_bounds(2*i));
    }

    Eigen::VectorXd box_bounds(2*prob->numdim_output);
    prob->goals.resize( number_goals );
    for (i = 0; i < number_goals; i++) {
        for (j = 0; j < prob->numdim_output; j++) {
            box_bounds(2*j) = Y_box(2*j)
                + (double(std::rand())/RAND_MAX)*(Y_box(2*j+1) - Y_box(2*j));
            box_bounds(2*j+1) = Y_box(2*j)
                + (double(std::rand())/RAND_MAX)*(Y_box(2*j+1) - Y_box(2*j));
            if (box_bounds(2*j+1) < box_bounds(2*j)) {
                double tmp = box_bounds(2*j+1);
                box_bounds(2*j+1) = box_bounds(2*j);
                box_bounds(2*j) = tmp;
            }
        }
        prob->goals[i] = LabeledPolytope::box( box_bounds,
                                               std::string("goal_") + int_to_str(i) );
    }
    prob->obstacles.resize( number_obstacles );
    for (i = 0; i < number_obstacles; i++) {
        for (j = 0; j < prob->numdim_output; j++) {
            box_bounds(2*j) = Y_box(2*j)
                + (double(std::rand())/RAND_MAX)*(Y_box(2*j+1) - Y_box(2*j));
            box_bounds(2*j+1) = Y_box(2*j)
                + (double(std::rand())/RAND_MAX)*(Y_box(2*j+1) - Y_box(2*j));
            if (box_bounds(2*j+1) < box_bounds(2*j)) {
                double tmp = box_bounds(2*j+1);
                box_bounds(2*j+1) = box_bounds(2*j);
                box_bounds(2*j) = tmp;
            }
        }
        prob->obstacles[i] = LabeledPolytope::box( box_bounds,
                                                   std::string("obstacle_") + int_to_str(i) );
    }

    prob->period = period_bounds(0);
    if (period_bounds(1) != period_bounds(0))
        prob->period += double(std::rand())/RAND_MAX*(period_bounds(1) - period_bounds(0));

    return prob;
}

void Problem::to_formula( std::ostream &out ) const
{
    if (obstacles.size() > 0) {
        out << "[]!(";
        for (int i = 0; i < obstacles.size(); i++) {
            if (i > 0)
                out << " || ";
            out << obstacles[i]->label;
        }
        out << ")";
    }
    if (goals.size() > 0) {
        if (obstacles.size() > 0)
            out << " && ";

        for (int i = 0; i < goals.size(); i++) {
            if (i > 0)
                out << " && ";
            out << "([]<> " << goals[i]->label << ")";
        }
    }
}

/** \ingroup integrator_chains */
class Labeler {
public:
    Labeler();

    /* importProblem() is called as part of instantiation. */
    Labeler( const Problem &probinstance );

    bool importProblem( const Problem &probinstance, bool check_collisions=true );
    std::list<std::string> get_label( const Eigen::VectorXd &X );
    void clear();

private:
    std::vector<LabeledPolytope *> regions;
};

Labeler::Labeler()
    : regions()
{ }

Labeler::Labeler( const Problem &probinstance )
{
    importProblem( probinstance, false );
}

bool Labeler::importProblem( const Problem &probinstance, bool check_collisions )
{
    int i, j;
    bool no_collisions = true;
    for (i = 0; i < probinstance.goals.size(); i++) {
        if (!check_collisions) {
            regions.push_back( probinstance.goals[i] );
        } else {
            for (j = 0; j < regions.size(); j++) {
                if (regions[j]->label == probinstance.goals[i]->label) {
                    std::cerr << "WARNING: Labeler found a collision while importing from Problem object." << std::endl;
                    no_collisions = false;
                    break;
                }
            }
            if (j >= regions.size())
                regions.push_back( probinstance.goals[i] );
        }
    }
    for (i = 0; i < probinstance.obstacles.size(); i++) {
        if (!check_collisions) {
            regions.push_back( probinstance.obstacles[i] );
        } else {
            for (j = 0; j < regions.size(); j++) {
                if (regions[j]->label == probinstance.obstacles[i]->label) {
                    std::cerr << "WARNING: Labeler found a collision while importing from Problem object." << std::endl;
                    no_collisions = false;
                    break;
                }
            }
            if (j >= regions.size())
                regions.push_back( probinstance.obstacles[i] );
        }
    }
    return no_collisions;
}

std::list<std::string> Labeler::get_label( const Eigen::VectorXd &X )
{
    std::list<std::string> label;
    for (int i = 0; i < regions.size(); i++) {
        if (regions[i]->is_in( X ))
            label.push_back( regions[i]->label );
    }
    return label;
}

void Labeler::clear()
{
    regions.clear();
}

} // namespace integrator_chains

#endif  // ifndef PROBLEM_H


#pragma once
#include <Eigen/Core>
#include <Eigen/Geometry>

namespace bear {

struct ListenerImpl {
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  // position of the listener relative to the origin
  // position_rel_listener = position_rel_origin - position
  Eigen::Vector3d position = {0, 0, 0};
  // translate from world coordinates to listener coordinates
  // position_rel_listener = orientation * position
  // position = orientation' * position_rel_listener
  //
  // beware: Eigen::Quaterniond constructor is {w, x, y, z} but coefficients
  // are stored as {x, y, z, w}!
  Eigen::Quaterniond orientation = {1, 0, 0, 0};

  Eigen::Vector3d look() const { return orientation.conjugate() * Eigen::Vector3d{0.0, 1.0, 0.0}; }
  Eigen::Vector3d right() const { return orientation.conjugate() * Eigen::Vector3d{1.0, 0.0, 0.0}; }
  Eigen::Vector3d up() const { return orientation.conjugate() * Eigen::Vector3d{0.0, 0.0, 1.0}; }
};

bool listeners_approx_equal(const ListenerImpl &a, const ListenerImpl &b);

}  // namespace bear


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

#include <nt2/core/functions/issquare.hpp>
#include <nt2/include/functions/ismatrix.hpp>
#include <nt2/include/functions/extent.hpp>
#include <boost/fusion/include/at.hpp>

namespace nt2 { namespace ext
{
  NT2_FUNCTOR_IMPLEMENTATION( nt2::tag::issquare_, tag::cpu_
                            , (A0)
                            , (unspecified_<A0>)
                            )
  {
    typedef bool result_type;

    BOOST_DISPATCH_FORCE_INLINE result_type operator()(const A0& a0) const
    {
      typename meta::call<tag::extent_(A0 const&)>::type ex = nt2::extent(a0);
      //std::size_t nz = nt2::numel(ex);

      return  ismatrix(a0)
          &&  (boost::fusion::at_c<0>(ex) == boost::fusion::at_c<1>(ex));
    }
  };
} }

#endif


#ifdef CANNON_BUILD_GRAPHICS

#include <cmath>

#include <Eigen/Dense>
#include <GLFW/glfw3.h>

#include <cannon/log/registry.hpp>

#include <cannon/plot/plotter.hpp>
#include <cannon/plot/line.hpp>
#include <cannon/plot/scatter.hpp>

#include <cannon/ml/rls.hpp>

using namespace cannon::plot;
using namespace cannon::log;
using namespace cannon::ml;

int main() {
  Plotter plotter(true);

  // Initial line
  MatrixX2f pts(2, 2);
  pts <<  -1.0, 0.0,
          1.0, 0.0;

  std::shared_ptr<Line> l = plotter.plot_line(pts, Vector4f(0.0, 0.0, 0.0, 1.0));
  std::shared_ptr<Scatter> s = plotter.plot_points(pts, Vector4f(1.0, 0.0, 0.0, 1.0), 15.0);

  plotter.set_xlim(-2.0, 2.0);
  plotter.set_ylim(-2.0, 2.0);

  float t_delta = 1.0 / 24.0;
  float last_time = 0.0;

  RLSFilter f(1, 1);

  plotter.render([&f, &l, &s, &t_delta, &last_time] {
      float t = (float)glfwGetTime();
      if (t < last_time + t_delta) {
        return;
      }

      VectorXd x = VectorXd::Random(1);
      VectorXd y = 2.0 * x + VectorXd::Random(1);
      MatrixX2f new_pt(1, 2);
      new_pt << x[0], y[0];

      f.process_datum(x, y);
      s->add_points(new_pt);

      VectorXd tmp_x1(1);
      tmp_x1 << -2.0;
      VectorXd tmp_x2(1);
      tmp_x2 << 2.0;

      float x1 = -2.0;
      float y1 = f.predict(tmp_x1)[0];
      float x2 = 2.0;
      float y2 = f.predict(tmp_x2)[0];

      MatrixX2f new_pts(2, 2);
      new_pts << x1, y1,
                 x2, y2;
      l->replace_points(new_pts);

      last_time = t;
      });
}
#else
int main() {}
#endif