#include "my_tarjan.cpp"
#include <boost/graph/erdos_renyi_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/graphml.hpp>
#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/graph/transitive_closure.hpp>

using namespace boost;

int main(int argc, char*argv[])
{
    //An example of alternative way to design a graph "by hand" in order to use our algorithm
    /*typedef std::pair<int, int> Edge;
    int n=1000;
    Edge edge_array[n-1];

    int k=0;
    for(int i=0;i<n-1;i++){
        edge_array[i]=Edge(i,i+1);
    }

    int num_arcs = sizeof(edge_array) / sizeof(Edge);
    Graph g(&edge_array[0], &edge_array[n-1], n);*/

    //This function takes a graph formatted by graphml fashion from the stdin
    Graph g;
    dynamic_properties dp;
    read_graphml(std::cin, g, dp);

    std::cout << "A directed graph:" << std::endl;
    print_graph(g, get(vertex_index,g));
    std::cout << std::endl;

    //This is the TarjanClass object
    TarjanClass<typeInt, typeInt, typeInt, typeBool, typeBool, typeInt> tarjan(&g);
    std::vector<int>* comp_tarjan = tarjan.tarjan_scc();

    //Printing
    IndexMap index = get(vertex_index,g);

    for (int i = 0; i != comp_tarjan->size(); ++i){
        std::cout << index[i] << " -> " << (*comp_tarjan)[i] << std::endl;
    }
    return 0;
}


//
// Copyright (c) 2009, Markus Rickert
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <iostream>
#include <boost/lexical_cast.hpp>
#include <rl/math/Polynomial.h>

int
main(int argc, char** argv)
{
	if (argc < 2)
	{
		std::cout << "Usage: rlPolynomialRootsDemo C0 ... CN" << std::endl;
		return EXIT_FAILURE;
	}

	std::vector<rl::math::Real> c(argc - 1);

	for (std::size_t i = 0; i < c.size(); ++i)
	{
		c[i] = boost::lexical_cast<rl::math::Real>(argv[i + 1]);
		std::cout << (i > 0 ? " + " : "") << c[i] << " * x^" << i;
	}

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

	std::vector<rl::math::Real> roots = rl::math::Polynomial<rl::math::Real>::realRoots(c);

	std::cout << roots.size() << " solution" << (roots.size() != 1 ? "(s)" : "") << std::endl;

	for (std::size_t i = 0; i < roots.size(); ++i)
	{
		std::cout << "x[" << i << "] = " << roots[i] << std::endl;
	}

	return EXIT_SUCCESS;
}


/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_COMPUTER_VISION_INTRISICS_MATRIX_HPP
#define PIC_COMPUTER_VISION_INTRISICS_MATRIX_HPP

#include <vector>
#include <random>
#include <stdlib.h>

#include "../base.hpp"

#include "../util/math.hpp"

#ifndef PIC_DISABLE_EIGEN

    #ifndef PIC_EIGEN_NOT_BUNDLED
        #include "../externals/Eigen/Dense"
        #include "../externals/Eigen/Geometry"
    #else
        #include <Eigen/Dense>
        #include <Eigen/Geometry>
    #endif

#endif

namespace pic {

/**
 * @brief getFocalLengthFromFOVAngle
 * @param fovy is an angle in radians.
 * @return
 */
PIC_INLINE double getFocalLengthFromFOVAngle(double fovy)
{
    return 1.0 / tan(fovy / 2.0);
}

/**
 * @brief getFOVAngleFromFocalSensor
 * @param f is the focal length in mm
 * @param x is the sensor width in mm
 * @param y is the sensor height in mm
 * @return
 */
PIC_INLINE double getFOVAngleFromFocalSensor(double f, double x, double y)
{
    double d = sqrt(x * x + y * y);
    return 2.0 * atan(d /  (2.0 * f));
}

/**
 * @brief getFocalLengthPixels
 * @param focal_length_mm
 * @param sensor_size_mm
 * @param sensor_size_px
 * @return
 */
PIC_INLINE double getFocalLengthPixels(double focal_length_mm, double sensor_size_mm, double sensor_size_px)
{
    return (focal_length_mm * sensor_size_px) / sensor_size_mm;
}

#ifndef PIC_DISABLE_EIGEN

/**
 * @brief getIntrinsicsMatrix
 * @param focal_length
 * @param m_x
 * @param m_y
 * @param opitical_center_x
 * @param opitical_center_y
 * @return
 */
PIC_INLINE Eigen::Matrix3d getIntrinsicsMatrix(double focal_length, double m_x, double m_y, double opitical_center_x, double opitical_center_y)
{
    Eigen::Matrix3d K;
    K.setZero();
    K(0, 0) = focal_length * m_x;
    K(1, 1) = focal_length * m_y;
    K(2, 2) = 1.0;

    K(0, 2) = opitical_center_x;
    K(1, 2) = opitical_center_y;

    return K;
}

/**
 * @brief getIntrinsicsMatrix
 * @param focal_length_x
 * @param focal_length_y
 * @param opitical_center_y
 * @return
 */
PIC_INLINE Eigen::Matrix3d getIntrinsicsMatrix(double focal_length_x, double focal_length_y, double opitical_center_x, double opitical_center_y)
{
    Eigen::Matrix3d K;
    K.setZero();
    K(0, 0) = focal_length_x;
    K(1, 1) = focal_length_y;
    K(2, 2) = 1.0;

    K(0, 2) = opitical_center_x;
    K(1, 2) = opitical_center_y;

    return K;
}

/**
 * @brief removeLensDistortion
 * @param point
 * @param K
 * @return
 */
PIC_INLINE Eigen::Vector2d removeLensDistortion(Eigen::Vector2d &p, double k[5])
{
    Eigen::Vector2d ret;

    double r_2 = p[0] * p[0] + p[1] * p[1];
    double r_4 = r_2 * r_2;

    double c = 1.0 + k[0] * r_2 + k[1] * r_4 + k[4] * r_4 *r_2;

    Eigen::Vector2d dx;
    dx[0] = 2 * k[2] * p[0] * p[1] + k[3] * (r_2 + 2.0 * p[0] * p[0]);
    dx[1] = k[2] * (r_2 + 2 * p[1] * p[1]) + 2.0 * k[3] * p[0] * p[1];

    ret = p * c + dx;

    return ret;
}

#endif // PIC_DISABLE_EIGEN

} // end namespace pic

#endif // PIC_COMPUTER_VISION_INTRISICS_MATRIX_HPP


#include "uint.h"

#include <algorithm>
#include <boost/static_assert.hpp>
#include <assert.h>

const char kDigits[] = "0123456789abcdef";
BOOST_STATIC_ASSERT(sizeof kDigits == 17);

std::string UnsignedInt::toHex() const
{
  std::string result;
  result.reserve(value_.size()*8);

  if (value_.empty())
  {
    result.push_back('0');
    return result;
  }

  assert(value_.size() > 0);
  for (size_t i = 0; i < value_.size()-1; ++i)
  {
    uint32_t x = value_[i];
    for (int j = 0; j < 8; ++j)
    {
      int lsd = x % 16;
      x /= 16;
      result.push_back(kDigits[lsd]);
    }
  }

  uint32_t x = value_.back();
  do
  {
    int lsd = x % 16;
    x /= 16;
    result.push_back(kDigits[lsd]);
  } while (x != 0);

  std::reverse(result.begin(), result.end());

  return result;
}

std::string UnsignedInt::toDec() const
{
  const uint32_t segment = 1000000000;
  std::string result;
  if (value_.empty())
  {
    result.push_back('0');
    return result;
  }

  result.reserve(9*value_.size() + 7*value_.size()/11 + 1);
  // log10(2**32) = 32*log10(2) = 9.633 digits per word
  UnsignedInt copy = *this;
  while (copy.value_.size() > 1)
  {
    uint32_t x = copy.devide(segment);
    for (int i = 0; i < 9; ++i)
    {
      int lsd = x  % 10;
      x /= 10;
      result.push_back(kDigits[lsd]);
    }
  }

  uint32_t x = copy.value_[0];
  do
  {
    int lsd = x % 10;
    x /= 10;
    result.push_back(kDigits[lsd]);
  } while (x != 0);

  std::reverse(result.begin(), result.end());

  return result;
}

UnsignedInt::UnsignedInt(const std::string& x, Radix r)
{
  if (r == kDec)
  {
    parseDec(x);
  }
  else if (r == kHex)
  {
    parseHex(x);
  }
  else
  {
    assert(0 && "Radix invalid");
    abort();
  }
}

uint32_t fromHex(char c)
{
  if (c >= '0' && c <= '9')
    return c - '0';
  if (c >= 'a' && c <= 'f')
    return c - 'a' + 10;
  if (c >= 'A' && c <= 'F')
    return c - 'A' + 10;
  return -1;
}

void UnsignedInt::parseHex(const std::string& str)
{
  value_.reserve((str.size()+7) / 8);
  for (size_t i = 0; i < str.size(); ++i)
  {
    if (i % 8 == 0)
      value_.push_back(0);
    uint32_t digit = fromHex(str[str.size() - i - 1]);
    uint32_t shift = 4 * (i % 8);
    value_.back() |= (digit << shift);
  }
  if (value_.size() == 1 && value_[0] == 0)
  {
    value_.clear();
  }
}

uint32_t fromDec(char c)
{
  if (c >= '0' && c <= '9')
    return c - '0';
  return -1;
}

uint32_t parseSegment(const char* str, int len)
{
  uint32_t seg = 0;
  for (int i = 0; i < len; ++i)
  {
    seg *= 10;
    seg += fromDec(str[i]);
  }
  return seg;
}

void UnsignedInt::parseDec(const std::string& str)
{
  const uint32_t kSegment = 1000 * 1000 * 1000;
  const uint32_t kSegmentDigits = 9;
  // log2(10)/32 = 0.10381025296523
  // 8/77 = 0.103896103896104
  value_.reserve(1 + str.size() * 8 / 77);

  int first = str.size() % kSegmentDigits;
  if (first)
  {
    uint32_t seg = parseSegment(str.c_str(), first);
    add(seg);
  }
  for (size_t i = first; i < str.size(); i += kSegmentDigits)
  {
    assert(i + kSegmentDigits <= str.size());
    uint32_t seg = parseSegment(str.c_str() + i, kSegmentDigits);
    multiply(kSegment);
    add(seg);
  }
}


// Copyright (c) 2013, Manuel Blum
// All rights reserved.

// Define this symbol to enable runtime tests for allocations
//#define EIGEN_RUNTIME_NO_MALLOC

#include <Eigen/Dense>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include "nn.h"

using namespace std;

typedef vector<int> vi;
typedef vector<vi> vvi;
inline void swap(int &val)
{
    val = (val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24);
}
class batch_manager
{
    int num_samples;
    int current_count;
    int batch_size;

  public:
    batch_manager(int num_samples, int batch_size)
    {
        this->num_samples = num_samples;
        this->batch_size = batch_size;
        current_count = 0;
    }
    pair<int, int> next_batch()
    {
        pair<int, int> res = make_pair(current_count, current_count + batch_size);
        if (current_count + batch_size > num_samples)
        {
            //cout << "Current count: " << current_count << endl;
            if (current_count == num_samples)
            {
                current_count = 0;
                return make_pair(0, batch_size);
            }
            res.second = num_samples;
            current_count = 0;

            return res;
        }
        current_count += res.second - res.first;
        return res;
    }
};
matrix_t read_mnist_images(std::string filename)
{

    matrix_t X;
    std::ifstream fs(filename.c_str(), std::ios::binary);
    if (fs)
    {
        int magic_number, num_images, num_rows, num_columns;
        fs.read((char *)&magic_number, sizeof(magic_number));
        fs.read((char *)&num_images, sizeof(num_images));
        fs.read((char *)&num_rows, sizeof(num_rows));
        fs.read((char *)&num_columns, sizeof(num_columns));
        if (magic_number != 2051)
        {
            swap(magic_number);
            swap(num_images);
            swap(num_rows);
            swap(num_columns);
        }

        X = matrix_t::Zero(num_images, num_rows * num_columns);

        for (size_t i = 0; i < num_images; ++i)
        {
            for (size_t j = 0; j < num_rows * num_columns; ++j)
            {
                unsigned char temp = 0;
                fs.read((char *)&temp, sizeof(temp));
                X(i, j) = (double)temp;
            }
        }
        fs.close();
    }
    else
    {
        std::cout << "error reading file: " << filename << std::endl;
        exit(1);
    }
    return X;
}

matrix_t read_mnist_labels(std::string filename)
{
    matrix_t Y;
    std::ifstream fs(filename.c_str(), std::ios::binary);
    if (fs)
    {
        int magic_number, num_images, num_rows, num_columns;
        fs.read((char *)&magic_number, sizeof(magic_number));
        fs.read((char *)&num_images, sizeof(num_images));
        if (magic_number != 2049)
        {
            swap(magic_number);
            swap(num_images);
        }

        Y = matrix_t::Zero(num_images, 10);

        for (size_t i = 0; i < num_images; ++i)
        {
            unsigned char temp = 0;
            fs.read((char *)&temp, sizeof(temp));
            Y(i, (int)temp) = 1.0;
        }
        fs.close();
    }
    else
    {
        std::cout << "error reading file: " << filename << std::endl;
        exit(1);
    }
    return Y;
}

