#include <gtest/gtest.h>
#include "../util/util.h"
#include <Eigen/Core>
#include <string>
#include <algorithm>

#ifndef _MSC_VER
extern "C" {
#include <csim/memory_ops.h>
#include <csim/stat_ops.h>
#include <csim/update_ops.h>
#include <csim/init_ops.h>
}
#else
#include <csim/memory_ops.h>
#include <csim/stat_ops.h>
#include <csim/update_ops.h>
#include <csim/init_ops.h>
#endif
#include <csim/update_ops_cpp.hpp>

void test_single_dense_matrix_gate(std::function<void(UINT, const CTYPE*, CTYPE*, ITYPE)> func) {
	const UINT n = 6;
	const ITYPE dim = 1ULL << n;
	const UINT max_repeat = 10;

	Eigen::Matrix<std::complex<double>, 2, 2, Eigen::RowMajor> U;

	UINT target;

	auto state = allocate_quantum_state(dim);
	initialize_Haar_random_state(state, dim);
	Eigen::VectorXcd test_state = Eigen::VectorXcd::Zero(dim);
	for (ITYPE i = 0; i < dim; ++i) test_state[i] = state[i];

	Eigen::MatrixXcd whole_I = Eigen::MatrixXcd::Identity(dim, dim);

	for (UINT rep = 0; rep < max_repeat; ++rep) {
		// single qubit dense matrix gate
		// NOTE: Eigen uses column major by default. To use raw-data of eigen matrix, we need to specify RowMajor.
		target = rand_int(n);
		U = get_eigen_matrix_random_single_qubit_unitary();
		func(target, (CTYPE*)U.data(), state, dim);
		test_state = get_expanded_eigen_matrix_with_identity(target, U, n) * test_state;
		state_equal(state, test_state, dim, "single dense gate");
	}
	release_quantum_state(state);
}

TEST(UpdateTest, SingleDenseMatrixTest) {
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate);
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_single);
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_single_unroll);
#ifdef _OPENMP
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_parallel);
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_parallel_unroll);
#endif
#ifdef _USE_SIMD
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_single_simd);
#ifdef _OPENMP
	test_single_dense_matrix_gate(single_qubit_dense_matrix_gate_parallel_simd);
#endif
#endif
}

void test_general_dense_matrix_gate(std::function<void(const UINT*, UINT, const CTYPE*, CTYPE*, ITYPE)> func) {
	const UINT n = 6;
	const ITYPE dim = 1ULL << n;
	const UINT max_repeat = 10;

	std::vector<UINT> index_list;
	for (UINT i = 0; i < n; ++i) index_list.push_back(i);

	Eigen::Matrix<std::complex<double>, 2, 2, Eigen::RowMajor> U1, U2, U3;
	UINT targets[3];

	auto state = allocate_quantum_state(dim);
	initialize_Haar_random_state(state, dim);
	Eigen::VectorXcd test_state = Eigen::VectorXcd::Zero(dim);
	for (ITYPE i = 0; i < dim; ++i) test_state[i] = state[i];

	Eigen::MatrixXcd whole_I = Eigen::MatrixXcd::Identity(dim, dim);

	// general single
	{
		Eigen::Matrix<std::complex<double>, 2,2, Eigen::RowMajor> Umerge;
		for (UINT rep = 0; rep < max_repeat; ++rep) {

			// two qubit dense matrix gate
			U1 = get_eigen_matrix_random_single_qubit_unitary();
			std::random_shuffle(index_list.begin(), index_list.end());
			targets[0] = index_list[0];
			Umerge = U1;

			test_state = get_expanded_eigen_matrix_with_identity(targets[0], U1, n)
				* test_state;
			func(targets, 1, (CTYPE*)Umerge.data(), state, dim);
			state_equal(state, test_state, dim, "single-qubit separable dense gate");
		}
	}
	// general double
	{
		Eigen::Matrix<std::complex<double>, 4,4, Eigen::RowMajor> Umerge;

		for (UINT rep = 0; rep < max_repeat; ++rep) {

			// two qubit dense matrix gate
			U1 = get_eigen_matrix_random_single_qubit_unitary();
			U2 = get_eigen_matrix_random_single_qubit_unitary();

			std::random_shuffle(index_list.begin(), index_list.end());
			targets[0] = index_list[0];
			targets[1] = index_list[1];
			Umerge = kronecker_product(U2, U1);

			test_state =
				get_expanded_eigen_matrix_with_identity(targets[1], U2, n)
				* get_expanded_eigen_matrix_with_identity(targets[0], U1, n)
				* test_state;
			func(targets, 2, (CTYPE*)Umerge.data(), state, dim);
			state_equal(state, test_state, dim, "two-qubit separable dense gate");
		}
	}
	// general triple
	{
		Eigen::Matrix<std::complex<double>, 8, 8, Eigen::RowMajor> Umerge;

		for (UINT rep = 0; rep < max_repeat; ++rep) {

			// two qubit dense matrix gate
			U1 = get_eigen_matrix_random_single_qubit_unitary();
			U2 = get_eigen_matrix_random_single_qubit_unitary();
			U3 = get_eigen_matrix_random_single_qubit_unitary();

			std::random_shuffle(index_list.begin(), index_list.end());
			targets[0] = index_list[0];
			targets[1] = index_list[1];
			targets[2] = index_list[2];
			Umerge = kronecker_product(U3, kronecker_product(U2, U1));

			test_state =
				get_expanded_eigen_matrix_with_identity(targets[2], U3, n)
				* get_expanded_eigen_matrix_with_identity(targets[1], U2, n)
				* get_expanded_eigen_matrix_with_identity(targets[0], U1, n)
				* test_state;
			func(targets, 3, (CTYPE*)Umerge.data(), state, dim);
			state_equal(state, test_state, dim, "three-qubit separable dense gate");
		}
	}
	release_quantum_state(state);
}

TEST(UpdateTest, ThreeQubitDenseMatrixTest) {
	test_general_dense_matrix_gate(multi_qubit_dense_matrix_gate);
	test_general_dense_matrix_gate(multi_qubit_dense_matrix_gate_single);
#ifdef _OPENMP
	test_general_dense_matrix_gate(multi_qubit_dense_matrix_gate_parallel);
#endif
}


///////////////////////////////////////////////////////////////////////////////
// sum_kahan.hpp
//
//  Copyright 2010 Gaetano Mendola, 2011 Simon West. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010
#define BOOST_ACCUMULATORS_STATISTICS_SUM_KAHAN_HPP_EAN_26_07_2010

#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/statistics_fwd.hpp>
#include <boost/accumulators/statistics/sum.hpp>
#include <boost/accumulators/statistics/weighted_sum_kahan.hpp>
#include <boost/numeric/conversion/cast.hpp>

namespace boost { namespace accumulators
{

namespace impl
{

#if _MSC_VER > 1400
# pragma float_control(push)
# pragma float_control(precise, on)
#endif

template<typename Sample, typename Tag>
struct sum_kahan_impl
  : accumulator_base
{
    typedef Sample result_type;

    ////////////////////////////////////////////////////////////////////////////
    // sum_kahan_impl
    /**
        @brief Kahan summation algorithm

        The Kahan summation algorithm reduces the numerical error obtained with standard
        sequential sum.

    */
    template<typename Args>
    sum_kahan_impl(Args const & args)
      : sum(args[parameter::keyword<Tag>::get() | Sample()]),
        compensation(boost::numeric_cast<Sample>(0.0))
    {
    }

    template<typename Args>
    void
#if BOOST_ACCUMULATORS_GCC_VERSION > 40305
    __attribute__((optimize("no-associative-math")))
#endif
    operator ()(Args const & args)
    {
        const Sample myTmp1 = args[parameter::keyword<Tag>::get()] - this->compensation;
        const Sample myTmp2 = this->sum + myTmp1;
        this->compensation = (myTmp2 - this->sum) - myTmp1;
        this->sum = myTmp2;
    }

    result_type result(dont_care) const
    {
      return this->sum;
    }

private:
    Sample sum;
    Sample compensation;
};

#if _MSC_VER > 1400
# pragma float_control(pop)
#endif

} // namespace impl

///////////////////////////////////////////////////////////////////////////////
// tag::sum_kahan
// tag::sum_of_weights_kahan
// tag::sum_of_variates_kahan
//
namespace tag
{

    struct sum_kahan
      : depends_on<>
    {
        /// INTERNAL ONLY
        ///
        typedef impl::sum_kahan_impl< mpl::_1, tag::sample > impl;
    };

    struct sum_of_weights_kahan
      : depends_on<>
    {
        typedef mpl::true_ is_weight_accumulator;
        /// INTERNAL ONLY
        ///
        typedef accumulators::impl::sum_kahan_impl<mpl::_2, tag::weight> impl;
    };

    template<typename VariateType, typename VariateTag>
    struct sum_of_variates_kahan
      : depends_on<>
    {
        /// INTERNAL ONLY
        ///
        typedef mpl::always<accumulators::impl::sum_kahan_impl<VariateType, VariateTag> > impl;
    };

} // namespace tag

///////////////////////////////////////////////////////////////////////////////
// extract::sum_kahan
// extract::sum_of_weights_kahan
// extract::sum_of_variates_kahan
//
namespace extract
{
    extractor<tag::sum_kahan> const sum_kahan = {};
    extractor<tag::sum_of_weights_kahan> const sum_of_weights_kahan = {};
    extractor<tag::abstract_sum_of_variates> const sum_of_variates_kahan = {};

    BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_kahan)
    BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_weights_kahan)
    BOOST_ACCUMULATORS_IGNORE_GLOBAL(sum_of_variates_kahan)
} // namespace extract

using extract::sum_kahan;
using extract::sum_of_weights_kahan;
using extract::sum_of_variates_kahan;

