#pragma once

#include "cfl_condition.hpp"
#include "mesh.hpp"
#include "numerical_flux.hpp"

#include <Eigen/Core>
#include <Eigen/Dense>
#include <chrono>
#include <fmt/format.h>

void print_progress(
    int n_steps,
    double T,
    double t,
    double dt,
    const std::chrono::high_resolution_clock::time_point &time_start);

Eigen::MatrixXd solveEuler(Eigen::MatrixXd U0, const Mesh &mesh, double T) {

    int n_cells = mesh.getNumberOfTriangles();

    Eigen::MatrixXd U_tmp(n_cells, 4);
    Eigen::MatrixXd dUdt(n_cells, 4);

    double t = 0;

    auto cfl_condition = CFLCondition(mesh);
    auto computeNetFlux = FluxRateOfChange(n_cells);

    int n_steps = 0;

    auto time_start = std::chrono::high_resolution_clock::now();

    std::cout << std::endl;
    while (t < T) {
        double dt = cfl_condition(U0);

        // Compute u^(*)
        computeNetFlux(dUdt, U0, mesh);
#pragma omp parallel for
        for (int i = 0; i < n_cells; ++i) {
            U_tmp.row(i) = U0.row(i) + dt * dUdt.row(i);
        }

        // Compute u^(**) and u^{n+1} in one step. We can update U0 directly.
        computeNetFlux(dUdt, U_tmp, mesh);
#pragma omp parallel for
        for (int i = 0; i < n_cells; ++i) {
            U0.row(i) = 0.5 * (U0.row(i) + U_tmp.row(i) + dt * dUdt.row(i));
        }

        t += dt;
        n_steps++;

        print_progress(n_steps, T, t, dt, time_start);
    }
    std::cout << "\n";

    return U0;
}

void print_progress(
    int n_steps,
    double T,
    double t,
    double dt,
    const std::chrono::high_resolution_clock::time_point &time_start) {

    auto now = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(
        now - time_start);
    double elapsed = duration.count();
    double eta = elapsed * (T - t) / t;

    std::cout << fmt::format("\r"
                             "n_steps = {: 3d}, t = {:.3e}, dt = {:.2e}, "
                             "elased = {:6.1f}s, eta = {:6.1f}s",
                             n_steps,
                             t,
                             dt,
                             elapsed,
                             eta);
    std::cout.flush();
}


#define BOOST_TEST_MODULE "root_name"
// #define BOOST_TEST_MAIN

// note we only test CalibratorSample.
#include "CalibratorSample.h"

#include <boost/test/unit_test.hpp>
#include <boost/shared_ptr.hpp>

#include <random>
#include <iostream>

// this bitpacker is only used in the unittests, so doesn't need to be fast.
struct BitPacker
{
    void clear()
    {
        m_val = 0;
    }

    void setCoarse(uint16_t c)
    {
        uint16_t mask = 0x001f;
        c <<= 0;
        c &= mask;
        m_val &= ~mask;
        m_val |= c;
    }
    void setFine(uint16_t f)
    {
        uint16_t mask = 0x1fe0;
        f <<= 5;
        f &= mask;
        m_val &= ~mask;
        m_val |= f;
    }
    void setGain(uint16_t g)
    {
        uint16_t mask = 0x6000;
        g <<= 13;
        g &= mask;
        m_val &= ~mask;
        m_val |= g;
    }
    uint16_t getBits()
    {
        return m_val;
    }
    void setBits(uint16_t val)
    {
        m_val = val;
    }
    uint16_t m_val = 0;
};

// note there are two versions of the same function: processFrameRowSIMD and processFrameRow
// These unit-tests should pass on BOTH, but our strategy is to test one of them, and then
// check they both produce the same results. Although we can also do a search-replace.
// recall the equation we are testing is:
// res = IdOf + Gc * (c-Oc) + Gf * (f-Of)

// these k values should be non-zero
static const float k1 = 1.1f;
static const float k2 = 2.2f;
static const float k3 = 3.4f;
static const float k4 = 4.8f;
static const float k5 = 5.2f;
static const float k6 = 6.5f;
static const float k7 = 7.8f;
static const float k8 = 8.3f;
static const float smallPercent = 0.001f;
static const float idealOffset = 128.0 * 32.0f;

BOOST_AUTO_TEST_CASE(CalibratorCreateAndDestroy)
{
    CalibratorSample calibrator;

    BOOST_CHECK_CLOSE(1000.0F, 1000.001f, smallPercent);
    // alignment check
    BOOST_CHECK((uint64_t)calibrator.m_Gc.data()%32 == 0);
}

// this one checks that IdOf is ok.
BOOST_AUTO_TEST_CASE(CalibratorIdealOffset)
{
    int rows=1, cols=8;
    CalibratorSample calibrator(rows,cols);

    calibrator.m_Gc.at(0,0) = 0.0;
    calibrator.m_Oc.at(0,0) = k2;
    calibrator.m_Gf.at(0,0) = 0.0;
    calibrator.m_Of.at(0,0) = k4;
    calibrator.m_Gain0.at(0,0) = 1.0;

    BitPacker bp;
    bp.clear();
    bp.setCoarse(4); // random value
    bp.setFine(4);
    bp.setGain(0);

    MemBlockI16 input;
    MemBlockF output;

    input.init(rows,cols);
    output.init(rows,cols);

    input.at(0,0) = bp.getBits();

    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), idealOffset, smallPercent);
}

// this one checks that the coarse value is processed ok
// then it checks that the fine value is processed ok
// then it checks the complete sum works out ok
// also known as ADC stage
BOOST_AUTO_TEST_CASE(CalibratorCoarseAndFine)
{
    int rows=1, cols=8;
    CalibratorSample calibrator(rows,cols);

    calibrator.m_Gc.at(0,0) = k1;
    calibrator.m_Oc.at(0,0) = k2;
    calibrator.m_Gf.at(0,0) = k3;
    calibrator.m_Of.at(0,0) = k4;
    calibrator.m_Gain0.at(0,0) = 1.0;

    BitPacker bp;
    bp.clear();
    bp.setCoarse(8);
    bp.setFine(150);
    bp.setGain(0);

    MemBlockI16 input;
    MemBlockF output;

    input.init(rows,cols);
    output.init(rows,cols);

    input.at(0,0) = bp.getBits();

    // check coarse alone
    calibrator.m_Gf.at(0,0) = 0.0;
    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), idealOffset + k1 * (8.0f - k2), smallPercent);

    // check fine alone
    input.at(0,0) = bp.getBits();
    calibrator.m_Gc.at(0,0) = 0.0;
    calibrator.m_Gf.at(0,0) = k3;
    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), idealOffset + k3 * (150.0f - k4), smallPercent);

    // now do both together:
    input.at(0,0) = bp.getBits();
    calibrator.m_Gc.at(0,0) = k1;
    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), idealOffset + k1 * (8.0f - k2) + k3 * (150.0f - k4), smallPercent);
}

// this one checks that the cds-stage = subtract reset frame, is ok
BOOST_AUTO_TEST_CASE(CalibratorReset)
{
    int rows=1, cols=8;
    CalibratorSample calibrator(rows,cols);

    calibrator.m_Gc.at(0,0) = 0.0;
    calibrator.m_Gf.at(0,0) = 0.0;
    calibrator.m_Gc.at(0,1) = 0.0;
    calibrator.m_Gf.at(0,1) = 0.0;
    calibrator.m_resetFrame.at(0,0) = k8;

    BitPacker bp;
    bp.clear();
    bp.setGain(0);

    MemBlockI16 input;
    MemBlockF output;

    input.init(rows,cols);
    output.init(rows,cols);

    input.at(0,0) = bp.getBits();
    bp.setGain(1);
    input.at(0,1) = bp.getBits();

    float idOf = 128.0f * 32.0f;
    // check reset frame is subtracted
    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), idOf - k8, smallPercent);
    // but not when gain = 1
    BOOST_CHECK_CLOSE(output.at(0,1), idOf, smallPercent);
}

// this one checks the Lat stage: subtract Ped and multiply
BOOST_AUTO_TEST_CASE(CalibratorLatPedGain)
{
    int rows=1, cols=8;
    CalibratorSample calibrator(rows,cols);

    calibrator.m_Gc.at(0,0) = 0.0;
    calibrator.m_Gf.at(0,0) = 0.0;
    calibrator.m_Gc.at(0,1) = 0.0;
    calibrator.m_Gf.at(0,1) = 0.0;
    calibrator.m_Ped0.at(0,0) = k1;
    calibrator.m_Ped1.at(0,1) = k2;
    calibrator.m_Ped2.at(0,2) = k3;
    calibrator.m_Gain0.at(0,0) = k4;
    calibrator.m_Gain1.at(0,1) = k5;
    calibrator.m_Gain2.at(0,2) = k6;

    BitPacker bp;
    bp.clear();
    bp.setGain(0);

    MemBlockI16 input;
    MemBlockF output;

    input.init(rows,cols);
    output.init(rows,cols);

    input.at(0,0) = bp.getBits();
    bp.setGain(1);
    input.at(0,1) = bp.getBits();
    bp.setGain(2);
    input.at(0,2) = bp.getBits();
    bp.setGain(3);
    input.at(0,3) = bp.getBits();

    float idOf = 128.0f * 32.0f;
    // check right things subtracted in each case
    calibrator.processFrameRow(input, output, 0);
    BOOST_CHECK_CLOSE(output.at(0,0), k4 * (idOf - k1), smallPercent);
    BOOST_CHECK_CLOSE(output.at(0,1), k5 * (idOf - k2), smallPercent);
    BOOST_CHECK_CLOSE(output.at(0,2), k6 * (idOf - k3), smallPercent);
    BOOST_CHECK(isnan(output.at(0,3)));

}

BOOST_AUTO_TEST_CASE(CalibratorAlgNanOk)
{
    int rows=1, cols=24;
    CalibratorSample calibrator(rows,cols);

    MemBlockI16 input;
    input.init(rows,cols);

    for(int c=0;c<cols;++c)
    {
        calibrator.m_Gc.at(0,c) = k1;
        calibrator.m_Oc.at(0,c) = k2;
        calibrator.m_Gf.at(0,c) = k3;
        calibrator.m_Of.at(0,c) = k4;
        calibrator.m_Gain0.at(0,c) = k5;
        calibrator.m_Gain1.at(0,c) = k6;
        calibrator.m_Gain2.at(0,c) = k7;
        calibrator.m_Gain3 = k8;

        input.at(0,c) = rand();
    }

    BitPacker bp;
    bp.clear();
    bp.setCoarse(1);
    bp.setFine(1);
    bp.setGain(0);

    input.at(0,0) = bp.getBits();
    calibrator.m_Gain0.at(0,0) = std::numeric_limits<float>::quiet_NaN();

    calibrator.m_Gc.at(0,1) = std::numeric_limits<float>::quiet_NaN();

    MemBlockF output1;
    output1.init(rows,cols);
    calibrator.processFrameRow(input, output1, 0);

    float lastOne = 0.0f;
    for(int c=0;c<cols;++c)
    {
        if( c==0 || c==1 )
        {
            BOOST_CHECK( isnan(output1.at(0,c)) );
        }
        else
        {
            BOOST_CHECK( !isnan(output1.at(0,c)) );
        }
    }
}

// this tests it when the cma value is not nan (all g0 on cma cols)
BOOST_AUTO_TEST_CASE(CalibratorCMA_real)
{
    int rows=1, cols=64;
    int col1 = 40;
    CalibratorSample calibrator(rows,cols);
    calibrator.setCMA(true, 0);

    MemBlockF pic;
    MemBlockI16 gain;
    pic.init(rows,cols);
    gain.init(rows,cols);
    gain.setAll(0);
    gain.at(0, col1) = 1;

    for(int c=0;c<cols;++c)
    {
        pic.at(0,c) = static_cast<float>(c);
    }

    calibrator.applyCMA(gain, pic, 0);

    for(int c=0;c<cols;++c)
    {
        if(c==col1)
        {
            // cma value not subtracted here cos G1
            BOOST_CHECK_CLOSE(pic.at(0,c), c, smallPercent);
        }
        else
        {
            BOOST_CHECK_CLOSE(pic.at(0,c), c - (31.0f/2.0f), smallPercent);
        }
    }
}