double measure_accuracy(matrix_t Y, matrix_t Y_test)
{
    int correct = 0;
    for (int i = 0; i < Y.rows(); i++)
    {
        int j = 0;
        for (; j < Y.cols(); j++)
        {
            int out = Y_test(i, j) > 0.7 ? 1 : 0;
            //printf("%3i   %4.4f", (int)Y(i, j), Y_test(i, j));

            if (out != Y(i, j))
                break;
        }
        //cout << endl;
        if (j == Y.cols())
        {
            correct++;
        }
        else
        {
            //cout << Y_test.row(i) << endl;
        }
    }
    //cout << "Correct answer " << correct << " among " << Y.rows() << " test" << endl;
    double accuracy = (double)correct / (double)Y.rows() * 100;
    return accuracy;
    //cout << "Accuracy: " <<  accuracy << "%" << endl;
}

void fill_type_info(matrix_t &Y, vi &type_info)
{
    int num_sample = Y.rows();
    int num_type = Y.cols();
    for (int i = 0; i < num_sample; i++)
    {
        for (int j = 0; j < num_type; j++)
        {
            if (Y(i, j) == 1)
            {
                type_info[j]++;
                break;
            }
        }
    }
}

void fill_position(matrix_t &Y, vvi &position)
{
    int num_sample = Y.rows();
    int num_type = Y.cols();
    for (int i = 0; i < num_sample; i++)
    {
        for (int j = 0; j < num_type; j++)
        {
            if (Y(i, j) == 1)
            {
                position[j].push_back(i);
                break;
            }
        }
    }
}

int distribution_in_batch(vi &type_distribution, vi &type_info, int proposed_batch_size, int num_sample)
{
    int batch_size = 0;
    int num_type = type_info.size();
    for (int i = 0; i < num_type; i++)
    {
        type_distribution[i] = (int)ceil((double)(type_info[i] * proposed_batch_size) / (double)num_sample);
        batch_size += type_distribution[i];
    }
    return batch_size;
}

void distribute_into_batch(matrix_t &X, matrix_t &Y, matrix_t &Xm, matrix_t &Ym, vi &type_distribution, vvi &position, int batch_size, vi &type_point, int batch_no)
{
    int cnt = 0;
    for (int i = 0; i < type_distribution.size(); i++)
    {
        for (int j = 0; j < type_distribution[i]; j++)
        {
            if (batch_no * batch_size + cnt == Xm.rows())
            {
                Xm.conservativeResize(Xm.rows() + batch_size - cnt, Xm.cols());
                Ym.conservativeResize(Ym.rows() + batch_size - cnt, Ym.cols());
            }
            Xm.row(batch_no * batch_size + cnt) = X.row(position[i][type_point[i]]);
            Ym.row(batch_no * batch_size + cnt) = Y.row(position[i][type_point[i]]);
            cnt++;
            type_point[i]++;
            if (type_point[i] >= position[i].size())
            {
                type_point[i] = 0;
            }
        }
    }
}
void distribute_into_matrix(matrix_t &X, matrix_t &Y, matrix_t &Xm, matrix_t &Ym, vi &type_info, vi &type_distribution, vvi &position, int batch_size)
{
    vi type_point(type_info.size(), 0);
    int num_batch = (int)ceil((double)Y.rows() / (double)batch_size);

    for (int i = 0; i < num_batch; i++)
    {
        distribute_into_batch(X, Y, Xm, Ym, type_distribution, position, batch_size, type_point, i);
    }
}
pair<matrix_t, matrix_t> make_uniform_dataset(matrix_t &X, matrix_t &Y, int &batch_size)
{
    int num_sample = Y.rows();
    int num_type = Y.cols();

    vi type_info(num_type, 0);
    fill_type_info(Y, type_info);

    vi type_distribution(num_type, 0);
    batch_size = distribution_in_batch(type_distribution, type_info, batch_size, num_sample);

    vvi position(num_type);
    fill_position(Y, position);

    matrix_t Xm(num_sample, X.cols());
    matrix_t Ym(num_sample, num_type);

    distribute_into_matrix(X, Y, Xm, Ym, type_info, type_distribution, position, batch_size);

    return make_pair(Xm, Ym);
}
pair<matrix_t, matrix_t> make_worst_batch(matrix_t &X, matrix_t &Y)
{
    matrix_t Xm(X.rows(), X.cols());
    matrix_t Ym(Y.rows(), Y.cols());

    int num_sample = Y.rows();
    int num_type = Y.cols();

    vi type_info(num_type, 0);
    fill_type_info(Y, type_info);

    vvi position(num_type);
    fill_position(Y, position);
    int cnt = 0;
    for (int i = 0; i < num_type; i++)
    {
        for (int j = 0; j < position[i].size(); j++)
        {
            Xm.row(cnt) = X.row(position[i][j]);
            Ym.row(cnt) = Y.row(position[i][j]);
            cnt++;
        }
    }

    return make_pair(Xm, Ym);
}
int main(int argc, const char *argv[])
{

    if (argc != 2)
    {
        std::cout << "please provide path to mnist data ..." << std::endl;
        std::cout << "you can download the dataset at http://yann.lecun.com/exdb/mnist/" << std::endl;
        std::cout << std::endl
                  << "usage: " << argv[0] << " path_to_data" << std::endl
                  << std::endl;
        return 1;
    }

    std::string path = argv[1];

    std::cout << "reading data" << std::endl;

    // matrix_t X_train = read_mnist_images(path + "/train-images.idx3-ubyte");
    // matrix_t Y_train = read_mnist_labels(path + "/train-labels.idx1-ubyte");
    // matrix_t X_test = read_mnist_images(path + "/t10k-images.idx3-ubyte");
    // matrix_t Y_test = read_mnist_labels(path + "/t10k-labels.idx1-ubyte");

    matrix_t X_train = read_mnist_images(path + "/train-images.idx3-ubyte");
    matrix_t Y_train = read_mnist_labels(path + "/train-labels.idx1-ubyte");
    matrix_t X_test = read_mnist_images(path + "/t10k-images.idx3-ubyte");
    matrix_t Y_test = read_mnist_labels(path + "/t10k-labels.idx1-ubyte");

    //cout << "Number of training sample: " << X_train.rows() << endl;
    int max_steps = 1500;
    double lambda = 0.001;

    // specify network topology
    Eigen::VectorXi topo(3);
    topo << X_train.cols(), 300, Y_test.cols();
    std::cout << "topology: " << topo.transpose() << std::endl;

    // initialize a neural network with given topology
    std::cout << "initializing network" << std::endl;
    NeuralNet nn(topo);

    int batch_size = 100;
    // pair<matrix_t, matrix_t> xy = make_uniform_dataset(X_train, Y_train, batch_size);

    // X_train = xy.first;
    // Y_train = xy.second;

    // pair<matrix_t, matrix_t> xy = make_worst_batch(X_train, Y_train);

    // X_train = xy.first;
    // Y_train = xy.second;

    std::cout<< "scaling the data" << std::endl;
    nn.autoscale(X_train, Y_train);

    int num_attribute = X_train.cols();
    int num_type = Y_train.cols();
    batch_manager batch(X_train.rows(), batch_size);

    std::cout << "starting training" << std::endl;
    std::cout << "iter        error" << std::endl;

    double err;
    clock_t begin = clock();
    for (int i = 0; i < max_steps; ++i)
    {
        pair<int, int> start_end = batch.next_batch();
        const int batch_size = start_end.second - start_end.first;

        matrix_t Xm = X_train.block(start_end.first, 0, batch_size, num_attribute);
        matrix_t Ym = Y_train.block(start_end.first, 0, batch_size, num_type);

        err = nn.loss(Xm, Ym, lambda);
        nn.rprop();
        printf("%4i   %10.7f\n", i, err);
    }
    clock_t end = clock();
    double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
    cout << "Training time: " << elapsed_secs << endl;

    // test accuracy
    nn.forward_pass(X_test);
    matrix_t prediction = nn.get_activation();
    int correct = 0;
    int k;
    for (size_t i = 0; i < Y_test.rows(); ++i)
    {
        prediction.row(i).maxCoeff(&k);
        correct += Y_test(i, k);
    }

    std::cout << "test accuracy: " << correct * 1.0 / Y_test.rows() * 100 << "%" << std::endl;
    // double accuracy = measure_accuracy(Y_test, prediction);
    // std::cout << "Accuracy: " << accuracy << std::endl;
    nn.write("mnist.nn");

    return 0;
}


// Copyright 2018-2019 Hans Dembinski and Henry Schreiner
//
// 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)
//
// Based on boost/histogram/accumulators/weighted_mean.hpp
//
// Changes:
//  * Internal values are public for access from Python
//  * A special constructor added for construction from Python

#pragma once

#include <boost/core/nvp.hpp>
#include <boost/histogram/weight.hpp>

namespace accumulators {

/**
  Calculates mean and variance of weighted sample.

  Uses West's incremental algorithm to improve numerical stability
  of mean and variance computation.
*/
template <typename ValueType>
struct weighted_mean {
    using value_type      = ValueType;
    using const_reference = const value_type&;

    weighted_mean() = default;

    weighted_mean(const value_type& wsum,
                  const value_type& wsum2,
                  const value_type& mean,
                  const value_type& variance)
        : sum_of_weights(wsum)
        , sum_of_weights_squared(wsum2)
        , value(mean)
        , sum_of_weighted_deltas_squared(
              variance * (sum_of_weights - sum_of_weights_squared / sum_of_weights)) {}

    weighted_mean(const value_type& wsum,
                  const value_type& wsum2,
                  const value_type& mean,
                  const value_type& sum_of_weighted_deltas_squared,
                  bool /* tag to trigger Python internal constructor */)
        : sum_of_weights(wsum)
        , sum_of_weights_squared(wsum2)
        , value(mean)
        , sum_of_weighted_deltas_squared(sum_of_weighted_deltas_squared) {}

    void operator()(const value_type& x) { operator()(boost::histogram::weight(1), x); }

    void operator()(const boost::histogram::weight_type<value_type>& w,
                    const value_type& x) {
        sum_of_weights += w.value;
        sum_of_weights_squared += w.value * w.value;
        const auto delta = x - value;
        value += w.value * delta / sum_of_weights;
        sum_of_weighted_deltas_squared += w.value * delta * (x - value);
    }

    weighted_mean& operator+=(const weighted_mean& rhs) {
        if(sum_of_weights != 0 || rhs.sum_of_weights != 0) {
            const auto tmp = value * sum_of_weights + rhs.value * rhs.sum_of_weights;
            sum_of_weights += rhs.sum_of_weights;
            sum_of_weights_squared += rhs.sum_of_weights_squared;
            value = tmp / sum_of_weights;
        }
        sum_of_weighted_deltas_squared += rhs.sum_of_weighted_deltas_squared;
        return *this;
    }

    weighted_mean& operator*=(const value_type& s) {
        value *= s;
        sum_of_weighted_deltas_squared *= s * s;
        return *this;
    }

    bool operator==(const weighted_mean& rhs) const noexcept {
        return sum_of_weights == rhs.sum_of_weights
               && sum_of_weights_squared == rhs.sum_of_weights_squared
               && value == rhs.value
               && sum_of_weighted_deltas_squared == rhs.sum_of_weighted_deltas_squared;
    }

    bool operator!=(const weighted_mean rhs) const noexcept { return !operator==(rhs); }

    value_type variance() const {
        return sum_of_weighted_deltas_squared
               / (sum_of_weights - sum_of_weights_squared / sum_of_weights);
    }

    template <class Archive>
    void serialize(Archive& ar, unsigned /* version */) {
        ar& boost::make_nvp("sum_of_weights", sum_of_weights);
        ar& boost::make_nvp("sum_of_weights_squared", sum_of_weights_squared);
        ar& boost::make_nvp("value", value);
        ar& boost::make_nvp("sum_of_weighted_deltas_squared",
                            sum_of_weighted_deltas_squared);
    }

    value_type sum_of_weights{};
    value_type sum_of_weights_squared{};
    value_type value{};
    value_type sum_of_weighted_deltas_squared{};
};

} // namespace accumulators


// Boost.Geometry

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

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

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP

#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/strategies/densify.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