// sum(kahan) -> sum_kahan
template<>
struct as_feature<tag::sum(kahan)>
{
    typedef tag::sum_kahan type;
};

// sum_of_weights(kahan) -> sum_of_weights_kahan
template<>
struct as_feature<tag::sum_of_weights(kahan)>
{
    typedef tag::sum_of_weights_kahan type;
};

// So that sum_kahan can be automatically substituted with
// weighted_sum_kahan when the weight parameter is non-void.
template<>
struct as_weighted_feature<tag::sum_kahan>
{
    typedef tag::weighted_sum_kahan type;
};

template<>
struct feature_of<tag::weighted_sum_kahan>
  : feature_of<tag::sum>
{};

// for the purposes of feature-based dependency resolution,
// sum_kahan provides the same feature as sum
template<>
struct feature_of<tag::sum_kahan>
  : feature_of<tag::sum>
{
};

// for the purposes of feature-based dependency resolution,
// sum_of_weights_kahan provides the same feature as sum_of_weights
template<>
struct feature_of<tag::sum_of_weights_kahan>
  : feature_of<tag::sum_of_weights>
{
};

template<typename VariateType, typename VariateTag>
struct feature_of<tag::sum_of_variates_kahan<VariateType, VariateTag> >
  : feature_of<tag::abstract_sum_of_variates>
{
};

}} // namespace boost::accumulators

#endif


///////////////////////////////////////////////////////////////////////////////
//  Copyright Christopher Kormanyos 2015.
//  Copyright Nikhar Agrawal 2015.
//  Copyright Paul Bristow 2015.
//  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)

//! \file
//!\brief Tests for exp(fixed_point) round::nearest_even.

#define BOOST_TEST_MODULE test_negatable_func_exp_nearest_even
#define BOOST_LIB_DIAGNOSTIC

#include <cmath>

#include <boost/fixed_point/fixed_point.hpp>
#include <boost/test/included/unit_test.hpp>

namespace local
{
  template<typename FixedPointType>
  const FixedPointType& tolerance_maker(const int fuzzy_bits)
  {
    static const FixedPointType the_tolerance = ldexp(FixedPointType(1), FixedPointType::resolution + fuzzy_bits);

    return the_tolerance;
  }

  template<typename FixedPointType,
           typename FloatPointType = typename FixedPointType::float_type>
  void test_exp(const int fuzzy_bits)
  {
    // Use at least 8 resolution bits.
    // Use at least 7 range bits.

    BOOST_STATIC_ASSERT(-FixedPointType::resolution >= 8);
    BOOST_STATIC_ASSERT( FixedPointType::range      >= 7);

    const FixedPointType a1(+1L    );                                       const FloatPointType b1(+1L    );
    const FixedPointType a2(+2L    );                                       const FloatPointType b2(+2L    );
    const FixedPointType a3(+4.375L);                                       const FloatPointType b3(+4.375L);
    const FixedPointType a4(+1.125L);                                       const FloatPointType b4(+1.125L);
    const FixedPointType a5(-1.125L);                                       const FloatPointType b5(-1.125L);
    const FixedPointType a6(+0.875L);                                       const FloatPointType b6(+0.875L);
    const FixedPointType a7(FixedPointType( 1) /  3);                       const FloatPointType b7(FloatPointType( 1) /  3);
    const FixedPointType a8(FixedPointType(11) / 10);                       const FloatPointType b8(FloatPointType(11) / 10);
    const FixedPointType a9(boost::math::constants::phi<FixedPointType>()); const FloatPointType b9(boost::math::constants::phi<FloatPointType>());

    using std::exp;

    BOOST_CHECK_CLOSE_FRACTION(exp(a1), FixedPointType(exp(b1)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a2), FixedPointType(exp(b2)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a3), FixedPointType(exp(b3)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a4), FixedPointType(exp(b4)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a5), FixedPointType(exp(b5)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a6), FixedPointType(exp(b6)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a7), FixedPointType(exp(b7)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a8), FixedPointType(exp(b8)), tolerance_maker<FixedPointType>(fuzzy_bits));
    BOOST_CHECK_CLOSE_FRACTION(exp(a9), FixedPointType(exp(b9)), tolerance_maker<FixedPointType>(fuzzy_bits));
  }
}

BOOST_AUTO_TEST_CASE(test_negatable_func_exp_nearest_even)
{
  // Test exp() for negatable round::nearest_even in various key digit
  // regions such as 16, 24, 32, 53, 64, 113.

  { typedef boost::fixed_point::negatable< 7,   -8, boost::fixed_point::round::nearest_even> fixed_point_type; local::test_exp<fixed_point_type>( 4); }
  { typedef boost::fixed_point::negatable< 7,  -24, boost::fixed_point::round::nearest_even> fixed_point_type; local::test_exp<fixed_point_type>( 6); }
  { typedef boost::fixed_point::negatable<10, -117, boost::fixed_point::round::nearest_even> fixed_point_type; local::test_exp<fixed_point_type>(12); }
}


/**
 * @file   AtomGroup.hpp
 * @author see AUTHORS
 * @brief  AtomGroup header file.
 */

#ifndef ATOMGROUP_HPP
#define ATOMGROUP_HPP

#include <vector>
#include <iostream>

#include <Eigen/Dense>

#include "Atom.hpp"

/**
 * @class AtomGroup
 * @brief represents a group of atoms
 */
class AtomGroup {
 public:
    explicit AtomGroup();

    ~AtomGroup();

    /**
     * @brief returns all the atoms in the group
     * @return a vector containing all the atoms
     */
    std::vector<Atom> get_atoms() const;

    /**
     * @brief returns all the coordinates of all the atoms in the group
     * @return a vector containing a coordinates for all the atoms
     */
    std::vector<Eigen::Vector3d> get_coordinates() const;

    /**
    * @brief returns the size of the group (which is the number of atoms)
    * @return the size of the group
    */
    int get_size() const;

    /**
    * @brief returns the total mass of the atom group
    * @return the total mass of the atom group
    */
    double get_total_mass() const;

    /**
    * @brief returns the center of mass of the group
    * @return the coordinates of the center of mass
    */
    Eigen::Vector3d get_center_of_mass() const;

    /**
    * @brief returns the positions of the atoms relative to the mass center of the group
    * @return a matrix containing the positions of the atoms relative to the groups center of mass
    */
    Eigen::Matrix3Xd get_relative_positions() const;

 protected:
    std::vector<Atom> atoms;
};

#endif

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4


/**
 * @file layer_main.cc
 * @brief Solves CD BVP for exact solution with an internal layer
 * @author Philippe Peter
 * @date July 2020
 * @copyright Developed at SAM, ETH Zurich
 */
#include <lf/fe/fe.h>
#include <lf/io/io.h>
#include <lf/mesh/hybrid2d/hybrid2d.h>
#include <lf/uscalfe/uscalfe.h>

#include <Eigen/Core>
#include <memory>
#include <string>

#include "cd_tools.h"
#include "standard_fem.h"
#include "supg.h"
#include "upwind.h"

int main() {
  // parameter functions:
  // boundary conditions
  const auto g = [](const Eigen::Vector2d &x) {
    return x(0) > x(1) ? 1.0 : 0.0;
  };
  // velocity field
  const auto v = [](const Eigen::Vector2d &x) {
    return Eigen::Vector2d(1.0, 1.0);
  };
  // diffusion coefficient
  const auto eps = [](const Eigen::Vector2d &x) { return 10E-10; };
  // source function
  const auto f = [](const Eigen::Vector2d &x) { return 0.0; };

  // Read Mesh from file
  std::string mesh_file = CURRENT_SOURCE_DIR "/meshes/mesh_square.msh";
  auto mesh_factory = std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
  lf::io::GmshReader reader(std::move(mesh_factory), mesh_file);
  auto mesh_p = reader.mesh();

  // Construct dofhanlder for linear finite element space on the mesh.
  auto fe_space =
      std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  // Compute solutions using Standard FE, Upwind, SUPG method
  Eigen::VectorXd sol_standard =
      ConvectionDiffusion::SolveCDBVPStandardFem(fe_space, eps, v, f, g);
  lf::fe::MeshFunctionFE sol_standard_mf(fe_space, sol_standard);

  Eigen::VectorXd sol_stable =
      ConvectionDiffusion::SolveCDBVPUpwind(fe_space, eps, v, f, g);
  lf::fe::MeshFunctionFE sol_upwind_mf(fe_space, sol_stable);

  Eigen::VectorXd sol_supg =
      ConvectionDiffusion::SolveCDBVPSupg(fe_space, eps, v, f, g);
  lf::fe::MeshFunctionFE sol_supg_mf(fe_space, sol_supg);

  // Output solution along the curve gamma
  auto gamma = [](double t) { return Eigen::Vector2d(t, 1 - t); };
  ConvectionDiffusion::SampleMeshFunction("results_standard_FEM.txt", mesh_p,
                                          gamma, sol_standard_mf, 300);
  ConvectionDiffusion::SampleMeshFunction("results_upwind.txt", mesh_p, gamma,
                                          sol_upwind_mf, 300);
  ConvectionDiffusion::SampleMeshFunction("results_supg.txt", mesh_p, gamma,
                                          sol_supg_mf, 300);

  // Plot
  std::system("python3 " CURRENT_SOURCE_DIR
              "/plot_layer.py " CURRENT_BINARY_DIR);
  return 0;
}


#pragma once

#include <cstdint>
#include <cmath>

#include <Eigen/Sparse>
#include <Eigen/Dense>

#include <crest/geometry/indexed_mesh.hpp>
#include <crest/util/eigen_extensions.hpp>
#include <crest/quadrature/triquad.hpp>
#include <crest/basis/basis.hpp>

namespace crest
{
    /**
     * A standard linear Lagrangian basis
     */
    template <typename Scalar>
    class LagrangeBasis2d : public Basis<Scalar, LagrangeBasis2d<Scalar>>
    {
    public:
        explicit LagrangeBasis2d(const IndexedMesh<Scalar, int> & mesh) : _mesh(mesh) {}