// this tests it when the cma value is nan (not G0 on cma cols)
BOOST_AUTO_TEST_CASE(CalibratorCMA_nan)
{
    int rows=1, cols=64;
    int col1 = 40, col2 = 0;
    CalibratorSample calibrator(rows,cols);
    calibrator.setCMA(true, 0);

    MemBlockF pic;
    MemBlockI16 gain;
    pic.init(rows,cols);
    gain.init(rows,cols);
    gain.setAll(0);
    gain.at(0, col2) = 2;
    gain.at(0, col1) = 1;

    for(int c=0;c<cols;++c)
    {
        pic.at(0,c) = static_cast<float>(c);
    }

    calibrator.applyCMA(gain, pic, 0);

    for(int c=0;c<cols;++c)
    {
        if(c==col1 || c==col2)
        {
            // cma value not subtracted here cos G1
            BOOST_CHECK_CLOSE(pic.at(0,c), c, smallPercent);
        }
        else
        {
            BOOST_CHECK(isnan(pic.at(0,c)));
        }
    }
}

// this one tests processFrameRowSIMD produces the same as processFrameRow for
// some random data. If they agree, they are both right because they are on
// different code paths. We can't test CMA because it requires gain 0 on its row.
BOOST_AUTO_TEST_CASE(CalibratorAlgSIMDSameAsNormal)
{
    const float percentDiff = 0.2;
    int rows=1, cols=24;
    CalibratorSample calibrator(rows,cols);

    MemBlockI16 input, input2;
    input.init(rows,cols);

    calibrator.m_resetFrame.setAll(k4);

    for(int c=0;c<cols;++c)
    {
        calibrator.m_Gc.at(0,c) = k1;
        calibrator.m_Oc.at(0,c) = k2;
        calibrator.m_Gf.at(0,c) = k3;
        calibrator.m_Of.at(0,c) = k4;

        calibrator.m_Ped0.at(0,c) = k3;
        calibrator.m_Ped1.at(0,c) = k6;
        calibrator.m_Ped2.at(0,c) = k7;

        calibrator.m_Gain0.at(0,c) = k5;
        calibrator.m_Gain1.at(0,c) = k6;
        calibrator.m_Gain2.at(0,c) = k7;
        calibrator.m_Gain3 = k8;

        input.at(0,c) = rand();
    }

    input2.clone(input);

    MemBlockF output1, output2;
    output1.init(rows,cols);
    output2.init(rows,cols);

    calibrator.processFrameRowSIMD(input, output1, 0);
    calibrator.processFrameRow(input2, output2, 0);

    float lastOne = 0.0f;
    for(int c=0;c<cols;++c)
    {
        {
            BOOST_CHECK_CLOSE(output1.at(0,c), output2.at(0,c), percentDiff);
            BOOST_CHECK(input.at(0,c) == input2.at(0,c));
            // just check it's not all the same garbage data
            BOOST_CHECK(lastOne != output1.at(0,c));
            lastOne = output1.at(0,c);
        }
    }
}


/*  $Id$
 *
 *  Copyright 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com)
 *
 *  This file is part of OpenCAMlib.
 *
 *  OpenCAMlib is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  OpenCAMlib is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenCAMlib.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TSP_H
#define TSP_H

#include <iostream>
#include <vector>
#include <fstream>
#include <set>
#include <ctime>

#include <boost/assert.hpp>
#include <boost/graph/adjacency_matrix.hpp>
#include <boost/graph/simple_point.hpp>
#include <boost/graph/metric_tsp_approx.hpp>

#include <boost/python.hpp>

namespace ocl {

namespace tsp {

// loosely based on metric tsp example:
// http://www.boost.org/doc/libs/1_46_1/libs/graph/test/metric_tsp_approx.cpp

//add edges to the graph (for each node connect it to all other nodes)
template< typename VertexListGraph,
          typename PointContainer,
          typename WeightMap,
          typename VertexIndexMap>
void connectAllEuclidean(VertexListGraph& g,
                        const PointContainer& points,  // vector of (x,y) points
                        WeightMap wmap,            // Property maps passed by value
                        const VertexIndexMap vmap) // Property maps passed by value
{
    using namespace boost;
    using namespace std;
    typedef typename graph_traits<VertexListGraph>::edge_descriptor Edge;
    typedef typename graph_traits<VertexListGraph>::vertex_iterator VItr;
    Edge e;
    bool inserted;
    pair<VItr, VItr> verts(vertices(g));
    for (VItr src(verts.first); src != verts.second; src++) {
        for (VItr dest(src); dest != verts.second; dest++) {
            if (dest != src) {
                double weight( sqrt(
                    pow(static_cast<double>( points[vmap[*src ]].x - points[vmap[*dest]].x), 2.0) +
                    pow(static_cast<double>( points[vmap[*dest]].y - points[vmap[*src ]].y), 2.0)) );
                boost::tie(e, inserted) = add_edge(*src, *dest, g);
                wmap[e] = weight; // passed by value??
            }
        }
    }
}

class TSPSolver {
    typedef boost::adjacency_matrix< boost::undirectedS,
                                     boost::no_property,
                                     boost::property< boost::edge_weight_t, double,
                                     boost::property< boost::edge_index_t, long unsigned int> >,
                                     boost::no_property
                                    > Graph;
    typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
    typedef boost::graph_traits<Graph>::edge_descriptor Edge;
    typedef boost::property_map<Graph, boost::edge_weight_t>::type WeightMap;
    typedef std::vector< boost::simple_point<double> > PointSet; // was std::set
    typedef std::vector< Vertex > Container;

public:
    TSPSolver () {}
    virtual ~TSPSolver() {
        if (g)
            delete g;
    }
    void run() {
        g = new Graph( points.size() );
        // connect all vertices
        WeightMap weight_map = boost::get( boost::edge_weight, *g);
        connectAllEuclidean( *g, points, weight_map, boost::get( boost::vertex_index, *g) );
        length = 0.0;
        // Run the TSP approx, creating the visitor on the fly.
        boost::metric_tsp_approx(*g, boost::make_tsp_tour_len_visitor(*g, std::back_inserter(output), length, weight_map) );
        //length = len;
        //std::cout << "Number of points: " << boost::num_vertices(*g) << std::endl;
        //std::cout << "Number of edges: " << boost::num_edges(*g) << std::endl;
        //std::cout << "Length of tour: " << len << std::endl;
        //std::cout << "vertices in tour: " << output.size() << std::endl;
        //std::cout << "Elapsed: " << t.elapsed() << std::endl;
    }
    void addPoint(double x, double y) {
        boost::simple_point<double> pnt;
        pnt.x=x;
        pnt.y=y;
        points.push_back(pnt);
    }
    void reset() {
        output.clear();
        points.clear();
        if (g)
            delete g;
    }
    void printOutput() const {
        int n=0;
        BOOST_FOREACH( Vertex v, output ) {
            std::cout << n++ << " : " << v << "\n" ;
        }
    }
    double getLength() const {
        return length;
    }
    boost::python::list getOutput() const {
        boost::python::list plist;
        BOOST_FOREACH(Vertex v, output) {
            plist.append( v );
        }
        return plist;
    }

protected:
    Container output;
    PointSet points;
    Graph* g;
    double length;
};

} // end tsp namespace

} // end ocl namespace
#endif


/*!
 * Copyright (C) tkornuta, IBM Corporation 2015-2019
 *
 * 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.
 */
/*!
 * @file: MatrixTests.cpp
 * @Author: Tomasz Kornuta <tkornut@us.ibm.com>
 * @Date:   Nov 22, 2016
 *
 * Copyright (c) 2016, IBM Corporation. All rights reserved.
 *
 */

#include <gtest/gtest.h>

#include <fstream>
// Include headers that implement a archive in simple text format
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

// Redefine word "public" so every class field/method will be accessible for tests.
#define private public
#include <types/Tensor.hpp>
#include <types/Matrix.hpp>

/*!
 * Tests whether matrix has proper dimensions (2x5).
 */
TEST(Tensor, Dimensions2x5) {
	// Default sizes of matrices.
	const size_t N = 2;
	const size_t M = 5;
	const size_t K = 13;

	mic::types::Tensor<float> nm({N, M, K});

	ASSERT_EQ(nm.dim(0), N);
	ASSERT_EQ(nm.dim(1), M);
	ASSERT_EQ(nm.dim(2), K);
}

/*!
 * Tests enumeration.
 */
TEST(Tensor, Enumeration2x3) {
	// Default sizes of matrices.
	const size_t N = 2;
	const size_t M = 3;

	mic::types::Tensor<float> nm({N, M});
	nm.enumerate();

//	std::cout << nm << std::endl;

	for (size_t i =0; i< N*M; i++)
		ASSERT_EQ(nm(i), i);

/*	for(size_t row=0; row<N; row++) {
		for(size_t col=0; col<M; col++)
			std::cout << " nm(" << row << "," << col << ") = " << nm({row,col});
		std::cout << std::endl;
	}//: for*/

	ASSERT_EQ(nm({0,0}), 0);
	ASSERT_EQ(nm({1,0}), 1);
	ASSERT_EQ(nm({0,1}), 2);
	ASSERT_EQ(nm({1,1}), 3);
	ASSERT_EQ(nm({0,2}), 4);
	ASSERT_EQ(nm({1,2}), 5);

}

/*!
 * Tests Tensor serialization.
 */
TEST(Tensor, Serialization) {
	// Default sizes of matrices.
	const size_t N = 2;
	const size_t M = 5;
	const size_t K = 11;

	mic::types::Tensor<float> nm({N, M, K});
	nm.randn();

	const char* fileName = "saved.txt";
	// Save data
	{
		// Create an output archive
		std::ofstream ofs(fileName);
		boost::archive::text_oarchive ar(ofs);
		// Write data
		ar & nm;
		//std::cout << "Saved matrix = " << nm << std::endl;
	}

	// Restore data
	mic::types::Tensor<float> restored_tensor;
	restored_tensor.randn();

	{
		// Create and input archive
		std::ifstream ifs(fileName);
		boost::archive::text_iarchive ar(ifs);
		// Load data
		ar & restored_tensor;
		//std::cout << "Restored tensor = " << restored_tensor << std::endl;
	}

	// Check dimensions.
	ASSERT_EQ(nm.elements, restored_tensor.elements);
	ASSERT_EQ(nm.dimensions.size(), restored_tensor.dimensions.size());
	for (size_t i =0; i< (size_t)nm.dimensions.size(); i++)
		ASSERT_EQ(nm.dimensions[i], restored_tensor.dimensions[i]);

	// Check values.
	float eps = 1e-8;
	for (size_t i =0; i< (size_t)nm.size(); i++)
		EXPECT_LE(fabs(nm(i) - restored_tensor(i)), eps);

}

/*!
 * Tests im2col.
 */
TEST(Tensor, Im2Col2x3) {
	// Default sizes of matrices.
	const size_t N = 2;
	const size_t M = 3;

	mic::types::Tensor<float> nm({N, M});
	nm.enumerate();

}

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


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

#ifndef MTL_MATRIX_INV_INCLUDE
#define MTL_MATRIX_INV_INCLUDE

#include <boost/numeric/mtl/mtl_fwd.hpp>
#include <boost/numeric/mtl/concept/collection.hpp>
#include <boost/numeric/mtl/matrix/identity.hpp>
#include <boost/numeric/mtl/operation/upper_trisolve.hpp>
#include <boost/numeric/mtl/operation/lu.hpp>
#include <boost/numeric/mtl/utility/exception.hpp>
#include <boost/numeric/mtl/utility/irange.hpp>
#include <boost/numeric/mtl/utility/tag.hpp>
#include <boost/numeric/mtl/vector/parameter.hpp>
#include <boost/numeric/mtl/vector/dense_vector.hpp>
#include <boost/numeric/mtl/vector/unit_vector.hpp>
#include <boost/numeric/mtl/interface/vpt.hpp>

namespace mtl { namespace mat {

namespace traits {