namespace boost { namespace geometry
{

namespace strategy { namespace densify
{

/*!
\brief Densification of cartesian segment.
\ingroup strategies
\tparam CalculationType \tparam_calculation

\qbk{
[heading See also]
[link geometry.reference.algorithms.densify.densify_4_with_strategy densify (with strategy)]
}
 */
template
<
    typename CalculationType = void
>
class cartesian
{
public:
    template <typename Point, typename AssignPolicy, typename T>
    static inline void apply(Point const& p0, Point const& p1, AssignPolicy & policy, T const& length_threshold)
    {
        typedef typename AssignPolicy::point_type out_point_t;
        typedef typename coordinate_type<out_point_t>::type out_coord_t;
        typedef typename select_most_precise
            <
                typename coordinate_type<Point>::type, out_coord_t,
                CalculationType
            >::type calc_t;

        typedef model::point<calc_t, geometry::dimension<Point>::value, cs::cartesian> calc_point_t;

        assert_dimension_equal<calc_point_t, out_point_t>();

        calc_point_t cp0, dir01;
        // dir01 = p1 - p0
        geometry::detail::for_each_dimension<calc_point_t>([&](auto index)
        {
            calc_t const coord0 = boost::numeric_cast<calc_t>(get<index>(p0));
            calc_t const coord1 = boost::numeric_cast<calc_t>(get<index>(p1));
            set<index>(cp0, coord0);
            set<index>(dir01, coord1 - coord0);
        });

        calc_t const dot01 = geometry::dot_product(dir01, dir01);
        calc_t const len = math::sqrt(dot01);

        BOOST_GEOMETRY_ASSERT(length_threshold > T(0));

        signed_size_type const n = signed_size_type(len / length_threshold);
        if (n <= 0)
        {
            return;
        }

        calc_t const den = calc_t(n + 1);
        for (signed_size_type i = 0 ; i < n ; ++i)
        {
            out_point_t out;

            calc_t const num = calc_t(i + 1);
            geometry::detail::for_each_dimension<out_point_t>([&](auto index)
            {
                // out = p0 + d * dir01
                calc_t const coord = get<index>(cp0) + get<index>(dir01) * num / den;

                set<index>(out, boost::numeric_cast<out_coord_t>(coord));
            });

            policy.apply(out);
        }
    }
};

#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{

template <>
struct default_strategy<cartesian_tag>
{
    typedef strategy::densify::cartesian<> type;
};

} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

}} // namespace strategy::densify

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DENSIFY_HPP


#include <stan/math/prim.hpp>
#include <gtest/gtest.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/math/distributions.hpp>
#include <limits>
#include <vector>

stan::math::vector_d get_simplex_inv_logit(double lambda,
                                           const stan::math::vector_d& c) {
  using stan::math::inv_logit;
  int K = c.size() + 1;
  stan::math::vector_d theta(K);
  theta(0) = 1.0 - inv_logit(lambda - c(0));
  for (int k = 1; k < (K - 1); ++k)
    theta(k) = inv_logit(lambda - c(k - 1)) - inv_logit(lambda - c(k));
  // - 0.0
  theta(K - 1) = inv_logit(lambda - c(K - 2));
  return theta;
}

TEST(ProbDistributions, ordered_logistic_vals) {
  using Eigen::Dynamic;
  using Eigen::Matrix;

  using stan::math::inv_logit;
  using stan::math::ordered_logistic_log;

  std::vector<int> y{1, 2, 3, 4, 5};
  std::vector<int> zero{1, 2, 0, 4, 5};
  std::vector<int> six{1, 2, 6, 4, 5};
  int K = 5;
  Matrix<double, Dynamic, 1> c(K - 1);
  c << -1.7, -0.3, 1.2, 2.6;

  Matrix<double, Dynamic, 1> lambda(K);
  lambda << 1.1, 1.1, 1.1, 1.1, 1.1;

  stan::math::vector_d theta = get_simplex_inv_logit(lambda[0], c);

  double sum = 0.0;
  double log_sum = 0.0;
  for (int k = 0; k < theta.size(); ++k) {
    sum += theta(k);
    log_sum += log(theta(k));
  }
  EXPECT_FLOAT_EQ(1.0, sum);

  for (int k = 0; k < K; ++k)
    EXPECT_FLOAT_EQ(log(theta(k)), ordered_logistic_log(k + 1, lambda[k], c));

  EXPECT_FLOAT_EQ(log_sum, ordered_logistic_log(y, lambda, c));

  EXPECT_THROW(ordered_logistic_log(0, lambda[0], c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(6, lambda[0], c), std::domain_error);

  EXPECT_THROW(ordered_logistic_log(zero, lambda, c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(six, lambda, c), std::domain_error);
}

TEST(ProbDistributions, ordered_logistic_vals_2) {
  using Eigen::Dynamic;
  using Eigen::Matrix;

  using stan::math::inv_logit;
  using stan::math::ordered_logistic_log;

  std::vector<int> y{1, 2, 3};
  std::vector<int> zero{1, 0, 3};
  std::vector<int> six{1, 6, 3};

  int K = 3;
  Matrix<double, Dynamic, 1> c(K - 1);
  c << -0.2, 4;
  Matrix<double, Dynamic, 1> lambda(K);
  lambda << -0.9, -0.9, -0.9;

  stan::math::vector_d theta = get_simplex_inv_logit(lambda[0], c);

  double sum = 0.0;
  double log_sum = 0.0;
  for (int k = 0; k < theta.size(); ++k) {
    sum += theta(k);
    log_sum += log(theta(k));
  }
  EXPECT_FLOAT_EQ(1.0, sum);

  for (int k = 0; k < K; ++k)
    EXPECT_FLOAT_EQ(log(theta(k)), ordered_logistic_log(k + 1, lambda[0], c));

  EXPECT_FLOAT_EQ(log_sum, ordered_logistic_log(y, lambda, c));

  EXPECT_THROW(ordered_logistic_log(0, lambda[0], c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(4, lambda[0], c), std::domain_error);

  EXPECT_THROW(ordered_logistic_log(zero, lambda, c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(six, lambda, c), std::domain_error);
}

TEST(ProbDistributions, ordered_logistic) {
  using stan::math::ordered_logistic_log;
  std::vector<int> y{1, 1, 1, 1};
  int K = 4;
  Eigen::Matrix<double, Eigen::Dynamic, 1> c(K - 1);
  c << -0.3, 0.1, 1.2;
  Eigen::Matrix<double, Eigen::Dynamic, 1> lambda(K);
  lambda << 0.5, 0.5, 0.5, 0.5;

  // init size zero
  Eigen::Matrix<double, Eigen::Dynamic, 1> c_zero;
  EXPECT_EQ(0, c_zero.size());
  EXPECT_THROW(ordered_logistic_log(1, lambda[0], c_zero),
               std::invalid_argument);
  EXPECT_THROW(ordered_logistic_log(y, lambda, c_zero), std::invalid_argument);

  Eigen::Matrix<double, Eigen::Dynamic, 1> c_neg(1);
  c_neg << -13.7;
  EXPECT_NO_THROW(ordered_logistic_log(1, lambda[0], c_neg));

  Eigen::Matrix<double, Eigen::Dynamic, 1> c_unord(3);
  c_unord << 1.0, 0.4, 2.0;
  EXPECT_THROW(ordered_logistic_log(1, lambda[0], c_unord), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, c_unord), std::domain_error);

  double nan = std::numeric_limits<double>::quiet_NaN();
  double inf = std::numeric_limits<double>::infinity();

  Eigen::Matrix<double, Eigen::Dynamic, 1> nan_vec(4);
  nan_vec << nan, nan, nan, nan;

  Eigen::Matrix<double, Eigen::Dynamic, 1> inf_vec(4);
  inf_vec << inf, inf, inf, inf;

  EXPECT_THROW(ordered_logistic_log(1, nan, c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(1, inf, c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, nan_vec, c), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, inf_vec, c), std::domain_error);

  Eigen::Matrix<double, Eigen::Dynamic, 1> cbad(2);
  cbad << 0.2, inf;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad), std::domain_error);
  cbad[1] = nan;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad), std::domain_error);

  Eigen::Matrix<double, Eigen::Dynamic, 1> cbad1(1);
  cbad1 << inf;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad1), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad1), std::domain_error);
  cbad1[0] = nan;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad1), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad1), std::domain_error);

  Eigen::Matrix<double, Eigen::Dynamic, 1> cbad3(3);
  cbad3 << 0.5, inf, 1.0;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad3), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad3), std::domain_error);
  cbad3[1] = nan;
  EXPECT_THROW(ordered_logistic_log(1, 1.0, cbad3), std::domain_error);
  EXPECT_THROW(ordered_logistic_log(y, lambda, cbad3), std::domain_error);

  Eigen::Matrix<double, Eigen::Dynamic, 1> lambda_small(3);
  lambda_small << 1, 1, 1;
  EXPECT_THROW(ordered_logistic_log(y, lambda_small, c), std::invalid_argument);

  Eigen::Matrix<double, Eigen::Dynamic, 1> c_small(K - 2);
  c_small << -0.3, 0.1;
  std::vector<Eigen::Matrix<double, Eigen::Dynamic, 1>> c_small_vec(4);
  c_small_vec[0] = c;
  c_small_vec[1] = c;
  c_small_vec[2] = c_small;
  c_small_vec[3] = c;
  EXPECT_THROW(ordered_logistic_log(y, lambda, c_small_vec),
               std::invalid_argument);
}

TEST(ProbDistributionOrderedLogistic, error_check) {
  boost::random::mt19937 rng;
  double inf = std::numeric_limits<double>::infinity();
  Eigen::VectorXd c(4);
  c << -2, 2.0, 5, 10;
  EXPECT_NO_THROW(stan::math::ordered_logistic_rng(4.0, c, rng));

  EXPECT_THROW(
      stan::math::ordered_logistic_rng(stan::math::positive_infinity(), c, rng),
      std::domain_error);
  c << -inf, 2.0, -5, inf;
  EXPECT_THROW(stan::math::ordered_logistic_rng(4.0, c, rng),
               std::domain_error);

  c << -2, 5, 2.0, 10;
  EXPECT_THROW(stan::math::ordered_logistic_rng(4.0, c, rng),
               std::domain_error);
}

TEST(ProbDistributionOrderedLogistic, chiSquareGoodnessFitTest) {
  using stan::math::inv_logit;
  boost::random::mt19937 rng;
  int N = 10000;
  double eta = 1.0;
  Eigen::VectorXd theta(3);
  theta << -0.4, 4.0, 6.2;
  Eigen::VectorXd prob(4);
  prob(0) = 1 - inv_logit(eta - theta(0));
  prob(1) = inv_logit(eta - theta(0)) - inv_logit(eta - theta(1));
  prob(2) = inv_logit(eta - theta(1)) - inv_logit(eta - theta(2));
  prob(3) = inv_logit(eta - theta(2));
  int K = prob.rows();
  boost::math::chi_squared mydist(K - 1);

  Eigen::VectorXd loc(prob.rows());
  for (int i = 0; i < prob.rows(); i++)
    loc(i) = 0;

  for (int i = 0; i < prob.rows(); i++) {
    for (int j = i; j < prob.rows(); j++)
      loc(j) += prob(i);
  }

  int count = 0;
  int bin[K];
  double expect[K];
  for (int i = 0; i < K; i++) {
    bin[i] = 0;
    expect[i] = N * prob(i);
  }

  while (count < N) {
    int a = stan::math::ordered_logistic_rng(eta, theta, rng);
    bin[a - 1]++;
    count++;
  }

  double chi = 0;

  for (int j = 0; j < K; j++)
    chi += ((bin[j] - expect[j]) * (bin[j] - expect[j]) / expect[j]);
  EXPECT_TRUE(chi < quantile(complement(mydist, 1e-6)));
}


#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/StdVector>

#include <power_diagram.h>
#include <testincludes.h>

using namespace POWER_DIAGRAM;

int main()
{
#ifdef _FLOATTEST
	//Specifying Number Type and Vector Type
	typedef float number_type;
	typedef Eigen::Vector3f Coord; //fake vector4->3f might be even faster
#else
	typedef double number_type;
	typedef Eigen::Vector3d Coord;
#endif
        typedef std::vector<Coord,Eigen::aligned_allocator<Coord> > PDVector;
	PDVector coords; //Vector of coordinates
	std::vector<number_type> weights; //Vector of weights
	std::vector<int> bond_to; //best guess for connectivity

	coords.push_back(Coord(1.0,2.0,3.0));
	weights.push_back(0.56789);
	bond_to.push_back(0);
	coords.push_back(Coord(5.0,3.0,3.0));
	weights.push_back(1.12);
	bond_to.push_back(0);
	coords.push_back(Coord(5.1,3.2,3.5));
	weights.push_back(1.23);
	bond_to.push_back(1);
	coords.push_back(Coord(1.3,3.2,1.5));
	weights.push_back(1.34);
	bond_to.push_back(2);
	coords.push_back(Coord(0.0,3.4,1.7));
	weights.push_back(1.45);
	bond_to.push_back(3);
	coords.push_back(Coord(5.4,3.4,1.7));
	weights.push_back(1.56);
	bond_to.push_back(4);
	coords.push_back(Coord(3.4,2.1,1.4));
	weights.push_back(1.67);
	bond_to.push_back(5);

	std::cout << "Testing Power Diagram, 7 verts: " << std::endl;
	PowerDiagram<number_type,Coord,3> pd = PowerDiagram<number_type,Coord,3>::create(coords.size(),coords.begin(),weights.begin(),bond_to.begin())
		.with_radiiGiven(1).with_calculate(1).with_cells(1).with_Warnings(0);
	bond_to.clear();
	parse("lucy25K",coords,weights);
	bond_to.push_back(0);
	const double scale=1;
	coords[0]*=scale;
	weights[0]*=scale;
	for (unsigned int i = 1; i < coords.size(); ++i)
	{
		coords[i]*=scale;
		weights[i]*=scale;
		bond_to.push_back(i-1);
	}
	std::cout << "Testing Power Diagram, bunny_set: " << std::endl;
	PowerDiagram<number_type,Coord,3> pd2 = PowerDiagram<number_type,Coord,3>::create(coords.size(),coords.begin(),weights.begin(),bond_to.begin())
		.with_radiiGiven(1).with_calculate(1).with_cells(1).with_Warnings(0);
	//pd2.update_coords(coords);

	return 0;
}