        virtual std::vector<int> boundary_nodes() const override { return _mesh.boundary_vertices(); }
        virtual std::vector<int> interior_nodes() const override { return _mesh.compute_interior_vertices(); }

        virtual Assembly<Scalar> assemble() const override;

        virtual int num_dof() const override { return _mesh.num_vertices(); }

        template <typename Function2d>
        VectorX<Scalar> interpolate(const Function2d &f) const;

        template <typename Function2d>
        VectorX<Scalar> interpolate_boundary(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        VectorX<Scalar> load(const Function2d &f) const;

        template <int QuadStrength, typename Function2d>
        Scalar error_l2(const Function2d &f, const VectorX<Scalar> & weights) const;

        template <int QuadStrength, typename Function2d_x, typename Function2d_y>
        Scalar error_h1_semi(const Function2d_x & f_x,
                             const Function2d_y & f_y,
                             const VectorX<Scalar> & weights) const;

    private:
        const IndexedMesh<double, int> & _mesh;
    };

    namespace detail
    {
        template <typename Scalar>
        struct assembly_triplets {
            std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
            std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        };

        template <typename Scalar>
        assembly_triplets<Scalar> assemble_linear_lagrangian_system_triplets(
                const crest::IndexedMesh<Scalar, int> & mesh);
    }

    /*
     * IMPLEMENTATION BELOW
     */

    template <typename Scalar>
    detail::assembly_triplets<Scalar> detail::assemble_linear_lagrangian_system_triplets(
            const crest::IndexedMesh<Scalar, int> & mesh)
    {
        const static Eigen::Matrix<Scalar, 3, 3> M_LOCAL_REF = (1.0 / 24.0) * (Eigen::Matrix3d()
                <<
                2.0, 1.0, 1.0,
                1.0, 2.0, 1.0,
                1.0, 1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A11 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                1.0, 0.0, -1.0,
                0.0, 0.0, 0.0,
                -1.0, 0.0, 1.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A12 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 1.0, -1.0,
                1.0, 0.0, -1.0,
                -1.0, -1.0, 2.0
        ).finished().cast<Scalar>();

        const static Eigen::Matrix<Scalar, 3, 3> A22 = (1.0 / 2.0) * (Eigen::Matrix3d()
                <<
                0.0, 0.0, 0.0,
                0.0, 1.0, -1.0,
                0.0, -1.0, 1.0
        ).finished().cast<Scalar>();

        std::vector<Eigen::Triplet<Scalar>> mass_triplets;
        std::vector<Eigen::Triplet<Scalar>> stiffness_triplets;
        mass_triplets.reserve(3 * mesh.num_elements());
        stiffness_triplets.reserve(3 * mesh.num_elements());

        for (const auto & element : mesh.elements())
        {
            const auto a = mesh.vertices()[element.vertex_indices[0]];
            const auto b = mesh.vertices()[element.vertex_indices[1]];
            const auto c = mesh.vertices()[element.vertex_indices[2]];

            const auto v1 = a - c;
            const auto v2 = b - c;

            const Eigen::Matrix2d jacobian = (Eigen::Matrix2d() << v1.x, v2.x, v1.y, v2.y).finished();
            const Eigen::Matrix2d jacobian_inverse = jacobian.inverse();
            const Eigen::Matrix2d C = jacobian_inverse * jacobian_inverse.transpose();
            const auto abs_det_jacobian = std::abs(jacobian.determinant());

            const Eigen::Matrix<Scalar, 3, 3> A_local = abs_det_jacobian * (C(0, 0) * A11 + C(0, 1) * A12 + C(1, 1) * A22);
            const Eigen::Matrix<Scalar, 3, 3> M_local = abs_det_jacobian * M_LOCAL_REF;

            typedef Eigen::Triplet<Scalar> T;
            for (size_t i = 0; i < 3; ++i)
            {
                for (size_t j = 0; j < 3; ++j)
                {
                    const auto I = element.vertex_indices[i];
                    const auto J = element.vertex_indices[j];
                    mass_triplets.emplace_back(T(I, J, M_local(i, j)));
                    stiffness_triplets.emplace_back(T(I, J, A_local(i, j)));
                }
            }
        }

        return detail::assembly_triplets<Scalar> {
                std::move(stiffness_triplets),
                std::move(mass_triplets)
        };
    }

    template <typename Scalar>
    Assembly<Scalar> LagrangeBasis2d<Scalar>::assemble() const
    {
        const auto triplets = detail::assemble_linear_lagrangian_system_triplets(_mesh);

        Assembly<Scalar> assembly;

        // Stiffness
        assembly.stiffness = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.stiffness.setFromTriplets(triplets.stiffness_triplets.cbegin(), triplets.stiffness_triplets.cend());

        // Mass
        assembly.mass = Eigen::SparseMatrix<Scalar>(num_dof(), num_dof());
        assembly.mass.setFromTriplets(triplets.mass_triplets.cbegin(), triplets.mass_triplets.cend());

        return assembly;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::load(const Function2d & f) const
    {
        Eigen::VectorXd load(_mesh.num_vertices());
        load.setZero();

        // See triquad.hpp for the mapping used here
        const auto a_basis = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto b_basis = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto c_basis = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

        for (const auto element : _mesh.elements())
        {
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto transformed_f = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            const auto absdet = transform.absolute_determinant();

            load(z0) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * a_basis(x, y); }
            );
            load(z1) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * b_basis(x, y); }
            );
            load(z2) += absdet * triquad_ref<QuadStrength, Scalar>(
                    [&] (auto x, auto y) { return transformed_f(x, y) * c_basis(x, y); }
            );
        }

        return load;
    }

    template <typename Scalar>
    template <typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::interpolate(const Function2d & f) const
    {
        // Simple nodal interpolation
        auto result = VectorX<Scalar>(_mesh.num_vertices());
        for (int i = 0; i < _mesh.num_vertices(); ++i)
        {
            const auto vertex = _mesh.vertices()[i];
            result(i) = f(vertex.x, vertex.y);
        }
        return result;
    }

    template <typename Scalar>
    template <typename Function2d>
    VectorX<Scalar> LagrangeBasis2d<Scalar>::interpolate_boundary(const Function2d & f) const
    {
        // Simple nodal interpolation
        auto result = VectorX<Scalar>(_mesh.num_boundary_vertices());
        const auto & boundary_indices = _mesh.boundary_vertices();
        for (int i = 0; i < _mesh.num_boundary_vertices(); ++i)
        {
            const auto vertex_index = boundary_indices[i];
            const auto vertex = _mesh.vertices()[vertex_index];
            result(i) = f(vertex.x, vertex.y);
        }
        return result;
    }

    template <typename Scalar>
    template <int QuadStrength, typename Function2d>
    Scalar LagrangeBasis2d<Scalar>::error_l2(const Function2d &f, const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0 = [] (auto x, auto  ) { return Scalar(0.5) * x + Scalar(0.5); };
        const auto basis1 = [] (auto  , auto y) { return Scalar(0.5) * y + Scalar(0.5); };
        const auto basis2 = [] (auto x, auto y) { return Scalar(0.5) * (-x - y); };

#pragma omp parallel for reduction(+:error_squared)
        for (int element_index = 0; element_index < _mesh.num_elements(); ++element_index)
        {
            const auto element = _mesh.elements()[element_index];
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);
            const auto f_ref = [&f, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                return f(coords.x, coords.y);
            };

            // Computes the square of the difference of f and f_h in the reference triangle
            const auto diff_ref_squared = [&] (auto x, auto y)
            {
                const auto f_h_ref = w0 * basis0(x, y) +
                                     w1 * basis1(x, y) +
                                     w2 * basis2(x, y);

                const auto diff = f_ref(x, y) - f_h_ref;
                return diff * diff;
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_ref_squared);
        }

        return std::sqrt(error_squared);
    };

    template <typename Scalar>
    template <int QuadStrength, typename Function2d_x, typename Function2d_y>
    Scalar LagrangeBasis2d<Scalar>::error_h1_semi(const Function2d_x & f_x,
                                                  const Function2d_y & f_y,
                                                  const VectorX<Scalar> & weights) const
    {
        Scalar error_squared = Scalar(0);

        // See triquad.hpp for the mapping used here
        const auto basis0_x = Scalar(0.5);
        const auto basis0_y = Scalar(0.0);
        const auto basis1_x = Scalar(0.0);
        const auto basis1_y = Scalar(0.5);
        const auto basis2_x = Scalar(-0.5);
        const auto basis2_y = Scalar(-0.5);

#pragma omp parallel for reduction(+:error_squared)
        for (int element_index = 0; element_index < _mesh.num_elements(); ++element_index)
        {
            const auto element = _mesh.elements()[element_index];
            const auto z0 = element.vertex_indices[0];
            const auto z1 = element.vertex_indices[1];
            const auto z2 = element.vertex_indices[2];

            const auto w0 = weights(z0);
            const auto w1 = weights(z1);
            const auto w2 = weights(z2);

            const auto & a = _mesh.vertices()[z0];
            const auto & b = _mesh.vertices()[z1];
            const auto & c = _mesh.vertices()[z2];
            const auto transform = triquad_transform(a, b, c);

            const auto f_grad_ref = [&f_x, &f_y, &transform] (auto x, auto y)
            {
                const auto coords = transform.transform_from_reference(x, y);
                Eigen::Matrix<Scalar, 2, 1> grad;
                grad(0) = f_x(coords.x, coords.y);
                grad(1) = f_y(coords.x, coords.y);
                return grad;
            };

            // Since we have linear elements, the gradients are constants
            Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref;
            f_h_grad_ref(0) = w0 * basis0_x +
                              w1 * basis1_x +
                              w2 * basis2_x;
            f_h_grad_ref(1) = w0 * basis0_y +
                              w1 * basis1_y +
                              w2 * basis2_y;

            // Due to change of variables, we have to left-apply J^-T
            const Eigen::Matrix<Scalar, 2, 2> J_inv_t = transform.jacobian().inverse().transpose();
            const Eigen::Matrix<Scalar, 2, 1> f_h_grad_ref_transformed = J_inv_t * f_h_grad_ref;

            // Computes the square of the difference of grad(f) and grad(f_h)
            // in the reference triangle
            const auto diff_squared = [&] (auto x, auto y)
            {
                // Note that J_inv_t cancels with J_t for f_grad_ref
                const Eigen::Matrix<Scalar, 2, 1> diff = f_grad_ref(x, y) - f_h_grad_ref_transformed;
                return diff.dot(diff);
            };

            const auto absdet = transform.absolute_determinant();
            error_squared += absdet * triquad_ref<QuadStrength, Scalar>(diff_squared);
        }

        return std::sqrt(error_squared);
    };
}