    /// Return type of inv(Matrix)
    /** Might be specialized later for the sake of efficiency **/
    template <typename Matrix>
    struct inv
    {
	typedef typename Collection<Matrix>::value_type    value_type;
	typedef ::mtl::mat::dense2D<value_type>         type;
    };

} // traits

/// Invert upper triangular matrix
template <typename Matrix, typename MatrixOut>
void inv_upper(Matrix const& A, MatrixOut& Inv)
{
    vampir_trace<5019> tracer;
    typedef typename Collection<Matrix>::value_type    value_type;
    typedef typename Collection<Matrix>::size_type     size_type;

    const size_type N= num_rows(A);
    MTL_DEBUG_THROW_IF(num_cols(A) != N, matrix_not_square());
    MTL_DEBUG_THROW_IF(N != num_rows(Inv) || num_cols(A) != num_cols(Inv), incompatible_size());

    Inv= math::zero(value_type());

    for (size_type k= 0; k < N; ++k) {
	irange r(k+1);
	typename mtl::ColumnInMatrix<MatrixOut>::type col_k(Inv[r][k]);
	upper_trisolve(A[r][r], vec::unit_vector<value_type>(k, k+1), col_k, mtl::tag::regular_diagonal());
    }
}

/// Invert upper triangular matrix
template <typename Matrix>
inline typename traits::inv<Matrix>::type
inv_upper(Matrix const& A)
{
    typedef typename Collection<Matrix>::size_type     size_type;
    const size_type N= num_rows(A);
    typename traits::inv<Matrix>::type Inv(N, N);
    inv_upper(A, Inv);
    return Inv;
}

#if 0
/// Invert lower triangular matrix
template <typename Matrix, typename MatrixOut>
inline void inv_lower(Matrix const& A, MatrixOut& Inv)
{
    vampir_trace<5020> tracer;
    typedef typename Collection<Matrix>::value_type    value_type;
    typedef typename Collection<Matrix>::size_type     size_type;

    const size_type N= num_rows(A);
    MTL_DEBUG_THROW_IF(num_cols(A) != N, matrix_not_square());
    MTL_DEBUG_THROW_IF(N != num_rows(Inv) || num_cols(A) != num_cols(Inv), incompatible_size());

    Inv= math::zero(value_type());

    for (size_type k= 0; k < N; ++k) {
	irange r(k, N);
	typename mtl::ColumnInMatrix<MatrixOut>::type col_k(Inv[r][k]);
	lower_trisolve(A[r][r], unit_vector<value_type>(0, N-k), col_k, mtl::tag::regular_diagonal());
    }
}

template <typename Matrix>
typename traits::inv<Matrix>::type
inline inv_lower(Matrix const& A)
{
    typedef typename Collection<Matrix>::size_type     size_type;
    const size_type N= num_rows(A);
    typename traits::inv<Matrix>::type Inv(N, N);
    inv_lower(A, Inv);
    return Inv;
}
#endif

#if 1
/// Invert lower triangular matrix
template <typename Matrix>
typename traits::inv<Matrix>::type
inline inv_lower(Matrix const& A)
{
    vampir_trace<5020> tracer;
    Matrix T(trans(A)); // Shouldn't be needed
    return typename traits::inv<Matrix>::type(trans(inv_upper(T)));
}
#endif

/// Invert matrix
/** Uses pivoting LU factorization and triangular inversion
    \sa \ref lu, \ref inv_upper, \ref inv_lower **/
template <typename Matrix, typename MatrixOut>
inline void inv(Matrix const& A, MatrixOut& Inv)
{
    vampir_trace<5021> tracer;
    typedef typename Collection<Matrix>::size_type     size_type;
    typedef typename Collection<Matrix>::value_type    value_type;
    typedef typename traits::inv<Matrix>::type         result_type;

    const size_type N= num_rows(A);
    MTL_THROW_IF(num_cols(A) != num_cols(A), matrix_not_square());
    MTL_DEBUG_THROW_IF(N != num_rows(Inv) || num_cols(A) != num_cols(Inv), incompatible_size());

    if (N == 1) {
	Inv[0][0]= value_type(1) / A[0][0];
	return;
    }

    result_type                    PLU(A);
    mtl::dense_vector<size_type, vec::parameters<> >   Pv(num_rows(A));

    lu(PLU, Pv);
    result_type  PU(upper(PLU)), PL(strict_lower(PLU));
    for (size_type i= 0; i < num_rows(A); i++)
	PL[i][i]= value_type(1);

    Inv= inv_upper(PU) * inv_lower(PL) * permutation(Pv);
}

template <typename Matrix>
typename traits::inv<Matrix>::type
inline inv(Matrix const& A)
{
    typedef typename Collection<Matrix>::size_type     size_type;
    const size_type N= num_rows(A);
    typename traits::inv<Matrix>::type Inv(N, N);
    inv(A, Inv);
    return Inv;
}

}} // namespace mtl::matrix

#endif // MTL_MATRIX_INV_INCLUDE


/* Main.cpp (exercise 1.5 problems 1-5)
Description:
	*Solutions to problems 1-5.
*/

#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS

#include <boost\assign.hpp>
#include <boost\date_time.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include "Builder.hpp"
#include "Calculator.hpp"
#include "Circle.hpp"
#include "CircleMonitorBuilder.hpp"
#include "CircleTVBuilder.hpp"
#include "Exception.hpp"
#include "Functions-1.hpp"
#include "Functions-3.hpp"
#include "Functions-4.hpp"
#include "LineMonitorBuilder.hpp"
#include "LineTVBuilder.hpp"
#include "Monitor.hpp"
#include "SizeExcept.hpp"
#include "TV.hpp"

int main()
{
	/* 1.5.1 */
	// a) Use std:tuple<> to emulate a Person class (std::tuple<Name, Address, DateOfBirth>)
	Person personA, personB, personC;
	// Set the name of each person:
	std::get<0>(personA) = "A";
	std::get<0>(personB) = "B";
	std::get<0>(personC) = "C";
	// Set the address of each person:
	std::get<1>(personA) = "123 Main St";
	std::get<1>(personB) = "124 Main St";
	std::get<1>(personC) = "125 Main St";
	// Set the date of birth for each person:
	std::get<2>(personA) = std::move(boost::gregorian::from_string("2016-3-14"));
	std::get<2>(personB) = std::move(boost::gregorian::from_string("2017-3-14"));
	std::get<2>(personC) = std::move(boost::gregorian::from_string("2018-3-14"));
	// c) Create a list/vector of Persons and add instances:
	std::vector<Person> persons = { personA, personB, personC };
	// d) Test the sorting function:
	// Display unsorted persons vector:
	std::cout << "Unsorted persons vector: " << std::endl;
	std::for_each(persons.begin(), persons.end(), printPerson);
	// Sort and display sorted persons vector (by Name ascending):
	SortPersons<0>(persons, false);
	std::cout << "Sorted persons vector (by Name ascending): " << std::endl;
	std::for_each(persons.begin(), persons.end(), printPerson);
	// Sort and display sorted persons vector (by Name descending):
	SortPersons<0>(persons, true);
	std::cout << "Sorted persons vector (by Name descending): " << std::endl;
	std::for_each(persons.begin(), persons.end(), printPerson);
	// Sort and display sorted persons vector (by Date ascending):
	SortPersons<2>(persons, false);
	std::cout << "Sorted persons vector (by Date ascending): " << std::endl;
	std::for_each(persons.begin(), persons.end(), printPerson);
	// Sort and display sorted persons vector (by Date descending):
	SortPersons<2>(persons, true);
	std::cout << "Sorted persons vector (by Date descending): " << std::endl;
	std::for_each(persons.begin(), persons.end(), printPerson);

	/* 1.5.2 */
	// b) Test Calculator struct's static functions on tuples of varying sizes:
	std::tuple<double, double> pair = std::make_tuple<double, double>(1.0, 2.0);
	std::tuple<double, double, double> triplet = std::make_tuple<double, double, double>(1.0, 2.0, 3.0);
	std::tuple<double, double, double, double> quadruplet = std::make_tuple<double, double, double, double>(1.0, 2.0, 3.0, 4.0);
	std::cout << "Pair { 1.0, 2.0 }" << std::endl;
	std::cout << "Max: " << Calculator<double, std::tuple<double, double>, 2>::maximum(pair) << std::endl;
	std::cout << "Sum: " << Calculator<double, std::tuple<double, double>, 2>::sum(pair) << std::endl;
	std::cout << "Avg: " << Calculator<double, std::tuple<double, double>, 2>::average(pair) << std::endl;
	std::cout << "Triplet { 1.0, 2.0, 3.0 }" << std::endl;
	std::cout << "Max: " << Calculator<double, std::tuple<double, double, double>, 3>::maximum(triplet) << std::endl;
	std::cout << "Sum: " << Calculator<double, std::tuple<double, double, double>, 3>::sum(triplet) << std::endl;
	std::cout << "Avg: " << Calculator<double, std::tuple<double, double, double>, 3>::average(triplet) << std::endl;
	std::cout << "Quadruplet { 1.0, 2.0, 3.0, 4.0 }" << std::endl;
	std::cout << "Max: " << Calculator<double, std::tuple<double, double, double, double>, 4>::maximum(quadruplet) << std::endl;
	std::cout << "Sum: " << Calculator<double, std::tuple<double, double, double, double>, 4>::sum(quadruplet) << std::endl;
	std::cout << "Avg: " << Calculator<double, std::tuple<double, double, double, double>, 4>::average(quadruplet) << std::endl;
	// c) Test sum and average functions with tuple of std::complex<int> type:
	std::tuple<std::complex<int>, std::complex<int>> complexPair = std::make_tuple<std::complex<int>, std::complex<int>>(std::complex<int>(4, 3), std::complex<int>(5, 6));
	std::cout << "Complex Tuple {(4,3), (5,6)}: " << std::endl;
	std::cout << "Sum: " << Calculator<std::complex<int>, std::tuple<std::complex<int>, std::complex<int>>, 2>::sum(complexPair) << std::endl;
	std::cout << "Avg: " << Calculator<std::complex<int>, std::tuple<std::complex<int>, std::complex<int>>, 2>::average(complexPair) << std::endl;

	/* 1.5.3: */
	// b) Test the function implemented in a):
	std::vector<double> geyserDataVector{ 78,74,68,76,80,84,50, 93,55,76,58,74,75 };
	double mean, meanDev, range, stdDev, var;
	boost::numeric::ublas::vector<double, std::vector<double>> geyserData(geyserDataVector);
	std::tuple<double, double, double, double, double> statProperties = GetStatisticalProperties(geyserData);
	std::tie(mean, std::ignore, std::ignore, std::ignore, std::ignore) = statProperties;
	std::tie(std::ignore, meanDev, std::ignore, std::ignore, std::ignore) = statProperties;
	std::tie(std::ignore, std::ignore, range, std::ignore, std::ignore) = statProperties;
	std::tie(std::ignore, std::ignore, std::ignore, var, std::ignore) = statProperties;
	std::tie(std::ignore, std::ignore, std::ignore, std::ignore, stdDev) = statProperties;
	std::cout << "Geyser data { 78,74,68,76,80,84,50,93,55,76,58,74,75 } statistical properties: " << std::endl;
	std::cout << "Mean :" << mean << ", Mean Deviation: " << meanDev << std::endl;
	std::cout << "Range:" << range << ", Standard Deviation: " << stdDev << ", Variance: " << var << std::endl;
	// c) Sort the vector, then get the median and mode of the dataset:
	std::sort(geyserData.begin(), geyserData.end());
	double med = median<boost::numeric::ublas::vector, double>(geyserData);
	double mod = mode<boost::numeric::ublas::vector, double>(geyserData);
	std::cout << "Median: " << med << ", Mode: " << mod << std::endl;
	/* 1.5.4 */
	//// TODO: ensure relative error and abs error are correct.
	// a) Test the findIndex() procedure that returns index where v[i] <= x < v[i + 1] for given vector v and passed value x:
	std::vector<double> temp1 { 1, 2, 2, 3 };
	std::vector<double> temp2 { 1, 1, 1, 3 };
	std::vector<double> temp3 { 1, 1, 1, 1 };
	std::size_t index1 = findIndex<std::vector, double>(temp1, 2);
	std::size_t index2 = findIndex<std::vector, double>(temp2, 2);
	std::size_t index3 = findIndex<std::vector, double>(temp3, 2);
	std::cout << "For v_1 = {1, 2, 2, 3}, index i where v[i] <= 2 < v[i + 1]: " << index1 << std::endl;
	std::cout << "For v_2 = {1, 1, 1, 3}, index i where v[i] <= 2 < v[i + 1]: " << index2 << std::endl;
	std::cout << "For v_3 = {1, 1, 1, 1}, index i where v[i] <= 2 < v[i + 1]: " << index3 <<" (i.e. not found)" << std::endl;
	// b) Test the maximum error finding adapter for above vectors:
	std::pair<double, std::size_t> mRelError = maxError<std::vector, double>(temp1, temp2, std::make_pair<std::size_t, std::size_t>(0, 3), true);
	std::cout << "For v_1 and v_2: " << std::endl;
	std::cout << "Maximum relative error: " << std::get<0>(mRelError) << " at index " << std::get<1>(mRelError) << std::endl;
	std::pair<double, std::size_t> mAbsError = maxError<std::vector, double>(temp1, temp2, std::make_pair<std::size_t, std::size_t>(0, 3), false);
	std::cout << "Maximum absolute error: " << std::get<0>(mAbsError) << " at index " << std::get<1>(mAbsError) << std::endl;

	/* 1.5.5 */
	// a) Instantiate circle and line objects and display using input-output devices:
	Circle circ(1.0, 2.0);
	Line lin(Point(1.0, 2.0), Point(2.0, 3.0));
	TV tv_io;
	Monitor mon;
	tv_io << circ;
	mon << circ;
	tv_io << lin;
	mon << lin;
	// b) Configure shapes for input-output devices with builder objects:
	CircleMonitorBuilder cm;
	CircleTVBuilder cTV;
	LineMonitorBuilder lm;
	LineTVBuilder lTV;
	std::cout << "Builder generated combinations of Circle/Line objects with Monitor/TV objects:" << std::endl;
	std::tuple<ShapePointer, IODevicePointer> output = cm.getProduct();
	output = cTV.getProduct();
	std::get<0>(output)->display(*std::get<1>(output));
	output = lm.getProduct();
	std::get<0>(output)->display(*std::get<1>(output));
	output = lTV.getProduct();
	std::get<0>(output)->display(*std::get<1>(output));

	system("pause");

	return 0;
}