#include <bits/stdc++.h>
#include <boost/optional.hpp>
using namespace std;

/**
 * 構築 O(NlogN)、クエリ O(1)
 * @tparam T
 */
template<typename T>
class SparseTable {
 private:
  vector<T> values;
  vector<vector<unsigned long>> table;
  vector<unsigned long> msb;
  function<T(T, T)> fn;

  static vector<vector<unsigned long >> build(const vector<T> &values, function<T(T, T)> fn) {
    unsigned long size = (unsigned long) log2(values.size()) + 1;

    vector<vector<unsigned long >> st(values.size(), vector<unsigned long>(size));
    for (unsigned long i = 0; i < values.size(); ++i) st[i][0] = i;
    for (unsigned long p = 1; p < size; ++p) {
      for (unsigned long i = 0; i < values.size(); ++i) {
        unsigned long q = min(i + (1 << (p - 1)), (unsigned long) values.size() - 1);
        unsigned long l = st[i][p - 1];
        unsigned long r = st[q][p - 1];
        if (values[l] == fn(values[l], values[r])) {
          st[i][p] = l;
        } else {
          st[i][p] = r;
        }
      }
    }
    return st;
  }

 public:
  SparseTable(const vector<T> &values, function<T(T, T)> fn) {
    this->values = values;
    this->fn = fn;

    // table[i][p]: [i, i + 2^p) に fn を適用した結果の値のインデックス
    table = build(values, fn);

    // msb[i]: 最上位ビット; どの p を見るべきか
    msb = vector<unsigned long>(values.size() + 1);
    for (unsigned long i = 2; i < values.size() + 1; ++i) {
      msb[i] = msb[i >> 1] + 1;
    }
  }

  /**
   * [a, b) に fn を適用した結果
   */
  T get(unsigned long a, unsigned long b) {
    if (b <= a) throw invalid_argument("a < b でないといけません");
    if (b > values.size()) throw invalid_argument("範囲外です");
    unsigned long p = msb[b - a];
    return fn(values[table[a][p]], values[table[b - (1 << p)][p]]);
  }
};


#include "../include/simple_fft/fft_settings.h"

#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR
#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR
#endif

#include "../include/simple_fft/fft.h"
#include "test_fft.h"
#include <iostream>
#include <armadillo>

using namespace arma;

namespace simple_fft {
namespace fft_test {

int testArmadillo()
{
    std::cout << "Testing FFT algorithms with Armadillo C++" << std::endl;

    using namespace pulse_params;

    std::vector<real_type> t, x;
    makeGridsForPulse(t, x);

    // typedefing arrays
    typedef Row<real_type> RealArray1D;
    typedef Row<complex_type> ComplexArray1D;
    typedef Mat<real_type> RealArray2D;
    typedef Mat<complex_type> ComplexArray2D;

    // 1D fields and spectrum
    RealArray1D E1_real(nt);
    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);

    // 2D fields and spectrum
    RealArray2D E2_real(nt, nx);
    ComplexArray2D E2_complex(nt, nx), G2(nt, nx), E2_restored(nt, nx);

    if (!commonPartsForTests(E1_real, E2_real, E1_complex, E2_complex, G1, G2,
                             E1_restored, E2_restored, t, x))
    {
        std::cout << "Tests of FFT algorithms with Armadillo C++ matrix and row "
                  << "returned with errors!" << std::endl;
        return FAILURE;
    }

    std::cout << "Tests of FFT with Armadillo C++ matrix and row completed successfully!"
              << std::endl;
    return SUCCESS;
}

} // namespace fft_test
} // namespace simple_fft


#define _USE_MATH_DEFINES
#include "matplotlibcpp.h"
#include <Eigen/Dense>
#include <cmath>
#include <iostream>

namespace plt = matplotlibcpp;

int main() {
  // Prepare data.
  int n = 5000;
  Eigen::VectorXd x(n), y(n), z(n), w = 2 * Eigen::VectorXd::Ones(n);
  for (int i = 0; i < n; ++i) {
    x(i) = i * i;
    y(i) = sin(2 * M_PI * i / 360.0);
    z(i) = log(i);
  }

  // Set the size of output image = 1200x780 pixels
  plt::figure_size(1200, 780);

  // Plot line from given x and y data. Color is selected automatically.
  plt::plot(x, y);

  // Plot a red dashed line from given x and y data.
  plt::plot(x, w, "r--");

  // Plot a line whose name will show up as "log(x)" in the legend.
  plt::plot(x, z, {{"label", "log(x)"}});

  // Set x-axis to interval [0,1000000]
  plt::xlim(0, 1000 * 1000);

  // Add graph title
  plt::title("Sample figure");

  // Enable legend.
  plt::legend();

  // save figure
  const char *filename = "./eigen_basic.png";
  std::cout << "Saving result to " << filename << std::endl;

  plt::savefig(filename);
}


#include<iostream>
#define EIGEN_USE_MKL_ALL
#include <Eigen/Eigenvalues>
#include"numerics.hpp"
#include"reddm.hpp"
#include"tpoperators.hpp"
#include "files.hpp"
#include"FTLanczos.hpp"
using namespace Many_Body;
    using Mat= Operators::Mat;
int main(int argc, char *argv[])
{
   using Mat= Operators::Mat;
    int L=3;
  double omega=1;
  double gamma=1;
  double t0=1;
  int M=2;
  double mean=0.5*omega*L*M;;

  double beta=1;

  double T=1./beta;
   using HolsteinBasis= TensorProduct<ElectronBasis, PhononBasis>;

  ElectronBasis e( L, 1);

  PhononBasis ph(L, M);

  HolsteinBasis TP(e, ph);

        Mat E1=Operators::EKinOperatorL(TP, e, t0, true);
       Mat Ebdag=Operators::NBosonCOperator(TP, ph, gamma, true);
       std::cout<< "dim "<< TP.dim<< std::endl;
       Mat Eb=Operators::NBosonDOperator(TP, ph, gamma, true);
       Mat Eph=Operators::NumberOperator(TP, ph, omega,  true);

      Mat N=Operators::NumberOperator(TP, ph, 1,  true);
      //    std::cout<< HH << std::endl;
      Eigen::VectorXd eigenVals(TP.dim);
       	Mat H=E1+Eph +Ebdag + Eb;
       Mat O=N;
       std::vector<Mat> v{H, O};
       //       auto HH=Eigen::MatrixXd(H);

      auto ev=Eigen::VectorXd(H.rows());
      //    diagMat(HH, ev);

      auto  o=FTLM(H, v, T, 800);

       std::cout<< "for beta/mean = " << beta << std::endl;
       for(auto& l: o)
   	{std::cout<< l<<std::endl; }

  return 0;
}


#include <boost/program_options.hpp>
#include <iostream>
#include <random>

namespace po = boost::program_options;

int main(int argc, char* argv[]) {
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("n", po::value<int>(), "number of random values to generate")
    ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }

    int n {1};
    if (vm.count("n"))
        n = vm["n"].as<int>();
    std::random_device device;
    std::mt19937 engine(device());
    std::uniform_real_distribution<double> distr(0.0, 1.0);
    for (int i = 0; i < n; ++i)
        std::cout << distr(engine) << std::endl;

    return 0;
}


// Petter Strandmark 2013
//
// This is a test suite of non-linear least-squares problems
// from NIST.
// http://www.itl.nist.gov/div898/strd/nls/nls_main.shtml
//
// The code loading the NIST data files has been adapted from
// Ceres, see http://code.google.com/ceres-solver .
//
// Note: g++ 4.5.3 gives array out of bounds warnings for
// specializations in auto_diff_term.h. As far as I can tell,
// these specializations are never executed and the warnings
// disappear when the number of tests change.
//

#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <random>
#include <sstream>
#include <stdexcept>
#include <string>

#include <Eigen/Dense>

#include <catch.hpp>

#include <spii/auto_diff_term.h>
#include <spii/solver.h>

using namespace spii;

std::ofstream output_file("nist.log");

void skip_lines(std::istream* in, int num_lines)
{
	std::string str;
	for (int i = 0; i < num_lines; ++i) {
		std::getline(*in, str);
	}
}

void split_string(const std::string& str, std::vector<std::string>* tokens)
{
	std::stringstream sin(str);
	tokens->clear();
	while (true) {
		std::string s;
		sin >> s;
		if (sin) {
			tokens->push_back(s);
		}
		else {
			break;
		}
	}
}

template<typename T>
T convert(const std::string& str)
{
	std::stringstream sin(str);
	T t;
	sin >> t;
	if (!sin) {
		throw std::runtime_error("Conversion failed.");
	}
	return t;
}

void get_and_split_line(std::istream* in, std::vector<std::string>* tokens)
{
	std::string str;
	std::getline(*in, str);
	split_string(str, tokens);
}

class NISTProblem
{
public:
	NISTProblem(std::string filename)
	{
		std::ifstream fin(filename);
		if (!fin) {
			// Perhaps we are running the command from the root
			// project folder.
			filename = "bin/" + filename;
			fin.open(filename);
			if (!fin) {
				// Perhaps we are running the command from the test
				// project folder.
				filename = "../" + filename;
				fin.open(filename);
				if (!fin) {
					std::string error = "Failed to open ";
					error += filename;
					throw std::runtime_error(error.c_str());
				}
			}
		}
		std::vector<std::string> tokens;

		skip_lines(&fin, 24);
		get_and_split_line(&fin, &tokens);
		const int num_responses = convert<int>(tokens.at(1));

		get_and_split_line(&fin, &tokens);
		const int num_predictors = convert<int>(tokens.at(0));

		get_and_split_line(&fin, &tokens);
		const int num_observations = convert<int>(tokens.at(0));

		skip_lines(&fin, 4);
		get_and_split_line(&fin, &tokens);
		const int num_parameters = convert<int>(tokens.at(0));
		skip_lines(&fin, 8);

		get_and_split_line(&fin, &tokens);
		const int num_tries = static_cast<int>(tokens.size() - 4);

		this->predictor.resize(num_observations, num_predictors);
		this->response.resize(num_observations, num_responses);
		this->initial_parameters.resize(num_tries, num_parameters);
		this->final_parameters.resize(1, num_parameters);

		int parameter_id = 0;
		for (int i = 0; i < num_tries; ++i) {
			this->initial_parameters(i, parameter_id) =
				convert<double>(tokens.at(i + 2));
		}
		final_parameters(0, parameter_id) =
			convert<double>(tokens.at(2 + num_tries));

		for (parameter_id = 1; parameter_id < num_parameters; ++parameter_id) {
			get_and_split_line(&fin, &tokens);
				for (int i = 0; i < num_tries; ++i) {
				this->initial_parameters(i, parameter_id) =
					convert<double>(tokens.at(i + 2));
			}
			final_parameters(0, parameter_id) =
				convert<double>(tokens.at(2 + num_tries));
		}

		skip_lines(&fin, 1);
		get_and_split_line(&fin, &tokens);
		this->certified_cost = convert<double>(tokens.at(4));

		skip_lines(&fin, 18 - num_parameters);
		for (int i = 0; i < num_observations; ++i) {
			get_and_split_line(&fin, &tokens);
			for (int j = 0; j < num_responses; ++j) {
				this->response(i, j) = convert<double>(tokens.at(j));
			}

			for (int j = 0; j < num_predictors; ++j) {
				this->predictor(i, j) =
					convert<double>(tokens.at(j + num_responses));
			}
		}
	}

	Eigen::MatrixXd predictor, response, initial_parameters, final_parameters;
	double certified_cost;
};

template<typename SolverClass>
SolverClass create_solver()
{
	return {};
}

template<>
NewtonSolver create_solver<NewtonSolver>()
{
	NewtonSolver solver;
	solver.maximum_iterations = 5000;
	solver.function_improvement_tolerance = 0;
	solver.argument_improvement_tolerance = 0;
	solver.gradient_tolerance = 1e-8;

	solver.line_search_rho = 0.6;

	solver.factorization_method = NewtonSolver::FactorizationMethod::MESCHACH;
	return solver;
}

const bool use_sym_ildl =
#ifdef USE_SYM_ILDL
	true;