<<<<<<< HEAD
/*    Copyright (c) 2010-2018, Delft University of Technology
=======
/*    Copyright (c) 2010-2019, Delft University of Technology
>>>>>>> origin/master
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 *
 *    References
 *      Burden, R.L., Faires, J.D. Numerical Analysis, 7th Edition, Books/Cole, 2001.
 *      Montenbruck, O., Gill, E. Satellite Orbits: Models, Methods, Applications, Springer, 2005.
 *
 *    Notes
 *      There might be a problem with the RKF78 and DOPRI8 integrators, as the coefficients do not
 *      meet the required conditions to the tolerance achieved for all the other Runge-Kutta-type
 *      integrators tested (1.0e-14 versus 1.0e-15 for the other integrators). This should be
 *      looked into further to ensure that there are no bugs introduced in the coefficients
 *      used.
 *
 */

#define BOOST_TEST_MAIN

#include <cmath>

#include <boost/test/unit_test.hpp>

#include "Tudat/Basics/testMacros.h"

#include "Tudat/Mathematics/NumericalIntegrators/rungeKuttaCoefficients.h"

namespace tudat
{
namespace unit_tests
{

BOOST_AUTO_TEST_SUITE( test_runge_kutta_coefficients )

using numerical_integrators::RungeKuttaCoefficients;

void checkValidityOfCoefficientSet( const RungeKuttaCoefficients::CoefficientSets& coefficientSet,
                                    const double tolerance )
{
    // Declare coefficient set.
    RungeKuttaCoefficients coefficients;
    coefficients = coefficients.get( coefficientSet );

    // Check that the sum of the b-coefficients for both the integrated order and the
    // error-checking order is one.
    TUDAT_CHECK_MATRIX_CLOSE_FRACTION(
                Eigen::VectorXd::Constant( 2, 1.0 ),
                coefficients.bCoefficients.rowwise( ).sum( ), tolerance );

    // Check that the first c-coefficient is zero.
    BOOST_CHECK_SMALL( coefficients.cCoefficients( 0 ), tolerance );

    // Check that the c-coefficient/a-coefficient relation holds.
    for ( int i = 1; i < coefficients.cCoefficients.size( ); i++ )
    {
        if ( std::fabs( coefficients.cCoefficients( i ) ) < tolerance )
        {
            BOOST_CHECK_SMALL( coefficients.aCoefficients.row( i ).sum( ), tolerance );
        }

        else
        {
            BOOST_CHECK_CLOSE_FRACTION( coefficients.cCoefficients( i ),
                                        coefficients.aCoefficients.row( i ).sum( ), tolerance );
        }
    }
}

BOOST_AUTO_TEST_CASE( testRungeKuttaFehlberg45Coefficients )
{
    // Check validity of Runge-Kutta-Fehlberg 45 coefficients.
    checkValidityOfCoefficientSet( RungeKuttaCoefficients::rungeKuttaFehlberg45, 1.0e-15 );
}

BOOST_AUTO_TEST_CASE( testRungeKuttaFehlberg78Coefficients )
{
    // Check validity of Runge-Kutta-Fehlberg 78 coefficients.
    // Note, for some reason, the RKF78 set fails the unit test when the tolerance in
    // checkValidityOfCoefficientSet() is set to lower than this value (rows 8 and 9 of
    // aCoefficients matrix sum does not correspond to cCoefficient counterpart with tolerance less
    // than 1.0e-14).
    checkValidityOfCoefficientSet( RungeKuttaCoefficients::rungeKuttaFehlberg78, 1.0e-14 );
}

BOOST_AUTO_TEST_CASE( testRungeKutta87DormandAndPrinceCoefficients )
{
    // Check validity of Runge-Kutta 87 (Dormand and Prince) coefficients.
    // Note, for some reason, the DOPRI8 set fails the unit test when the tolerance in
    // checkValidityOfCoefficientSet() is set to lower than this value (row 10 of aCoefficients
    // matrix sum does not correspond to cCoefficient counterpart with tolerance less than
    // 1.0e-14).
    checkValidityOfCoefficientSet( RungeKuttaCoefficients::rungeKutta87DormandPrince, 1.0e-14 );
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat


#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/erdos_renyi_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/graph_traits.hpp>

typedef boost::adjacency_list<> Graph;
typedef boost::erdos_renyi_iterator<boost::minstd_rand, Graph> ERGen;

using namespace boost;
#include <random>
#include <vector>
#include<string>
#include<iostream>
#include<fstream>
using std::vector;
using std::string;
int main()
{
    int nodes=100;
    std::mt19937 weightgenerator { std::random_device{}() };
    std::uniform_int_distribution<int> dist(1, nodes);
    boost::minstd_rand prng(std::random_device{}());
    // Create graph with 100 nodes and edges with probability 0.05
    Graph g(ERGen(prng, nodes, 0.5), ERGen(), nodes);
    auto vertex_idMap = get(boost::vertex_index, g);
    boost::graph_traits <Graph>::vertex_iterator i, end;
    boost::graph_traits <Graph>::adjacency_iterator ai, a_end;

    vector<vector<int>> matrix(nodes);
    for (auto& rows:matrix)
    {
        rows=vector<int>(nodes,-1);
    }

    for (boost::tie(i, end) = vertices(g); i != end; ++i) {
        //std::cout << vertex_idMap[*i] << ": ";

        for (boost::tie(ai, a_end) = adjacent_vertices(*i, g); ai != a_end; ++ai) {
            weightgenerator.seed(std::random_device{}());
            matrix[vertex_idMap[*i]][vertex_idMap[*ai]]=dist(weightgenerator);
            //std::cout << vertex_idMap[*ai]<<'('<<matrix[vertex_idMap[*i]][vertex_idMap[*ai]]<<')';
            //if (boost::next(ai) != a_end)
               // std::cout << ", ";
        }
        //std::cout << std::endl;
    }

    // output matrix

    std::ofstream of("tempMatrix.data",std::ios::trunc);
    of<<std::to_string(nodes)<<std::endl;
    for (int i=1;i<nodes;i++) {
        for(int j=0;j<i;j++){
            if(matrix[i][j]!=-1)
            {
                of<<std::to_string(matrix[i][j]);
            }else{
                of<<'x';
            }
            if((j+1)==i){
                of<<std::endl;
            }else {
                of<<' ';
            }
    }
    }

    return 0;
}


/* Boost numeric test of the adams-bashforth steppers test file

 Copyright 2013 Karsten Ahnert
 Copyright 2013-2015 Mario Mulansky

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

// disable checked iterator warning for msvc
#include <boost/config.hpp>
#ifdef BOOST_MSVC
    #pragma warning(disable:4996)
#endif

#define BOOST_TEST_MODULE numeric_adaptive_adams_bashforth_moulton

#include <iostream>
#include <cmath>

#include <boost/array.hpp>

#include <boost/test/unit_test.hpp>

#include <boost/mpl/vector.hpp>

#include <boost/numeric/odeint.hpp>

using namespace boost::unit_test;
using namespace boost::numeric::odeint;
namespace mpl = boost::mpl;

typedef double value_type;

typedef boost::array< double , 2 > state_type;
typedef runge_kutta_fehlberg78<state_type> initializing_stepper;

// harmonic oscillator, analytic solution x[0] = sin( t )
struct osc
{
    void operator()( const state_type &x , state_type &dxdt , const double t ) const
    {
        dxdt[0] = x[1];
        dxdt[1] = -x[0];
    }
};

BOOST_AUTO_TEST_SUITE( numeric_adaptive_adams_bashforth_moulton_test )

/* generic test for all adams bashforth steppers */
template< class Stepper >
struct perform_adaptive_adams_bashforth_moulton_test
{
    void operator()( void )
    {
        Stepper stepper;
        initializing_stepper init_stepper;

        const int o = stepper.order()+1; //order of the error is order of approximation + 1

        const state_type x0 = {{ 0.0 , 1.0 }};
        state_type x1 = x0;
        double t = 0.0;
        double dt = 0.25;
        // initialization, does a number of steps to self-start the stepper with a small stepsize
        stepper.initialize( init_stepper, osc() , x1 , t ,  dt);
        double A = std::sqrt( x1[0]*x1[0] + x1[1]*x1[1] );
        double phi = std::asin(x1[0]/A) - t;

        // now we do the actual step
        stepper.do_step( osc() , x1 , t , dt );
        // only examine the error of the adams-bashforth step, not the initialization
        const double f = 2.0 * std::abs( A*sin(t+dt+phi) - x1[0] ) / std::pow( dt , o ); // upper bound

        std::cout << o << " , " << f << std::endl;

        /* as long as we have errors above machine precision */
        while( f*std::pow( dt , o ) > 1E-16 )
        {
            x1 = x0;
            t = 0.0;
            stepper.initialize( init_stepper, osc() , x1 , t , dt );
            A = std::sqrt( x1[0]*x1[0] + x1[1]*x1[1] );
            phi = std::asin(x1[0]/A) - t;
            // now we do the actual step
            stepper.do_step( osc() , x1 , t , dt );
            stepper.reset();
            // only examine the error of the adams-bashforth step, not the initialization
            std::cout << "Testing dt=" << dt << " , " << std::abs( A*sin(t+dt+phi) - x1[0] ) << std::endl;
            BOOST_CHECK_LT( std::abs( A*sin(t+dt+phi) - x1[0] ) , f*std::pow( dt , o ) );
            dt *= 0.5;
        }
    }
};

typedef mpl::vector<
    adaptive_adams_bashforth_moulton< 2 , state_type > ,
    adaptive_adams_bashforth_moulton< 3 , state_type > ,
    adaptive_adams_bashforth_moulton< 4 , state_type > ,
    adaptive_adams_bashforth_moulton< 5 , state_type > ,
    adaptive_adams_bashforth_moulton< 6 , state_type > ,
    adaptive_adams_bashforth_moulton< 7 , state_type >
    > adaptive_adams_bashforth_moulton_steppers;

BOOST_AUTO_TEST_CASE_TEMPLATE( adaptive_adams_bashforth_moulton_test , Stepper, adaptive_adams_bashforth_moulton_steppers )
{
    perform_adaptive_adams_bashforth_moulton_test< Stepper > tester;
    tester();
}

BOOST_AUTO_TEST_SUITE_END()


/*
 * Copyright 2020 Robert Bosch GmbH
 *
 * 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.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * \file cloe/utility/statistics_test.cpp
 * \see  cloe/utility/statistics.hpp
 */

#include <gtest/gtest.h>

#include <string>
#include <utility>
#include <vector>

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/count.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/median.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/variance.hpp>
namespace ba = boost::accumulators;
namespace tag = boost::accumulators::tag;

#include <cloe/utility/statistics.hpp>
using cloe::utility::Accumulator;
using cloe::utility::Pie;

TEST(utility_statistics_pie, with_int) {
  std::vector<int> data{1, 1, 1, 1, 2, 2, 3, 4, 1, 2, 0, 3, 2};

  Pie<int> pie;
  for (auto x : data) {
    pie.push_back(x);
  }

  EXPECT_EQ(1, pie.mode());
  EXPECT_EQ(data.size(), pie.count());
  EXPECT_EQ(static_cast<uint64_t>(2), pie.count(3));
  EXPECT_EQ(static_cast<uint64_t>(4), pie.count(2));
  EXPECT_EQ(static_cast<double>(5) / static_cast<double>(data.size()), pie.proportion(1));
}

TEST(utility_statistics_accumulator, with_double) {
  std::vector<double> data{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

  Accumulator my_acc;
  ba::accumulator_set<
      double, ba::stats<tag::mean, tag::count, tag::max, tag::min, tag::variance, tag::median>>
      ref_acc;
  for (auto x : data) {
    my_acc.push_back(x);
    ref_acc(x);
  }

  EXPECT_EQ(ba::count(ref_acc), my_acc.count());
  EXPECT_EQ(ba::min(ref_acc), my_acc.min());
  EXPECT_EQ(ba::max(ref_acc), my_acc.max());  // NOLINT
  EXPECT_EQ(ba::mean(ref_acc), my_acc.mean());
  EXPECT_EQ(ba::variance(ref_acc), my_acc.variance());
}


/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 by Rokko Developers https://github.com/t-sakashita/rokko
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*****************************************************************************/

#include <iostream>
#include <vector>
#include <boost/tuple/tuple.hpp>

#include <rokko/solver.hpp>
#include <rokko/grid.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/localized_matrix.hpp>
#include <rokko/utility/xyz_hamiltonian.hpp>
#include <rokko/utility/xyz_hamiltonian_mpi.hpp>
#include <rokko/collective.hpp>

int main(int argc, char *argv[]) {
  MPI_Init(&argc, &argv);
  rokko::parallel_dense_solver solver;
  solver.initialize(argc, argv);
  rokko::grid g(MPI_COMM_WORLD);

  int L = 4;
  int num_bonds = L - 1;
  std::vector<std::pair<int, int> > lattice;
  std::vector<boost::tuple<double, double, double> > coupling;
  for (int i=0; i<L-1; ++i) {
    lattice.push_back(std::make_pair(i, i+1));
    coupling.push_back(boost::make_tuple(1, 0.3, 0.2));
  }

  int myrank, nprocs;
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
  MPI_Status status;
  const int root = 0;
  int ierr;

  if (myrank == root) {
    std::cout << "L=" << L << " num_bonds=" << num_bonds << std::endl;
    for (int i=0; i<num_bonds; ++i) {
      std::cout << lattice[i].first << " " << lattice[i].second << " " << coupling[i].get<0>()
                << " " << coupling[i].get<1>() << " " << coupling[i].get<2>() << std::endl;
    }
  }
  MPI_Barrier(MPI_COMM_WORLD);

  int n = nprocs;
  int p = -1;
  do {
    n /= 2;
    ++p;
  } while (n > 0);

  if (nprocs != (1 << p)) {
    if ( myrank == 0 ) {
      std::cout << "This program can be run only for powers of 2" << std::endl;
    }
    MPI_Abort(MPI_COMM_WORLD, 1);
  }
  int N = 1 << (L-p);

  // creating column vectors which forms a heisenberg hamiltonian.
  int N_seq = 1 << L;
  std::vector<double> buffer(N);
  for (int i=0; i<N; ++i) {
    // sequential version
    std::vector<double> v_seq, w_seq;
    v_seq.assign(N_seq, 0);
    v_seq[i] = 1;
    w_seq.assign(N_seq, 0);
    if (myrank == root) {
      rokko::xyz_hamiltonian::multiply(L, lattice, coupling, v_seq, w_seq);
      std::cout << "sequential version:" << std::endl;
      for (int j=0; j<N_seq; ++j) {
        std::cout << w_seq[j] << " ";
      }
      std::cout << std::endl;
    }
    MPI_Barrier(MPI_COMM_WORLD);

    // MPI version
    std::vector<double> v, w;
    v.assign(N, 0);
    if (myrank == (i / N))
      v[i % N] = 1;
    w.assign(N, 0);
    rokko::xyz_hamiltonian::multiply(MPI_COMM_WORLD, L, lattice, coupling, v, w, buffer);
    for (int proc=0; proc<nprocs; ++proc) {
      if (proc == myrank) {
        std::cout << "myrank=" << myrank << std::endl;
        for (int j=0; j<N; ++j) {
          std::cout << w[j] << " ";
        }
        std::cout << std::endl;
      }
      MPI_Barrier(MPI_COMM_WORLD);
    }
    if (myrank == root) {
      std::cout << std::endl;
    }
  }

  // test fill_diagonal of quantum heisenberg hamiltonian.
  // sequential version
  std::vector<double> w_seq;
  w_seq.assign(N_seq, 0);
  if (myrank == root) {
    rokko::xyz_hamiltonian::fill_diagonal(L, lattice, coupling, w_seq);
    std::cout << "fill_diagonal sequential version:" << std::endl;
    for (int j=0; j<N_seq; ++j) {
      std::cout << w_seq[j] << " ";
    }
    std::cout << std::endl;
  }
  MPI_Barrier(MPI_COMM_WORLD);
  // MPI version
  std::vector<double> w;
  w.assign(N, 0);
  if (myrank == root) {
    std::cout << "fill_diagonal MPI version:" << std::endl;
  }
  rokko::xyz_hamiltonian::fill_diagonal(MPI_COMM_WORLD, L, lattice, coupling, w);
  for (int proc=0; proc<nprocs; ++proc) {
    if (proc == myrank) {
      std::cout << "myrank=" << myrank << std::endl;
      for (int j=0; j<N; ++j) {
        std::cout << w[j] << " ";
      }
      std::cout << std::endl;
    }
    MPI_Barrier(MPI_COMM_WORLD);
  }

  // test for generate function
  rokko::localized_matrix<rokko::matrix_col_major> lmat(N_seq, N_seq);
  rokko::xyz_hamiltonian::generate(L, lattice, coupling, lmat);

  rokko::distributed_matrix<rokko::matrix_col_major> mat(N_seq, N_seq, g, solver);
  rokko::xyz_hamiltonian::generate(L, lattice, coupling, mat);
  rokko::localized_matrix<rokko::matrix_col_major> lmat_gather(N_seq, N_seq);
  rokko::gather(mat, lmat_gather, root);

  if (myrank == root) {
    std:: cout << "lmat:" << std::endl << lmat << std::endl;
    std:: cout << "lmat_gather:" << std::endl << lmat_gather << std::endl;
    if (lmat_gather == lmat) {
      std::cout << "OK: distributed_matrix by 'generate' equals to a localized_matrix by 'generate'." << std::endl;
    } else {
      std::cout << "ERROR: distributed_matrix by 'generate' is differnet from a localized_matrix by 'generate'."<< std::endl;
      exit(1);
    }
  }

  MPI_Finalize();
  return 0;
}


#include <metaSMT/DirectSolver_Context.hpp>
#include <metaSMT/backend/Boolector.hpp>
#include <metaSMT/support/cardinality.hpp>

#include <metaSMT/support/run_algorithm.hpp>

#include <boost/mpl/vector.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>

using namespace metaSMT;
using namespace metaSMT::logic;
using namespace metaSMT::solver;
using namespace std;

#define foreach BOOST_FOREACH

template<typename Solver>
struct nqueens
{
  typedef bool result_type;

  nqueens ( unsigned size )
  {
    field_size = size;

    init_field ();
    field_constraints();
  }

  bool operator() ()
  {
    std::cout << "Solving" << std::endl;
    bool sat = solve(ctx);
    if(sat) print_solution();
    return sat;
  }

  void init_field ()
  {
    field.resize ( field_size );

    foreach ( vector<predicate>& row, field )
    {
      row.clear ();
      for ( unsigned i = 0; i < field_size; i++ )
      {
        row.push_back ( new_variable () );
      }
    }
  }

  void field_constraints()
  {
    for ( unsigned i = 0; i < field_size; ++i )
    {
      row ( i );
      column ( i );

      if(i != 0)
      {
      	falling ( i, 0 );
        rising ( field_size-1, i );
      }
      rising ( i, 0 );
      falling ( 0 , i );

    }
  }

  void falling(unsigned row, unsigned col)
  {
    std::vector<predicate> vec1;
    while( row < field_size && col < field_size)
    {

      vec1.push_back(field[row][col]);

      col++;
      row++;
    }
    if( vec1.size() > 1 )
    {
      assertion( ctx, cardinality_leq( ctx, vec1, 1));
    }
  }

  void rising(int row, int col)
  {
    std::vector<predicate> vec1;
    while ( row >= 0 && col < static_cast<int>(field_size)  )
    {
      vec1.push_back(field[row][col]);
      row--;
      col++;
    }
    if(vec1.size() > 1)
    {
      assertion( ctx, cardinality_leq( ctx, vec1, 1));
    }
  }

  void row ( unsigned row )
  {
    assertion ( ctx, one_hot( ctx , field[row] ) );
  }

  void column ( unsigned col )
  {
    std::vector<predicate> vec1;
    for ( unsigned i = 0; i < field_size; i++ )
    {
      vec1.push_back(field[i][col]);

    }
    assertion( ctx, one_hot( ctx, vec1));

  }

  void print_solution()
  {
    for (unsigned i = 0; i < field_size; ++i) {
      for (unsigned k = 0; k < field_size; ++k) {
        bool val = read_value(ctx, field[i][k]);
        printf("%d", val);
      }
      printf("\n");
    }
  }

  Solver ctx;
  unsigned field_size;
  vector < vector < predicate > > field;
};

int
main(int argc, const char *argv[])
{
  typedef mpl::vector <
      DirectSolver_Context < Boolector >
      > SolverVec;

  if( argc < 2) {
    cout << "usage: "<< argv[0] << " <size of the field>" << endl;
    exit(1);
  }

  unsigned solver = 0; //atoi ( argv[1] );
  unsigned size = atoi ( argv[1] );

  bool val = run_algorithm<SolverVec, nqueens> ( solver, size );

  std::cout << "found solution? " << (val ? "yes" : "no") << std::endl;

  return 0;
}


///////////////////////////////////////////////////////////////////////////////
// contingency_table1.cpp                                                    //
//                                                                           //
//  Copyright 2010 Erwann Rogard. 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/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>

#include <string>
#include <boost/mpl/int.hpp>
#include <boost/mpl/vector/vector10.hpp>
#include <boost/mpl/detail/wrapper.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/fusion/include/make_map.hpp>
#include <boost/fusion/container/map/detail/sequence_to_map.hpp>
#include <boost/accumulators/framework/accumulator_set.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/include/factor.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/include/cells.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/include/pearson_chisq/independence.hpp>

#include <boost/statistics/detail/non_parametric/contingency_table/pearson_chisq/independence/tag.hpp>

void test_contingency_table1()
{
    namespace ac = boost::accumulators;
	namespace ct = boost::statistics::detail::contingency_table;
    namespace ps = ct::pearson_chi_square_statistic;

    typedef double val_;
    typedef boost::mpl::int_<0> x_; typedef int data_x_;
    typedef boost::mpl::int_<1> y_; typedef std::string data_y_;
    typedef boost::mpl::int_<2> z_; typedef int data_z_;

    typedef boost::fusion::detail::sequence_to_map<
        boost::mpl::vector6<x_,data_x_,y_,data_y_,z_,data_z_>
    >::type sample_;

    typedef boost::mpl::vector2<x_,y_> keys_;
    typedef ps::tag::independence_between<keys_> hypothesis_;
    typedef ac::stats< hypothesis_> stats_;
    typedef ac::accumulator_set< sample_, stats_, long int > acc_;

    using namespace boost::assign;
    acc_ acc(( ct::_map_of_levels = boost::fusion::make_map<x_,y_>(
        list_of(-1)(1), list_of("a")("b")("c") ) ));

    {
        // Check levels
     	BOOST_CHECK( ct::cells_count<keys_>( acc ) == 2 * 3 );
     	BOOST_CHECK( ct::extract::levels<x_>( acc ).count( -1  ) == 1 );
     	BOOST_CHECK( ct::extract::levels<x_>( acc ).count(  1  ) == 1 );
     	BOOST_CHECK( ct::extract::levels<x_>( acc ).count(  2  ) == 0 );
     	BOOST_CHECK( ct::extract::levels<y_>( acc ).count( "a" ) == 1 );
     	BOOST_CHECK( ct::extract::levels<y_>( acc ).count( "b" ) == 1 );
     	BOOST_CHECK( ct::extract::levels<y_>( acc ).count( "c" ) == 1 );
     	BOOST_CHECK( ct::extract::levels<y_>( acc ).count( "d" ) == 0 );
    }
    {                                                                        //.....|.....|.....|.....|.....|.....|.....|
                                                                             //     |non- |    x =    |       y =       |
                                                                             //total|empty|...........|.................|
        // Filling the cells                                                 //count|cells| -1  |  1  | "a" | "b" | "c" |
        using namespace ac;                                 //.....|count|.....|.....|.....|.....|.....|
        acc( boost::fusion::make_map<x_,y_,z_>( -1, "a", 1 ), weight = 1 );  //  1  |  1  |  1  |  0  |  1  |  0  |  0  |
        acc( boost::fusion::make_map<x_,y_,z_>(  1, "b", 1 ), weight = 2 );  //  3  |  2  |  1  |  2  |  1  |  2  |  0  |
    }
    {   // Check degrees of freedom
        // lost df = (r-1) + (c-1) = 1 + 2 = 3;
        //  df = rc -r -c + 1 = 3 * 2 - 3  -2 + 1 = 2

        typedef boost::mpl::detail::wrapper<hypothesis_> h0_;
        BOOST_CHECK( ps::lost_degrees_of_freedom( h0_(), acc ) == 3 );
        BOOST_CHECK( ps::degrees_of_freedom( h0_(),acc ) == 2 );
    }
    {
        // Check cells
        typedef boost::mpl::vector1<x_> vec_x_;
        typedef boost::mpl::vector1<y_> vec_y_;
        std::size_t n;
        n = ac::extract::weighted_count( acc );
     	BOOST_CHECK( n == 3 );

        n = ct::non_empty_cells_count<vec_x_>(acc);
        BOOST_CHECK( n == 2 );
        n = ct::non_empty_cells_count<vec_y_>(acc);
        BOOST_CHECK( n == 2 );
        n = ct::non_empty_cells_count<keys_>( acc );
        BOOST_CHECK( n == 2 );

        n = ct::cells_count<vec_x_>(acc);
        BOOST_CHECK( n == 2 );
        n = ct::cells_count<vec_y_>(acc);
        BOOST_CHECK( n == 3 );
        n = ct::cells_count<keys_>( acc );
        BOOST_CHECK( n == 6 );

        n = ct::count_matching<vec_x_>(
            acc, boost::fusion::make_map<x_>( -1 ) );
     	BOOST_CHECK( n == 1 );
        n = ct::count_matching<vec_x_>(
            acc, boost::fusion::make_map<x_>( 1 ) );
     	BOOST_CHECK( n == 2 );
        n = ct::count_matching<vec_y_>(
            acc, boost::fusion::make_map<y_>( "a" ) );
     	BOOST_CHECK( n == 1 );
        n = ct::count_matching<vec_y_>(
            acc, boost::fusion::make_map<y_>( "b" ) );
     	BOOST_CHECK( n == 2 );
        n = ct::count_matching<vec_y_>(
            acc, boost::fusion::make_map<y_>( "c" ) );
     	BOOST_CHECK( n == 0 );
        n = ct::count_matching<keys_>( acc,
            boost::fusion::make_map<x_,y_,z_>( -1, "a", 1 ) );
        BOOST_CHECK( n == 1 );
        n = ct::count_matching<keys_>( acc,
            boost::fusion::make_map<x_,y_,z_>(  1, "b", 1 ) );
        BOOST_CHECK( n == 2 );
    }

}


//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_ACOTD_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_ACOTD_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!
    @ingroup group-trigonometric
    This function object returns the inverse cotangent in degree.

    @par Header <boost/simd/function/acotd.hpp>

    @par Note

      For every parameter of floating type `acotd(x)`
      returns the arc @c r in the interval  \f$[0, 180[\f$ such that
      <tt>cotd(r) == x</tt>.

    @see acot, acotpi, cotd

    @par Example:

      @snippet acotd.cpp acotd

    @par Possible output:

      @snippet acotd.txt acotd

  **/
  IEEEValue acotd(IEEEValue const & x);
} }
#endif

#include <boost/simd/function/scalar/acotd.hpp>
#include <boost/simd/function/simd/acotd.hpp>

#endif


#include <boost/gil/image_view.hpp>
#include <boost/gil/rgb.hpp>
#include <boost/gil/pixel.hpp>
#include <boost/gil/image_processing/numeric.hpp>

namespace boost{ namespace gil{
/// \defgroup ScalingAlgorithms
/// \brief Algorthims suitable for rescaling
///
/// These algorithms are used to improve image
/// quality after image resizing is made.

/// \defgroup DownScalingAlgorithms
/// \ingroup ScalingAlgorithms
/// \brief Algorthims suitable for downscaling
///
/// These algorithms provide best results when used
/// for downscaling. Using for upscaling will probably
/// provide less than good results.

/// \brief a single step of lanczos downscaling
/// \ingroup DownScalingAlgorithms
///
/// Use this algorithm to scale down source image
/// into a smaller image with reasonable quality.
/// Do note that having a look at the output once
/// is a good idea, since it might have ringing
/// artifacts.
template <typename ImageView>
void lanczos_at(
    ImageView input_view,
    ImageView output_view,
    typename ImageView::x_coord_t source_x,
    typename ImageView::y_coord_t source_y,
    typename ImageView::x_coord_t target_x,
    typename ImageView::y_coord_t target_y,
    std::ptrdiff_t a)
{
    using x_coord_t = typename ImageView::x_coord_t;
    using y_coord_t = typename ImageView::y_coord_t;
    using pixel_t = typename std::remove_reference<
                      decltype(std::declval<ImageView>()(0, 0))
                    >::type;
    // C++11 doesn't allow auto in lambdas
    using channel_t = typename std::remove_reference<
                        decltype(
                            std::declval<pixel_t>().at(
                                std::integral_constant<int, 0>{}
                            )
                        )
                       >::type;
    pixel_t result_pixel;
    boost::gil::static_transform(result_pixel, result_pixel,
        [](channel_t) { return static_cast<channel_t>(0); });
    auto x_zero = static_cast<x_coord_t>(0);
    auto x_one = static_cast<x_coord_t>(1);
    auto y_zero = static_cast<y_coord_t>(0);
    auto y_one = static_cast<y_coord_t>(1);

    for (y_coord_t y_i = std::max(source_y - static_cast<y_coord_t>(a) + y_one, y_zero);
         y_i <= std::min(source_y + static_cast<y_coord_t>(a), input_view.height() - y_one);
         ++y_i)
    {
        for (x_coord_t x_i = std::max(source_x - static_cast<x_coord_t>(a) + x_one, x_zero);
             x_i <= std::min(source_x + static_cast<x_coord_t>(a), input_view.width() - x_one);
             ++x_i)
        {
            double lanczos_response = boost::gil::lanczos(source_x - x_i, a)
                                      * boost::gil::lanczos(source_y - y_i, a);
            auto op = [lanczos_response](channel_t prev, channel_t next)
            {
                return static_cast<channel_t>(prev + next * lanczos_response);
            };
            boost::gil::static_transform(result_pixel,
                                         input_view(source_x, source_y),
                                         result_pixel,
                                         op);
        }
    }

    output_view(target_x, target_y) = result_pixel;
}

/// \brief Complete Lanczos algorithm
/// \ingroup DownScalingAlgorithms
///
/// This algorithm does full pass over
/// resulting image and convolves pixels from
/// original image. Do note that it might be a good
/// idea to have a look at test output as there
/// might be ringing artifacts.
/// Based on wikipedia article:
/// https://en.wikipedia.org/wiki/Lanczos_resampling
/// with standardinzed cardinal sin (sinc)
template <typename ImageView>
void scale_lanczos(ImageView input_view, ImageView output_view, std::ptrdiff_t a)
{
    double scale_x = (static_cast<double>(output_view.width()))
                     / static_cast<double>(input_view.width());
    double scale_y = (static_cast<double>(output_view.height()))
                     / static_cast<double>(input_view.height());

    using x_coord_t = typename ImageView::x_coord_t;
    using y_coord_t = typename ImageView::y_coord_t;
    for (y_coord_t y = 0; y < output_view.height(); ++y)
    {
        for (x_coord_t x = 0; x < output_view.width(); ++x)
        {
            boost::gil::lanczos_at(
                input_view,
                output_view,
                x / scale_x,
                y / scale_y,
                x,
                y,
                a);
        }
    }
}
}}


//
// OpenTissue, A toolbox for physical based simulation and animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <OpenTissue/configuration.h>

#include <OpenTissue/core/math/big/big_types.h>
#include <OpenTissue/core/math/optimization/non_smooth_newton/optimization_compute_inverse_D.h>

#define BOOST_AUTO_TEST_MAIN
#include <OpenTissue/utility/utility_push_boost_filter.h>
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>
#include <OpenTissue/utility/utility_pop_boost_filter.h>

BOOST_AUTO_TEST_SUITE(opentissue_math_big_non_smooth_newton_compute_inverse_D);

BOOST_AUTO_TEST_CASE(test_case)
{
  typedef ublas::compressed_matrix<double> matrix_type;

  matrix_type D;
  matrix_type invD;
  matrix_type I;

  D.resize(6,6,false);
  invD.resize(6,6,false);
  I.resize(6,6,false);

  D(0,0) = 1.0;  D(0,1) = 0.0;  D(0,2) = 0.0;  D(0,3) = 0.0;  D(0,4) = 0.0;  D(0,5) = 0.0;
  D(1,0) = 2.0;  D(1,1) = 1.0;  D(1,2) = 0.0;  D(1,3) = 0.0;  D(1,4) = 0.0;  D(1,5) = 0.0;
  D(2,0) = 3.0;  D(2,1) = 0.0;  D(2,2) = 1.0;  D(2,3) = 0.0;  D(2,4) = 0.0;  D(2,5) = 0.0;
  D(3,0) = 0.0;  D(3,1) = 0.0;  D(3,2) = 0.0;  D(3,3) = 1.0;  D(3,4) = 0.0;  D(3,5) = 0.0;
  D(4,0) = 0.0;  D(4,1) = 0.0;  D(4,2) = 0.0;  D(4,3) = 4.0;  D(4,4) = 1.0;  D(4,5) = 0.0;
  D(5,0) = 0.0;  D(5,1) = 0.0;  D(5,2) = 0.0;  D(5,3) = 5.0;  D(5,4) = 0.0;  D(5,5) = 1.0;

  invD = D;
  OpenTissue::math::optimization::detail::compute_inverse_D( invD );

  ublas::sparse_prod(D, invD, I);

  double tol = 0.01;

  BOOST_CHECK_CLOSE( double( I(0,0) ), double( 1.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(0,1) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(0,2) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(0,3) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(0,4) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(0,5) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,0) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,1) ), double( 1.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,2) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,3) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,4) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(1,5) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,0) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,1) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,2) ), double( 1.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,3) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,4) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(2,5) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,0) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,1) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,2) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,3) ), double( 1.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,4) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(3,5) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,0) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,1) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,2) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,3) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,4) ), double( 1.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(4,5) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,0) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,1) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,2) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,3) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,4) ), double( 0.0 ), tol );
  BOOST_CHECK_CLOSE( double( I(5,5) ), double( 1.0 ), tol );

}