Advanced C++ Course/Benjamin Rutan HW 1 Submission/1.5/1.5/Main.cpp


/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 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)
*
*****************************************************************************/

#define ROKKO_ENABLE_TIMER

#include <mpi.h>
#include <iostream>
#include <fstream>

#include <rokko/solver.hpp>
#include <rokko/grid.hpp>
#include <rokko/distributed_matrix.hpp>
#include <rokko/localized_matrix.hpp>
#include <rokko/localized_vector.hpp>

#include <rokko/collective.hpp>

#include <rokko/utility/heisenberg_hamiltonian_mpi.hpp>
#include <rokko/utility/sort_eigenpairs.hpp>
#include <rokko/config.h>
#include <rokko/utility/timer.hpp>

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

int main(int argc, char *argv[]) {
  MPI_Init(&argc, &argv);
  //typedef rokko::matrix_row_major matrix_major;
  typedef rokko::matrix_col_major matrix_major;

  if (argc <= 1) {
    std::cerr << "error: " << argv[0] << " solver_name" << std::endl;
    MPI_Abort(MPI_COMM_WORLD, 34);
  }
  rokko::timer timer;
  timer.registrate( 1, "diagonalize");
  std::string solver_name(argv[1]);

  int L = 12;
  std::vector<std::pair<int, int> > lattice;
  for (int i=0; i<L-1; ++i) {
    lattice.push_back(std::make_pair(i, i+1));
  }

  std::cout << "L=" << L << std::endl;

  int dim = 1 << L;
  std::cout << "dim=" << dim << std::endl;
  rokko::parallel_dense_solver solver(solver_name);
  solver.initialize(argc, argv);

  MPI_Comm comm = MPI_COMM_WORLD;
  rokko::grid g(comm);
  int myrank = g.get_myrank();
  int nprocs = g.get_nprocs();

  const int root = 0;

  rokko::distributed_matrix<double, matrix_major> mat(dim, dim, g, solver);
  rokko::heisenberg_hamiltonian::generate(L, lattice, mat);
  std::cout << "finished generate" << std::endl;

  rokko::localized_vector<double> w(dim);
  rokko::distributed_matrix<double, matrix_major> Z(dim, dim, g, solver);

  for (int count=0; count<1; ++count) {
    try {
      solver.diagonalize(mat, w, Z);
    }

    catch (const char *e) {
      std::cout << "Exception : " << e << std::endl;
      MPI_Abort(MPI_COMM_WORLD, 22);
    }
  }
  std::cout << "finished eigensolver" << std::endl;

  /*
  // gather of eigenvectors
  rokko::localized_matrix<double, matrix_major> eigvec_global;
  rokko::localized_matrix<double, matrix_major> eigvec_sorted(dim, dim);
  rokko::localized_vector<double> eigval_sorted(dim);
  rokko::gather(Z, eigvec_global, root);
  Z.print();
  //if (myrank == root) {
  //  std::cout << "eigvec:" << std::endl << eigvec_global << std::endl;
  //}

  std::cout.precision(20);
  */

  /*
  std::cout << "w=" << std::endl;
  for (int i=0; i<dim; ++i) {
    std::cout << w[i] << " ";
  }
  std::cout << std::endl;
  */

  if (myrank == 0) {

    std::cout << "num_procs = " << nprocs << std::endl;
#ifdef _OPENMP_
    std::cout << "num_threads = " << omp_get_max_threads() << std::endl;
    //std::cout << "num_threads = " << mkl_get_num_threads() << std::endl;
#endif
    std::cout << "solver_name = " << solver_name << std::endl;
    std::cout << "matrix = frank" << std::endl;
    std::cout << "dim = " << dim << std::endl;
    std::cout << "time = " << timer.get_average(1) << std::endl;
    std::cout << "rokko_version = " << ROKKO_VERSION << std::endl;
    std::cout << "hostname = " << boost::asio::ip::host_name() << std::endl;
    std::time_t now = std::time(0);
    std::cout << "date = " << ctime(&now)<< std::endl;
  }

  solver.finalize();
  MPI_Finalize();
  return 0;
}


//////////////////////////////////////////////////////////////////////////////
///   Copyright 2003 and onward LASMEA UMR 6602 CNRS/U.B.P Clermont-Ferrand
///   Copyright 2009 and onward 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_TOOLBOX_IEEE_FUNCTION_SIMD_COMMON_NEXT_HPP_INCLUDED
#define NT2_TOOLBOX_IEEE_FUNCTION_SIMD_COMMON_NEXT_HPP_INCLUDED
#include <nt2/sdk/constant/infinites.hpp>
#include <nt2/sdk/constant/real.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/constant/properties.hpp>
#include <nt2/sdk/constant/digits.hpp>
#include <nt2/sdk/constant/eps_related.hpp>
#include <boost/fusion/tuple.hpp>
#include <nt2/sdk/meta/strip.hpp>
#include <nt2/include/functions/seladd.hpp>
#include <nt2/include/functions/select.hpp>
#include <nt2/include/functions/fast_frexp.hpp>
#include <nt2/include/functions/fast_ldexp.hpp>
#include <nt2/include/functions/is_eqz.hpp>
#include <nt2/include/functions/is_finite.hpp>

/////////////////////////////////////////////////////////////////////////////
// Implementation when type A0 is arithmetic_
/////////////////////////////////////////////////////////////////////////////
NT2_REGISTER_DISPATCH(tag::next_, tag::cpu_,
                       (A0)(X),
                       ((simd_<arithmetic_<A0>,X>))
                      );

namespace nt2 { namespace ext
{
  template<class X, class Dummy>
  struct call<tag::next_(tag::simd_<tag::arithmetic_, X> ),
              tag::cpu_, Dummy> : callable
  {
    template<class Sig> struct result;
    template<class This,class A0>
    struct result<This(A0)> : meta::strip<A0>{};//

    NT2_FUNCTOR_CALL(1)
    {
      return a0+One<A0>();
    }
  };
} }

/////////////////////////////////////////////////////////////////////////////
// Implementation when type A0 is real_
/////////////////////////////////////////////////////////////////////////////
NT2_REGISTER_DISPATCH(tag::next_, tag::cpu_,
                       (A0)(X),
                       ((simd_<real_<A0>,X>))
                      );

namespace nt2 { namespace ext
{
  template<class X, class Dummy>
  struct call<tag::next_(tag::simd_<tag::real_, X> ),
              tag::cpu_, Dummy> : callable
  {
    template<class Sig> struct result;
    template<class This,class A0>
    struct result<This(A0)> : meta::strip<A0>{};//

    NT2_FUNCTOR_CALL(1)
    {
      typedef typename meta::as_integer<A0, signed>::type itype;
      A0 m;
      itype expon;
      boost::fusion::tie(m, expon) = fast_frexp(a0);
      expon =  seladd(is_equal(m, Mhalf<A0>()), expon, Mone<itype>());
      A0 diff =  fast_ldexp(One<A0>(), expon-Nbdigits<A0>());
      diff = b_and(sel(is_eqz(diff)||is_eqz(a0),  Mindenormal<A0>(), diff), is_finite(a0));
//       std::cout << "diff  "<< diff << std::endl;
//       std::cout << "a0    "<< a0   << std::endl;
      return sel(is_equal(a0, Minf<A0>()), Valmin<A0>(), a0+diff);
    }
  };
} }

#endif
// modified by jt the 04/01/2011


/******************************************************************************
 *
 * 	filename   : Camera.h
 *  author     : Do Won Cha
 *  content    : Container class to output a buffer to image.
 *
 ******************************************************************************/

#pragma once
#ifndef _RAY_CAMERA_
#define _RAY_CAMERA_

#include <Eigen/Core>
#include <cassert>

#include "ray.hpp"
#include "../utility.h"

namespace raytracer
{

using namespace Eigen;

class Camera
{
public:
  Camera() :
    position  (0.0f, 0.0f, 0.0f),
    target_    (0.0f, 0.0f, -1.0f),
    right_     (1.0f, 0.0f, 0.0f),
    up_        (0.0f, 1.0f, 0.0f),
    forward_   (0.0f, 0.0f, 1.0f),
    l(-0.1f), r(0.1f), t(0.1f), b(-0.1f), d(0.1f)
  {
  }

  Camera(int width, int height) :
    position  (0.0f, 0.0f, 0.0f),
    target_    (0.0f, 0.0f, -1.0f),
    right_     (1.0f, 0.0f, 0.0f),
    up_        (0.0f, 1.0f, 0.0f),
    forward_   (0.0f, 0.0f, 1.0f),
    l(-0.1f), r(0.1f), t(0.1f), b(-0.1f), d(0.1f),
    screen_width_(width),
    screen_height_(height)
  {}

  // default offset is to the center of the pixel
  Ray GetRayFromEye(int x, int y) const
  {
    assert(x < screen_width_);
    assert(y < screen_height_);

  	float invW = 1.0f / screen_width_;
  	float invH = 1.0f / screen_height_;

  	float u = l + (r - l) * ((float)x + 0.5f) * invW;
  	float v = b + (t - b) * ((float)y + 0.5f) * invH;

    // NOTE: Had to change up calculation to negative to set y to bottom?
    // forward_ is also negative
  	Vector3f dir = ((right_ * u) - (up_ * v) - (forward_ * d)).normalized();

  	return Ray(position, dir);
  }

  //
  Ray GetRayFromEye(int x, int y, float offsetx, float offsety) const
  {
    assert( x < screen_width_ );
    assert( y < screen_height_ );

    offsetx = Utility::clamp(0.0f, offsetx, 1.0f);
    offsety = Utility::clamp(0.0f, offsety, 1.0f);

    float invW = 1.0f / screen_width_;
    float invH = 1.0f / screen_height_;

    float u = l + (r - l) * (x + offsetx) * invW;
  	float v = b + (t - b) * (y + offsety) * invH;

    Vector3f dir = ((right_ * u) - (up_ * v) - (forward_ * d)).normalized();

  	return Ray(position, dir);
  }

  void resize(int width, int height)
  {
    screen_width_ = width;
    screen_height_ = height;
  }

  int screen_width()  const { return screen_width_; }
  int screen_height() const { return screen_height_; }

private:
  Vector3f position;                // position vector
  Vector3f target_;                  // What are we looking at
  Vector3f forward_;                 // forward_ vector
  Vector3f up_;                      // up_ vector, typically y-axis
  Vector3f right_;                   // right_ vector
  float l, r, t, b, d;              // Viewport constants
  int screen_width_, screen_height_;    // Resolution of camera
};

}     // end of namespace raytracer

#endif // _RAY_CAMERA_


///////////////////////////////////////////////////////////////
//  Copyright 2011 John Maddock. 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_