#else
	false;
#endif

class NewtonSolverSYM_ILDL
	: public NewtonSolver
{
};

template<>
NewtonSolverSYM_ILDL create_solver<NewtonSolverSYM_ILDL>()
{
	NewtonSolverSYM_ILDL solver;
	static_cast<NewtonSolver&>(solver) = create_solver<NewtonSolver>();
	solver.factorization_method = NewtonSolver::FactorizationMethod::SYM_ILDL;
	return solver;
}

template<>
LBFGSSolver create_solver<LBFGSSolver>()
{
	LBFGSSolver solver;
	solver.maximum_iterations = 10000;
	solver.function_improvement_tolerance = 0;
	solver.argument_improvement_tolerance = 0;
	solver.gradient_tolerance = 1e-7;

	return solver;
}

template<>
NelderMeadSolver create_solver<NelderMeadSolver>()
{
	NelderMeadSolver solver;
	solver.maximum_iterations = 10000;
	solver.function_improvement_tolerance = 1e-14;
	solver.argument_improvement_tolerance = 1e-14;
	solver.gradient_tolerance = 1e-12;
	solver.area_tolerance = 1e-60;

	return solver;
}

template<typename SolverClass, typename Model, int num_variables>
void run_problem_main(const std::string& filename)
{
	NISTProblem problem(filename);
	REQUIRE(problem.response.cols() == 1);
	REQUIRE(problem.initial_parameters.cols() == num_variables);

	// Run a test for each starting point provicded by the data file.
	for (int start = 0; start < problem.initial_parameters.rows(); ++start) {
		INFO("Start " << start + 1 << " of " << problem.initial_parameters.rows());

		Eigen::VectorXd initial_parameters =
			problem.initial_parameters.row(start);
		REQUIRE(initial_parameters.size() == num_variables);

		Function function;
		function.add_variable(initial_parameters.data(), num_variables);

		for (int i = 0; i < problem.predictor.rows(); ++i) {
			double x = problem.predictor(i, 0);
			double y = problem.response(i, 0);
			auto term = std::make_shared<AutoDiffTerm<Model, num_variables>>(x, y);
			function.add_term(term, initial_parameters.data());
		}

		auto initial_cost = function.evaluate();

		auto solver = create_solver<SolverClass>();

		std::stringstream sout;
		solver.log_function = [&sout](const std::string& s) { sout << s << std::endl; };

		SolverResults results;
		solver.solve(function, &results);

		auto final_cost = function.evaluate();

		// Print the solver results to the log stringstream.
		INFO(sout.str());
		INFO(results);
		for (int i = 0; i < num_variables; ++i) {
			INFO("b[" << i << "] = " << initial_parameters[i]);
		}

		const double optimum = problem.certified_cost;
		int num_matching_digits = static_cast<int>(
			-std::log10(fabs(function.evaluate() - optimum) / optimum));

		INFO("Number of matching digits: " << num_matching_digits);

		// Compute log_relative_error with code from Ceres Solver.
		//
		// Compute the LRE by comparing each component of the solution
		// with the ground truth, and taking the minimum.
		auto final_parameters = problem.final_parameters;
		const double kMaxNumSignificantDigits = 11;
		double log_relative_error = kMaxNumSignificantDigits + 1;
		for (int i = 0; i < num_variables; ++i) {
			const double tmp_lre =
				-std::log10(std::fabs(final_parameters(i) - initial_parameters(i)) /
							std::fabs(final_parameters(i)));
			// The maximum LRE is capped at 11 - the precision at which the
			// ground truth is known.
			//
			// The minimum LRE is capped at 0 - no digits match between the
			// computed solution and the ground truth.
			log_relative_error =
			std::min(log_relative_error,
					 std::max(0.0, std::min(kMaxNumSignificantDigits, tmp_lre)));
		}

		output_file << typeid(Model).name() << " "
		            << typeid(SolverClass).name() << " "
		            << "start: " << start + 1 << " "
					<< (log_relative_error < 4 ? "FAILURE" : "SUCCESS") << " "
		            << "LRE: " << log_relative_error << " "
		            << "Initial cost: " << initial_cost << " "
		            << "Final cost: " << final_cost << " "
		            << "Certified cost: " << problem.certified_cost
					<< std::endl;

		// If the optimum was reached, everything is OK.
		if (num_matching_digits >= 4) {
			CHECK(num_matching_digits >= 4);  // To log the test.
			continue;
		}

		// Otherwise, reaching a stationary point is enough.
		CHECK(results.exit_condition ==
		      SolverResults::GRADIENT_TOLERANCE);

		// But for Nelder-Mead, a small area is not equivalent to a
		// stationary point.
		if (typeid(SolverClass) == typeid(NelderMeadSolver)) {
			CHECK(num_matching_digits >= 4);
		}
	}
}