BOOST_AUTO_TEST_SUITE_END();


#include "cor_algorithm/sources/utilities.h"
#include "cor_system/sources/logger.h"
#include "cor_type/sources/math/matrix4x4_tmpl_impl.h"

#define BOOST_TEST_NO_LIB
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(matrix)

BOOST_AUTO_TEST_CASE(matrix4x4)
{
    cor::type::Matrix4x4F rx = cor::type::Matrix4x4F::rot_x(30.0f);
    cor::type::Matrix4x4F irx = cor::type::Matrix4x4F::rot_x(-30.0f);
    cor::type::Matrix4x4F idt;
    cor::type::Matrix4x4F rx0 = rx * irx;

    cor::RString idts = cor::algorithm::join(idt, ",");
    cor::RString rx0s = cor::algorithm::join(rx0, ",");
    cor::RString rxs = cor::algorithm::join(rx, ",");

    cor::type::Matrix4x4F::iterator ip;
    cor::type::Matrix4x4F::iterator jp;
    cor::type::Matrix4x4F::iterator ied;

    ip = idt.begin();
    ied = idt.end();
    jp = rx0.begin();

    for(; ip != ied ; ip++, jp++)
    {
        BOOST_CHECK_CLOSE(*ip, *jp, 0.00001);
    }

}