#define BOOST_MATH_MAX_ROOT_ITERATION_POLICY 750
#define BOOST_MATH_PROMOTE_DOUBLE_POLICY false

#if !defined(TEST_MPFR) && !defined(TEST_MPREAL) && !defined(TEST_MPF) && !defined(TEST_MPREAL) \
   && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR_CLASS) && !defined(TEST_FLOAT) && !defined(TEST_CPP_BIN_FLOAT)
#  define TEST_MPFR
#  define TEST_MPF
#  define TEST_CPP_DEC_FLOAT
#  define TEST_CPP_BIN_FLOAT
//#  define TEST_MPFR_CLASS
//#  define TEST_MPREAL
#  define TEST_FLOAT
#endif

#ifdef TEST_FLOAT
#include "arithmetic_backend.hpp"
#endif
#ifdef TEST_MPFR_CLASS
#include <boost/math/bindings/mpfr.hpp>
#endif
#ifdef TEST_MPFR
#include <boost/multiprecision/mpfr.hpp>
#endif
#ifdef TEST_MPREAL
#include <boost/math/bindings/mpreal.hpp>
#endif
#ifdef TEST_MPF
#include <boost/multiprecision/gmp.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <boost/multiprecision/cpp_dec_float.hpp>
#endif
#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/mpfr.hpp>
#endif
#include <boost/math/special_functions/bessel.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/distributions/non_central_t.hpp>
#include <libs/math/test/table_type.hpp>
#include <boost/chrono.hpp>
#include <boost/array.hpp>
#include <boost/thread.hpp>

template <class Real>
Real test_bessel();

template <class Clock>
struct stopwatch
{
   typedef typename Clock::duration duration;
   stopwatch()
   {
      m_start = Clock::now();
   }
   duration elapsed()
   {
      return Clock::now() - m_start;
   }
   void reset()
   {
      m_start = Clock::now();
   }

private:
   typename Clock::time_point m_start;
};

template <class Real>
Real test_bessel()
{
   try{
#  define T double
#  define SC_(x) x
#  include "libs/math/test/bessel_i_int_data.ipp"
#  include "libs/math/test/bessel_i_data.ipp"

      Real r;

      for(unsigned i = 0; i < bessel_i_int_data.size(); ++i)
      {
         r += boost::math::cyl_bessel_i(Real(bessel_i_int_data[i][0]), Real(bessel_i_int_data[i][1]));
      }
      for(unsigned i = 0; i < bessel_i_data.size(); ++i)
      {
         r += boost::math::cyl_bessel_i(Real(bessel_i_data[i][0]), Real(bessel_i_data[i][1]));
      }

#include "libs/math/test/bessel_j_int_data.ipp"
      for(unsigned i = 0; i < bessel_j_int_data.size(); ++i)
      {
         r += boost::math::cyl_bessel_j(Real(bessel_j_int_data[i][0]), Real(bessel_j_int_data[i][1]));
      }

#include "libs/math/test/bessel_j_data.ipp"
      for(unsigned i = 0; i < bessel_j_data.size(); ++i)
      {
         r += boost::math::cyl_bessel_j(Real(bessel_j_data[i][0]), Real(bessel_j_data[i][1]));
      }

#include "libs/math/test/bessel_j_large_data.ipp"
      for(unsigned i = 0; i < bessel_j_large_data.size(); ++i)
      {
         r += boost::math::cyl_bessel_j(Real(bessel_j_large_data[i][0]), Real(bessel_j_large_data[i][1]));
      }

#include "libs/math/test/sph_bessel_data.ipp"
      for(unsigned i = 0; i < sph_bessel_data.size(); ++i)
      {
         r += boost::math::sph_bessel(static_cast<unsigned>(sph_bessel_data[i][0]), Real(sph_bessel_data[i][1]));
      }

      return r;
   }
   catch(const std::exception& e)
   {
      std::cout << e.what() << std::endl;
   }
   return 0;
}

template <class Real>
Real test_polynomial()
{
   static const unsigned t[] = {
      2, 3, 4, 5, 6, 7, 8 };
   Real result = 0;
   for(Real k = 2; k < 1000; ++k)
      result += boost::math::tools::evaluate_polynomial(t, k);

   return result;
}

template <class Real>
Real test_nct()
{
#define T double
#include "libs/math/test/nct.ipp"

   Real result = 0;
   for(unsigned i = 0; i < nct.size(); ++i)
   {
      try{
         result += quantile(boost::math::non_central_t_distribution<Real>(nct[i][0], nct[i][1]), nct[i][3]);
         result += cdf(boost::math::non_central_t_distribution<Real>(nct[i][0], nct[i][1]), nct[i][2]);
      }
      catch(const std::exception&)
      {}
   }
   return result;
}

extern unsigned allocation_count;

template <class Real>
void basic_allocation_test(const char* name, Real x)
{
   static const unsigned a[] = { 2, 3, 4, 5, 6, 7, 8 };
   allocation_count = 0;
   Real result = (((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0];
   std::cout << "Allocation count for type " << name << " = " << allocation_count << std::endl;
}

template <class Real>
void poly_allocation_test(const char* name, Real x)
{
   static const unsigned a[] = { 2, 3, 4, 5, 6, 7, 8 };
   allocation_count = 0;
   Real result = boost::math::tools::evaluate_polynomial(a, x);
   std::cout << "Allocation count for type " << name << " = " << allocation_count << std::endl;
}

template <class Real>
void time_proc(const char* name, Real (*proc)(), unsigned threads = 1)
{
   try{
      static Real total = 0;
      allocation_count = 0;
      boost::chrono::duration<double> time;
      stopwatch<boost::chrono::high_resolution_clock> c;
      total += proc();
      time = c.elapsed();
      std::cout << "Time for " << name << " = " << time << std::endl;
      std::cout << "Total allocations for " << name << " = " << allocation_count << std::endl;

      for(unsigned thread_count = 1; thread_count < threads; ++thread_count)
      {
         c.reset();
         boost::thread_group g;
         for(unsigned i = 0; i <= thread_count; ++i)
            g.create_thread(proc);
         g.join_all();
         time = c.elapsed();
         std::cout << "Time for " << name << " (" << (thread_count + 1) << " threads) = " << time << std::endl;
         std::cout << "Total allocations for " << name << " = " << allocation_count << std::endl;
      }
   }
   catch(const std::exception& e)
   {
      std::cout << e.what() << std::endl;
   }
}

using namespace boost::multiprecision;

void basic_tests();
void bessel_tests();
void poly_tests();
void nct_tests();


//==================================================================================================
/*!
  @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_ROUND_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_ROUND_HPP_INCLUDED

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

  /*!

    @ingroup group-arithmetic
    This function object computes the rounding away from zero of its parameter.

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

    @par Notes:

    - With a second integral parameter  `round(x,n)` rounds aways from 0 to n digits:
    this is similar to  `round(x*exp10(n))*exp10(-n)`

      - n default to 0,
      - n > 0: round to n digits to the right of the decimal point.
      - n = 0: round to the nearest integer.
      - n < 0: round to n digits to the left of the decimal point.

    - aways from 0 means that half integer values are rounded to the nearest
    integer of greatest absolute value

    The current rounding mode has no effect.

    - If x is \f$\pm\infty\f$ or \f$\pm0\f$, it is returned, unmodified
    - If x is a NaN, a NaN is returned

    @par Example:

      @snippet round.cpp round

    @par Possible output:

      @snippet round.txt round
  **/
  IEEEValue round(IEEEValue const& x, IntegerValue const& n = 0);
} }
#endif

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

#endif


//==================================================================================================
/*!

  Copyright 2015 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)
*/
//==================================================================================================
#include <boost/simd/function/scalar/muls.hpp>
#include <simd_test.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/simd/constant/inf.hpp>
#include <boost/simd/constant/minf.hpp>
#include <boost/simd/constant/mone.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/constant/one.hpp>
#include <boost/simd/constant/zero.hpp>

STF_CASE_TPL (" mulssigned_int",  STF_SIGNED_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;

  using bs::muls;

  using r_t = decltype(muls(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
  STF_EQUAL(muls(bs::Mone<T>(), bs::Mone<T>()), bs::One<T>());
  STF_EQUAL(muls(bs::One<T>(), bs::One<T>()), bs::One<T>());
  STF_EQUAL(muls(bs::Valmax<T>(), bs::Valmax<T>()), bs::Valmax<T>());
  STF_EQUAL(muls(bs::Valmax<T>(),T(2)), bs::Valmax<T>());
  STF_EQUAL(muls(bs::Valmax<T>(),bs::Mone<T>()), bs::Valmin<T>()+bs::One<T>());
  STF_EQUAL(muls(bs::Valmax<T>(),bs::One<T>()), bs::Valmax<T>());
  STF_EQUAL(muls(bs::Valmin<T>(),bs::Mone<T>()), bs::Valmax<T>());
  STF_EQUAL(muls(bs::Zero<T>(), bs::Zero<T>()), bs::Zero<T>());
} // end of test for signed_int_

STF_CASE_TPL (" mulsunsigned_int",  STF_UNSIGNED_INTEGRAL_TYPES)
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::muls;
  using r_t = decltype(muls(T(), T()));

  // return type conformity test
  STF_TYPE_IS(r_t, T);

  // specific values tests
  STF_EQUAL(muls(bs::One<T>(), bs::One<T>()), bs::One<T>());
  STF_EQUAL(muls(bs::Valmax<T>(),T(2)), bs::Valmax<T>());
  STF_EQUAL(muls(bs::Zero<T>(), bs::Zero<T>()), bs::Zero<T>());
} // end of test for unsigned_int_

STF_CASE("mul sspecial")
{
  namespace bs = boost::simd;
  namespace bd = boost::dispatch;
  using bs::muls;
  using bs::splat;
  using bs::Valmin;

  typedef short int T1;
  STF_EQUAL(muls(splat<T1>(-5165), splat<T1>(23258)), Valmin<T1>());

  typedef int T2;
  STF_EQUAL(muls(splat<T2>(-1306766858), splat<T2>(1550772331)), Valmin<T2>());
  STF_EQUAL(muls(splat<T2>(1467238299), splat<T2>(-900961598)), Valmin<T2>());
}


//---------------------------------------------------------------------------//
// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#include <iostream>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <boost/compute/system.hpp>
#include <boost/compute/algorithm/inclusive_scan.hpp>
#include <boost/compute/algorithm/inclusive_scan.hpp>
#include <boost/compute/interop/opencv/core.hpp>
#include <boost/compute/interop/opencv/highgui.hpp>
#include <boost/compute/random/default_random_engine.hpp>
#include <boost/compute/random/uniform_real_distribution.hpp>
#include <boost/compute/utility/source.hpp>

namespace compute = boost::compute;

// this example uses the random-number generation functions in Boost.Compute
// to calculate a large number of random "steps" and then plots the final
// random "walk" in a 2D image on the GPU and displays it with OpenCV
int main()
{
    // number of random steps to take
    size_t steps = 250000;

    // height and width of image
    size_t height = 800;
    size_t width = 800;

    // get default device and setup context
    compute::device gpu = compute::system::default_device();
    compute::context context(gpu);
    compute::command_queue queue(context, gpu);

    using compute::int2_;

    // calaculate random values for each step
    compute::vector<float> random_values(steps, context);
    compute::default_random_engine random_engine(queue);
    compute::uniform_real_distribution<float> random_distribution(0.f, 4.f);

    random_distribution.generate(
        random_values.begin(), random_values.end(), random_engine, queue
    );

    // calaculate coordinates for each step
    compute::vector<int2_> coordinates(steps, context);

    // function to convert random values to random directions (in 2D)
    BOOST_COMPUTE_FUNCTION(int2_, take_step, (const float x),
    {
        if(x < 1.f){
            // move right
            return (int2)(1, 0);
        }
        if(x < 2.f){
            // move up
            return (int2)(0, 1);
        }
        if(x < 3.f){
            // move left
            return (int2)(-1, 0);
        }
        else {
            // move down
            return (int2)(0, -1);
        }
    });

    // transform the random values into random steps
    compute::transform(
        random_values.begin(), random_values.end(), coordinates.begin(), take_step, queue
    );

    // set staring position
    int2_ starting_position(width / 2, height / 2);
    compute::copy_n(&starting_position, 1, coordinates.begin(), queue);

    // scan steps to calculate position after each step
    compute::inclusive_scan(
        coordinates.begin(), coordinates.end(), coordinates.begin(), queue
    );

    // create output image
    compute::image2d image(
        context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8)
    );

    // program with two kernels, one to fill the image with white, and then
    // one the draw to points calculated in coordinates on the image
    const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
        __kernel void draw_walk(__global const int2 *coordinates,
                                __write_only image2d_t image)
        {
            const uint i = get_global_id(0);
            const int2 coord = coordinates[i];

            if(coord.x > 0 && coord.x < get_image_width(image) &&
               coord.y > 0 && coord.y < get_image_height(image)){
                uint4 black = { 0, 0, 0, 0 };
                write_imageui(image, coord, black);
            }
        }

        __kernel void fill_white(__write_only image2d_t image)
        {
            const int2 coord = { get_global_id(0), get_global_id(1) };

            if(coord.x < get_image_width(image) &&
               coord.y < get_image_height(image)){
                uint4 white = { 255, 255, 255, 255 };
                write_imageui(image, coord, white);
            }
        }
    );

    // build the program
    compute::program draw_program =
        compute::program::build_with_source(draw_walk_source, context);

    // fill image with white
    compute::kernel fill_kernel(draw_program, "fill_white");
    fill_kernel.set_arg(0, image);

    const size_t offset[] = { 0, 0 };
    const size_t bounds[] = { width, height };

    queue.enqueue_nd_range_kernel(fill_kernel, 2, offset, bounds, 0);

    // draw random walk
    compute::kernel draw_kernel(draw_program, "draw_walk");
    draw_kernel.set_arg(0, coordinates);
    draw_kernel.set_arg(1, image);
    queue.enqueue_1d_range_kernel(draw_kernel, 0, coordinates.size(), 0);

    // show image
    compute::opencv_imshow("random walk", image, queue);

    // wait and return
    cv::waitKey(0);

    return 0;
}