#define NIST_TEST_START(Problem)         \
struct Problem                           \
{                                        \
	double x_param, y_param;             \
	Problem(double x, double y)          \
	{                                    \
		this->x_param = x;               \
		this->y_param = y;               \
	}                                    \
	template<typename R>                 \
	R operator()(const R* const b) const \
	{                                    \
		const R x(x_param);              \
		const R y(y_param);              \
		R d = y - (                      \

#define NIST_TEST_END(Category, Problem, n) \
		);                               \
		return d*d;                      \
	}                                    \
};                                       \
TEST_CASE(#Category "/" #Problem, "")    \
{                                        \
	SECTION("Newton") {					 \
		run_problem_main<NewtonSolver, Problem, n>(    \
			"nist/" #Problem ".dat");    \
	}                                    \
	SECTION("NewtonSolverSYM_ILDL") {    \
		if (use_sym_ildl) {              \
			run_problem_main<NewtonSolverSYM_ILDL, Problem, n>(    \
			"nist/" #Problem ".dat");    \
		}                                \
	}                                    \
	SECTION("LBFGS") {                   \
		run_problem_main<LBFGSSolver, Problem, n>(    \
			"nist/" #Problem ".dat");    \
	}                                    \
}

const double kPi = 3.141592653589793238462643383279;

NIST_TEST_START(Bennett5)
	b[0] * pow(b[1] + x, R(-1.0) / b[2])
NIST_TEST_END(Hard, Bennett5, 3)

NIST_TEST_START(BoxBOD)
  b[0] * (R(1.0) - exp(-b[1] * x))
NIST_TEST_END(Hard, BoxBOD, 2)

NIST_TEST_START(Chwirut1)
  exp(-b[0] * x) / (b[1] + b[2] * x)
NIST_TEST_END(Easy, Chwirut1, 3)

NIST_TEST_START(Chwirut2)
  exp(-b[0] * x) / (b[1] + b[2] * x)
NIST_TEST_END(Easy, Chwirut2, 3)

NIST_TEST_START(DanWood)
  b[0] * pow(x, b[1])
NIST_TEST_END(Easy, DanWood, 2)

NIST_TEST_START(Gauss1)
  b[0] * exp(-b[1] * x) +
  b[2] * exp(-pow((x - b[3])/b[4], 2)) +
  b[5] * exp(-pow((x - b[6])/b[7],2))
NIST_TEST_END(Easy, Gauss1, 8)

NIST_TEST_START(Gauss2)
  b[0] * exp(-b[1] * x) +
  b[2] * exp(-pow((x - b[3])/b[4], 2)) +
  b[5] * exp(-pow((x - b[6])/b[7],2))
NIST_TEST_END(Medium, Gauss2, 8)

NIST_TEST_START(Gauss3)
  b[0] * exp(-b[1] * x) +
  b[2] * exp(-pow((x - b[3])/b[4], 2)) +
  b[5] * exp(-pow((x - b[6])/b[7],2))
NIST_TEST_END(Medium, Gauss3, 8)

NIST_TEST_START(Lanczos1)
  b[0] * exp(-b[1] * x) + b[2] * exp(-b[3] * x) + b[4] * exp(-b[5] * x)
NIST_TEST_END(Medium, Lanczos1, 6)

NIST_TEST_START(Lanczos2)
  b[0] * exp(-b[1] * x) + b[2] * exp(-b[3] * x) + b[4] * exp(-b[5] * x)
NIST_TEST_END(Medium, Lanczos2, 6)

NIST_TEST_START(Hahn1)
  (b[0] + b[1] * x + b[2] * x * x + b[3] * x * x * x) /
  (R(1.0) + b[4] * x + b[5] * x * x + b[6] * x * x * x)
NIST_TEST_END(Medium, Hahn1, 7)

NIST_TEST_START(Kirby2)
  (b[0] + b[1] * x + b[2] * x * x) /
  (R(1.0) + b[3] * x + b[4] * x * x)
NIST_TEST_END(Medium, Kirby2, 5)

NIST_TEST_START(MGH09)
  b[0] * (x * x + x * b[1]) / (x * x + x * b[2] + b[3])
NIST_TEST_END(Hard, MGH09, 4)

NIST_TEST_START(MGH10)
  b[0] * exp(b[1] / (x + b[2]))
NIST_TEST_END(Hard, MGH10, 3)

NIST_TEST_START(MGH17)
  b[0] + b[1] * exp(-x * b[3]) + b[2] * exp(-x * b[4])
NIST_TEST_END(Medium, MGH17, 5)

NIST_TEST_START(Misra1a)
  b[0] * (R(1.0) - exp(-b[1] * x))
NIST_TEST_END(Easy, Misra1a, 2)

NIST_TEST_START(Misra1b)
  b[0] * (R(1.0) - R(1.0)/ ((R(1.0) + b[1] * x / 2.0) * (R(1.0) + b[1] * x / 2.0)))
NIST_TEST_END(Easy, Misra1b, 2)

NIST_TEST_START(Misra1c)
  b[0] * (R(1.0) - pow(R(1.0) + R(2.0) * b[1] * x, -0.5))
NIST_TEST_END(Medium, Misra1c, 2)

NIST_TEST_START(Misra1d)
  b[0] * b[1] * x / (R(1.0) + b[1] * x)
NIST_TEST_END(Medium, Misra1d, 2)

NIST_TEST_START(Roszman1)
  b[0] - b[1] * x - atan(b[2] / (x - b[3]))/R(kPi)
NIST_TEST_END(Medium, Roszman1, 4)

NIST_TEST_START(Rat42)
  b[0] / (R(1.0) + exp(b[1] - b[2] * x))
NIST_TEST_END(Hard, Rat42, 3)

NIST_TEST_START(Rat43)
  b[0] / pow(R(1.0) + exp(b[1] - b[2] * x), R(1.0) / b[3])
NIST_TEST_END(Hard, Rat43, 4)

NIST_TEST_START(Thurber)
  (b[0] + b[1] * x + b[2] * x * x  + b[3] * x * x * x) /
  (R(1.0) + b[4] * x + b[5] * x * x + b[6] * x * x * x)
NIST_TEST_END(Hard, Thurber, 7)

NIST_TEST_START(ENSO)
  b[0] + b[1] * cos(R(2.0 * kPi) * x / R(12.0)) +
         b[2] * sin(R(2.0 * kPi) * x / R(12.0)) +
         b[4] * cos(R(2.0 * kPi) * x / b[3]) +
         b[5] * sin(R(2.0 * kPi) * x / b[3]) +
         b[7] * cos(R(2.0 * kPi) * x / b[6]) +
         b[8] * sin(R(2.0 * kPi) * x / b[6])
NIST_TEST_END(Medium, ENSO, 9)

NIST_TEST_START(Eckerle4)
  b[0] / b[1] * exp(R(-0.5) * pow((x - b[2])/b[1], 2))
NIST_TEST_END(Hard, Eckerle4, 3)


#include <aslam/backend/ErrorTermMotionBST.hpp>
#include <aslam/backend/ErrorTermPriorBST.hpp>
#include <aslam/backend/ExpressionErrorTerm.hpp>
#include <aslam/backend/OptimizationProblem.hpp>
#include <aslam/backend/Optimizer2.hpp>
#include <aslam/backend/Optimizer2Options.hpp>
#include <aslam/backend/DenseQrLinearSystemSolver.hpp>
#include <iostream>
// Bring in some random number generation from Schweizer Messer.
#include <sm/random.hpp>
#include <vector>
#include <algorithm>
#include <boost/shared_ptr.hpp>

#include <aslam/backend/EuclideanPoint.hpp>
#include <sm/kinematics/RotationVector.hpp>
#include <aslam/splines/OPTBSpline.hpp>
#include <bsplines/EuclideanBSpline.hpp>
#include <aslam/backend/Scalar.hpp>

int main(int argc, char ** argv)
{
  if(argc != 2)
    {
      std::cout << "Usage: example K\n";
      std::cout << "The argument K is the number of timesteps to include in the optimization\n";
      return 1;
    }

  const int K = atoi(argv[1]);

  try
    {
      // The true wall position
      const double true_w = 5.0;

      // The noise properties.
      const double sigma_n = 0.01;
      const double sigma_u = 0.1;
      const double sigma_x = 0.01;

      // Create random odometry
      std::vector<double> true_u_k(K);
      for(double& u : true_u_k)
      {
        u = 1;//sm::random::uniform();
      }

      // Create the noisy odometry
      std::vector<double> u_k(K);
      for(int k = 0; k < K; ++k)
      {
        u_k[k] = true_u_k[k] + (sigma_u * sm::random::normal());
      }

      // Create the states from noisy odometry.
      std::vector<double> x_k(K);
      std::vector<double> true_x_k(K);
      x_k[0] = 10.0;
      true_x_k[0] = 10.0;
      for(int k = 1; k < K; ++k)
      {
        true_x_k[k] = true_x_k[k-1] + true_u_k[k];
        x_k[k] = x_k[k-1] + u_k[k];
      }

      // Create the noisy measurments
      std::vector<double> y_k(K);
      for(int k = 0; k < K; ++k)
      {
        y_k[k] = (true_w / true_x_k[k]) + sigma_n * sm::random::normal();
      }

      // Now we can build an optimization problem.
      boost::shared_ptr<aslam::backend::OptimizationProblem> problem( new aslam::backend::OptimizationProblem);

      typedef aslam::splines::OPTBSpline<bsplines::EuclideanBSpline<4, 1>::CONF> PosSpline;
      PosSpline robotPosSpline;
      const int pointSize = robotPosSpline.getPointSize();

      PosSpline::point_t initPoint(pointSize);

      initPoint(0,0) = x_k[0];

      // initialize the spline uniformly with from time 0 to K with K segments and the initPoint as a constant value
      robotPosSpline.initConstantUniformSpline(0, K, K, initPoint);

      // add the robot pose spline to the problem
      for(size_t i = 0; i < robotPosSpline.numDesignVariables(); i++)
      {
        robotPosSpline.designVariable(i)->setActive(true);
        problem->addDesignVariable(robotPosSpline.designVariable(i), false);
      }

      // set up wall position
      double wallPosition = true_w + sm::random::normal();
      std::cout << "Noisy wall position : " << wallPosition << std::endl;

      // First, create a design variable for the wall position.
      boost::shared_ptr<aslam::backend::Scalar> dv_w(new aslam::backend::Scalar(true_w));
      // Setting this active means we estimate it.
      dv_w->setActive(true);
      // Add it to the optimization problem.
      problem->addDesignVariable(dv_w.get(), false);

      // Now create a prior for this initial state.
      auto vecPosExpr = robotPosSpline.getExpressionFactoryAt<0>(0).getValueExpression(0);
      boost::shared_ptr<aslam::backend::ErrorTermPriorBST> prior(new aslam::backend::ErrorTermPriorBST(vecPosExpr, true_x_k[0], sigma_x * sigma_x));
      // and add it to the problem.
      problem->addErrorTerm(prior);

      // Now march through the states creating design variables,
      // odometry error terms and measurement error terms.
      for(int k = 0; k < K; ++k)
      {
        // Create expression factory at time k, prepared for time derivatives up to 1 (for that we need the "<1>").
        auto exprFactory = robotPosSpline.getExpressionFactoryAt<1>(k);

        // Create odometry error via ErrorTermMotionBST
        auto vecVelExpr = exprFactory.getValueExpression(1); // 1 => first derivative of position ~ robot velocity
        boost::shared_ptr<aslam::backend::ErrorTermMotionBST> em(new aslam::backend::ErrorTermMotionBST(vecVelExpr, u_k[k], sigma_u * sigma_u));
        problem->addErrorTerm(em);

        // Create observation error using expressions and toErrorTerm to create an ExpressionErrorTerm
        auto vecPosExpr = exprFactory.getValueExpression(0); // 0 => spline value itself ~ robot position
        // We want to compute an error term e := dv_w / vecPosExpr[0] - y_k[k] + v, with v ~ N(0, sigma_n)
        problem->addErrorTerm(toErrorTerm(dv_w->toExpression() / vecPosExpr.toScalarExpression<0>() - y_k[k], 1.0 / (sigma_n * sigma_n)));
      }

      // Now we have a valid optimization problem full of design variables and error terms.
      // Create some optimization options.
      aslam::backend::Optimizer2Options options;
      options.verbose = true;
      options.linearSystemSolver.reset(new aslam::backend::DenseQrLinearSystemSolver());
//      options.levenbergMarquardtLambdaInit = 10;
      options.doSchurComplement = false;
//      options.doLevenbergMarquardt = true;
      // Force it to over-optimize
      options.convergenceDeltaX = 1e-12;
      options.convergenceDeltaError = 1e-12;
      // Then create the optimizer and go!
      aslam::backend::Optimizer2 optimizer(options);
      optimizer.setProblem(problem);

      optimizer.optimize();

      // the wall is at
      std::cout << "After optimization, the wall is at: " << std::endl << dv_w->toExpression().toScalar() << std::endl;

      for(int i = 0; i < K; i++)
      {
        // This time we don't need expressions because we are only going to print the values. There fore we only create an "evaluator" instead of an expression factory.
        // Create evaluator at time k, supporting time derivatives up to 1 (for that we need the "<1>").
        auto evaluator = robotPosSpline.getEvaluatorAt<1>(i);
        auto vecPos = evaluator.evalD(0);
        auto vecVel = evaluator.evalD(1);

        std::cout << "Robot at " << i << " is: " << vecPos(0) << std::endl;
        std::cout << "Velocity at " << i << " is: " << vecVel(0) << std::endl;
      }
    }
  catch(const std::exception & e)
    {
      std::cout << "Exception during processing: " << e.what();
      return 1;
    }

  std::cout << "Processing completed successfully\n";
  return 0;
}


#ifndef _FITTING_HPP_
#define _FITTING_HPP_

#include <Eigen/Dense>
#include "Eigen/Spline/Spline.h"
#include "Eigen/Spline/SplineFitting.h"

#include <boost/function.hpp>

using namespace std;

namespace spline_planner {

  template<unsigned int D>
  class Spline3D {
  public:
    typedef Eigen::Spline3d SplineType;

    typedef boost::function<void(double, double, const Eigen::MatrixXd&)> SampleCallbackType;

    /*
     * points: input points for fitting spline
     */
    Spline3D(const Eigen::MatrixXd &points, const Eigen::MatrixXd &derivatives, const Eigen::VectorXi &index) {
      this->spline_ = Eigen::SplineFitting<Spline3D::SplineType>::InterpolateWithDerivatives(points, derivatives,
                                                                                index, D);
    }

    /*
     * points: input points for fitting spline
     */
    Spline3D(const Eigen::MatrixXd &points) {
      Spline3D::SplineType::KnotVectorType chord_vector;
      Eigen::ChordLengths(points, chord_vector);

      this->spline_ = Eigen::SplineFitting<Spline3D::SplineType>::Interpolate(points, D, chord_vector);
    }

    void Sample(SampleCallbackType callback, double sample_ds = 0.1, double s_limit = 100.0, unsigned int degree = D, double dt = 0.01) {
      std::size_t i = 0;
      double t = 0.0;
      double s = 0.0;
      double last_s = 0.0;
      double last_deriv1_norm = 0;
      while ((t = i++ * dt) <= 1 && s <= s_limit) {
        const Eigen::MatrixXd& derivs = spline_.derivatives(t, degree);
        double deriv1_norm = static_cast<const Eigen::VectorXd&>(derivs.col(1)).norm();
        if (t > 1e-7) {
          s += 0.5 * (deriv1_norm + last_deriv1_norm) * dt;
        }
        last_deriv1_norm = deriv1_norm;

        if ((s - last_s) >= sample_ds || (i * dt) > 1.0 || s <= 1e-7) {
          last_s = s;
          callback(t, s, derivs);
        }
      }
    }

  private:
    SplineType spline_;

  };
}

#endif


#include <iostream>
#include <chrono>
#include <memory>
#include <cmath>
#include <Eigen/Dense>
#include <Eigen/Dense>
#include "minimize.h"

using Matrix = minimize::Matrix;
using Vector = minimize::Vector;

// Define interpolation procedure for minimization algorithm
double minimize::interpolate(double x2, double f2, double d2, double x3, double f3, double d3, double f0, double INT, double RHO)
{

  // choose subinterval
  // move point 3 to point 4
  double x4 = x3;
  double f4 = f3;
  double d4 = d3;

  //double tolerance = 1e-32;
  double tolerance = 1e-64;

  if ( f4 > f0 )
    {
      double denom = f4-f2-d2*(x4-x2);
      if ( std::abs(denom) < tolerance )
        // bisect
        x3 = (x2+x4)/2;
      else
        // quadratic interpolation
        x3 = x2-(0.5*d2*std::pow(x4-x2,2))/(denom);
    }
  else
    {
      // cubic interpolation
      double A = 6*(f2-f4)/(x4-x2)+3*(d4+d2);
      double B = 3*(f4-f2)-(2*d2+d4)*(x4-x2);
      double radical = B*B-A*d2*std::pow(x4-x2,2);

      if ( ( radical < 0 ) || ( std::abs(A) < tolerance ) )
        x3 = (x2+x4)/2;
      else
        x3 = x2+( std::sqrt(radical) - B)/A;
    }

  // don't accept too close
  if ( x4-INT*(x4-x2) < x3 )
    x3 = x4-INT*(x4-x2);

  if ( x2+INT*(x4-x2) > x3 )
    x3 = x2+INT*(x4-x2);

  return x3;
};

// Define cubic extrapolation routine for minimization algorithm
double minimize::cubic_extrap(double x1, double x2, double f1, double f2, double d1, double d2, double EXT, double INT)
{
  // make cubic extrapolation
  double A = 6*(f1-f2)+3*(d2+d1)*(x2-x1);
  double B = 3*(f2-f1)-(2*d1+d2)*(x2-x1);

  double x3;
  //double tolerance = 1e-32;
  double tolerance = 1e-64;
  double radical = B*B-A*d1*(x2-x1);

  if ( radical < 0.0 )
    x3 = x2*EXT;
  else if ( B + std::sqrt(radical) < tolerance )
    x3 = x2*EXT;
  else
    {
      x3 = x1-d1*std::pow(x2-x1,2)/( B + std::sqrt(radical) );

      if ( ( x3 < 0 ) || ( x3 > x2*EXT ) )
        x3 = x2*EXT;
      else if ( x3 < x2+INT*(x2-x1) )
        x3 = x2+INT*(x2-x1);
    }

  return x3;
};

//
//  ORIGINAL CODE BY CARL EDWARD RASMUSSEN
//  http://learning.eng.cam.ac.uk/carl/code/minimize/
//
//  % Minimize a differentiable multivariate function.
//  %
//  % Usage: [X, fX, i] = minimize(X, f, length, P1, P2, P3, ... )
//  %
//  % where the starting point is given by "X" (D by 1), and the function named in
//  % the string "f", must return a function value and a vector of partial
//  % derivatives of f wrt X, the "length" gives the length of the run: if it is
//  % positive, it gives the maximum number of line searches, if negative its
//  % absolute gives the maximum allowed number of function evaluations. You can
//  % (optionally) give "length" a second component, which will indicate the
//  % reduction in function value to be expected in the first line-search (defaults
//  % to 1.0). The parameters P1, P2, P3, ... are passed on to the function f.
//  %
//  % The function returns when either its length is up, or if no further progress
//  % can be made (ie, we are at a (local) minimum, or so close that due to
//  % numerical problems, we cannot get any closer). NOTE: If the function
//  % terminates within a few iterations, it could be an indication that the
//  % function values and derivatives are not consistent (ie, there may be a bug in
//  % the implementation of your "f" function). The function returns the found
//  % solution "X", a vector of function values "fX" indicating the progress made
//  % and "i" the number of iterations (line searches or function evaluations,
//  % depending on the sign of "length") used.
//  %
//  % The Polack-Ribiere flavour of conjugate gradients is used to compute search
//  % directions, and a line search using quadratic and cubic polynomial
//  % approximations and the Wolfe-Powell stopping criteria is used together with
//  % the slope ratio method for guessing initial step sizes. Additionally a bunch
//  % of checks are made to make sure that exploration is taking place and that
//  % extrapolation will not be unboundedly large.
//  %
//  % See also: checkgrad
//  %
//  % Copyright (C) 2001 - 2006 by Carl Edward Rasmussen (2006-09-08).
//
//  INT = 0.1;    % don't reevaluate within 0.1 of the limit of the current bracket
//  EXT = 3.0;                  % extrapolate maximum 3 times the current step-size
//  MAX = 20;                         % max 20 function evaluations per line search
//  RATIO = 10;                                       % maximum allowed slope ratio
//  SIG = 0.1; RHO = SIG/2; % SIG and RHO are the constants controlling the Wolfe-
//  % Powell conditions. SIG is the maximum allowed absolute ratio between
//  % previous and new slopes (derivatives in the search direction), thus setting
//  % SIG to low (positive) values forces higher precision in the line-searches.
//  % RHO is the minimum allowed fraction of the expected (from the slope at the
//  % initial point in the linesearch). Constants must satisfy 0 < RHO < SIG < 1.
//  % Tuning of SIG (depending on the nature of the function to be optimized) may
//  % speed up the minimization; it is probably not worth playing much with RHO.
//
//  % The code falls naturally into 3 parts, after the initial line search is
//  % started in the direction of steepest descent. 1) we first enter a while loop
//  % which uses point 1 (p1) and (p2) to compute an extrapolation (p3), until we
//  % have extrapolated far enough (Wolfe-Powell conditions). 2) if necessary, we
//  % enter the second loop which takes p2, p3 and p4 chooses the subinterval
//  % containing a (local) minimum, and interpolates it, unil an acceptable point
//  % is found (Wolfe-Powell conditions). Note, that points are always maintained
//  % in order p0 <= p1 <= p2 < p3 < p4. 3) compute a new search direction using
//  % conjugate gradients (Polack-Ribiere flavour), or revert to steepest if there
//  % was a problem in the previous line-search. Return the best value so far, if
//  % two consecutive line-searches fail, or whenever we run out of function
//  % evaluations or line-searches. During extrapolation, the "f" function may fail
//  % either with an error or returning Nan or Inf, and minimize should handle this
//  % gracefully.
//

// Conjugate gradient minimization algorithm
void minimize::cg_minimize(Vector & X, minimize::GradientObj * target, Vector & D, int length, double SIG, double EXT, double INT, int MAX)
{
  // specify optimization hyperparameters
  //double RATIO = 10.0;
  double RATIO = 100.0;
  double RHO = SIG/2;

  // determine problem dimension
  int N = static_cast<int>(X.size());

  // initialize values
  int i = 0;
  bool ls_failed = false;
  Vector df0(N);
  double f0;
  (*target).computeValueAndGradient(X, f0, df0);

  // initial search direction (steepest) and slope
  Vector s = -df0;
  double d0 = -s.transpose()*s;

  // initial step is 1/(|s|+1)
  double x3 = 1/(1-d0);

  // declare placeholders for storing optimal values
  Vector X0(N);
  double F0;
  Vector dF0(N);

  // declare variables in main loop
  int M;
  bool continue_extrap;
  double x1, f1, d1, x2, f2, d2, f3, d3;
  Vector df3(N);

  // "realmin" = smallest positive normalized floating-point number in IEEE double precision format
  double realmin = 2.2251e-308;

  // MAIN LOOP
  bool request_break = false;
  while ( ( i < length ) && ( !request_break ) )
    {
      i++;

      // make a copy of current values
      X0 = X;
      F0 = f0;
      dF0 = df0;

      // Display current parameter values
      //std::cout << " X  =  " << X.transpose().array().exp().matrix() << std::endl;

      // initialize iteration count
      M = MAX;

      // EXTRAPOLATE
      continue_extrap = true;
      while ( continue_extrap )
        {
          x2 = 0.0;
          f2 = f0;
          d2 = d0;
          M = M - 1;
          (*target).computeValueAndGradient(X+x3*s, f3, df3);

          // keep best values
          if ( f3 < F0 )
            {
              X0 = X+x3*s;
              F0 = f3;
              dF0 = df3;
            }

          // new slope
          d3 = df3.transpose()*s;

          // are we done extrapolating?
          if ( ( ( d3 > SIG*d0 ) || ( f3 > f0+x3*RHO*d0 ) ) || ( M == 0 ) )
              continue_extrap = false;

          // move point 2 to point 1
          x1 = x2;
          f1 = f2;
          d1 = d2;
          // move point 3 to point 2
          x2 = x3;
          f2 = f3;
          d2 = d3;

          // cubic extrapolation
          x3 = cubic_extrap(x1, x2, f1, f2, d1, d2, EXT, INT);

        } // END EXTRAPOLATE

      // INTERPOLATE
      while ( ( ( std::abs(d3) > -SIG*d0 ) || ( f3 > f0+x3*RHO*d0) )  &&  ( M > 0 ) )
        {

          x3 = interpolate(x2, f2, d2, x3, f3, d3, f0, INT, RHO);

          (*target).computeValueAndGradient(X+x3*s, f3, df3);

          // keep best values
          if ( f3 < F0 )
            {
              X0 = X+x3*s;
              F0 = f3;
              dF0 = df3;
            }

          // decrement line-search count
          M = M - 1;

          // new slope
          d3 = df3.transpose()*s;

        } // END INTERPOLATE

      //  START COMPUTE NEW SEARCH DIRECTION
      if ( ( std::abs(d3) < -SIG*d0 ) && ( f3 < f0+x3*RHO*d0 ) )
        {
          // if line search succeeded
          // update variables
          X = X+x3*s;
          f0 = f3;

          // Polack-Ribiere CG direction
          s = ( (df3.transpose()*df3 - df0.transpose()*df3)(0) / (df0.transpose()*df0)(0) )*s - df3;

          // swap derivatives
          df0 = df3;
          d3 = d0;
          d0 = df0.transpose()*s;

          // new slope must be negative
          if ( d0 > 0 )
            {
              // otherwise use steepest direction
              s = -df0;
              d0 = -s.transpose()*s;
            }

          // slope ratio but max RATIO
          if ( RATIO <  d3/(d0-realmin) )
            {
              x3 = x3 * RATIO;
              //std::cout << "\n[*] RATIO parameter enforced\n";
            }
          else
              x3 = x3 * d3/(d0-realmin);

          // this line search did not fail
          ls_failed = false;
        }

      else
        {
          // restore best point so far
          X = X0;
          f0 = F0;
          df0 = dF0;

          // line search failed twice in a row
          // or we ran out of time, so we give up
          if ( ( ls_failed ) || ( i > length ) )
              request_break = true;

          // DEBUGGING INFO TO SEE WHY OPTIMIZATION EXITS EARLY
          /*
          if ( ls_failed )
            {
              std::cout << "\n[*] Line Search Failed  ( i = " << i << " )\n";
              std::cout << "\n The following conditions failed:   [ SIG = " << SIG << " , RHO = " << RHO << " ]\n";
              if ( std::abs(d3) >= -SIG*d0 )
                {
                  double lhs = std::abs(d3);
                  double rhs = -SIG*d0;
                  std::cout << "abs(" << d3 << ")   <   -SIG * " << d0 << " [   i.e. " << lhs << " < " << rhs << " ]\n";
                }
              if ( f3 >= f0+x3*RHO*d0 )
                {
                  double lhs = f3;
                  double rhs = f0+x3*RHO*d0;
                  std::cout <<  f3 << "   <   " << f0 << " + " << x3 << " * RHO * " << d0 << "   [ i.e. " << lhs << " < " << rhs << " ]\n";
                }
            }
          if ( i > length )
            std::cout << "\n[*] Exceeded 'length' value\n";
          */

          // try steepest
          s = -df0;
          d0 = -s.transpose()*s;
          x3 = 1/(1-d0);

          // this line search failed
          ls_failed = true;

        } // END COMPUTE NEW SEARCH DIRECTION

    }  // END MAIN LOOP

  //std::cout << "\nMinimized Function Value (???) :\n";
  //std::cout << f0 << std::endl;

};


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include <boost/test/unit_test.hpp>

#include "LayerTests.hpp"
#include "test/TensorHelpers.hpp"

#include "backends/RefWorkloadFactory.hpp"

#include "test/UnitTests.hpp"

BOOST_AUTO_TEST_SUITE(Compute_Reference)
using FactoryType = armnn::RefWorkloadFactory;

// ============================================================================
// UNIT tests

// Convolution
ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5, SimpleConvolution2d3x5Test, true)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x5Uint8, SimpleConvolution2d3x5Uint8Test, true)

ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2d, SimpleConvolution2d3x5Test, false)
ARMNN_AUTO_TEST_CASE(UnbiasedConvolutionUint8, SimpleConvolution2d3x5Uint8Test, false)

ARMNN_AUTO_TEST_CASE(SimpleConvolution1d, Convolution1dTest, true)
ARMNN_AUTO_TEST_CASE(SimpleConvolution1dUint8, Convolution1dUint8Test, true)

ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x3, SimpleConvolution2d3x3Test, true)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2d3x3Uint8, SimpleConvolution2d3x3Uint8Test, true)