BOOST_AUTO_TEST_SUITE_END()


// Copyright (c) 2019 Graphcore Ltd. All rights reserved.
#define BOOST_TEST_MODULE Train0MatmulTest

#include <../random_util.hpp>
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <filereader.hpp>
#include <popart/builder.hpp>
#include <popart/dataflow.hpp>
#include <popart/devicemanager.hpp>
#include <popart/inputshapeinfo.hpp>
#include <popart/ndarraywrapper.hpp>
#include <popart/op/identity.hpp>
#include <popart/op/l1.hpp>
#include <popart/session.hpp>
#include <popart/sgd.hpp>
#include <popart/tensorinfo.hpp>
#include <popart/tensornames.hpp>
#include <popart/testdevice.hpp>

#include <algorithm>
#include <map>
#include <tuple>
#include <vector>

// Test:
// C = matmul (A, B) where both A and B are weight matrices,
// loss = lambda*|C|_1
BOOST_AUTO_TEST_CASE(DatalessTrainingMatmul) {

  // genPdf : generate of dot file pdf of the training computation
  auto test = [](bool genPdf) {
    using namespace popart;

    // the dimensions of the matrices
    int K = 6;
    int M = 7;
    int N = 8;

    // we will generate random initializations
    int seed = 1013;
    DefaultRandomEngine eng(seed);
    UniformRealDistribution<float> fdis(-4.f, 4.f);

    // prepare a Builder for creating onnx model
    auto bder   = Builder::create();
    auto aiOnnx = bder->aiOnnxOpset9();

    // matrix A of shape M x K
    TensorInfo A_info{"FLOAT", std::vector<int64_t>{M, K}};
    std::vector<float> v_A_init(A_info.nelms());
    for (auto &val : v_A_init) {
      val = fdis(eng);
    }
    TensorId A_id = bder->addInitializedInputTensor({v_A_init.data(), A_info});

    // matrix B of shape K x N
    TensorInfo B_info{"FLOAT", std::vector<int64_t>{K, N}};
    std::vector<float> v_B_init(B_info.nelms());
    for (auto &val : v_B_init) {
      val = fdis(eng);
    }
    TensorId B_id = bder->addInitializedInputTensor({v_B_init.data(), B_info});

    // matrix C = A * B (output of network)
    TensorInfo C_info{"FLOAT", std::vector<int64_t>{M, N}};
    TensorId C_id = aiOnnx.matmul({A_id, B_id});

    // l1 loss with penalty term, will be applied to C
    float lossLambda = 0.26;
    auto l1          = bder->aiGraphcoreOpset1().l1loss(
        {C_id}, lossLambda, ReductionType::Sum);

    // compute the baseline
    std::vector<float> v_C_data(C_info.nelms());
    std::vector<float> v_C_grad(C_info.nelms());
    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        int index       = m * N + n;
        v_C_data[index] = 0;
        for (int k = 0; k < K; ++k) {
          v_C_data[index] += v_A_init[m * K + k] * v_B_init[k * N + n];
        }
        v_C_grad[index] = 2 * (v_C_data[index] > 0) - 1;
        v_C_grad[index] *= lossLambda;
      }
    }

    // gradients of A and B,
    // dA = dC.BT
    // dB = AT.dC
    std::vector<float> v_A_grad(A_info.nelms(), 0);
    std::vector<float> v_B_grad(B_info.nelms(), 0);
    for (int m = 0; m < M; ++m) {
      for (int n = 0; n < N; ++n) {
        for (int k = 0; k < K; ++k) {
          v_A_grad[m * K + k] += v_C_grad[m * N + n] * v_B_init[k * N + n];
          v_B_grad[k * N + n] += v_C_grad[m * N + n] * v_A_init[m * K + k];
        }
      }
    }

    auto proto      = bder->getModelProto();
    auto modelProto = io::getModelFromString(proto);
    auto art        = AnchorReturnType("All");
    // one batch per step
    int batchesPerStep = 1;
    auto dataFlow      = DataFlow(batchesPerStep,
                             {{C_id, art},
                              {reservedGradientPrefix() + A_id, art},
                              {reservedGradientPrefix() + B_id, art}});

    auto device = popart::createTestDevice(TEST_TARGET);

    auto opts            = SessionOptions();
    opts.enableOutlining = true;
    if (genPdf) {
      opts.firstDotOp = 0;
      opts.finalDotOp = 100;
      opts.dotChecks.insert("Final");
      opts.logDir = "./dotfiles";
      if (!boost::filesystem::exists(opts.logDir)) {
        boost::filesystem::create_directories(opts.logDir);
      }
    }

    // training info
    float learnRate = 0.321;
    auto optimizer  = ConstSGD(learnRate);

    auto session = popart::TrainingSession::createFromOnnxModel(
        proto,
        dataFlow,
        l1,
        optimizer,
        device,
        popart::InputShapeInfo(),
        opts,
        popart::Patterns(PatternsLevel::Default));

    // prepare the anchors. We have the output C,
    std::vector<float> raw_C_out(C_info.nelms());
    popart::NDArrayWrapper<float> C_wrapper(raw_C_out.data(), C_info.shape());

    // the gradient of A,
    std::vector<float> raw_A_grad_out(A_info.nelms());
    popart::NDArrayWrapper<float> A_grad_wrapper(raw_A_grad_out.data(),
                                                 A_info.shape());
    // and the gradient of B.
    std::vector<float> raw_B_grad_out(B_info.nelms());
    popart::NDArrayWrapper<float> B_grad_wrapper(raw_B_grad_out.data(),
                                                 B_info.shape());

    std::map<popart::TensorId, popart::IArray &> anchors = {
        {C_id, C_wrapper},
        {reservedGradientPrefix() + A_id, A_grad_wrapper},
        {reservedGradientPrefix() + B_id, B_grad_wrapper}};

    session->prepareDevice();

    // inputs:
    popart::NDArrayWrapper<float> A_wrapper(v_A_init.data(), A_info);
    popart::NDArrayWrapper<float> B_wrapper(v_B_init.data(), B_info);
    std::map<popart::TensorId, popart::IArray &> inputs = {{A_id, A_wrapper},
                                                           {B_id, B_wrapper}};

    popart::StepIO stepio(inputs, anchors);

    session->weightsFromHost();
    session->run(stepio);

    // confirm the gradient values agree (exactly...)
    BOOST_CHECK_EQUAL_COLLECTIONS(
        v_C_data.begin(), v_C_data.end(), raw_C_out.begin(), raw_C_out.end());

    BOOST_CHECK_EQUAL_COLLECTIONS(v_A_grad.begin(),
                                  v_A_grad.end(),
                                  raw_A_grad_out.begin(),
                                  raw_A_grad_out.end());

    BOOST_CHECK_EQUAL_COLLECTIONS(v_B_grad.begin(),
                                  v_B_grad.end(),
                                  raw_B_grad_out.begin(),
                                  raw_B_grad_out.end());

    // we will read the updated weights back, and check that they are correct
    std::vector<float> v_A_updated_baseline = v_A_init;
    std::vector<float> v_B_updated_baseline = v_B_init;
    for (int k = 0; k < K; ++k) {
      for (int n = 0; n < N; ++n) {
        v_B_updated_baseline[k * N + n] -= learnRate * v_B_grad[k * N + n];
      }

      for (int m = 0; m < M; ++m) {
        v_A_updated_baseline[m * K + k] -= learnRate * v_A_grad[m * K + k];
      }
    }
    WeightsIO weightsRead;
    // to be readback:
    std::vector<float> A_readback(A_info.nelms(), -9.0f);
    std::vector<float> B_readback(B_info.nelms(), -99.0f);
    weightsRead.insert(A_id, {A_readback.data(), A_info});
    weightsRead.insert(B_id, {B_readback.data(), B_info});

    session->weightsToHost();
    session->readWeights(weightsRead);

    BOOST_CHECK_EQUAL_COLLECTIONS(v_A_updated_baseline.begin(),
                                  v_A_updated_baseline.end(),
                                  A_readback.begin(),
                                  A_readback.end());

    BOOST_CHECK_EQUAL_COLLECTIONS(v_B_updated_baseline.begin(),
                                  v_B_updated_baseline.end(),
                                  B_readback.begin(),
                                  B_readback.end());

    // dot -Tpdf -o final.pdf final.dot
    if (genPdf) {
      for (auto dot_string : opts.dotChecks) {
        std::stringstream command_ss;
        command_ss << "dot "
                   << " -Tpdf "
                   << " -o "
                   << io::appendDirFn(opts.logDir, dot_string + ".pdf") << " "
                   << io::appendDirFn(opts.logDir, dot_string + "_r.dot");
        std::string command = command_ss.str();
        int ran             = std::system(command.c_str());
        std::cout << command << " returned with status " << ran << std::endl;
        BOOST_CHECK(ran == 0);
        auto pdfFileNames =
            io::getMatchFns(io::getCanonicalDirName(opts.logDir), ".pdf");
        BOOST_CHECK(pdfFileNames.size() == 1);
      }
    }
  };

  // should only be true for debugging (on a machine with dot program)
  bool genPdf = false;
  test(genPdf);
}