//
// Copyright (c) 2020-2021 Huang Qinjin (huangqinjin@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          https://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ICP2D_HPP
#define ICP2D_HPP

#if defined(_MSC_VER)
#  define ICP2D_EXPORT __declspec(dllexport)
#  define ICP2D_IMPORT __declspec(dllimport)
#else
#  define ICP2D_EXPORT __attribute__((visibility("default")))
#  define ICP2D_IMPORT __attribute__((visibility("default")))
#endif

#if defined(ICP2D_EXPORTS)
#  define ICP2D_API ICP2D_EXPORT
#elif ICP2D_SHARED_LIBRARY
#  define ICP2D_API ICP2D_IMPORT
#else
#  define ICP2D_API
#endif

#include <cstdio>
#include <vector>
#include <ostream>
#include <Eigen/Geometry>

namespace ICP2D
{
    using Scaling = Eigen::UniformScaling<double>;
    using Rotation = Eigen::Rotation2Dd;
    using Translation = Eigen::Translation2d;
    using Transform = Eigen::Affine2d;

    using Point = Eigen::Vector2d;
    using PointSet = std::vector<Point, Eigen::aligned_allocator<Point>>;
    using WeightVector = Eigen::VectorXd;
    using BoundingBox = Eigen::AlignedBox2d;

    struct Sim2D
    {
        double s;
        double r;
        double x;
        double y;

        Scaling scaling() const noexcept
        {
            return Scaling(s);
        }

        Rotation rotation() const noexcept
        {
            return Rotation(r);
        }

        Translation translation() const noexcept
        {
            return Translation(x, y);
        }

        Transform transform() const noexcept
        {
            return translation() * rotation() * scaling();
        }

        static Sim2D Identity()
        {
            Sim2D T;
            T.s = 1;
            T.r = 0;
            T.x = 0;
            T.y = 0;
            return T;
        }

        Sim2D operator*(const Sim2D& other) const noexcept
        {
            Eigen::Vector2d t = transform() * other.translation().vector();
            Sim2D T;
            T.s = s * other.s;
            T.r = r + other.r;
            T.x = t.x();
            T.y = t.y();
            return T;
        }
    };

    template<class CharT, class Traits>
    std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const Sim2D& T)
    {
        return os
            << '{'
            << 's' << ':' << T.s << ',' << ' '
            << 'r' << ':' << T.r << ',' << ' '
            << 'x' << ':' << T.x << ',' << ' '
            << 'y' << ':' << T.y
            << '}'
            ;
    }

    ICP2D_API Sim2D solve(const PointSet& src, const PointSet& dst, const WeightVector& w);
    ICP2D_API double error(const Sim2D& T, const PointSet& src, const PointSet& dst, const WeightVector& w);

    struct ICP2D_API Sampler
    {
        virtual ~Sampler() = default;
        virtual std::size_t size() const noexcept = 0; // size() <= maximum() + 1
        virtual std::size_t maximum() const noexcept = 0;
        virtual void sample(std::size_t* output) noexcept = 0;
        static std::size_t population(std::size_t num, size_t (max)) noexcept;
        static Sampler* random(std::size_t num, std::size_t (max)) noexcept;
        static Sampler* ordered(std::size_t num, std::size_t (max)) noexcept;
    };

    struct ICP2D_API RANSAC
    {
        Sim2D model;
        double score; // [0, 1]

        PointSet src;
        PointSet dst;
        WeightVector w;

        double inlier_distance_threshold;
        std::size_t num_min_inliers;
        std::size_t num_max_iterations;

        void solve() noexcept;
    };

    class ICP2D_API SVG
    {
        FILE* out;
        Sim2D T;
        Point scale;
        BoundingBox view;

    public:
        SVG() noexcept;
        ~SVG();
        void open(const char* file, const Point& scale = Point::Ones()) noexcept;
        void close() noexcept;
        void push(const Sim2D& transform) noexcept;
        void pop() noexcept;
        void draw(const PointSet& points, double radius, const char* color) noexcept;
    };
}

#endif //ICP2D_HPP


/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/

#include <NumericalMethods_precompiled.h>
#include <NumericalMethods/Eigenanalysis.h>
#include <NumericalMethods/Optimization.h>
#include <Optimization/SolverBFGS.h>
#include <Eigenanalysis/Solver3x3.h>

namespace NumericalMethods
{
    namespace Optimization
    {
        SolverResult SolverBFGS(const Function& function, const AZStd::vector<double>& initialGuess)
        {
            return MinimizeBFGS(function, initialGuess);
        }
    }

    namespace Eigenanalysis
    {
        SolverResult<Real, 3> Solver3x3RealSymmetric(const SquareMatrix<Real, 3>& matrix)
        {
            // The matrix must be symmetric.
            if (matrix[0][1] == matrix[1][0] && matrix[0][2] == matrix[2][0] && matrix[1][2] == matrix[2][1])
            {
                return NonIterativeSymmetricEigensolver3x3(
                    matrix[0][0], matrix[0][1], matrix[0][2],
                                  matrix[1][1], matrix[1][2],
                                                matrix[2][2]
                );
            }
            else
            {
                return SolverResult<Real, 3>{SolverOutcome::FailureInvalidInput};
            }
        }
    }
} // namespace NumericalMethods


/*! \headerfile Material.hpp "include/Material.hpp"
* "Material.hpp" contains the class definition encapsulating the
* data structure interface for a Geemetry in a swSim Model.
*/

// Copyright 2020 United States Government as represented by the Administrator of the National
// Aeronautics and Space Administration. No copyright is claimed in the United States under
// Title 17, U.S. Code. All Other Rights Reserved. See Appendix A for 3rd party licenses.
//
// The Solid-Wave Sim (swSIM) platform is 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 MATERIAL_HPP
#define MATERIAL_HPP

#include <mpi.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <stddef.h>
#include <math.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <Eigen/Dense>

#include "ParsableObject.hpp"

typedef Eigen::Matrix<float, 6, 6> Matrix6f;
namespace swSim{
    /*! \class Material Material.hpp "include/Material.hpp"
    *
    * Defines data structures for Material in swSim
    */
    class Material: public ParsableObject {
    public:
        struct material_s {
            uint32_t materialID; /*!< Unique identification number for this material */
            float density; /*!< Material density in kg/cubic meter */
            float stiffnessValues[21]; /*!< 21 Unique stiffness values (in Pascals) in the 6x6, symmetric stiffness matrix */

        };
        material_s matS; /*!< Material struct */
        MPI_Datatype mpi_material; /*!< MPI datatype for communication */
        /*!
        * Create the Material
        */
        Material();
        /*!
        * Destroy the Material
        */
        ~Material();
        /*!
        * Initilize data values
        */
        void Init(uint32_t id, float rho, float *c);
        /*!
        * Copy values of one Material to another.
        */
        void Copy(Material *other);
        /*!
        * Create the MPI datatype for the Material.
        */
        MPI_Datatype MPICreate();
        /*!
        * Get a local stiffness Matrix for that voxel base on the material stiffness matrix and a rotation vector.
        */
        void RotateStiffnessMatrix(float *rotVec, float *C);
        /*!
        * Provide parsing instructions for reading inputs associated with the Material
        */
        void ParseSwitch(xmlDocPtr doc, xmlNodePtr cur, int caseNumber) override;
        /*!
        * Convert the array of stiffness Values to an Eigen Matrix
        */
        Matrix6f StiffnessValuesArrayToMatrix();
     private:
        /*!
        * Get a 3D Rotation matrix based on a 3 element rotation vector.
        */
        Eigen::Matrix3f get3DRotation(float *rotVec);
        /*!
        * Get a Rotation Matrix from a rotation abotu the Z axis
        */
        Eigen::Matrix3f getRotationAboutZ(float angle);
        /*!
        * Get a Rotation Matrix from a rotation abotu the Y axis
        */
        Eigen::Matrix3f getRotationAboutY(float angle);
        /*!
        * Get a Rotation Matrix from a rotation abotu the X axis
        */
        Eigen::Matrix3f getRotationAboutX(float angle);
        /*!
        * Get a 3D Rotation Transformation Matrix
        */
        Matrix6f get3DTransformationMatrix(Eigen::Matrix3f R);
        /*!
        * Convert MAtrix Values back to an array
        */
        void MatrixToStiffnessValuesArray(float *valueArray, Matrix6f C);
    };
};

#endif


#include <fstream>
#include <string>
#include <cerrno>
#include <iostream>
#include <Eigen/Dense>
#include <json/json.h>

using Eigen::MatrixXd;

std::string get_file_contents(const char* filename)
{
    std::ifstream in(filename,std::ios::in|std::ios::binary);
    if(in) {
        std::string contents;
        in.seekg(0,std::ios::end);
        contents.reserve(in.tellg());
        in.seekg(0,std::ios::beg);
        contents.assign((std::istreambuf_iterator<char>(in)),std::istreambuf_iterator<char>());
        in.close();
        return(contents);
    }
    throw(errno);
}

int main()
{
    MatrixXd m(2,2);
    m(0,0)=3;
    m(1,0)=2.5;
    m(0,1)=-1;
    m(1,1)=m(1,0)+m(0,1);
    std::cout<<m<<std::endl;

    Json::Value root;
    Json::Reader reader;
    bool parsingSuccess=reader.parse(get_file_contents("test.json"),root);
    std::cout<<parsingSuccess<<std::endl;
    const Json::Value objects=root["objects"];
    for (int index=0;index<objects.size();++index){
        std::cout<<objects[index].asString()<<std::endl;
    }
}


//
// Copyright (c) 2021 INRIA
//

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/algorithm/parallel/aba.hpp"
#include "pinocchio/algorithm/aba.hpp"
#include "pinocchio/algorithm/joint-configuration.hpp"
#include "pinocchio/parsers/sample-models.hpp"
#include "pinocchio/utils/timer.hpp"

#include <iostream>

#include <boost/test/unit_test.hpp>
#include <boost/utility/binary.hpp>

using namespace pinocchio;

BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE(test_parallel_aba)
{
  pinocchio::Model model; buildModels::humanoidRandom(model);
  Data data_ref(model);

  model.lowerPositionLimit.head<3>().fill(-1.);
  model.upperPositionLimit.head<3>().fill( 1.);

  const Eigen::DenseIndex batch_size = 128;
  const int num_threads = omp_get_max_threads();

  Eigen::MatrixXd q(model.nq,batch_size);
  Eigen::MatrixXd v(model.nv,batch_size);
  Eigen::MatrixXd tau(model.nv,batch_size);
  Eigen::MatrixXd a(model.nv,batch_size);
  Eigen::MatrixXd a_ref(model.nv,batch_size);

  for(Eigen::DenseIndex i = 0; i < batch_size; ++i)
  {
    q.col(i) = randomConfiguration(model);
    v.col(i) = Eigen::VectorXd::Random(model.nv);
    tau.col(i) = Eigen::VectorXd::Random(model.nv);
  }

  ModelPool pool(model);
  aba(num_threads,pool,q,v,tau,a);

  for(Eigen::DenseIndex i = 0; i < batch_size; ++i)
  {
    a_ref.col(i) = aba(model,data_ref,q.col(i),v.col(i),tau.col(i));
  }

  BOOST_CHECK(a == a_ref);
}

BOOST_AUTO_TEST_SUITE_END()


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

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  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_TWO_PROD_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_TWO_PROD_HPP_INCLUDED

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

 /*!

    @ingroup group-arithmetic
    Function object implementing two_prod capabilities

    For any two reals @c x and @c y two_prod computes two reals (in an std::pair)
    @c r0 and @c r1 so that:

    @code
    r0 = x * y
    r1 = r0 -(x * y)
    @endcode

    using perfect arithmetic.

    Its main usage is to be able to compute
    sum of reals and the residual error using IEEE 754 arithmetic.

  **/
  const boost::dispatch::functor<tag::two_prod_> two_prod = {};
} }
#endif

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

#endif


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

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  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_IDIVFIX_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IDIVFIX_HPP_INCLUDED

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

 /*!

    @ingroup group-arithmetic
    Function object implementing idivfix capabilities

    Computes the integer conversion of the truncated division of its parameters.

    @par semantic:
    For any given value @c x,  @c y of type @c T:

    @code
    T r = idivfix(x, y);
    @endcode

    The code is similar to:

    @code
    as_integer_t<T> r = toints(trunc(x/y));
    @endcode

    If y is @ref Zero, it returns @ref Valmax (resp. @ref Valmin)
    if x is positive (resp. negative) and 0 if x is @ref Zero.

    @see toints, trunc
  **/
  const boost::dispatch::functor<tag::idivfix_> idivfix = {};
} }
#endif

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

#endif


/*!
  \file 2d_uncertain_values.cpp
  \brief Simple 2D plot example showing how uncertain values can also be labelled with their uncertainty, confidence interval and degrees of freedom.
*/

// Copyright Jacob Voytko 2007
// Copyright Paul A Bristow 2007, 2020
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/cstdlib.hpp> // Boost exit_success and failure values.

#include <boost/svg_plot/svg_2d_plot.hpp> // svg_plot function
#include <boost/svg_plot/show_2d_settings.hpp> // boost/libs/svg_plot/doc/html/header/boost/svg_plot/show_2d_settings_hpp.html

#include <iostream>
#include <map> // Container for data.
// using std::map

#include <vector>
// using std::vector
#include <utility>
// using std::pair
// using std::make_pair
#include <algorithm>
// using std::foreach
#include <boost/quan/unc.hpp>
//#include <boost/quan/unc_init.hpp>

int main()
{
  std::cout << "svg_plot 2D Uncertain value-labels." << std::endl;

  using boost::quan::unc;
  using boost::quan::uncun;
  using boost::quan::setUncDefaults;
  using boost::quan::adddegfree;
  using boost::quan::addlimits;
  using boost::quan::plusminus;

  typedef unc<false> uncun; // Uncertain type to use (Uncorrelated the normal case).
  setUncDefaults(std::cout);  // Initialisation of uncertain type.

  try
  {
    //! Data to plot stored in container type `std::map`.

   uncun ux1(2.23, 0.056F, 7); // For an X-value.
   // Using the  uncertain class unc `operator<<` provided we can output all the details of the uncertain values.
    std::cout << std::scientific << plusminus << addlimits << adddegfree << std::setw(20) << std::left
      << "ux = " << ux1 << std::endl; // ux =             2.23 +/-0.056 <2.19, 2.27> (7)
    uncun uy1(3.45, 0.67F, 9); // For a Y-value.
    std::cout << "uy = " << uy1 << std::endl; // uy = 3.5 +/-0.67 <3.01, 3.89> (9)
    std::pair<uncun, uncun > up1 = make_pair(ux1, uy1); // Make an X & Y pair of uncertain values.
    std::cout << "up1 = " << up1 << std::endl;
    // up1 = 2.23 +/-0.056 <2.19, 2.27> (7), 3.5 +/-0.67 <3.01, 3.89> (9)

    uncun ux2(5.45, 0.45F, 8); // For 2nd X-value.
    uncun uy2(6.08, 0.52F, 5); // For 2nd Y-value.
    std::pair<uncun, uncun > up2 = make_pair(ux2, uy2); // Make a second X & Y pair of uncertain values.
    std::cout << "up2 = " << up2 << std::endl;
    // up2 = 5.5 +/-0.45 <5.14, 5.76> (8), 6.1 +/-0.52 <5.62, 6.54> (5)

    std::vector<std::pair<uncun, uncun> > uncertains;
    std::cout << uncertains.size() << std::endl; // zero.
    uncertains.reserve(10);
    uncertains.push_back(up1);
    uncertains.push_back(up2);
    // Display the uncertain values packaged in a vector using conventional for loop.
    for (size_t i = 0; i < uncertains.size(); i++)
    {
      std::cout << "#" << i << " " << uncertains[i] << std::endl;
    }

   //// Display the uncertain values packaged in a vector using a C++ lambda with functor.
   // auto show = [](const std::pair<uncun, uncun>& u) { std::cout << " " << u << std::endl; };
   // std::for_each(uncertains.begin(), uncertains.end(), show); std::cout << std::endl;

   // // Display using std::copy.
   // std::copy(uncertains.begin(), uncertains.end(), std::ostream_iterator<std::pair<uncun, uncun>>(std::cout, "\n"));
   // std::cout << std::endl;

    using namespace boost::svg;  // Convenient for access to all SVG functions and colors.

    svg_2d_plot my_2d_plot;

    my_2d_plot
      .title("Uncertains - labelled with X and Y values and uncertainty info.")
      .title_font_size(10)
      // No legend needed as only one data-series?
      //.legend_on(true)
      //.legend_title("Knowns")
      .x_range(0, 10)
      .y_range(0, 10)
      .x_major_grid_on(true)
      .y_major_grid_on(true)
     // .plusminus_sds(2.) // Optionally display uncertainty (standard deviation) multplied by a factor of two.
      ;

    /*`To put a value-label against each data-point, switch on or other, or both the options:
*/
//my_2d_plot.x_values_on(true); // Add a label for the X-axis.
//my_2d_plot.y_values_on(true); // Add a label for the X-axis.
    my_2d_plot.xy_values_on(true); // Add a label for both the X and Y-axis.

    /*`If the default size and color are not to your taste, set more options, like:
*/
    my_2d_plot.x_values_font_size(8) // Change font size for the X-axis value-labels.
      .x_values_font_family("Times New Roman") // Change font for the X-axis value-labels.
      .x_values_color(red); // Change X-values color from default black to red.

    my_2d_plot.y_values_font_size(10) // Change font size for the Y-axis value-labels.
      .y_values_font_family("Arial") // Change font for the Y-axis value-labels.
      .y_values_color(blue); // Change Y-values color from default black to blue.

/*`The default value-label position is horizontal, centered slightly above the data_point marker,
but, depending on the type and density of data_points, and the length of the values
(controlled in turn by choice of options, the `precision` and `ioflags` in use),
it is often clearer to use a different orientation.
This can be controlled in steps using an 'enum rotate_style` for convenience (or in degrees).

* `leftward` - writing level with the data_point but to its left.
* `rightward` - writing level with the data-point but to its right.
* `uphill` - writing up at 45 degree slope is often a good choice,
* `upward` - writing vertically up and
* `backup` - writing to the left are also useful.
``
    enum rotate_style
    {
      // Also need a no_rotate, = -1;
      horizontal = 0, //!< normal horizontal left to right, centered.
      slopeup = -30, //!< slope up.
      uphill = -45, //!< 45 steep up.
      steepup = -60, //!< up near vertical.
      upward = -90, //!< vertical writing up.
      backup = -135, //!< slope up backwards - upside down!
      leftward= -180, //!< horizontal to left.
      rightward = 360, //!< horizontal to right.
      slopedownhill = 30, //!< 30 gentle slope down.
      downhill = 45, //!< 45 down.
      steepdown = 60, //!<  60 steeply down.
      downward = 90,  //!< vertical writing downwards from marker.
      backdown = 135, //!< slope down backwards.
      upsidedown = 180 //!< upside down!  (== -180)
    };

``

(For 1-D plots other directions are less attractive,
placing the values below the horizontal Y-axis line,
but for 2-D plots all writing orientations can be useful).
*/
    my_2d_plot.x_values_rotation(rightward); // Orientation for the Y-axis value-labels, placing information to the right of the data-point marker.
   // my_2d_plot.x_values_rotation(horizontal); // Orientation for the Y-axis value-labels, placing information above the data-point marker.
   // my_2d_plot.x_values_rotation(uphill); // Orientation for the Y-axis value-labels, placing information to the right of the data-point marker.
   // my_2d_plot.x_values_rotation(upward); // Orientation for the Y-axis value-labels, placing information to the right of the data-point marker.
  //  my_2d_plot.x_values_rotation(leftward); // Orientation for the Y-axis value-labels, placing information to the right of the data-point marker.
    // This is only useful for x prefix and value, like "X = 1.23" not any following information.

  /*`Add some information about uncertainty to both the X and Y-values:*/
    my_2d_plot.x_plusminus_on(true); // Uncertainty (standard deviation) +/- value-label for the X-axis value.
    my_2d_plot.x_plusminus_color(blue); // Change from default color black to color blue.
    my_2d_plot.x_df_on(true); // Degrees of freedom (observations-1) value-label for the X-axis value.
    my_2d_plot.x_addlimits_on(true); // Confidence limit value-label for the X-axis value.
    my_2d_plot.x_datetime_on(true);
    my_2d_plot.x_order_on(true);
    my_2d_plot.x_decor("X= ", "",""); // Suffix value-label for the X-axis value.
    // https://jkorpela.fi/chars/spaces.html describes Unicode spaces that must be explicit, not just spaces in the string.
    // Normal space is  " ", but hair space " " is most useful between digits and characters,
    // for example: "X= " and "X= " is em quad, 1 em (nominally, the height of the font).
    // and about Y-values:
    my_2d_plot.y_decor(", Y=", ""," g"); // Suffix value-label for the Y-axis value.

    my_2d_plot.y_plusminus_on(true); // Uncertainty (standard deviation) value-label for the X-axis value.
    my_2d_plot.y_plusminus_color(green);
    // Degrees of freedom for the Y-axis value is rather redundant if already shown for X-axis values.
    my_2d_plot.y_df_on(true); // Degrees of freedom for the Y-axis value.
    my_2d_plot.y_addlimits_on(true); // Confidence limit or interval for the X-axis value.

    std::cout << "x_values_color() = " << my_2d_plot.x_values_color() << std::endl; // y_values_color() = RGB(0,0,255) == blue for fill and stroke
    std::cout << "y_values_color() = " << my_2d_plot.y_values_color() << std::endl; // y_values_color() = RGB(0,0,255) == blue for fill and stroke

  //  my_2d_plot.plot(doubles, "data-series 1 - doubles").stroke_color(blue).fill_color(red);

    // These affect all the marker points.
    //my_2d_plot.y_values_font_size(16) // Change font size for the Y-axis value-labels.
    //  .y_values_font_family("bold") // Change font for the Y-axis value-labels.
    //  .y_values_color(green); // Change Y color from default black to blue.

///   Change the data-point markers colors to green circle filled with a yellow center.
    my_2d_plot.plot(uncertains, "1 data-series - 2 uncertains").stroke_color(green).fill_color(yellow);

    my_2d_plot.write("./demo_2d_uncertain_values_1.svg");

  //  show_2d_plot_settings(my_2d_plot, std::cout); // Needs include <boost/svg_plot/show_2d_settings.hpp>

    return boost::exit_success;
  }
  catch (std::exception& ex)
  {
    std::cout << "svg_plot exception " << ex.what() << std::endl;
    return boost::exit_exception_failure;
  }
} // int main()