ARMNN_AUTO_TEST_CASE(UnbiasedConvolution2dSquare, SimpleConvolution2d3x3Test, false)

ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPaddingLargerThanHalfKernelSize,
    Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTest)
ARMNN_AUTO_TEST_CASE(SimpleConvolution2dAsymmetricPadding, Convolution2dAsymmetricPaddingTest)

// Depthwise Convolution
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2d, DepthwiseConvolution2dTest, true)
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dUint8, DepthwiseConvolution2dUint8Test, true)

ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2d, DepthwiseConvolution2dTest, false)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dUint8, DepthwiseConvolution2dUint8Test, false)

ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1, DepthwiseConvolution2dDepthMul1Test, true)
ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dDepthMul1Uint8, DepthwiseConvolution2dDepthMul1Uint8Test, true)

ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1, DepthwiseConvolution2dDepthMul1Test, false)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dDepthMul1Uint8, DepthwiseConvolution2dDepthMul1Uint8Test, false)

ARMNN_AUTO_TEST_CASE(DepthwiseConvolution2dAsymmetric, DepthwiseConvolution2dAsymmetricTest, true)
ARMNN_AUTO_TEST_CASE(UnbiasedDepthwiseConvolution2dAsymmetric, DepthwiseConvolution2dAsymmetricTest, false)

// Pooling
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize2x2Stride2x2, SimpleMaxPooling2dSize2x2Stride2x2Test, false)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize2x2Stride2x2Uint8, SimpleMaxPooling2dSize2x2Stride2x2Uint8Test, false)

ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4, SimpleMaxPooling2dSize3x3Stride2x4Test, false)
ARMNN_AUTO_TEST_CASE(SimpleMaxPooling2dSize3x3Stride2x4Uint8, SimpleMaxPooling2dSize3x3Stride2x4Uint8Test, false)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleMaxPooling2d, IgnorePaddingSimpleMaxPooling2dTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleMaxPooling2dUint8, IgnorePaddingSimpleMaxPooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingMaxPooling2dSize3, IgnorePaddingMaxPooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingMaxPooling2dSize3Uint8, IgnorePaddingMaxPooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2d, IgnorePaddingSimpleAveragePooling2dTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dUint8, IgnorePaddingSimpleAveragePooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dNoPadding, IgnorePaddingSimpleAveragePooling2dNoPaddingTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleAveragePooling2dNoPaddingUint8,
    IgnorePaddingSimpleAveragePooling2dNoPaddingUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3, IgnorePaddingAveragePooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3Uint8, IgnorePaddingAveragePooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleL2Pooling2d, IgnorePaddingSimpleL2Pooling2dTest)
ARMNN_AUTO_TEST_CASE(IgnorePaddingSimpleL2Pooling2dUint8, IgnorePaddingSimpleL2Pooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingL2Pooling2dSize3, IgnorePaddingL2Pooling2dSize3Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingL2Pooling2dSize3Uint8, IgnorePaddingL2Pooling2dSize3Uint8Test)

ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2d, SimpleAveragePooling2dTest)
ARMNN_AUTO_TEST_CASE(SimpleAveragePooling2dUint8, SimpleAveragePooling2dUint8Test)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3x2Stride2x2,
                     IgnorePaddingAveragePooling2dSize3x2Stride2x2Test, false)
ARMNN_AUTO_TEST_CASE(IgnorePaddingAveragePooling2dSize3x2Stride2x2NoPadding,
                     IgnorePaddingAveragePooling2dSize3x2Stride2x2Test, true)

ARMNN_AUTO_TEST_CASE(LargeTensorsAveragePooling2d, LargeTensorsAveragePooling2dTest)
ARMNN_AUTO_TEST_CASE(LargeTensorsAveragePooling2dUint8, LargeTensorsAveragePooling2dUint8Test)

ARMNN_AUTO_TEST_CASE(SimpleL2Pooling2d, SimpleL2Pooling2dTest)
ARMNN_AUTO_TEST_CASE(SimpleL2Pooling2dUint8, SimpleL2Pooling2dUint8Test)

ARMNN_AUTO_TEST_CASE(L2Pooling2dSize7, L2Pooling2dSize7Test)
ARMNN_AUTO_TEST_CASE(L2Pooling2dSize7Uint8, L2Pooling2dSize7Uint8Test)

ARMNN_AUTO_TEST_CASE(AsymmNonSquarePooling2d, AsymmetricNonSquarePooling2dTest)
ARMNN_AUTO_TEST_CASE(AsymmNonSquarePooling2dUint8, AsymmetricNonSquarePooling2dUint8Test)

// Activation
ARMNN_AUTO_TEST_CASE(ConstantLinearActivation, ConstantLinearActivationTest)
ARMNN_AUTO_TEST_CASE(ConstantLinearActivationUint8, ConstantLinearActivationUint8Test)