#include <algorithm>
#include <boost/optional.hpp>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#define REP(i, n) for(int i = 0, i##_MACRO = (n); i < i##_MACRO; i++)
#define RANGE(i, a, b) for(int i = (a), i##_MACRO = (b); i < i##_MACRO; i++)
#define EACH(e, a) for(auto&& e : a)
#define ALL(a) std::begin(a), std::end(a)
#define RALL(a) std::rbegin(a), std::rend(a)
#define FILL(a, n) memset((a), n, sizeof(a))
#define FILLZ(a) FILL(a, 0)
#define INT(x) (static_cast<int>(x))
#define PRECISION(x) std::fixed << std::setprecision(x)

using namespace std;

using ll = long long;
using VI = vector<int>;
using VI2D = vector<vector<int>>;

constexpr int INF = 2e9;
constexpr double EPS = 1e-10;
constexpr double PI = acos(-1.0);

constexpr int dx[] = {-1, 0, 1, 0};
constexpr int dy[] = {0, -1, 0, 1};

template <typename T>
constexpr int sign(T x) {
	return x < 0 ? -1 : x > 0 ? 1 : 0;
}

template <>
constexpr int sign(double x) {
	return x < -EPS ? -1 : x > EPS ? 1 : 0;
}

template <typename T, typename U>
constexpr void chmax(T& m, U x) {
	m = max(m, x);
}