/*

Build started...
1>------ Build started: Project: demo_2d_uncertain_values, Configuration: Debug x64 ------
1>demo_2d_uncertain_values.cpp
1>demo_2d_uncertain_values.vcxproj -> I:\Cpp\SVG_plot\svg_plot\x64\Debug\demo_2d_uncertain_values.exe
1>Autorun "I:\Cpp\SVG_plot\svg_plot\x64\Debug\demo_2d_uncertain_values.exe"
1>svg_plot 2D Uncertain values
1>ux =                5.2 +/-0.56 <4.82, 5.64> (7)
1>uy = 8.4 +/-0.67 <8.01, 8.89> (9)
1>0
1> 5.2 +/-0.56 <4.82, 5.64> (7), 8.4 +/-0.67 <8.01, 8.89> (9)
1> 7.5 +/-0.45 <7.14, 7.76> (8), 6.1 +/-0.52 <5.62, 6.54> (5)
1>
1>Done building project "demo_2d_uncertain_values.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Projects build report:
  Status    | Project [Config|platform]
 -----------|---------------------------------------------------------------------------------------------------
  Succeeded | demo_2d_uncertain_values\demo_2d_uncertain_values.vcxproj [Debug|x64]

Build time 00:00:04.211
Build ended at 22Jan2021 17:36:03

1>#0 5.2 +/-0.56 <4.82, 5.64> (7), 8.4 +/-0.67 <8.01, 8.89> (9)
1>#1 7.5 +/-0.45 <7.14, 7.76> (8), 6.1 +/-0.52 <5.62, 6.54> (5)

*/


//==============================================================================
//         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
//==============================================================================
//////////////////////////////////////////////////////////////////////////////
// cover test behavior of arithmetic components in scalar mode
//////////////////////////////////////////////////////////////////////////////

#include <nt2/ieee/include/functions/frexp.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <nt2/include/constants/valmin.hpp>
#include <nt2/include/constants/valmax.hpp>
#include <nt2/include/functions/mantissa.hpp>
#include <nt2/include/functions/exponent.hpp>

#include <nt2/sdk/unit/tests/cover.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <vector>

NT2_TEST_CASE_TPL ( frexp_real__1_0_1,  NT2_REAL_TYPES)
{

  using nt2::frexp;
  using nt2::tag::frexp_;
  typedef typename nt2::meta::call<frexp_(T)>::type r_t;

  nt2::uint32_t NR = NT2_NB_RANDOM_TEST;
  std::vector<T> in1(NR);
  std::vector<r_t> ref(NR);
  nt2::roll(in1, nt2::Valmin<T>()/2, nt2::Valmax<T>()/2);
  for(nt2::uint32_t i=0; i < NR ; ++i)
  {
    ref[i].first = nt2::mantissa(in1[i])/2;
    ref[i].second = nt2::exponent(in1[i])+1;
  }
  NT2_COVER_ULP_EQUAL(frexp_, ((T, in1)), ref, 0);
}


//  Copyright 2013 John Maddock. 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_

#ifndef BOOST_MP_MATH_SETUP_HPP
#define BOOST_MP_MATH_SETUP_HPP

#ifdef _MSC_VER
#  define _SCL_SECURE_NO_WARNINGS
#endif

#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#undef BOOST_MATH_SMALL_CONSTANT
#define BOOST_MATH_SMALL_CONSTANT(x) x

#if !defined(TEST_MPF_50) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) \
      && !defined(TEST_MPFR_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT)
#  define TEST_MPF_50
#  define TEST_MPFR_50
#  define TEST_CPP_DEC_FLOAT
#  define TEST_FLOAT128
#  define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50)
#include <boost/multiprecision/gmp.hpp>
#include <boost/multiprecision/debug_adaptor.hpp>

#define MPF_TESTS    /*test(number<gmp_float<18> >(), "number<gmp_float<18> >");*/\
   mpf_float::default_precision(20);\
   test(mpf_float(), "number<gmp_float<0> > (20 digit precision)");\
   mpf_float::default_precision(35);\
   test(mpf_float(), "number<gmp_float<0> > (35 digit precision)");\
   test(number<gmp_float<30> >(), "number<gmp_float<30> >");\
   test(number<gmp_float<35> >(), "number<gmp_float<35> >");\
   /* there should be at least one test with expression templates off: */ \
   test(number<gmp_float<35>, et_off>(), "number<gmp_float<35>, et_off>");
#define MPF_SMALL_TESTS    /*test(number<gmp_float<18> >(), "number<gmp_float<18> >");*/\
   test(number<gmp_float<30> >(), "number<gmp_float<30> >");\
   test(number<gmp_float<35> >(), "number<gmp_float<35> >");\
   /* there should be at least one test with expression templates off: */ \
   test(number<gmp_float<35>, et_off>(), "number<gmp_float<35>, et_off>");\
   mpf_float::default_precision(20); \
   test(mpf_float(), "number<gmp_float<0> > (20 digit precision)"); \
   mpf_float::default_precision(35); \
   test(mpf_float(), "number<gmp_float<0> > (35 digit precision)"); \

typedef boost::multiprecision::number<boost::multiprecision::gmp_float<18> > test_type_1;
typedef boost::multiprecision::number<boost::multiprecision::gmp_float<30> > test_type_2;
typedef boost::multiprecision::number<boost::multiprecision::gmp_float<35> > test_type_3;
typedef boost::multiprecision::number<boost::multiprecision::gmp_float<35>, boost::multiprecision::et_off> test_type_4;
typedef boost::multiprecision::mpf_float test_type_5;

#else

#define MPF_TESTS
#define MPF_SMALL_TESTS

#endif

#if defined(TEST_MPFR_50)
#include <boost/multiprecision/mpfr.hpp>

#define MPFR_TESTS    test(number<mpfr_float_backend<18> >(), "number<mpfr_float_backend<18> >");\
   test(number<mpfr_float_backend<30> >(), "number<mpfr_float_backend<30> >");\
   test(number<mpfr_float_backend<35> >(), "number<mpfr_float_backend<35> >");\
  /* Test variable precision at 2 different precisions - checks our ability to handle dynamic changes in precision */\
  mpfr_float::default_precision(20);\
  test(mpfr_float(), "number<mpfr_float_backend<0> > (20-digit precision)");\
  mpfr_float::default_precision(35);\
  test(mpfr_float(), "number<mpfr_float_backend<0> > (35-digit precision)");

typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<18> > test_type_1;
typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<30> > test_type_2;
typedef boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<35> > test_type_3;
typedef boost::multiprecision::mpfr_float test_type_4;

#else

#define MPFR_TESTS

#endif

#ifdef TEST_BACKEND
#include <boost/multiprecision/concepts/mp_number_archetypes.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <boost/multiprecision/cpp_dec_float.hpp>

#define CPP_DEC_FLOAT_TESTS    test(number<cpp_dec_float<18> >(), "number<cpp_dec_float<18> >");\
   test(number<cpp_dec_float<30> >(), "number<cpp_dec_float<30> >");\
   test(number<cpp_dec_float<35, long long, std::allocator<void> > >(), "number<cpp_dec_float<35, long long, std::allocator<void> > >");

typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<18> > test_type_1;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<30> > test_type_2;
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<35, long long, std::allocator<void> > > test_type_3;

#else

#define CPP_DEC_FLOAT_TESTS

#endif

#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/multiprecision/debug_adaptor.hpp>

//#define CPP_BIN_FLOAT_TESTS test(number<debug_adaptor<cpp_bin_float_quad::backend_type>, et_off>(), "cpp_bin_float_quad");
#define CPP_BIN_FLOAT_TESTS test(cpp_bin_float_quad(), "cpp_bin_float_quad");

//typedef boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::cpp_bin_float_quad::backend_type>, boost::multiprecision::et_off> test_type_1;
typedef boost::multiprecision::cpp_bin_float_quad test_type_1;

#else

#define CPP_BIN_FLOAT_TESTS

#endif

#ifdef TEST_FLOAT128
#include <boost/multiprecision/float128.hpp>

#define FLOAT128_TESTS test(float128(), "float128");

typedef boost::multiprecision::float128 test_type_1;

#else

#define FLOAT128_TESTS

#endif

#ifndef BOOST_MATH_TEST_TYPE
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#endif

#define ALL_TESTS \
 MPF_TESTS\
 MPFR_TESTS\
 CPP_DEC_FLOAT_TESTS\
 FLOAT128_TESTS\
 CPP_BIN_FLOAT_TESTS

#define ALL_SMALL_TESTS\
 MPF_SMALL_TESTS\
 MPFR_TESTS\
 CPP_DEC_FLOAT_TESTS\
 FLOAT128_TESTS\
 CPP_BIN_FLOAT_TESTS

#endif


#include <iostream>
#include <typeinfo>
#define BOOST_TEST_MODULE ImplicitMIAFunctionTests

#include "MIAConfig.h"

#ifdef MIA_USE_HEADER_ONLY_TESTS
#include <boost/test/included/unit_test.hpp>
#else
#include <boost/test/unit_test.hpp>
#endif

#include "ImplicitMIA.h"
#include "DenseMIA.h"
#include "LibMIAUtil.h"
#include "Index.h"

template<class _data_type>
void functions_work(){

    size_t dim1=2;
    size_t dim2=3;
    size_t dim3=4;

    typedef LibMIA::ImplicitMIA<_data_type,3> MIAType;
    typedef LibMIA::ImplicitMIA<_data_type,3,true> MIAType_ref;
    typedef LibMIA::DenseMIA<_data_type,3> DenseMIAType;
    typedef typename LibMIA::internal::index_type<MIAType>::type index_type;
    typedef typename LibMIA::internal::function_type<MIAType>::type function_type;
    typedef typename LibMIA::internal::function_type<MIAType_ref>::type function_type_ref;
    function_type _func=[](index_type idx){
        if(idx%2==0)
            return 1;
        else
            return 2;
    };
    MIAType a(_func,dim1,dim2,dim3);
    bool _correct=true;
    for(auto it=a.data_begin();it<a.data_end();++it){
        if((it-a.data_begin())%2==0){
            if(*it!=1)
                _correct=false;
        }
        else{
            if(*it!=2)
                _correct=false;
        }

    }
    BOOST_CHECK_MESSAGE(_correct,std::string("Basic data iterator test for ImplicitMIA for ")+typeid(_data_type).name());

    DenseMIAType dense_a(dim1,dim2,dim3);
    for(size_t idx=0;idx<dense_a.dimensionality();++idx){
        if(idx%2==0)
            dense_a.atIdx(idx)=1;
        else
            dense_a.atIdx(idx)=2;

    }
    BOOST_CHECK_MESSAGE(a==dense_a,std::string("Basic ImplicitMIA Function Test for ")+typeid(_data_type).name());

    //Now test ImplicitMIAs that refer to another piece of data
    function_type_ref _func_ref=[&dense_a](index_type idx)->_data_type&{

        return dense_a.atIdx(idx);;
    };
    MIAType_ref a_ref(_func_ref,dim1,dim2,dim3);
    BOOST_CHECK_MESSAGE(a_ref==dense_a,std::string("Value test for ImplicitMIA with reference for ")+typeid(_data_type).name());
    _correct=true;
    for(size_t idx=0;idx<dense_a.dimensionality();++idx){
        if(&(dense_a.atIdx(idx))!=&(a_ref.atIdx(idx))){
            _correct=false;
            break;
        }

    }
    BOOST_CHECK_MESSAGE(_correct,std::string("Reference test for ImplicitMIA with reference for ")+typeid(_data_type).name());

    //now test the assign to data_type operation - which implicity tests the iterators of ImplicitMIA
    a_ref.fill(2);
    _correct=true;
    for(size_t idx=0;idx<a_ref.dimensionality();++idx){
        if(a_ref.atIdx(idx)!=2){
            _correct=false;
            break;
        }

    }
    BOOST_CHECK_MESSAGE(_correct,std::string("Basic assignment functionality test to referred data for ImplicitMIA with reference for ")+typeid(_data_type).name());
    _correct=true;
    for(size_t idx=0;idx<dense_a.dimensionality();++idx){
        if(dense_a.atIdx(idx)!=2){
            _correct=false;
            break;
        }

    }

}

BOOST_AUTO_TEST_CASE( ImplicitMIAFunctionTests )
{

    functions_work<double>();

    functions_work<float>();
    functions_work<int>();
    functions_work<long>();

}