ARMNN_AUTO_TEST_CASE(SimpleNormalizationAcross, SimpleNormalizationAcrossTest)
ARMNN_AUTO_TEST_CASE(SimpleNormalizationWithin, SimpleNormalizationWithinTest)

ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta1, SimpleSoftmaxTest, 1.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta2, SimpleSoftmaxTest, 2.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta1Uint8, SimpleSoftmaxUint8Test, 1.0f)
ARMNN_AUTO_TEST_CASE(SimpleSoftmaxBeta2Uint8, SimpleSoftmaxUint8Test, 2.0f)

ARMNN_AUTO_TEST_CASE(SimpleSigmoid, SimpleSigmoidTest)
ARMNN_AUTO_TEST_CASE(SimpleSigmoidUint8, SimpleSigmoidUint8Test)

ARMNN_AUTO_TEST_CASE(ReLu1, BoundedReLuUpperAndLowerBoundTest)
ARMNN_AUTO_TEST_CASE(ReLu6, BoundedReLuUpperBoundOnlyTest)
ARMNN_AUTO_TEST_CASE(ReLu1Uint8, BoundedReLuUint8UpperAndLowerBoundTest)
ARMNN_AUTO_TEST_CASE(ReLu6Uint8, BoundedReLuUint8UpperBoundOnlyTest)

// Fully Conected
ARMNN_AUTO_TEST_CASE(SimpleFullyConnected, FullyConnectedFloat32Test, false, false)
ARMNN_AUTO_TEST_CASE(FullyConnectedUint8, FullyConnectedUint8Test, false)
ARMNN_AUTO_TEST_CASE(SimpleFullyConnectedWithBias, FullyConnectedFloat32Test, true, false)
ARMNN_AUTO_TEST_CASE(FullyConnectedBiasedUint8, FullyConnectedUint8Test, true)
ARMNN_AUTO_TEST_CASE(SimpleFullyConnectedWithTranspose, FullyConnectedFloat32Test, false, true)

ARMNN_AUTO_TEST_CASE(FullyConnectedLarge, FullyConnectedLargeTest, false)
ARMNN_AUTO_TEST_CASE(FullyConnectedLargeTransposed, FullyConnectedLargeTest, true)

// Splitter
BOOST_AUTO_TEST_CASE(SimpleSplitter)
{
    armnn::RefWorkloadFactory workloadFactory;
    auto testResult = SplitterTest(workloadFactory);
    for (unsigned int i = 0; i < testResult.size(); ++i)
    {
        BOOST_TEST(CompareTensors(testResult[i].output, testResult[i].outputExpected));
    }
}

BOOST_AUTO_TEST_CASE(SplitterUint8)
{
    armnn::RefWorkloadFactory workloadFactory;
    auto testResult = SplitterUint8Test(workloadFactory);
    for (unsigned int i = 0; i < testResult.size(); ++i)
    {
        BOOST_TEST(CompareTensors(testResult[i].output, testResult[i].outputExpected));
    }
}

ARMNN_AUTO_TEST_CASE(CopyViaSplitter, CopyViaSplitterTest)
ARMNN_AUTO_TEST_CASE(CopyViaSplitterUint8, CopyViaSplitterUint8Test)

// Merger
ARMNN_AUTO_TEST_CASE(SimpleMerger, MergerTest)
ARMNN_AUTO_TEST_CASE(MergerUint8, MergerUint8Test)

// Add
ARMNN_AUTO_TEST_CASE(SimpleAdd, AdditionTest)
ARMNN_AUTO_TEST_CASE(AddBroadcast1Element, AdditionBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(AddBroadcast, AdditionBroadcastTest)

ARMNN_AUTO_TEST_CASE(AdditionUint8, AdditionUint8Test)
ARMNN_AUTO_TEST_CASE(AddBroadcastUint8, AdditionBroadcastUint8Test)
ARMNN_AUTO_TEST_CASE(AddBroadcast1ElementUint8, AdditionBroadcast1ElementUint8Test)

// Mul
ARMNN_AUTO_TEST_CASE(SimpleMultiplication, MultiplicationTest)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1Element, MultiplicationBroadcast1ElementTest)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1DVector, MultiplicationBroadcast1DVectorTest)
ARMNN_AUTO_TEST_CASE(MultiplicationUint8, MultiplicationUint8Test)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1ElementUint8, MultiplicationBroadcast1ElementUint8Test)
ARMNN_AUTO_TEST_CASE(MultiplicationBroadcast1DVectorUint8, MultiplicationBroadcast1DVectorUint8Test)

// Batch Norm
ARMNN_AUTO_TEST_CASE(BatchNorm, BatchNormTest)
ARMNN_AUTO_TEST_CASE(BatchNormUint8, BatchNormUint8Test)

// Resize Bilinear
ARMNN_AUTO_TEST_CASE(SimpleResizeBilinear, SimpleResizeBilinearTest)
ARMNN_AUTO_TEST_CASE(SimpleResizeBilinearUint8, SimpleResizeBilinearUint8Test)
ARMNN_AUTO_TEST_CASE(ResizeBilinearNop, ResizeBilinearNopTest)
ARMNN_AUTO_TEST_CASE(ResizeBilinearNopUint8, ResizeBilinearNopUint8Test)
ARMNN_AUTO_TEST_CASE(ResizeBilinearSqMin, ResizeBilinearSqMinTest)
ARMNN_AUTO_TEST_CASE(ResizeBilinearSqMinUint8, ResizeBilinearSqMinUint8Test)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMin, ResizeBilinearMinTest)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMinUint8, ResizeBilinearMinUint8Test)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMag, ResizeBilinearMagTest)
ARMNN_AUTO_TEST_CASE(ResizeBilinearMagUint8, ResizeBilinearMagUint8Test)

// Fake Quantization
ARMNN_AUTO_TEST_CASE(FakeQuantization, FakeQuantizationTest)

// L2 Noramlization
ARMNN_AUTO_TEST_CASE(L2Normalization1d, L2Normalization1dTest)
ARMNN_AUTO_TEST_CASE(L2Normalization2d, L2Normalization2dTest)
ARMNN_AUTO_TEST_CASE(L2Normalization3d, L2Normalization3dTest)
ARMNN_AUTO_TEST_CASE(L2Normalization4d, L2Normalization4dTest)

// Constant
ARMNN_AUTO_TEST_CASE(Constant, ConstantTest)
ARMNN_AUTO_TEST_CASE(ConstantUint8, ConstantUint8Test)

// Concat
ARMNN_AUTO_TEST_CASE(Concatenation1d, Concatenation1dTest)
ARMNN_AUTO_TEST_CASE(Concatenation1dUint8, Concatenation1dUint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation2dDim0, Concatenation2dDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim0Uint8, Concatenation2dDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1, Concatenation2dDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1Uint8, Concatenation2dDim1Uint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation2dDim0DiffInputDims, Concatenation2dDim0DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim0DiffInputDimsUint8, Concatenation2dDim0DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1DiffInputDims, Concatenation2dDim1DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation2dDim1DiffInputDimsUint8, Concatenation2dDim1DiffInputDimsUint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation3dDim0, Concatenation3dDim0Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim0Uint8, Concatenation3dDim0Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1, Concatenation3dDim1Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1Uint8, Concatenation3dDim1Uint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2, Concatenation3dDim2Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2Uint8, Concatenation3dDim2Uint8Test)

ARMNN_AUTO_TEST_CASE(Concatenation3dDim0DiffInputDims, Concatenation3dDim0DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim0DiffInputDimsUint8, Concatenation3dDim0DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1DiffInputDims, Concatenation3dDim1DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim1DiffInputDimsUint8, Concatenation3dDim1DiffInputDimsUint8Test)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2DiffInputDims, Concatenation3dDim2DiffInputDimsTest)
ARMNN_AUTO_TEST_CASE(Concatenation3dDim2DiffInputDimsUint8, Concatenation3dDim2DiffInputDimsUint8Test)

// Floor
ARMNN_AUTO_TEST_CASE(SimpleFloor, SimpleFloorTest)

// Reshape
ARMNN_AUTO_TEST_CASE(SimpleReshapeFloat32, SimpleReshapeFloat32Test)
ARMNN_AUTO_TEST_CASE(SimpleReshapeUint8, SimpleReshapeUint8Test)

// Permute
ARMNN_AUTO_TEST_CASE(SimplePermuteFloat32, SimplePermuteFloat32Test)
ARMNN_AUTO_TEST_CASE(SimplePermuteUint8, SimplePermuteUint8Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet1, PermuteFloat32ValueSet1Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet2, PermuteFloat32ValueSet2Test)
ARMNN_AUTO_TEST_CASE(PermuteFloat32ValueSet3, PermuteFloat32ValueSet3Test)

BOOST_AUTO_TEST_SUITE_END()


// 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 MATH_POWER_INCLUDE
#define MATH_POWER_INCLUDE

#include <concepts>
#include <boost/numeric/linear_algebra/concepts.hpp>
#include <boost/numeric/linear_algebra/identity.hpp>
#include <stdexcept>

namespace math {

    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	std::cout << "[Magma] ";
	if (n < 1) throw std::range_error("power [magma]: n must be > 0");

	Element value= a;
	for (; n > 1; --n)
	    value= op(value, a);
	return value;
    }

#if 0
    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires SemiGroup<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element multiply_and_square_horner(const Element& a, Exponent n, Op op)
    {
	if (n < 1) throw std::range_error("mult&square Horner: n must be > 0");

        // Set mask to highest bit
        Exponent mask= 1 << (8 * sizeof(mask) - 1);

        // If this is a negative number right shift can insert 1s instead of 0s -> infinite loop
        // Therefore we take the 2nd-highest bit
        if (mask < 0)
	    mask= 1 << (8 * sizeof(mask) - 2);

        // Find highest 1 bit
        while(!bool(mask & n)) mask>>= 1;

        Element value= a;
        for (mask>>= 1; mask; mask>>= 1) {
	    value= op(value, value);
	    if (n & mask)
		value= op(value, a);
        }
        return value;
    }

    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires SemiGroup<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	return multiply_and_square_horner(a, n, op);
    }
#endif

#if 1
    // With Horner scheme we can avoid recursion
    // This one is more intuitive (I believe)
    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires SemiGroup<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	std::cout << "[SemiGroup] ";
	if (n < 1) throw std::range_error("power [SemiGroup]: n must be > 0");

	Exponent half(n / 2);
        // If half is 0 then n must be 1 and the result is a
        if (half == 0)
	    return a;

        // Compute power of downward rounded exponent and "square" the result
        Element value= power(a, half, op);
        value= op(value, value);

        // If n is odd another operation with a is needed
        if (n & 1)
	    value= op(value, a);
        return value;
    }
#endif

    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires Monoid<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element multiply_and_square(const Element& a, Exponent n, Op op)
    {
	// Same as the simpler form except that the first multiplication is made before
	// the loop and one squaring is saved this way
	if (n < 0) throw std::range_error("mult&square: n must be >= 0");

	using math::identity;
	Element value= bool(n & 1) ? Element(a) : Element(identity(op, a)), square= a;

	for (n>>= 1; n > 0; n>>= 1) {
	    square= op(square, square);
	    if (n & 1)
		value= op(value, square);
	}
	return value;
    }

    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires Monoid<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	std::cout << "[Monoid] ";
	return multiply_and_square(a, n, op);
    }

    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires PIMonoid<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	std::cout << "[PIMonoid] ";
	if (n < 0 && !is_invertible(op, a))
	    throw std::range_error("power [PIMonoid]: a must be invertible with n < 0");

	return n < 0 ? multiply_and_square(Element(inverse(op, a)), Exponent(-n), op)
	             : multiply_and_square(a, n, op);
    }

#if 1
    template <typename Op, std::Semiregular Element, Integral Exponent>
        requires Group<Op, Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	std::cout << "[Group] ";
	// For groups we don't need any range test

	return n < 0 ? multiply_and_square(Element(inverse(op, a)), Exponent(-n), op)
	             : multiply_and_square(a, n, op);
    }
#endif

#if 0
    template <typename Op, typename Element, typename Exponent>
        requires Group<Op, Element>
              && Integral<Exponent>
              && std::Semiregular<Element>
              && std::Callable2<Op, Element, Element>
              && std::Convertible<std::Callable2<Op, Element, Element>::result_type, Element>
              && std::Semiregular<math::Inversion<Op, Element>::result_type>
              && std::HasNegate<Exponent>
              && math::Monoid<Op, math::Inversion<Op, Element>::result_type>
              && Integral< std::HasNegate<Exponent>::result_type>
              && std::Callable2<Op, math::Inversion<Op, Element>::result_type,
				math::Inversion<Op, Element>::result_type>
              && std::Convertible<std::Callable2<Op, math::Inversion<Op, Element>::result_type,
						 math::Inversion<Op, Element>::result_type>::result_type,
				  math::Inversion<Op, Element>::result_type>
    inline Element power(const Element& a, Exponent n, Op op)
    {
	return n < 0 ? multiply_and_square(inverse(op, a), -n, op)
	             : multiply_and_square(a, n, op);
    }
#endif

} // namespace math

#endif // MATH_POWER_INCLUDE