template <typename T, typename U>
constexpr void chmin(T& m, U x) {
	m = min(m, x);
}

template <typename T>
constexpr T square(T x) {
	return x * x;
}

template <typename T>
std::unordered_map<size_t, T> group_count(std::vector<T>& v) {
	std::unordered_map<size_t, T> c;
	for(T& e : v) {
		c[e]++;
	}
	return c;
}

double memo[301][301][301];

double solve(int n, int c1, int c2, int c3) {
	if(memo[c1][c2][c3] >= 0) {
		return memo[c1][c2][c3];
	}
	if(c1 == 0 && c2 == 0 && c3 == 0) {
		return 0.0;
	}

	return memo[c1][c2][c3] =
			   ((c1 > 0 ? (solve(n, c1 - 1, c2, c3) * c1) : 0.0) +
				(c2 > 0 ? (solve(n, c1 + 1, c2 - 1, c3) * c2) : 0.0) +
				(c3 > 0 ? (solve(n, c1, c2 + 1, c3 - 1) * c3) : 0.0) + n) /
			   static_cast<double>(c1 + c2 + c3);
}

int main() {
	int n;
	cin >> n;
	VI a(n);
	REP(i, n) { cin >> a[i]; }
	unordered_map<size_t, int> cnt = group_count(a);
	FILL(memo, -1);
	cout << PRECISION(15) << solve(n, cnt[1], cnt[2], cnt[3]) << endl;
	return 0;
}