/*
  Solves the one-particle Schrodinger equation
  for a potential specified in function
  potential(). This example is for the harmonic oscillator in 3d
*/
#include <cmath>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <armadillo>

using namespace  std;
using namespace  arma;

double potential(double);
void output(double, double, int, vec& );

// Begin of main program

int main(int argc, char* argv[])
{
  int       i, j, Dim, lOrbital;
  double    RMin, RMax, Step, DiagConst, NondiagConst, OrbitalFactor;
  // With spherical coordinates RMin = 0 always
  RMin = 0.0;

  RMax = 8.0;  lOrbital = 0;  Dim =2000;
  mat Hamiltonian = zeros<mat>(Dim,Dim);
  // Integration step length
  Step    = RMax/ Dim;
  DiagConst = 2.0 / (Step*Step);
  NondiagConst =  -1.0 / (Step*Step);
  OrbitalFactor = lOrbital * (lOrbital + 1.0);

  // local memory for r and the potential w[r]
  vec r(Dim); vec w(Dim);
  for(i = 0; i < Dim; i++) {
    r(i) = RMin + (i+1) * Step;
    w(i) = potential(r(i)) + OrbitalFactor/(r(i) * r(i));
  }

  // Setting up tridiagonal matrix and brute diagonalization using Armadillo
  Hamiltonian(0,0) = DiagConst + w(0);
  Hamiltonian(0,1) = NondiagConst;
  for(i = 1; i < Dim-1; i++) {
    Hamiltonian(i,i-1)    = NondiagConst;
    Hamiltonian(i,i)    = DiagConst + w(i);
    Hamiltonian(i,i+1)    = NondiagConst;
  }
  Hamiltonian(Dim-1,Dim-2) = NondiagConst;
  Hamiltonian(Dim-1,Dim-1) = DiagConst + w(Dim-1);
  // diagonalize and obtain eigenvalues

  vec Eigval(Dim);
  eig_sym(Eigval, Hamiltonian);
  output(RMin , RMax, Dim, Eigval);

  return 0;
}  //  end of main function

/*
  The function potential()
  calculates and return the value of the
  potential for a given argument x.
  The potential here is for the hydrogen atom
*/

double potential(double x)
{
  return x*x;

} // End: function potential()

void output(double RMin , double RMax, int Dim, vec& d)
{
  int i;
  cout << "RESULTS:" << endl;
  cout << setiosflags(ios::showpoint | ios::uppercase);
  cout <<"Rmin = " << setw(15) << setprecision(8) << RMin << endl;
  cout <<"Rmax = " << setw(15) << setprecision(8) << RMax << endl;
  cout <<"Number of steps = " << setw(15) << Dim << endl;
  cout << "Five lowest eigenvalues:" << endl;
  for(i = 0; i < 5; i++) {
    cout << setw(15) << setprecision(8) << d[i] << endl;
  }
}  // end of function output

//   vec q1 = randu<vec>(100);


/*

*/

#include <boost/math/special_functions/next.hpp>
#include <iostream>
#include <limits>
#include <stdexcept>
#include "Functions.hpp"

int main()
{
	/* 2.5.1 */
	// a) Test the classify function with following values:
	double val = std::numeric_limits<double>::max();
	std::cout << "For val = numeric_limits<double>::max(): " << std::endl;
	std::cout << "val classification: " << Classify(val) << std::endl;
	std::cout << "2.0 * val classification: " << Classify(2.0 * val) << std::endl;
	std::cout << "3.1415 + val classification: " << Classify(3.1415 + val) << std::endl;
	double val2 = std::numeric_limits<double>::min() - 3.1415;
	std::cout << "For val2 = numeric_limits<double>::min(): " << std::endl;
	std::cout << "val2 classification: " << Classify(val2) << std::endl;
	std::cout << "val2 / 2.0 classification: " << Classify(val2 / 2.0) << std::endl;
	std::cout << "DBL_MIN / 2.0 classification: " << Classify(DBL_MIN / 2.0) << std::endl;
	// b) Test std::isfinite, std::isinf, std::isnan, std::isnormal on values:
	double factor = 2.0;
	val = factor*std::numeric_limits<double>::max();
	std::cout << "For val = 2.0 * numeric_limits<double>::max()" << std::endl;

	std::cout << "val classifications: " << std::endl;
	std::cout << "\t isfinite(val): " << std::isfinite(val) << std::endl;
	std::cout << "\t isfinite(val): " << std::isinf(val) << std::endl;
	std::cout << "\t isfinite(val): " << std::isnan(val) << std::endl;
	std::cout << "\t isfinite(val): " << std::isnormal(val) << std::endl;

	std::cout << "val - val classification: " << std::endl;
	std::cout << "\t isfinite(val - val): " << std::isfinite(val - val) << std::endl;
	std::cout << "\t isfinite(val - val): " << std::isinf(val - val) << std::endl;
	std::cout << "\t isfinite(val - val): " << std::isnan(val - val) << std::endl;
	std::cout << "\t isfinite(val - val): " << std::isnormal(val - val) << std::endl;

	std::cout << "sqrt(-1.0) classification: " << std::endl;
	std::cout << "\t isfinite(sqrt(-1.0)): " << std::isfinite(std::sqrt(-1.0)) << std::endl;
	std::cout << "\t isfinite(sqrt(-1.0)): " << std::isinf(std::sqrt(-1.0)) << std::endl;
	std::cout << "\t isfinite(sqrt(-1.0)): " << std::isnan(std::sqrt(-1.0)) << std::endl;
	std::cout << "\t isfinite(sqrt(-1.0)): " << std::isnormal(std::sqrt(-1.0)) << std::endl;

	std::cout << "log(0.0) classification: " << std::endl;
	std::cout << "\t isfinite(log(0.0)): " << std::isfinite(std::log(0.0)) << std::endl;
	std::cout << "\t isfinite(log(0.0)): " << std::isinf(std::log(0.0)) << std::endl;
	std::cout << "\t isfinite(log(0.0)): " << std::isnan(std::log(0.0)) << std::endl;
	std::cout << "\t isfinite(log(0.0)): " << std::isnormal(std::log(0.0)) << std::endl;

	std::cout << "exp(val) classification: " << std::endl;
	std::cout << "\t isfinite(exp(val)): " << std::isfinite(std::exp(val)) << std::endl;
	std::cout << "\t isfinite(exp(val)): " << std::isinf(std::exp(val)) << std::endl;
	std::cout << "\t isfinite(exp(val)): " << std::isnan(std::exp(val)) << std::endl;
	std::cout << "\t isfinite(exp(val)): " << std::isnormal(std::exp(val)) << std::endl;

	/* 2.5.2 */
	// b) Compare FindEpsilon outputs to std::numeric_limits<>::epsilon() outputs:
	double epsilon1 = FindEpsilon<double>();
	std::cout << "FindEpsilon<double>() == numeric_limits<double>::epsilon(): " << ((epsilon1 == std::numeric_limits<double>::epsilon())? "True": "False") << std::endl;
	int epsilon2 = FindEpsilon<int>();
	std::cout << "FindEpsilon<int>() == numeric_limits<int>::epsilon(): " << ((epsilon2 == std::numeric_limits<int>::epsilon()) ? "True" : "False") << std::endl;
	float epsilon3 = FindEpsilon<float>();
	std::cout << "FindEpsilon<float>() == numeric_limits<float>::epsilon(): " << ((epsilon3 == std::numeric_limits<float>::epsilon()) ? "True" : "False") << std::endl;

	/* 2.5.3 */
	// Experiment with the Boost C++ math toolkit:
	// Test float_distance:
	double a = 0.1; double b =
		a + std::numeric_limits<double>::min();
	std::cout << "Distance between 0.1 and 0.1 + numeric_limits<double>::min(): " << boost::math::float_distance(a, b) << std::endl;
	a = 1.0; b = 0.0;
	std::cout << "Distance between 1.0 and 0.0: " << boost::math::float_distance(a, b) << std::endl;
	// Test float_next:
	unsigned long long steps = 0;
	try
	{
		// Will throw exception in float_next if std::numeric_limits<double>::max() minus any number is used as an input, thus need to use literal:
		b = 1.797693134862315805e+308 - std::numeric_limits<double>::min();
		while(true)
		{
			b = boost::math::float_next(b);
			steps++;
		}
	}
	catch (std::overflow_error& err)
	{
		std::cout << "Overflow exception caught:" << std::endl;
		std::cout << err.what() << std::endl;
		std::cout << "Steps between numeric_limits<double>::max() - 10 and numeric_limits<double>::max(): " << steps << std::endl;
	}
	// Test float_prior:
	steps = 0;
	try
	{
		b = std::numeric_limits<double>::min() + 1.0;
		while (true)
		{
			b = boost::math::float_prior(b);
			steps++;
		}
	}
	catch (std::underflow_error& err)
	{
		std::cout << "Underflow exception caught: " << std::endl;
		std::cout << err.what() << std::endl;
		std::cout << "Steps between ... " << steps << std::endl;
	}
	// Test boost::nextafter():
	std::cout << "nextafter(): " << std::nextafter(a, b) << std::endl;
	system("pause");

	return 0;
}

Advanced C++ Course/Benjamin Rutan HW 2 Submission/2.5+2.6/Main.cpp


#ifndef UTIL_H
#define UTIL_H
#include <cmath>
#include <cassert>
#include <boost/operators.hpp>

template<class T> class Maybe {
    T value;
    bool has_value;
public:
    Maybe() : value(), has_value(false) {}
    Maybe(T val) : value(val), has_value(true) {}

    operator bool() {
        return has_value;
    }

    T val() {
        assert(has_value);
        return value;
    }
};

void log(const char* s) {
    printf("%s\n", s);
    fflush(stdout);
}

inline double sq(double val) {
    return val*val;
}

const double EPS = 1e-6;

inline bool almost_zero(double val) {
    return fabs(val) < EPS;
}

struct Vector : boost::additive<Vector>, boost::multiplicative2<Vector, double>, boost::equality_comparable<Vector> {
    double coord[3];
    Vector() : coord{0, 0, 0} {}
    Vector(double x, double y, double z) : coord{x, y, z} {}

    double length() const {
        return sqrt(sq(coord[0]) + sq(coord[1]) + sq(coord[2]));
    }

    bool operator==(const Vector& other) {
        for (int i = 0; i < 3; ++i) {
            if (fabs(coord[i] - other.coord[i]) > EPS) {
                return false;
            }
        }
        return true;
    }

    Vector& operator+=(const Vector& other) {
        for (int i = 0; i < 3; ++i) {
            coord[i] += other.coord[i];
        }
        return *this;
    }

    Vector& operator-=(const Vector& other) {
        for (int i = 0; i < 3; ++i) {
            coord[i] -= other.coord[i];
        }
        return *this;
    }

    Vector& operator*=(double factor) {
        for (int i = 0; i < 3; ++i) {
            coord[i] *= factor;
        }
        return *this;
    }

    Vector& operator/=(double factor) {
        for (int i = 0; i < 3; ++i) {
            coord[i] /= factor;
        }
        return *this;
    }

    Vector normalized() const {
        return *this / length();
    }

    friend Vector operator*(Vector a, Vector b) {
        return Vector(a.coord[0]*b.coord[0], a.coord[1]*b.coord[1], a.coord[2]*b.coord[2]);
    }

    friend double dot(Vector a, Vector b) {
        double ans = 0;
        for (int i = 0; i < 3; ++i) {
            ans += a.coord[i]*b.coord[i];
        }
        return ans;
    }

    friend Vector vec(Vector a, Vector b) {
        return Vector(a.coord[1]*b.coord[2]-a.coord[2]*b.coord[1], -(a.coord[0]*b.coord[2]-a.coord[2]*b.coord[0]), a.coord[0]*b.coord[1]-a.coord[1]*b.coord[0]);
    }

    friend double angle(Vector a, Vector b) {
        return dot(a, b) / a.length() / b.length();
    }
};

inline double sq(Vector v) {
    return dot(v, v);
}

typedef Vector Point;

#endif


#include <Eigen/Dense>
#include <iostream>
#include <ctime>

using namespace Eigen;

template <class Matrix>

// The function arrowmatvec computes the product the desired product directly as A*A*x
void arrowmatvec(const Matrix & d, const Matrix & a, const Matrix & x, Matrix & y)
{
    // Here, we choose a MATLAB style implementation using block construction
    // you can also use loops
    // If you are interested you can compare both implementation and see if and how they differ
    int n=d.size();
    VectorXd dcut= d.head(n-1);
    VectorXd acut = a.head(n-1);
    MatrixXd ddiag=dcut.asDiagonal();
    MatrixXd A(n,n);
    MatrixXd D = dcut.asDiagonal();
    // If you do not create the temporary matrix D, you will get an error: D must be casted to MatrixXd
    A << D, a.head(n-1), acut.transpose(), d(n-1);

    y=A*A*x;
}

// We test the function arrowmatvec with 5 dimensional random vectors.

int main(void)
{
//     srand((unsigned int) time(0));
    VectorXd a=VectorXd::Random(5);
    VectorXd d=VectorXd::Random(5);
    VectorXd x=VectorXd::Random(5);
    VectorXd y;

    arrowmatvec(d,a,x,y);
    std::cout << "A*A*x = " << y << std::endl;
}

Nummerical Methods for CSE/PS1/solutions_ps1/C++/arrowmatvec.cpp


/**
 * \file SinusGeneratorFilter.cpp
 */

#include <ATK/Tools/SinusGeneratorFilter.h>

#include <cmath>

#include <boost/math/constants/constants.hpp>

namespace ATK
{
  template<typename DataType_>
  SinusGeneratorFilter<DataType_>::SinusGeneratorFilter()
  :Parent(0, 2)
  {
  }

  template<typename DataType_>
  void SinusGeneratorFilter<DataType_>::set_frequency(DataType_ frequency)
  {
    if(frequency <= 0)
    {
      throw std::out_of_range("Frequency must be strictly positive");
    }
    this->frequency = frequency;
    this->frequ_cos = std::cos(2 * boost::math::constants::pi<DataType_>() * frequency / output_sampling_rate);
    this->frequ_sin = std::sin(2 * boost::math::constants::pi<DataType_>() * frequency / output_sampling_rate);
  }

  template<typename DataType_>
  DataType_ SinusGeneratorFilter<DataType_>::get_frequency() const
  {
    return frequency;
  }

  template<typename DataType_>
  void SinusGeneratorFilter<DataType_>::set_volume(DataType_ volume)
  {
    this->volume = volume;
  }

  template<typename DataType_>
  DataType_ SinusGeneratorFilter<DataType_>::get_volume() const
  {
    return volume;
  }

  template<typename DataType_>
  void SinusGeneratorFilter<DataType_>::set_offset(DataType_ offset)
  {
    this->offset = offset;
  }

  template<typename DataType_>
  DataType_ SinusGeneratorFilter<DataType_>::get_offset() const
  {
    return offset;
  }

  template<typename DataType_>
  void SinusGeneratorFilter<DataType_>::full_setup()
  {
    Parent::full_setup();
    cos = 1;
    sin = 0;
  }

  template<typename DataType_>
  void SinusGeneratorFilter<DataType_>::process_impl(gsl::index size) const
  {
    DataType* ATK_RESTRICT output_cos = outputs[0];
    DataType* ATK_RESTRICT output_sin = outputs[1];

    for(gsl::index i = 0; i < size; ++i)
    {
      auto new_cos = cos * frequ_cos - sin * frequ_sin;
      auto new_sin = cos * frequ_sin + sin * frequ_cos;
      auto norm = (new_cos * new_cos + new_sin * new_sin);

      cos = new_cos / norm;
      sin = new_sin / norm;

      output_cos[i] = volume * cos + offset;
      output_sin[i] = volume * sin + offset;
    }
  }

#if ATK_ENABLE_INSTANTIATION
  template class SinusGeneratorFilter<float>;
#endif
  template class SinusGeneratorFilter<double>;
}


#define BOOST_TEST_MODULE School test
#include <boost/test/unit_test.hpp>
#include "Sum.h"
#include "Variable.h"

using namespace omnn::math;
using namespace boost::unit_test;

BOOST_AUTO_TEST_CASE(P_474)
{
	std::cout
		<< std::endl
		<< "No 474 Equations"
		<< std::endl;

	DECL_VA(x);
	std::cout << "x+318=645		x=" << (x + 318 - 645)(x) << std::endl;

	DECL_VA(y);
	std::cout << "870-y=187		y=" << (870-y-187)(y) << std::endl;

	DECL_VA(z);
	std::cout << "z-234=356		z=" << (z-234-356)(z) << std::endl;

}

BOOST_AUTO_TEST_CASE(N456)
{
	std::cout
		<< std::endl
		<<
		"№456"
		<< std::endl;

	DECL_VA(all);
	DECL_VA(soldfirst);
	DECL_VA(soldsecond);
	DECL_VA(free);

	// Усього = ПродалиСпочатку + ПродалиПотім + ВільнихМісць
	// (ПродалиСпочатку + ПродалиПотім + ВільнихМісць) - Усього == 0
	auto formula = (soldfirst + soldsecond + free) - all;
	std::cout << "formula: " << formula.str() << " = 0" << std::endl;

	formula.eval({
		{ all, 586 },
		{ soldfirst, 29 },
		{ soldsecond, 459 }
		});
	std::cout << "evaluated: " << formula.str() << " = 0" << std::endl;

	auto root = formula(free);
	std::cout << "x = " << root << std::endl;

	formula.eval({ { free, root } });
	std::cout << "check: " << formula << " = 0" << std::endl;
	BOOST_TEST(formula == 0);
}

BOOST_AUTO_TEST_CASE(N_451_3)
{
	std::cout
		<< std::endl
		<< "451_3"
		<< std::endl;

	DECL_VA(S);
	DECL_VA(P);
	DECL_VA(x);

	auto formula = (P + x) - S; // S = P+x
	std::cout << "formula: " << formula.str() << " = 0" << std::endl;

	formula.eval({
		{ S, 235 },
		{ P, 127 }
		});
	std::cout << "evaluated: " << formula.str() << " = 0" << std::endl;

	auto root = formula(x);
	std::cout << "x = " << root << std::endl;

	formula.eval({ { x, root } });
	std::cout << "check: " << formula << " = 0" << std::endl;
	BOOST_TEST(formula == 0);
}

BOOST_AUTO_TEST_CASE(P_465_358)
{
	std::cout
		<< std::endl
		<< "Primer: 465-358=" << 586-459
		<< std::endl;
}

BOOST_AUTO_TEST_CASE(Perimeter)
{
    std::cout
        << std::endl
        << "perimeter"
        << std::endl;

    DECL_VA(x);
    DECL_VA(P);
    DECL_VA(a);
    DECL_VA(b);

    auto formula = (a+b)*2 - P;
    std::cout <<"formula: " << formula.str() << " = 0" << std::endl;

    formula.eval({
        { P, 20 },
        { a, x },
        { b, 6 }
    });
    std::cout <<"evaluated: " << formula.str() << " = 0" << std::endl;

    auto root = formula(x);
    std::cout <<"x = " << root << std::endl;

    BOOST_TEST(root == 4);

    formula.eval({ { x, root }});
    std::cout << "check: " << formula << " = 0" << std::endl;
    BOOST_TEST(formula == 0);
}


/**
 * @file
 * @brief NPDE homework ElementMatrixComputation code
 * @author Janik Schüttler, edited by Oliver Rietmann
 * @date 03.03.2019
 * @copyright Developed at ETH Zurich
 */

#include "mylinearloadvector.h"

#include <lf/base/base.h>
#include <lf/geometry/geometry.h>
#include <lf/mesh/mesh.h>

#include <Eigen/Core>
#include <functional>

namespace ElementMatrixComputation {

namespace {

/* SAM_LISTING_BEGIN_1 */
Eigen::Vector4d computeLoadVector(
    const Eigen::MatrixXd &vertices,
    std::function<double(const Eigen::Vector2d &)> f) {
  // Number of nodes of the element: triangles = 3, rectangles = 4
  const int num_nodes = vertices.cols();
  // Vector for returning element vector
  Eigen::Vector4d elem_vec = Eigen::Vector4d::Zero();

  //====================
  // Your code goes here
  //====================

  Eigen::MatrixXd midpoints(2,num_nodes);

  double area;
  switch(num_nodes){
    case 3: {
      area = 0.5*(vertices(0,1)-vertices(0,0)*(vertices(1,2)-vertices(1,0))-
                  vertices(0,2)-vertices(0,0)*(vertices(1,1)-vertices(1,0))
              );
      midpoints<<
        vertices(0,0)+vertices(0,1),
        vertices(0,1)+vertices(0,2),
        vertices(0,2)+vertices(0,0),
        vertices(1,0)+vertices(1,1),
        vertices(1,1)+vertices(1,2),
        vertices(1,2)+vertices(1,0);
      break;
    }
    case 4: {
      area = (vertices(0,1)-vertices(0,0))*(vertices(1,3)-vertices(1,0));
      midpoints<<
        vertices(0,0)+vertices(0,1),
        vertices(0,1)+vertices(0,2),
        vertices(0,2)+vertices(0,3),
        vertices(0,3)+vertices(0,0),
        vertices(1,0)+vertices(1,1),
        vertices(1,1)+vertices(1,2),
        vertices(1,2)+vertices(1,3),
        vertices(1,3)+vertices(1,0);
      break;
    }
  }
  midpoints *= 0.5;

  Eigen::VectorXd fvals = Eigen::VectorXd::Zero(num_nodes);
  for (int i=0;i<num_nodes;i++){
    fvals[i] = f(midpoints.col(i));
  }

  for (int i=0;i<num_nodes;i++){
    elem_vec[i%num_nodes] += 0.5*fvals[i];
    elem_vec[(i+1)%num_nodes] += 0.5*fvals[i];
  }
  elem_vec *= area/(double)num_nodes;
  return elem_vec;
}
/* SAM_LISTING_END_1 */

}  // namespace

Eigen::Vector4d MyLinearLoadVector::Eval(const lf::mesh::Entity &cell) {
  // Topological type of the cell
  const lf::base::RefEl ref_el{cell.RefEl()};
  const lf::base::size_type num_nodes{ref_el.NumNodes()};

  // Obtain the vertex coordinates of the cell, which completely
  // describe its shape.
  const lf::geometry::Geometry *geo_ptr = cell.Geometry();

  // Matrix storing corner coordinates in its columns
  auto vertices = geo_ptr->Global(ref_el.NodeCoords());

  return computeLoadVector(vertices, f_);
}

}  // namespace ElementMatrixComputation


/*
 * Copyright Nick Thompson, 2017
 * Use, modification and distribution are subject to the
 * Boost Software License, Version 1.0. (See accompanying file
 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 */

#include <random>
#include <iostream>
#include <boost/type_index.hpp>
#include <boost/math/special_functions/chebyshev.hpp>
#include <boost/math/special_functions/sinc.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/array.hpp>
#include "math_unit_test.hpp"

using boost::multiprecision::cpp_bin_float_quad;
using boost::math::chebyshev_t;
using boost::math::chebyshev_t_prime;
using boost::math::chebyshev_u;

template<class Real>
void test_polynomials()
{
    std::cout << "Testing explicit polynomial representations of the Chebyshev polynomials on type " << boost::typeindex::type_id<Real>().pretty_name()  << "\n";

    Real x = -2;
    Real tol = 32*std::numeric_limits<Real>::epsilon();
    while (x < 2)
    {
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(0, x), Real(1), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(1, x), x, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(2, x), 2*x*x - 1, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(3, x), x*(4*x*x-3), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(4, x), 8*x*x*(x*x - 1) + 1, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t(5, x), x*(16*x*x*x*x - 20*x*x + 5), tol);
        x += 1/static_cast<Real>(1<<7);
    }

    x = -2;
    while (x < 2)
    {
        CHECK_MOLLIFIED_CLOSE(chebyshev_u(0, x), Real(1), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_u(1, x), 2*x, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_u(2, x), 4*x*x - 1, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_u(3, x), 4*x*(2*x*x - 1), tol);
        x += 1/static_cast<Real>(1<<7);
    }
}

template<class Real>
void test_derivatives()
{
    std::cout << "Testing explicit polynomial representations of the Chebyshev polynomial derivatives on type " << boost::typeindex::type_id<Real>().pretty_name()  << "\n";

    Real x = -2;
    Real tol = 4*std::numeric_limits<Real>::epsilon();
    while (x < 2)
    {
        CHECK_MOLLIFIED_CLOSE(chebyshev_t_prime(0, x), Real(0), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t_prime(1, x), Real(1), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t_prime(2, x), 4*x, tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t_prime(3, x), 3*(4*x*x - 1), tol);
        CHECK_MOLLIFIED_CLOSE(chebyshev_t_prime(4, x), 16*x*(2*x*x - 1), tol);
        // This one makes the tolerance have to grow too large; the Chebyshev recurrence is more stable than naive polynomial evaluation anyway.
        //BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(5, x), 5*(4*x*x*(4*x*x - 3) + 1), tol);
        x += 1/static_cast<Real>(1<<7);
    }
}

template<class Real>
void test_clenshaw_recurrence()
{
    using boost::math::chebyshev_clenshaw_recurrence;
    boost::array<Real, 5> c0 = { {2, 0, 0, 0, 0} };
    // Check the size = 1 case:
    boost::array<Real, 1> c01 = { {2} };
    // Check the size = 2 case:
    boost::array<Real, 2> c02 = { {2, 0} };
    boost::array<Real, 4> c1 = { {0, 1, 0, 0} };
    boost::array<Real, 4> c2 = { {0, 0, 1, 0} };
    boost::array<Real, 5> c3 = { {0, 0, 0, 1, 0} };
    boost::array<Real, 5> c4 = { {0, 0, 0, 0, 1} };
    boost::array<Real, 6> c5 = { {0, 0, 0, 0, 0, 1} };
    boost::array<Real, 7> c6 = { {0, 0, 0, 0, 0, 0, 1} };

    Real x = -1;
    // It's not clear from this test which one is more accurate; higher precision cast testing is required, and is done elsewhere:
    int ulps = 50;
    while (x <= 1)
    {
        Real y = chebyshev_clenshaw_recurrence(c0.data(), c0.size(), x);
        Real expected = chebyshev_t(0, x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c0.data(), c0.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        y = chebyshev_clenshaw_recurrence(c01.data(), c01.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c01.data(), c01.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        y = chebyshev_clenshaw_recurrence(c02.data(), c02.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c02.data(), c02.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(1,x);
        y = chebyshev_clenshaw_recurrence(c1.data(), c1.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c1.data(), c1.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(2, x);
        y = chebyshev_clenshaw_recurrence(c2.data(), c2.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c2.data(), c2.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(3, x);
        y = chebyshev_clenshaw_recurrence(c3.data(), c3.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c3.data(), c3.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(4, x);
        y = chebyshev_clenshaw_recurrence(c4.data(), c4.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c4.data(), c4.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(5, x);
        y = chebyshev_clenshaw_recurrence(c5.data(), c5.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c5.data(), c5.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        expected = chebyshev_t(6, x);
        y = chebyshev_clenshaw_recurrence(c6.data(), c6.size(), x);
        CHECK_ULP_CLOSE(expected, y, ulps);
        y = chebyshev_clenshaw_recurrence(c6.data(), c6.size(), Real(-1), Real(1), x);
        CHECK_ULP_CLOSE(expected, y, ulps);

        x += static_cast<Real>(1)/static_cast<Real>(1 << 7);
    }
}

template<typename Real>
void test_translated_clenshaw_recurrence()
{
    using boost::math::chebyshev_clenshaw_recurrence;
    std::mt19937_64 mt(123242);
    std::uniform_real_distribution<Real> dis(-1,1);

    std::vector<Real> c(32);
    for (auto & d : c) {
        d = dis(mt);
    }
    int samples = 0;
    while (samples++ < 250) {
        Real x = dis(mt);
        Real expected = chebyshev_clenshaw_recurrence(c.data(), c.size(), x);
        // The computed value, in this case, should actually be better, since it has more information to use.
        // In any case, this test doesn't show Reinch's modification to the Clenshaw recurrence is better;
        // it shows they are doing roughly the same thing.
        Real computed = chebyshev_clenshaw_recurrence(c.data(), c.size(), Real(-1), Real(1), x);
        if (!CHECK_ULP_CLOSE(expected, computed, 1000)) {
            std::cerr << "  Problem occured at x = " << x << "\n";
        }
    }
}

int main()
{
    test_polynomials<float>();
    test_polynomials<double>();
    test_polynomials<long double>();
    test_polynomials<cpp_bin_float_quad>();

    test_derivatives<float>();
    test_derivatives<double>();
    test_derivatives<long double>();
    test_derivatives<cpp_bin_float_quad>();

    test_clenshaw_recurrence<float>();
    test_clenshaw_recurrence<double>();
    test_clenshaw_recurrence<long double>();

    test_translated_clenshaw_recurrence<double>();
    return boost::math::test::report_errors();
}


/**
 * 2D Data builder class definition
 */

#pragma once

#define _USE_MATH_DEFINES

#include <Eigen/Dense>
#include <math.h>

namespace DeepLearningFramework {
/**
 * Build Data class
 *
 * generateDiscSet: generate 2D data with label 1 inside a circle, otherwise 0
 */
class DataBuilder2D {
public:
  DataBuilder2D() = delete;
  ~DataBuilder2D() = delete;

  /**
   * generateDiscSet static method
   *
   * Generate features in [0.f; 1.f] and labels in function of radius value
   * One-hot encoded labels [0, 1] inside radius, otherwise [1, 0]
   *
   * @param[out] labels one-hot encoded labels, [0, 1] inside radius otherwise
   * [1, 0]
   * @param[out] features random number in range [0.f, 1.f]
   * @param[in] samplesCount number of samples to generate.
   * @param[in] discRadius radius of the circle in range [0.f, 1.f].
   */
  static void generateDiscSet(Eigen::MatrixXf &labels,
                              Eigen::MatrixXf &features, uint32_t samplesCount,
                              float discRadius);
};
}; // namespace DeepLearningFramework


#include <eigen3/Eigen/Core>
#include <Eigen/LU>
#include <vector>

#include "nntree/dataset.h"

namespace nntree {
    namespace core {

// TODO(equivalence1) memory leaks here, but we will rewrite it anyways
        void LeastSquares(Tensor<double>& x, Tensor<double>& y, Tensor<double>& res) {
            namespace E = Eigen;

            assert(x.Ndim() == 2);
            assert(y.Ndim() == 2);

            E::Map<E::MatrixXd, 0, E::Stride<E::Dynamic, E::Dynamic>>
                mxX_t(x.Data(),
                      x.Ncols(),
                      x.Nrows(),
                      E::Stride<E::Dynamic, E::Dynamic>(x.Strides()[0] / sizeof(double),
                                                        x.Strides()[1] / sizeof(double)));
            auto mxX = mxX_t.transpose();
            E::Map<E::MatrixXd, 0, E::Stride<E::Dynamic, E::Dynamic>>
                mxY_t(y.Data(),
                      y.Ncols(),
                      y.Nrows(),
                      E::Stride<E::Dynamic, E::Dynamic>(y.Strides()[0] / sizeof(double),
                                                        y.Strides()[1] / sizeof(double)));
            auto mxY = mxY_t.transpose();

            auto solution = (mxX.transpose() * mxX).inverse() * mxX.transpose() * mxY;
            auto solution_t = solution.transpose();

            auto result = new double[solution_t.rows() * solution_t.cols()];
            assert(result != nullptr);
            E::Map<E::MatrixXd> resultMap(result, solution_t.rows(), solution_t.cols());
            resultMap = solution_t;

            std::vector<uint64_t> shape({(uint64_t) solution.rows(),
                                         (uint64_t) solution.cols()});
            std::vector<uint64_t> strides({(uint64_t) resultMap.outerStride() * sizeof(double),
                                           (uint64_t) resultMap.innerStride() * sizeof(double)});
            res.FromMem(resultMap.data(), shape, strides, true);
        }

// TODO(equivalence1) reference is not const
        void LeastSquares(core::DataSet<double, double>& ds, Tensor<double>& res) {
            auto& x = ds.GetInput();
            auto& y = ds.GetOutput();
            assert(y.Nrows() == x.Nrows());
            LeastSquares(x, y, res);
        }

    }
}


// Copyright Yamaha 2021
// MIT License
// https://github.com/yamaha-bps/cbr_control/blob/master/LICENSE

#ifndef DLTV_PROBLEM_HPP_
#define DLTV_PROBLEM_HPP_

#include <Eigen/Dense>
#include <cstdint>

template<std::size_t _nPts = 100>
struct DltvOcpDi
{
  static_assert(_nPts > 1, "Number of trajectory points must be > 1.");

  // Must be defined
  constexpr static std::size_t nPts = _nPts;
  constexpr static std::size_t nx = 2;
  constexpr static std::size_t nu = 1;

  // Time step
  constexpr static double dt = 0.01;

  // Custom types
  using state_t = Eigen::Matrix<double, nx, 1>;
  using input_t = Eigen::Matrix<double, nu, 1>;
  using A_t = Eigen::Matrix<double, nx, nx>;
  using B_t = Eigen::Matrix<double, nx, nu>;
  using Q_t = Eigen::Matrix<double, nx, nx>;
  using R_t = Eigen::Matrix<double, nu, nu>;

  // Constants
  const A_t A = (A_t() << 1., 0.01, 0., 1.).finished();
  const B_t B = (B_t() << 5.0e-5, 0.01).finished();
  const state_t E = (state_t() << 0., 0.).finished();
  const Q_t Q = (Q_t() << 10., 0., 0., 0.1 ).finished();
  const R_t R = (R_t() << 0.01).finished();
  const Q_t QT = (Q_t() << 1., 0., 0., 1.).finished();

  void get_x0(Eigen::Ref<state_t> x0) const
  {
    x0 << 1., 0.;
  }

  void get_T(std::size_t k, double & t) const
  {
    t = static_cast<double>(k) * dt;
  }

  void get_state_lb(std::size_t, Eigen::Ref<state_t> state_lb) const
  {
    state_lb <<
      -1000.,
      -0.5;
  }

  void get_state_ub(std::size_t, Eigen::Ref<state_t> state_ub) const
  {
    state_ub <<
      1000.,
      0.5;
  }

  void get_input_lb(std::size_t, Eigen::Ref<input_t> input_lb) const
  {
    input_lb << -1;
  }

  void get_input_ub(std::size_t, Eigen::Ref<input_t> input_ub) const
  {
    input_ub << 1;
  }

  const A_t & get_A(std::size_t) const
  {
    return A;
  }

  const B_t & get_B(std::size_t) const
  {
    return B;
  }

  const state_t & get_E(std::size_t) const
  {
    return E;
  }

  const Q_t & get_Q(std::size_t) const
  {
    return Q;
  }

  const R_t & get_R(std::size_t) const
  {
    return R;
  }

  const Q_t & get_QT() const
  {
    return QT;
  }

  state_t get_xldot(double) const {return state_t::Zero();}
};

#endif  // DLTV_PROBLEM_HPP_


/**
 * @file matode_main.cc
 * @brief NPDE homework MatODE code
 * @copyright Developed at ETH Zurich
 */

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

#include "matode.h"

int main(int /*argc*/, char** /*argv*/) {
  /* SAM_LISTING_BEGIN_6 */
  double h = 0.01;  // stepsize
  Eigen::Vector3d norms;
  // Build M
  Eigen::Matrix3d M;
  M << 8, 1, 6, 3, 5, 7, 9, 9, 2;
  // Build A
  Eigen::Matrix3d A;
  A << 0, 1, 1, -1, 0, 1, -1, -1, 0;
  Eigen::MatrixXd I = Eigen::Matrix3d::Identity();
  //====================
  // Your code goes here
  //====================
  /* SAM_LISTING_END_6 */
  return 0;
}


#include "spectral_clustering.h"
#include <Eigen/Eigenvalues>
#include <iostream>
#include <ctime>

using namespace std;

//these functions are defined later in this file
void repair_clusters(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F, Eigen::MatrixXi& sF, Eigen::VectorXi& sFC);
std::vector<std::vector<int> > spectral_clustering(const Eigen::MatrixXd& A, int K);
std::vector<std::vector<int> > kmeans_cluster(const Eigen::MatrixXd& data, int K);

/*
Spectral clustering of the faces
- use similarity matrix and face connectivity to determine the clusters

Input:

K: number of clusters
V, F: the mesh
similarity: a |F|*|F| symmetric matrix

Output:

sF: A face index matrix of size |F|*3. Faces in the same cluster are in consecutive rows of sF
sFC: A K*1 vector. Each element indicates the size of each cluster stored in sF
*/

void spectral_clustering
(int K, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F, const Eigen::MatrixXd& similarity,
 Eigen::MatrixXi& sF, Eigen::VectorXi& sFC)
{

	//Requirements
	// - similar faces are clustered together based on the similarity matrix
	// - faces in a cluster must be contiguous and form a single connected component

  //dummy segmentation, replace the following code
  int cluster_size=F.rows()/K;
  sFC=Eigen::VectorXi::Constant(K,cluster_size);
  sFC[K-1]=F.rows()-cluster_size*(K-1);
  sF=F;

  //YOUR CODE HERE

  //make sure that faces in the same cluster are connected
  repair_clusters(V,F,sF,sFC);
}

/// repair clusters so that each cluster contains a compact connected component
void repair_clusters
(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F, Eigen::MatrixXi& sF, Eigen::VectorXi& sFC)
{
  //YOUR CODE HERE
}

/**
* Spectral clustering into K clusters
*
* @param A 		the affinity matrix
* @param K    the number of clusters
*
* @return		   ordered set of data row indices for each cluster
*/

std::vector<std::vector<int> > spectral_clustering(const Eigen::MatrixXd& A, int K)
{
	// compute normalized laplacian
  // using Ng, Jordan and Weiss, "On Spectral Clustering: Analysis and an Algorithm", NIPS 2002
  Eigen::VectorXd S=A.colwise().sum().array().pow(-0.5);
  Eigen::MatrixXd D=S.asDiagonal();
  Eigen::MatrixXd I=Eigen::MatrixXd::Identity(A.rows(),A.cols());
  Eigen::MatrixXd L = I - (D* A *D);

  //solve, eigenvalues are sorted in increasing order
  cout<<"- Solving Eigen Decomposition"<<endl;
	Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(L);
	Eigen::VectorXd E = es.eigenvalues();
	Eigen::MatrixXd V = es.eigenvectors();

  // keep only the k-principal components (Eigen's eigenvectors are colwise)
  V = V.block(0,1,V.rows(),K);

  //normalize V
  Eigen::VectorXd norm = V.array().pow(2).matrix().rowwise().sum();
  for (unsigned int k = 0; k < K; ++k) V.col(k) = V.col(k).array() / norm.array();

  return kmeans_cluster(V, K);
}

/**
 * kmeans clustering
 * based on kmeans matlab script by Ian T Nabney (1996-2001)
 *
 * @param data 	affinity matrix
 * @oaram ncentres	number of clusters
 * @return		ordered set of data row indices for each cluster
 * 			    	(order is based on distance to cluster centre)
 */
std::vector<std::vector<int> >
kmeans_cluster(const Eigen::MatrixXd& data, int ncentres)
{
  std::srand(std::time(nullptr));
  //std::srand(0); //use this to debug so you get the same results

	int ndims = data.cols();
	int ndata = data.rows();

	Eigen::MatrixXd centres = Eigen::MatrixXd::Zero(ncentres, ndims);
	Eigen::MatrixXd old_centres;

	std::vector<int> rands;
	for (int i=0; i < ncentres; i++)
  {
		//randomly initialise centers
		bool flag;
		do {
			flag = false;
			int randIndex = std::rand()%ndata;
			//make sure same row not chosen twice
			for (unsigned int j=0; j < rands.size(); ++j) {
				if (randIndex == rands[j]) {
					flag = true;
					break;
				}
			}
			if (!flag) {
				centres.row(i) = data.row(randIndex);
				rands.push_back(randIndex);
			}
		} while (flag);
	}
	Eigen::MatrixXd id = Eigen::MatrixXd::Identity(ncentres, ncentres);
	//maps vectors to centres.
	Eigen::MatrixXd post(ndata, ncentres);

	Eigen::VectorXd minvals(ndata);

	double old_e = 0;
	int niters = 100;
	for (int n=0; n < niters; n++) {
		//Save old centres to check for termination
		old_centres = centres;

		// Calculate posteriors based on existing centres
		Eigen::MatrixXd d2(ndata, ncentres);
		for (int j = 0; j < ncentres; j++) {
			for (int k=0; k < ndata; k++) {
				d2(k,j) = (data.row(k)-centres.row(j)).squaredNorm();
			}
		}

		int r,c;
		// Assign each point to nearest centre
		for (int k=0; k < ndata; k++) {
			//get centre index (c)
			minvals[k] = d2.row(k).minCoeff(&r, &c);
			//set centre
			post.row(k) = id.row(c);
		}

		Eigen::VectorXd num_points = post.colwise().sum();
		// Adjust the centres based on new posteriors
		for (int j = 0; j < ncentres; j++) {
			if (num_points[j] > 0) {
				Eigen::MatrixXd s = Eigen::MatrixXd::Zero(1,ndims);
				for (int k=0; k<ndata; k++) {
					if (post(k,j) == 1) {
						s += data.row(k);
					}
				}
				centres.row(j) = s / num_points[j];
			}
		}

		// Error value is total squared distance from cluster centres
		double e = minvals.sum();
		double ediff = fabs(old_e - e);
		double cdiff = (centres-old_centres).array().abs().maxCoeff();
		//std::cout << "Cycle " << n << " Error " << e << " Movement " << cdiff << ", " << ediff << std::endl;

		if (n > 1) {
			//Test for termination
			if (cdiff < 0.0000000001 && ediff < 0.0000000001) {
				break;
			}
		}
		old_e = e;
	}

	//------- finished kmeans ---------

	//find the item closest to the centre for each cluster
	std::vector<std::vector<int> > clustered_items;
	for (int j=0; j < ncentres; j++) {
		//put data into map (multimap because minvals[k] could be the same for multiple units)
		std::multimap<double,int> cluster;
		for (int k=0; k < ndata; k++) {
			if (post(k,j) == 1) {
				cluster.insert(std::make_pair(minvals[k], k));
			}
		}
		//extract data from map
		std::vector<int> units;
		//the map will be sorted based on the key (the minval) so just loop through it
		//to get set of data indices sorted on the minval
		for (std::multimap<double,int>::iterator it = cluster.begin(); it != cluster.end(); it++) {
			units.push_back(it->second);
		}

		clustered_items.push_back(units);
	}
	//return the ordered set of item indices for each cluster centre
	return clustered_items;
}


#include <graphlab.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <limits>
#include <graphlab/engine/warp_engine.hpp>
#include <graphlab/engine/warp_parfor_all_vertices.hpp>
#include <unsupported/Eigen/MatrixFunctions>

#include <Eigen/Dense>

int verbose;
std::vector<double> Hleft;
//#include <functional>

/*

  Total Subgraph Centrality.

  For a graph G with adjacency matrix A, TSC(G) = exp(A)*b, where 1 is
  the ones vector.

  We're going to implement this with an Arnoldi solver, following Saad
  (1992).

  The algorithm works like this:
  Choose a maximum iteration m.  Then make matrices V and H:
  b = ones(A.nodecount)
  V[0] = b/||b||
  for j in 0..m:
      w = A*V[j]
      for i in 0..j:
         H[i,j] = (w,V[i])
	 w = w - H[i,j] * V[i]
      H[j+1,j] = ||w||
      V[j+1] =w/||w||

  Then TSC = exp(A)*b ~= (V * exp(H) / ||b||)[:,0].  Stop when
  successive approximations converge, or we run out of steps.

  We still have that matrix exponential, but it's small and dense, and
  there's an implementation in Eigen.

*/

class node {
public:
std::vector<double> V;
double w;
  double TSC;
  double prev;
  node(): w(0.0),TSC(0.0),prev(0.0){};
  void load(graphlab::iarchive& infile) {
    infile>>V>>w>>TSC>>prev;
  }
  void save(graphlab::oarchive& outfile) const {
    outfile<<V<<w<<TSC<<prev;
  }

};

class edge {
public:
  double weight;
  edge(): weight(1.0) {} ;
  edge(double weight) : weight(weight) {};

  void save(graphlab::oarchive& outfile) const {
    outfile<<weight;
  }

  void load(graphlab::iarchive& infile) {
    infile>>weight;
  }

};

typedef node vertex_data_type;
typedef edge edge_data_type;
typedef graphlab::distributed_graph<vertex_data_type, edge_data_type> graph_type;
typedef graphlab::warp::warp_engine<graph_type> engine_type;

// This is just a little class to be used to find the maximum change in TSC values.
class max_finder{
public:
  double data;
  max_finder& operator+=(const max_finder& other){
    if (this->data <other.data){
      this->data = other.data;
    }
    return *this;
  }

  max_finder(): data(std::numeric_limits<double>::max()) {};
  max_finder(double x): data(x) {};
  void load(graphlab::iarchive& infile) {
    infile>>data;
  }
  void save(graphlab::oarchive& outfile) const {
    outfile<<data;
  }

};

// These three functions compute the A*w step of the
// Arnoldi iteration.
double arnoldi_map(graph_type::edge_type e,
		   graph_type::vertex_type v){
  return v.data().V.back();

}
void arnoldi_combine(double& v1, const double& v2) {
  v1 += v2;
}
void AVj_to_w(graph_type::vertex_type& v) {
  v.data().w = graphlab::warp::map_reduce_neighborhood(v,
						       graphlab::IN_EDGES,
						       arnoldi_map,
						       arnoldi_combine);
  return;
}

// Pushes the current w onto the V matrix
void w_to_v(graph_type::vertex_type& v){
  v.data().V.push_back(v.data().w);
}
// Scales w by a constant factor.  This is meant to be called through transform_vertices
// with a boost::bind to take care of the argument list
void scale_w(graph_type::vertex_type& v, double scale_factor){
  v.data().w /= scale_factor;
}

// Dumps the TSC to stdout
void print_TSC(graph_type::vertex_type& v){
  std::cout<<v.id()<<" " <<v.data().TSC<<std::endl;
}

// For debugging.
void print_w(graph_type::vertex_type& v){
  std::cout<<v.id()<<" " <<v.data().w<<" "<<v.data().V.size()<<" "<<v.data().V.back()<<std::endl;
}

// Make initial vector if we want a column from exp(A)
void initialize_column(graph_type::vertex_type& v, int i,int m) {
  if (v.id()==i){
    v.data().w = 1.0;
  } else{
    v.data().w = 0.0;
  }
  v.data().V.reserve(m);

}
// Make initial vector if we want the TSC
void initialize_TSC(graph_type::vertex_type& v, int m) {
  v.data().w = 1.0/sqrt((double)m);
  v.data().V.reserve(m);
}

// ||w||**2
double sum_w(const graph_type::vertex_type&  v){
  return v.data().w*v.data().w;
}

// w*V[i].  Call via boost::bind to select the i.
double w_dot_V(const graph_type::vertex_type&  v, int i){
  return v.data().w * v.data().V[i];
}

// w - (h,w)*V[i].  Call via boost::bind to set i, hdot.
void w_minus_hdot(graph_type::vertex_type& v, int i, double hdot) {
  v.data().w -= hdot * v.data().V[i];
}

// TSC = V*Hleft
void accumulate_hleft(graph_type::vertex_type&v){
  v.data().prev = v.data().TSC;
  v.data().TSC = 0;
  for(int j=0;j<Hleft.size();j++){
    v.data().TSC += v.data().V[j] * Hleft[j];
  }
  if (verbose){
    if (v.id()<10){
      std::cout<<"TSC "<<v.id()<<" "<<Hleft.size()<<" "<<v.data().TSC<<" "<<v.data().prev<< " "<<(v.data().TSC-v.data().prev)/(1e-15+v.data().TSC) <<std::endl;
    }
  }
  return;
}

// sum ((TSC-prevTSC)/TSC)
double total_error(const graph_type::vertex_type& v){
  return fabs((v.data().TSC-v.data().prev)/(1e-15+v.data().TSC));
}

// max ((TSC-prevTSC)/TSC)
max_finder max_error(const graph_type::vertex_type& v){
  return max_finder(fabs((v.data().TSC-v.data().prev)/(1e-15+v.data().TSC)));
}

int main(int argc, char** argv) {
  graphlab::command_line_options clopts("Total Subgraph Centrality");
  graphlab::distributed_control dc;
  std::string infile;
  std::string format = "tsv";
  int verbose=0;
  int m=100;
  int column = -1;
  clopts.attach_option("graph",infile,"Input graph.");
  clopts.attach_option("format",format,"Input format. Default tsv.");
  clopts.attach_option("m",m,"Maximum number of orthogonal vectors to approximate with. Default 100.");
  clopts.attach_option("column",column,"Column of exponential to calculate (instead of row-sum)");
  clopts.attach_option("verbose",verbose,"Verbosity level.");
  if(!clopts.parse(argc, argv)) {
    dc.cout() << "Error in parsing command line arguments." << std::endl;
    return EXIT_FAILURE;
  }
  if (infile==""){
    dc.cout() <<"ERROR: Must specify --graph! \n";
    return EXIT_FAILURE;
  }
  graph_type graph(dc,clopts);
  graph.load_format(infile, format);
  graph.finalize();
  if (m>graph.num_vertices()) {
    m = graph.num_vertices();
  }
  engine_type engine(dc,graph,clopts);

  engine.signal_all();
  Eigen::MatrixXd H = Eigen::MatrixXd::Zero(m+1,m+1);
  Hleft.resize(m);
  for(int i=0;i<m;i++) { Hleft[i] = 0.0;}
  double beta;
  if (column>=0) {
    if (column>graph.num_vertices()){
      column = 0;
    }
    graph.transform_vertices(boost::bind(initialize_column,_1,column,m));
    beta = 1.0;
  } else {
    graph.transform_vertices(boost::bind(initialize_TSC,_1,m));
    beta = sqrt(m);
  }

  // The first column of V is just w
  graph.transform_vertices(w_to_v);

  for(int j=0;j<m;j++) {
    graphlab::warp::parfor_all_vertices(graph,AVj_to_w);
    // We should be able to move this loop inside the map-reduce and transform steps
    for(int i=0;i<=j;i++) {
      H(i,j)= graph.map_reduce_vertices<double>(boost::bind(w_dot_V,_1,i));
      graph.transform_vertices(boost::bind(w_minus_hdot,_1,i,H(i,j)));
    }
    H(j+1,j)= sqrt(graph.map_reduce_vertices<double>(sum_w));
    // If we're in this case, it means we have a spanning set and we shouldn't
    // prep for the next iteration.  Otherwise, make the data we'll need next time.
    if ( ( !std::isnan(H(j+1,j))) && (H(j+1,j) > 0) ) {
      graph.transform_vertices(boost::bind(scale_w, _1, H(j+1,j)));
      graph.transform_vertices(w_to_v);
    }

    if (j>0) {
      // Have we converged?
      Eigen::MatrixXd EH(H);
      EH = EH.exp();
      Hleft.resize(j+1);

      for(int i=0;i<=j;i++) { Hleft[i] = EH(i,0) * beta;}
      graph.transform_vertices(accumulate_hleft);
      if (j>1) {
 	max_finder largest_error= graph.map_reduce_vertices<max_finder>(max_error);
	double all_error = graph.map_reduce_vertices<double>(total_error);
	if (verbose){
	  std::cerr<<"ARNOLDI STEP FINISHED "<<j<<std::endl;
	  std::cout<<"MAX ERROR: "<<largest_error.data<<" TOTAL ERROR: "<<all_error<<std::endl;
	}
	if (largest_error.data < 1e-15) { break; };
	if (all_error < 1e-15){  break; }
      }
    }
    // If we know we are in the last iteration, break
    if (std::isnan(H(j+1,j))){ break;}
    if (fabs(H(j+1,j))<1e-15){ break;}

  }
  graph.transform_vertices(print_TSC);

}


/******************************************************************************

  Basic N-dimensional topology.

  Copyright (c) 2013
  Dzmitry Hlindzich <hlindzich@gmail.com>
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:
  1.  Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
  2.  Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.

*******************************************************************************/

#ifndef TOPOLOGY_HPP_79A57FE0_9EFD_11E2_9E96_0800200C9A66_
#define TOPOLOGY_HPP_79A57FE0_9EFD_11E2_9E96_0800200C9A66_

#include <vector>
#include <utility>
#include <set>
#include <boost/static_assert.hpp>

#include "bo/core/vector.hpp"

namespace bo {
namespace math {

// Basic N-dimensional hyperrectangle (N-orthotope) geometry.
template <typename RealType, std::size_t N>
class OrthotopeTopology
{
private:
    BOOST_STATIC_ASSERT(N > 0);

public:
    typedef Vector<RealType, N> Point;
    typedef std::pair<Point, Point> Edge;
    typedef std::vector<Edge> Edges;

    // Returns all the edges of a unit N-orthotope.
    static Edges edges()
    {
        // Initialize the source of the edge traverse.
        PointSet in_vertices;
        in_vertices.insert(Point(0));

        // Traverse the edges.
        Edges e;
        traverse_edges(in_vertices, e);

        return e;
    }

    // Returns the number of edges in a N-orthotope.
    static std::size_t edge_count()
    {
        return (1 << (N - 1)) * N;
    }

    // Returns the number of vertices in a N-orthotope.
    static std::size_t vertex_count()
    {
        return 1 << N;
    }

    // Returns the number of facets ((N-1)-dimensional faces) in a N-othotope.
    static std::size_t facet_count()
    {
        return 2 * N;
    }

private:

    typedef std::set<Point> PointSet;

    // Recursively traverses the edges of a N-orthotope starting from the given set
    // of vertices in ascending order and pushes the edges into the given container.
    static void traverse_edges(const PointSet &in_vertices, Edges &edges)
    {
        if (in_vertices.size() == 1 && *in_vertices.begin() == Point(1))
            return;

        PointSet out_vertices;

        for (typename PointSet::const_iterator it = in_vertices.begin(); it != in_vertices.end(); ++it)
        {
            Point edge_begin = *it;

            // Find all adjacent vertices for the current one.
            for (std::size_t k = 0; k < N; ++k)
            {
                if (edge_begin[k] == 1)
                    continue;

                // An adjacent vertex differs only in one dimension.
                Point edge_end = edge_begin;
                edge_end[k] = 1;

                // Insert the edge into the collection.
                edges.push_back(Edge(edge_begin, edge_end));

                // Save the end vertex.
                out_vertices.insert(edge_end);
            }
        }

        traverse_edges(out_vertices, edges);
    }

};

} // namespace math
} // namespace bo

#endif // TOPOLOGY_HPP_79A57FE0_9EFD_11E2_9E96_0800200C9A66_


// Copyright 2020, Madhur Chauhan

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// This is an example to calculate Reciprocal Fibonacci Constant (A079586 in the OEIS)
// compile with flags: -std=c++11 -lmpfr

//[fibonacci_eg

#include <boost/math/special_functions/fibonacci.hpp>
#include <boost/multiprecision/mpfr.hpp>
#include <iomanip>
#include <iostream>

int main() {
    using Real = boost::multiprecision::mpfr_float_1000;
    boost::math::fibonacci_generator<Real> gen;
    gen.set(1); // start producing values from 1st fibonacci number
    Real ans = 0;
    const int ITR = 1000;
    for (int i = 0; i < ITR; ++i) {
        ans += 1.0 / gen();
    }
    std::cout << std::setprecision(1000) << "Reciprocal fibonacci constant after "
              << ITR << " iterations is: " << ans << std::endl;
}

//]


#include "LogisticRegression.h"
#include "TrainingType.h"
#include <armadillo>
#include <assert.h>
#include <iostream>
#include <math.h>

using namespace arma;

LogisticRegression::LogisticRegression(mat &x, vec &y, double regPara)
    : x{x}, y{y}, regPara{regPara}, trained{false} {
  assert(x.n_rows == y.n_rows);

  // Create bias column and append at the end of  x
  mat bias = ones<mat>(this->ExampleNumber(), 1);
  this->x.insert_cols(0, bias);
}

LogisticRegression::~LogisticRegression() {}

void LogisticRegression::AddData(mat &extraX, vec &extraY) {
  assert(extraX.n_rows == extraY.n_rows);
  // Add 1 because x has a bias column
  assert((extraX.n_cols + 1) == this->x.n_cols);

  this->trained = false;
  // Add Bias column to latest added input
  mat bias = ones<mat>(extraX.n_rows, 1);
  mat inputX = extraX;
  inputX.insert_cols(0, bias);
  this->x.insert_rows(this->x.n_rows, inputX);
  this->y.insert_rows(this->y.n_rows, extraY);
}

void LogisticRegression::Train(TrainingType Type, double alpha,
                               unsigned int iters) {
  /*if (Type == normalEquation) {
    this->NormalEquation();
  } else*/
  if (Type == gradientDescent) {
    this->GradientDescent(alpha, iters);
  } else {
    std::cerr << "Invalid training type" << std::endl;
  }
}

uword LogisticRegression::ExampleNumber() { return this->x.n_rows; }

double LogisticRegression::Probablity(vec &x) {
  if (!this->trained) {
    std::cerr << "This model hasn't been trained" << std::endl;
    return 0.0;
  }
  vec bias = vec("1");
  vec input = x;
  input.insert_rows(0, bias);
  double prob = (input.t() * this->theta).eval()(0, 0);
  return prob;
}

double LogisticRegression::Predict(vec &x) {
  double prob = this->Probablity(x);
  if (prob >= probabilityThreshold) {
    return 1;
  } else {
    return 0;
  }
}

arma::mat LogisticRegression::SigmoidFunction(arma::mat inputX) {
  //--     1      --//
  //-- ---------- --//
  //-- 1 + e^(-inpuX) --//
  return 1 / (1 + exp(-inputX));
}

double LogisticRegression::SelfCost() { return this->Cost(this->x); }

double LogisticRegression::Cost(mat &inputX) {
  this->InitializeTheta();
  //--                    h = g(X Theta)                   --//
  //--J(Theta) = 1/m * (-y^T log(h) - (1-y)^T log(1-h)) +lambda/2m theta^2--//
  assert(inputX.n_cols == this->theta.n_rows);
  vec h = this->SigmoidFunction(inputX * this->theta);
  vec ve = (-this->y.t() * log(h)) - ((1 - y).t() * log(1 - h));
  vec thetaWithoutFirst = this->theta;
  thetaWithoutFirst[0] = 0;

  return (1 / (float)this->ExampleNumber() * ve +
          this->regPara / (double)this->ExampleNumber() * 2 *
              thetaWithoutFirst.t() * thetaWithoutFirst)
      .eval()(0, 0);
}

vec LogisticRegression::CostDerivative() {
  vec h = this->SigmoidFunction(this->x * this->theta);
  vec deriv = this->x.t() * (h - this->y);
  vec thetaWithoutFirst = this->theta;
  thetaWithoutFirst[0] = 0;
  return 1 / (double)this->ExampleNumber() * deriv +
         this->regPara / (double)this->ExampleNumber() * thetaWithoutFirst;
}

void LogisticRegression::GradientDescent(double alpha, unsigned int iters) {
  this->InitializeTheta();
  for (unsigned int i = 0; i < iters; i++) {
    this->theta = this->theta - (alpha * this->CostDerivative());
  }

  this->trained = true;
}

void LogisticRegression::InitializeTheta() {
  if (this->trained != true || this->theta.n_rows != this->x.n_cols) {
    // Initialize Theta
    this->theta = zeros<vec>(this->x.n_cols);
  }
}


#include <iostream>
#include <numeric>
#include <type.hpp>

#include <Eigen/Eigen>

#include "FEM/FEM1DApp.hpp"
#include "imgui/implot.h"
#include "Visualization/Visualizer.h"

#include <numeric>

using Linear = PolynomialFEMApp<1>;
using Quadratic = PolynomialFEMApp<2>;

class FEM1DVisualizer :public Visualizer
{
protected:

	void evaluate()
	{
		int segement_ = segemnt;

		if (segement_ % 2 != 0)
		{
			segement_ += 1;
		}

		//Homework 2
		//auto rhs = [](Float x) {return  -4 - x + Power(x, 2) - Power(x, 3) + Power(x, 4) + Cos(x) - 2 * x * Cos(x) - 2 * Sin(x); };
		//auto a = [](Float x) {return sin(x) + 2; };
		//auto c = [](Float x) {return x * x + 1; };
		auto rhs = [](Float x) {return  2 * cos(1 - x) * cos(x) + 2 * sin(1 - x) * sin(x); };
		auto d = [this](Float x) {return 1; };
		auto b = [](Float x) {return 0;	};
		auto c = [](Float x) {return 0; };

		Interval interval(0.0, 1.0);

		interval.SetPartitionCount(segement_);

		StaticFEM1DMG mg_linear(rhs, d, b, c, interval);
		Linear cg_linear(rhs, d, b, c, interval);
		mg_linear.evaluate();
		cg_linear.evaluate();
		for (int i = 0; i < Length; ++i)
		{
			cg_val[i] = cg_linear.Value(1.0 / (Length - 1) * i);
			mg_val[i] = mg_linear.Value(1.0 / (Length - 1) * i);

			cg_diff[i] = cg_val[i] - precise_val[i];
			mg_diff[i] = mg_val[i] - precise_val[i];
		}
	}

	void Control_UI();
	void draw(bool* p_open) override;

	std::vector<Point2d> points;
	bool updated = true;
	int segemnt = 16;
	float epsilon = 1E-7;

	void error(std::vector<float>& ref, std::vector<float>& eval, Float& L_1, Float& L_2, Float& L_inf)
	{
		assert(ref.size() == eval.size());

		std::vector<Float> minus(ref.size());

		for (int i = 0; i < ref.size(); ++i)
		{
			minus[i] = abs(ref[i] - eval[i]);
		}

		L_inf = *std::max_element(minus.begin(), minus.end(), [](Float a, Float b) {return a < b; });
		L_2 = sqrt(std::accumulate(minus.begin(), minus.end(), static_cast<Float>(0), [](Float r, Float a) {return r + a * a; }) / Float(ref.size()));
		L_1 = std::accumulate(minus.begin(), minus.end(), static_cast<Float>(0), [](Float r, Float a) {return r + a; }) / Float(ref.size());
	}

public:
	void CalcAccurateRst()
	{
		Float h = 1.0 / (Length - 1);
		for (int i = 0; i < Length; ++i)
		{
			xs[i] = i * h;

			auto accurate_func = [this](Float x) {return sin(x) * sin(1 - x); };

			precise_val[i] = accurate_func(xs[i]);
		}
	}

	FEM1DVisualizer() {
		CalcAccurateRst();
		segemnt = 16;
		Float L1, L2, L_inf;
		do
		{
			//std::cout << "Segmentations: " << segemnt << std::endl;
			evaluate();

			error(precise_val, mg_val, L1, L2, L_inf);

			using std::cout;
			using std::endl;

			//if (segemnt == 16)
			//{
			//	cout << segemnt << '&' << L1 << '&' << '-' << '&' << L2 << '&' << '-' << '&' << L_inf << '&' << '-' << "\\\\" << endl;
			//}
			//else
			//	cout << segemnt << '&' << L1 << '&' <<- log2(L1 / linear_L1.back()) << '&' << L2 << '&' << -log2(L2 / mg_L2.back()) << '&' << L_inf << '&' << -log2(L_inf / mg_Linf.back()) << "\\\\" << endl;

			pointcount.push_back(segemnt);
			mg_L1.push_back(L1);
			mg_L2.push_back(L2);
			mg_Linf.push_back(L_inf);
			error(precise_val, cg_val, L1, L2, L_inf);

			//if (segemnt == 16)
			//{
			//	cout << segemnt << '&' << L1 << '&' << '-' << '&' << L2 << '&' << '-' << '&' << L_inf << '&' << '-' << "\\\\" << endl;
			//}
			//else
			//	cout << segemnt << '&' << L1 << '&' << -log2(L1 / cg_L1.back()) << '&' << L2 << '&' << -log2(L2 / cg_L2.back()) << '&' << L_inf << '&' << -log2(L_inf / cg_Linf.back()) << "\\\\" << endl;

			cg_L1.push_back(L1);
			cg_L2.push_back(L2);
			cg_Linf.push_back(L_inf);

			segemnt *= 2;
		} while (segemnt != 8192);
		segemnt = 16;

		evaluate();
	}
	const size_t Length = 10001;

	std::vector<float> xs = std::vector<float>(Length);
	std::vector<float> precise_val = std::vector<float>(Length);
	std::vector<float> cg_val = std::vector<float>(Length);
	std::vector<float> mg_val = std::vector<float>(Length);
	std::vector<float> cg_diff = std::vector<float>(Length);
	std::vector<float> mg_diff = std::vector<float>(Length);

	std::vector<float> pointcount;
	std::vector<float> mg_L1;
	std::vector<float> mg_L2;
	std::vector<float> mg_Linf;

	std::vector<float> cg_L1;
	std::vector<float> cg_L2;
	std::vector<float> cg_Linf;
};

static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }

void FEM1DVisualizer::Control_UI()
{
	if (ImGui::SliderInt("Number of segments", &segemnt, 3, 200))
	{
		segemnt = segemnt < 2 ? 2 : segemnt;
		evaluate();
	}
	if (ImGui::SliderFloat("Epsilon", &epsilon, 1E-7, 1E-1, "%.8f", ImGuiSliderFlags_Logarithmic))
	{
		evaluate();
		CalcAccurateRst();
	}
}

void FEM1DVisualizer::draw(bool* p_open)
{
	if (ImGui::BeginTabBar("FEM 1D App")) {
		if (ImGui::BeginTabItem("FEM1D"))
		{
			if (ImPlot::BeginPlot("Line Plot", "x", "f(x)", ImGui::GetContentRegionAvail() - ImVec2(0, 100), ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMenus)) {
				ImPlot::PlotLine("Precise solution", &xs[0], &precise_val[0], Length);
				ImPlot::PlotLine("FEM Conjugate Gradient", &xs[0], &cg_val[0], Length);
				ImPlot::PlotLine("FEM Multigrid", &xs[0], &mg_val[0], Length);

				ImPlot::EndPlot();
			}
			Control_UI();
			ImGui::EndTabItem();
		}
		if (ImGui::BeginTabItem("FEM1D difference"))
		{
			if (ImPlot::BeginPlot("Line Plot", "x", "f(x)", ImGui::GetContentRegionAvail() - ImVec2(0, 100), ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMenus)) {
				ImPlot::PlotLine("FEM diff Multigrid", &xs[0], &mg_diff[0], Length);
				ImPlot::PlotLine("FEM diff Conjugate Gradient", &xs[0], &cg_diff[0], Length);

				ImPlot::EndPlot();
			}
			Control_UI();
			ImGui::EndTabItem();
		}

		if (ImGui::BeginTabItem("Error Plot"))
		{
			if (ImPlot::BeginPlot("Line Plot", "x", "f(x)", ImGui::GetContentRegionAvail() - ImVec2(0, 100), ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMenus, ImPlotAxisFlags_LogScale, ImPlotAxisFlags_LogScale)) {
				ImPlot::PlotLine("Multigrid L1    Error", &pointcount[0], &mg_L1[0], pointcount.size());
				ImPlot::PlotLine("Multigrid L2    Error", &pointcount[0], &mg_L2[0], pointcount.size());
				ImPlot::PlotLine("Multigrid L_inf Error", &pointcount[0], &mg_Linf[0], pointcount.size());

				ImPlot::PlotLine("Conjugate Gradient L1    Error", &pointcount[0], &cg_L1[0], pointcount.size());
				ImPlot::PlotLine("Conjugate Gradient L2    Error", &pointcount[0], &cg_L2[0], pointcount.size());
				ImPlot::PlotLine("Conjugate Gradient L_inf Error", &pointcount[0], &cg_Linf[0], pointcount.size());

				ImPlot::EndPlot();
			}

			ImGui::EndTabItem();
		}
		ImGui::EndTabBar();
	}

	ImGui::End();
}

int main()
{
	FEM1DVisualizer visualizer;
	visualizer.RenderLoop();
}


#include <Eigen/Dense>
extern "C"
{
#include "induct.h"
}

//#include <cmath>

/*Starts by applying QR decomposition using the householder transform and then applies
SVD to obtain the recompressed U and V matrices.
The Eigen Library is used to assist in computing QR and SVD.*/
int SVD_QR(double **U, double **V, int m, int n, int rank, double tol)
{
	using namespace Eigen;

	MatrixXd U2(m, rank);
	MatrixXd V2(n, rank);
	MatrixXd Q_u(m, rank);
	MatrixXd R_u(rank, rank);
	MatrixXd Q_v(n, rank);
	MatrixXd R_v(rank, rank);

	int new_rank = 0;

	for (int i = 0; i < rank; i++)
	{
		for (int j = 0; j < m; j++)
		{
			U2(j, i) = U[i][j];
		}
		for (int j = 0; j < n; j++)
		{
			V2(j, i) = V[i][j];
		}
	}

	HouseholderQR<MatrixXd> qr(U2);
	Q_u = qr.householderQ()* MatrixXd::Identity(m, rank);

	R_u = Q_u.transpose()*U2;

	HouseholderQR<MatrixXd> qr2(V2);
	//Q_v = V2.colPivHouseholderQr().householderQ().setLength(V2.colPivHouseholderQr().nonzeroPivots());
	Q_v = qr2.householderQ()*MatrixXd::Identity(n, rank);

	//R_v = V2.colPivHouseholderQr().matrixR().topLeftCorner(rank, rank).template triangularView<Upper>();
	R_v = Q_v.transpose()*V2;

	JacobiSVD<MatrixXd> svd(R_u*R_v.transpose(), ComputeFullU | ComputeFullV);
	//BDCSVD<MatrixXd> svd(R_u.block(0, 0, rank, rank)*R_v.transpose().block(0, 0, rank, rank), ComputeFullU | ComputeFullV);

	for (int i = 0; i < rank; i++)
	{
		if (svd.singularValues()(i) >= tol*svd.singularValues()(0))
		{
			++new_rank;
		}
		else
		{
			for (int j = 0; j < m; j++)
			{
				U[i][j] = 0;
			}
			for (int j = 0; j < n; j++)
			{
				V[i][j] = 0;
			}
		}
	}

	double temp_U = 0;
	double temp_V = 0;
	MatrixXd U_temp(new_rank, new_rank);

	for (int i = 0; i < new_rank; i++)
	{
		for (int j = 0; j < new_rank; j++)
		{
			U_temp(i, j) = svd.matrixU()(j, i)*svd.singularValues()(i);//check
		}
	}

	for (int i = 0; i < m; i++)
	{
		for (int k = 0; k < new_rank; k++)
		{

			for (int j = 0; j < new_rank; j++)
			{
				temp_U += Q_u(i, j)*U_temp(k, j);
			}
			U[k][i] = temp_U;
			temp_U = 0;
		}
	}

	for (int i = 0; i < n; i++)
	{
		for (int k = 0; k < new_rank; k++)
		{

			for (int j = 0; j < new_rank; j++)
			{
				temp_V += Q_v(i, j)*svd.matrixV()(j, k);
			}
			V[k][i] = temp_V;
			temp_V = 0;
		}
	}
	return new_rank;
}


//! [nbody-all]
#include <chrono>
#include <vector>
#include <iostream>
#include <cmath>

#include <boost/simd/pack.hpp>
#include <boost/simd/function/aligned_load.hpp>
#include <boost/simd/function/aligned_store.hpp>
#include <boost/simd/function/sqrt.hpp>

#include <boost/simd/memory/allocator.hpp>

typedef float T;
namespace bs = boost::simd;
using pack_t = bs::pack<T>;

struct particles
{
  std::vector<T, bs::allocator<T>> x, y, z, m, vx, vy, vz;
  std::size_t size_;

  particles(std::size_t size) : size_(size)
                              , x(size + pack_t::static_size)
                              , y(size + pack_t::static_size)
                              , z(size + pack_t::static_size)
                              , m(size + pack_t::static_size)
                              , vx(size + pack_t::static_size)
                              , vy(size + pack_t::static_size)
                              , vz(size + pack_t::static_size)
  {}

  std::size_t size() const {return size_;}
};

//! [nbody-simd]
void nbody_step(particles & ps)
{
  pack_t grav_con {6.67408e-11};
  pack_t epsilon {0.00125f};
  for(std::size_t i = 0 ; i <ps.size() ; i += pack_t::static_size)
  {
    pack_t ax{0};
    pack_t ay{0};
    pack_t az{0};

    pack_t pix{&ps.x[i]};
    pack_t piy{&ps.y[i]};
    pack_t piz{&ps.z[i]};

    pack_t pim {&ps.m[ i ]};

    for(std::size_t j = i + 1 ; j <ps.size() ; ++j)
    {
      auto pjx = bs::load<pack_t>(&ps.x[ j ]);
      auto pjy = bs::load<pack_t>(&ps.y[ j ]);
      auto pjz = bs::load<pack_t>(&ps.z[ j ]);

      auto dx = pjx - pix;
      auto dy = pjy - piy;
      auto dz = pjz - piz;

      auto inorm = grav_con / bs::sqrt(dx * dx + dy * dy + dz * dz + epsilon);
      auto inorm3 = inorm * inorm *inorm;

      auto fi = bs::load<pack_t>(&ps.m[ j ]) * inorm3;
      auto fj = pim * inorm3;

      ax += dx * fi;
      ay += dy * fi;
      az += dz * fi;

      auto pjvx = bs::load<pack_t>(&ps.vx[ j ]);
      pjvx -= dx * fj;
      bs::store(pjvx, &ps.vx[ j ]);
      auto pjvy = bs::load<pack_t>(&ps.vy[ j ]);
      pjvy -= dy * fj;
      bs::store(pjvy, &ps.vy[ j ]);
      auto pjvz = bs::load<pack_t>(&ps.vz[ j ]);
      pjvz -= dz * fj;
      bs::store(pjvz, &ps.vz[ j ]);
    }

    pack_t pivx {&ps.vx[ i ]};
    pack_t pivy {&ps.vy[ i ]};
    pack_t pivz {&ps.vz[ i ]};

    pivx += ax;
    pivy += ay;
    pivz += az;

    pix += pivx;
    piy += pivy;
    piz += pivz;

    bs::aligned_store(pivx, &ps.vx[ i ]);
    bs::aligned_store(pivy, &ps.vy[ i ]);
    bs::aligned_store(pivz, &ps.vz[ i ]);

    bs::aligned_store(pix, &ps.x[ i ]);
    bs::aligned_store(piy, &ps.y[ i ]);
    bs::aligned_store(piz, &ps.z[ i ]);
  }
}
//! [nbody-simd]

//! [nbody-scalar]
void nbody_step_scalar(particles & ps)
{
  T epsilon = 0.00125f;
  for(std::size_t i = 0 ; i <ps.size() ; ++i)
  {
    T ax{0};
    T ay{0};
    T az{0};

    T pix = ps.x[ i ];
    T piy = ps.y[ i ];
    T piz = ps.z[ i ];

    T pim = ps.m[ i ];

    for(std::size_t j = i + 1 ; j <ps.size() ; ++j)
    {
      T pjx = ps.x[ j ];
      T pjy = ps.y[ j ];
      T pjz = ps.z[ j ];

      T dx = pjx - pix;
      T dy = pjy - piy;
      T dz = pjz - piz;

      T inorm = 6.667408e-11 / std::sqrt(dx * dx + dy * dy + dz * dz + epsilon);

      T fi = ps.m[ j ] * inorm * inorm * inorm;
      T fj = pim * inorm * inorm * inorm;

      ax += dx * fi;
      ay += dy * fi;
      az += dz * fi;

      ps.vx[ j ] -= dx * fj;
      ps.vy[ j ] -= dy * fj;
      ps.vz[ j ] -= dz * fj;
    }

    T pivx = ps.vx[ i ];
    T pivy = ps.vy[ i ];
    T pivz = ps.vz[ i ];

    pivx += ax;
    pivy += ay;
    pivz += az;

    pix += pivx;
    piy += pivy;
    piz += pivz;

    ps.vx[ i ] = pivx;
    ps.vy[ i ] = pivy;
    ps.vz[ i ] = pivz;

    ps.x[ i ]  = pix;
    ps.y[ i ]  = piy;
    ps.z[ i ]  = piz;
  }
}
//! [nbody-scalar]

int main(int argc, char * argv[])
{
  std::size_t size  = 4096
    , steps = 10;

  if(argc != 3)
  {
    std::cerr <<"E: Incorrect number of arguments, using " <<size <<" particles and " <<steps <<" steps." <<std::endl;
  }
  else {
    size  = std::stoll(argv[ 1 ], 0, 10);
    steps = std::stoll(argv[ 2 ], 0, 10);
  }

  particles ps_scalar(size);
  particles ps_simd(size);

  for(std::size_t i = 0 ; i <size ; ++i)
  {
    ps_scalar.x[ i ] = (0.5f + i - size / 2) * 10.0f;
    ps_scalar.y[ i ] = 0.0f;
    ps_scalar.z[ i ] = 0.0f;
    ps_scalar.m[ i ] = 1.0f;
    ps_simd.x[ i ] = (0.5f + i - size / 2) * 10.0f;
    ps_simd.y[ i ] = 0.0f;
    ps_simd.z[ i ] = 0.0f;
    ps_simd.m[ i ] = 1.0f;
  }

  auto start = std::chrono::system_clock::now();

  for(std::size_t step = 0 ; step <steps ; ++step)
  {
    nbody_step_scalar(ps_scalar);
  }

  auto stop = std::chrono::system_clock::now();

  auto duration = stop - start;

  std::cout <<" Time scalar: " <<std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() <<std::endl;

  start = std::chrono::system_clock::now();

  for(std::size_t step = 0 ; step <steps ; ++step)
  {
    nbody_step(ps_simd);
  }

  stop = std::chrono::system_clock::now();

  duration = stop - start;

  std::cout <<" Time SIMD: " <<std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() <<std::endl;

  if(size < 64)
  {
    for(std::size_t i = 0 ; i <ps_scalar.size() ; ++i)
    {
      std::cout <<"(" <<ps_scalar.x[ i ] <<", " <<ps_scalar.y[ i ] << ", " <<ps_scalar.z[ i ] <<")" <<std::endl;
      std::cout <<"(" <<ps_simd.x[ i ] <<", " <<ps_simd.y[ i ] << ", " <<ps_simd.z[ i ] <<")" <<std::endl;
    }
  }
  return 0;
}
//! [nbody-all]


#include <Eigen/Eigen>
#include <Eigen/Dense>
#include <Eigen/Cholesky>
#include <iostream>
#include <chrono>
#include <cstdlib>

/*
This code is entirely based on the examples from Eigen.
This file simply creates dynamic sized symmetric positive definite matrices and calls Eigen/Cholesky and times the calls.
Eigen can use MKL if installed, but for the purposes of this test, MKL was not used as MKL was tested separately already.
If using Eigen in a real-life project, you may want to use Eigen with MKL.
See instruction on Eigen's website: https://eigen.tuxfamily.org/dox/TopicUsingIntelMKL.html
*/

using namespace Eigen;
namespace cn = std::chrono;
cn::time_point<cn::high_resolution_clock> startTimer()
{
	return cn::high_resolution_clock::now();
}

double endTimer(cn::time_point<cn::high_resolution_clock> t1)
{
	auto t2 = cn::high_resolution_clock::now();
	cn::duration<double> diff = t2 - t1;
	return diff.count() * 1000;
}

MatrixXf genRandomPosDefMatrix(int size)
{
	srand(111970);
	// Generate random matrix
	MatrixXf M(size, size);
	for (int i = 0; i < size; i++)
		for (int j = 0; j < size; j++)
			M(i, j) = (float)rand() / RAND_MAX;
	// prod = M^T M to guarantee positive-definite
	MatrixXf MT = M.transpose();
	MatrixXf prod(size, size);
	prod = MT * M;
	return prod;
}

int main(int argc, const char * argv[])
{
	int numRuns = 10;
	for(int mSize = 4; mSize <= 4096; mSize *= 2)
	{
		MatrixXf A = genRandomPosDefMatrix(mSize);
		MatrixXf L(mSize,mSize);

		//Warm up run
		L = A.ldlt().matrixL();

		auto t1 = startTimer();
		for(int i = 0; i < numRuns; i++)
			L = A.llt().matrixL();
		auto time1 = endTimer(t1)/numRuns;
		//std::cout << "The Cholesky factor L is" << std::endl << L << std::endl;
		std::cout << mSize << "\t\t" << time1 << " ms"<< std::endl;
	}
	return 0;
}


#include <iostream>
#include <cmath>

#include <Eigen/Core>
// Eigen 几何模块
#include <Eigen/Geometry>
#include <Eigen/SVD>

#include <chrono>
using namespace std::chrono;
using namespace std;

/****************************
* 本程序演示了 Eigen 几何模块的使用方法
****************************/

// TO-DO: 搞清楚四元数的顺序问题，明天去填下。

int main ( int argc, char** argv )
{
    // Eigen/Geometry 模块提供了各种旋转和平移的表示
    // 3D 旋转矩阵直接使用 Matrix3d 或 Matrix3f
    Eigen::Matrix3d rotation_matrix = Eigen::Matrix3d::Identity();
    // 旋转向量使用 AngleAxis, 它底层不直接是Matrix，但运算可以当作矩阵（因为重载了运算符）
    // 构造函数初始化
    Eigen::AngleAxisd rotation_vector ( M_PI/4, Eigen::Vector3d ( 0,0,1 ) );     //沿 Z 轴旋转 45 度
    // 保留三位小数！
    cout .precision(3);
    // 将旋转向量用矩阵的形式表征出来
    cout<<"rotation matrix =\n"<<rotation_vector.matrix() <<endl;                //用matrix()转换成矩阵
    // 将旋转向量形式转换成旋转矩阵形式
    cout<<"rotation matrix =\n"<<rotation_vector.toRotationMatrix() <<endl;
    rotation_matrix = rotation_vector.toRotationMatrix();

    // 定义了一个待旋转的向量
    Eigen::Vector3d v ( 1,0,0 );
    // 这里应该是重载<<的时候存在顺序的问题，因此需要加上transpose来正确显示想要展示的内容
    cout<<"(1,0,0) before rotation = "<<v.transpose()<<endl;
    // 用 AngleAxis 可以进行坐标变换
    // 里面应该是重载了*运算符
    Eigen::Vector3d v_rotated = rotation_vector * v;
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;
    // 或者用旋转矩阵，效果一样，同理重载
    v_rotated = rotation_matrix * v;
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl;

    // 欧拉角: 可以将旋转矩阵直接转换成欧拉角
    // 这里的2,1,0分别代指ZYX，表示先后以这三个为轴旋转
    Eigen::Vector3d euler_angles = rotation_matrix.eulerAngles ( 2,1,0 ); // ZYX顺序，即roll pitch yaw顺序
    cout<<"yaw pitch roll = "<<euler_angles.transpose()<<endl;

    // 欧式变换，包括了旋转与平移
    // 欧氏变换矩阵使用 Eigen::Isometry（等距）
    Eigen::Isometry3d T=Eigen::Isometry3d::Identity();    // 虽然称为3d，实质上是4＊4的矩阵
    // 通过调用成员函数的方式来赋值
    T.rotate ( rotation_vector );                         // 按照rotation_vector进行旋转
    // pretranslate函数用于inital position setting
    // Applies on the right the translation matrix represented by the vector
    T.pretranslate ( Eigen::Vector3d ( 1,3,4 ) );         // 把平移向量设成(1,3,4)
    cout << "Transform matrix = \n" << T.matrix() <<endl;

    Eigen::Matrix3d rotation_T = T.rotation();
    cout<<"---- T ---- rotation matrix  =\n"<<rotation_T <<endl;

    Eigen::Quaterniond q_T = Eigen::Quaterniond ( rotation_T );
    cout<<"---- T ---- quaternion = \n"<<q_T.coeffs() <<endl;

    Eigen::Vector3d translation_T = T.translation();
    cout<<"---- T ---- translation = \n"<<translation_T.transpose() <<endl;

    // 用变换矩阵进行坐标变换，v是（1，0，0）
    Eigen::Vector3d v_transformed = T*v;                              // 相当于R*v+t，理解！
    cout<<"v tranformed = "<<v_transformed.transpose()<<endl;         // 结果正确

    // 对于仿射和射影变换，使用 Eigen::Affine3d 和 Eigen::Projective3d 即可，略

    // 四元数
    // 可以直接把AngleAxis赋值给四元数，反之亦然，也就是用角轴转成四元数
    Eigen::Quaterniond q = Eigen::Quaterniond ( rotation_vector );
    cout<<"quaternion = \n"<<q.coeffs() <<endl;   // 请注意coeffs的顺序是(x,y,z,w),w为实部，前三者为虚部，顺序不一样

    Eigen::Quaterniond q1(0.924, 0, 0, 0.383); // 赋值的时候是w,x,y,z
    cout<<"quaternion1 = \n"<<q1.coeffs() <<endl;

    // 也可以把旋转矩阵赋给它，结果一样！
    Eigen::Quaterniond q2 = Eigen::Quaterniond ( rotation_matrix );
    cout<<"quaternion = \n"<<q2.coeffs() <<endl;

    cout<<"--- rotation matrix =\n"<<q2.toRotationMatrix() <<endl;

    // 使用四元数旋转一个向量，使用重载的乘法即可
    v_rotated = q*v; // 注意数学上是qvq^{-1}
    cout<<"(1,0,0) after rotation = "<<v_rotated.transpose()<<endl; //结果正确

    auto t0 = std::chrono::high_resolution_clock::now();
    Eigen::Quaterniond quat = Eigen::Quaterniond ( T.rotation() );
    Eigen::Vector3d pos = T.translation();
    std::cout <<"time is " << std::chrono::duration_cast<std::chrono::nanoseconds> (std::chrono::high_resolution_clock::now() - t0).count()<< '\n';

    Eigen::Matrix4d T_m = Eigen::Matrix4d::Identity();
    T_m.block<3, 3>(0, 0) = rotation_matrix;
    T_m.block<3, 1>(0, 3) = Eigen::Vector3d ( 1,3,4 );
    cout << "Transform matrix = \n" << T_m <<endl;
    cout << "Rotation matrix= \n" << T_m.block<3, 3>(0, 0) << endl;
    cout << "Translation matrix= \n" << T_m.block<3, 1>(0, 3) << endl;

    // Test if Quaterniond only takes normalized rotation matrix
    cout << "Rotation matrix= \n" << rotation_matrix << endl;
    rotation_matrix *= 2.0;
    cout << "Rotation matrix= \n" << rotation_matrix << endl;
    double scale = std::sqrt((rotation_matrix.transpose() * rotation_matrix)(0, 0));
    Eigen::Matrix3d ret = (1. / scale) * rotation_matrix;
    Eigen::Matrix3d rotation_matrix_quat = Eigen::Quaterniond ( ret ).normalized().toRotationMatrix();;
    cout << "Rotation matrix= \n" << rotation_matrix_quat << endl;

    return 0;
}


#pragma once

#include <armadillo>
#include "../guia2/estructura_capas_red.cpp"

using namespace std;
using namespace arma;

namespace ic {

vec sigmoid(const vec& v)
{
	return 2 / (1 + exp(-v)) - 1;
}

vec winnerTakesAll(const vec& v)
{
	if (v.n_elem == 1)
		// Si la red tiene una sola salida, aplicar la función signo
		return v(0) >= 0 ? vec{1} : vec{-1};
	else {
		vec result = v;
		// Si la red tiene varias salidas, asignarle +1 a "la que ganó"
		// y -1 a las demás.
		const double maximo = max(result);

		result.transform([maximo](double val) {
            // Comparación de igualdad de números de coma flotante
            if (abs(val - maximo) < 1e-9)
                return 1;
            else
                return -1;
		});

		return result;
	}
}

vector<vec> salidaMulticapa(const vector<mat>& pesos,
                            const vec& patron)
{
	vector<vec> ySalidas;

	// Calculo de la salida para la primer capa
	{
		const vec v = pesos[0] * join_vert(vec{-1}, patron); // agrega entrada correspondiente al sesgo
		ySalidas.push_back(sigmoid(v));
	}

	// Calculo de las salidas para las demas capas
	for (unsigned int i = 1; i < pesos.size(); ++i) {
		const vec v = pesos[i] * join_vert(vec{-1}, ySalidas[i - 1]); // agrega entrada correspondiente al sesgo
		ySalidas.push_back(sigmoid(v));                               // TODO: ver qué valor le pasamos como parámetro
		                                                              // a la sigmoidea
	}

	return ySalidas;
}

double errorCuadraticoMulticapa(const vector<mat>& pesos,
                                const mat& patrones,
                                const mat& salidaDeseada)
{
	double errorCuadraticoTotal = 0;

	for (unsigned int n = 0; n < patrones.n_rows; ++n) {
		vector<vec> ySalidas = salidaMulticapa(pesos, patrones.row(n).t());
		const vec salidaRed = ySalidas.back();

		const double errorCuadraticoPatron = sum(pow(salidaDeseada.row(n).t() - salidaRed, 2));
		errorCuadraticoTotal += errorCuadraticoPatron;
	}

	return errorCuadraticoTotal;
}

double errorClasificacionMulticapa(const vector<mat>& pesos,
                                   const mat& patrones,
                                   const mat& salidaDeseada)
{
	int errores = 0;

	for (unsigned int n = 0; n < patrones.n_rows; ++n) {
		vector<vec> ySalidas = salidaMulticapa(pesos, patrones.row(n).t());

		const vec salidaRed = winnerTakesAll(ySalidas.back()); // fija los valores en -1 o 1.

		if (any(salidaRed.t() != salidaDeseada.row(n)))
			++errores;
	}

	double tasaError = static_cast<double>(errores) / patrones.n_rows * 100;

	return tasaError;
}

double errorClasificacionMulticapa(const vector<mat>& pesos,
                                   const mat& datos)
{
	const int nEntradas = pesos.front().n_cols - 1;
	const int nSalidas = pesos.back().n_rows;
	if (nEntradas + nSalidas != int(datos.n_cols))
		throw runtime_error("Están mal calculados el número de entradas y salidas");

	return errorClasificacionMulticapa(pesos,
	                                   datos.head_cols(nEntradas),
	                                   datos.tail_cols(nSalidas));
}

pair<vector<mat>, double> epocaMulticapa(const mat& patrones,
                                         const mat& salidaDeseada,
                                         double tasaAprendizaje,
                                         double inercia,
                                         vector<mat> pesos)
{
	//Entrenamiento
	vector<mat> deltaWOld;
	for (unsigned int i = 0; i < pesos.size(); ++i)
		deltaWOld.push_back(zeros(size(pesos[i])));

	for (unsigned int n = 0; n < patrones.n_rows; ++n) {
		// Calcular las salidas para cada capa
		const vector<vec> ySalidas = salidaMulticapa(pesos, patrones.row(n).t());

		// Calculo del error
		const vec error = salidaDeseada.row(n).t() - ySalidas.back();

		// Calculo retropropagacion
		// Calculo de gradiente error local instantaneo
		vector<vec> delta;
		// Tenemos tantos vectores de deltas como capas
		delta.resize(ySalidas.size());

		// Delta de ultima capa
		delta[delta.size() - 1] = error
		                          % (1 + ySalidas.back())
		                          % (1 - ySalidas.back());
		// Deltas de las capas anteriores
		for (int i = ySalidas.size() - 2; i >= 0; --i) {
			// No participan los pesos correspondientes al sesgo en el cálculo de los deltas
			const mat pesosAux = pesos[i + 1].tail_cols(pesos[i + 1].n_cols - 1);
			delta[i] = (pesosAux.t() * delta[i + 1])
			           % (1 + ySalidas[i])
			           % (1 - ySalidas[i]);
		}

        // Actualizacion de pesos de todas las capas menos la primera.
        // Si la red tiene una sola capa, no se entra acá.
		for (int i = pesos.size() - 1; i >= 1; --i) {
			const mat deltaWnuevo = tasaAprendizaje
			                            * delta[i]
			                            * join_horiz(vec{-1}, ySalidas[i - 1].t())
			                        + inercia * deltaWOld[i];
			pesos[i] += deltaWnuevo;
			deltaWOld[i] = deltaWnuevo;
		}

		// Actualización de pesos de la primer capa
		const mat deltaW = tasaAprendizaje
		                       * delta[0]
		                       * join_horiz(vec{-1}, patrones.row(n))
		                   + inercia * deltaWOld[0];
		pesos[0] += deltaW;
		deltaWOld[0] = deltaW;
	}

	// Calculo de Tasa de error
	double tasaError = errorClasificacionMulticapa(pesos, patrones, salidaDeseada);

	return {pesos, tasaError};
} // fin funcion Epoca

tuple<vector<mat>, vec, vec, int> entrenarMulticapa(const EstructuraCapasRed& estructura,
                                                    const mat& datos,
                                                    int nEpocas,
                                                    double tasaAprendizaje,
                                                    double inercia,
                                                    double toleranciaErrorClasificacion,
                                                    long long semilla = -1)
{
	const int nSalidas = estructura(estructura.n_elem - 1);
	const int nEntradas = datos.n_cols - nSalidas;
	const int nCapas = estructura.n_elem;
	// Vamos a tener tantas columnas en salidaDeseada
	// como neuronas en la capa de salida
	const mat salidaDeseada = datos.tail_cols(nSalidas);
	// Extender la matriz de patrones con la entrada correspondiente al umbral
	const mat patrones = datos.head_cols(nEntradas);

	// Inicializar pesos y tasa de error
	vector<mat> pesos;

#pragma omp critical(inicializarPesos)
	{
		if (semilla != -1)
			arma_rng::set_seed(semilla);

		// La primer matriz matriz de pesos tiene tantas filas como neuronas en la primer capa
		// y tantas columnas como componentes tiene la entrada, más la entrada correspondiente
		// al sesgo.
		pesos.push_back(randu(estructura(0), nEntradas + 1) - 0.5);

		for (int i = 1; i < nCapas; ++i) {
			// Las siguientes matrices de pesos tienen tantas filas como neuronas en dicha capa
			// y tantas columnas como entradas a esa capa, que van a ser las salidas de
			// la capa anterior mas la entrada correspondiente al sesgo.
			// Las salidas de la capa anterior es igual al nro de neuronas en la capa anterior.
			pesos.push_back(randu(estructura(i), estructura(i - 1) + 1) - 0.5);
		}
	}

	double tasaError = 100;
	vec erroresClasificacion;
	vec erroresCuadraticos;

	// Ciclo de las epocas
	int epoca = 1;
	for (; epoca <= nEpocas; ++epoca) {
		// Ciclo para una época
		tie(pesos, tasaError) = epocaMulticapa(patrones,
		                                       salidaDeseada,
		                                       tasaAprendizaje,
		                                       inercia,
		                                       pesos);

		erroresClasificacion.insert_rows(erroresClasificacion.n_elem, vec{tasaError});
		const double errorCuadratico = errorCuadraticoMulticapa(pesos, patrones, salidaDeseada);
		erroresCuadraticos.insert_rows(epoca - 1, vec{errorCuadratico});

		if (tasaError <= toleranciaErrorClasificacion)
			break;
	}
	// Fin ciclo (epocas)

	// Si el bucle anterior no cortó por tolerancia de error,
	// el for va a incrementar la variable una vez de más.
	if (epoca > nEpocas)
		epoca = nEpocas;

	return make_tuple(pesos, erroresClasificacion, erroresCuadraticos, epoca);
}

struct ParametrosMulticapa {
	EstructuraCapasRed estructuraRed;
	int nEpocas;
	double tasaAprendizaje;
	double inercia;
	double toleranciaError;
};
}

istream& operator>>(istream& is, ic::ParametrosMulticapa& parametros)
{
	// Formato:
	// estructura: [3 2 1]
	// n_epocas: 200
	// tasa_entrenamiento: 0.1
	// inercia: 0.5
	// parametro_sigmoidea: 1
	// tolerancia_error: 5
	string str;

	// No chequeamos si la etiqueta de cada línea está bien o no. No nos importa
	is >> str >> parametros.estructuraRed
	    >> str >> parametros.nEpocas
	    >> str >> parametros.tasaAprendizaje
	    >> str >> parametros.inercia
	    >> str >> parametros.toleranciaError;

	// Control básico de valores de parámetros
	if (parametros.nEpocas <= 0
	    || parametros.tasaAprendizaje <= 0
	    || parametros.toleranciaError <= 0
	    || parametros.toleranciaError >= 100)
		is.clear(ios::failbit);

	return is;
}


#include <Eigen/Core>
#include <Eigen/Dense>
#include <CGAL/barycenter.h>
#include <CGAL/Simple_cartesian.h>
#include <boost/iterator/transform_iterator.hpp>

// Typedefs.
using Kernel   = CGAL::Simple_cartesian<double>;
using Point_2  = Kernel::Point_2;
using VectorXd = Eigen::VectorXd;
using MatrixXd = Eigen::MatrixXd;

using Output_iterator =
  std::back_insert_iterator< std::vector<double> >;

int main() {

  // Create a set of vertices.
  const std::vector<Point_2> vertices = {
    Point_2(0.0, 0.0), Point_2(0.75, 0.25), Point_2(0.5, 0.5), Point_2(0.4, -0.2) };

  // Create a set of query points.
  const std::vector<Point_2> queries = {
    Point_2(0.2, 0.2), Point_2(0.3, 0.3), Point_2(0.4, 0.4) };

  // Create a lambda function with affine coordinates.
  // This implementation is based on the following paper:
  // S. Waldron. Affine generalized barycentric coordinates.
  // Jaen Journal on Approximation, 3(2):209-226, 2011.
  // This function is a model of the `AnalyticWeights_2` concept.
  const auto affine = [&](
    const Point_2& query,
    Output_iterator coordinates) {

    const std::size_t n = vertices.size();
    const auto lambda = [](const Point_2& p){ return std::make_pair(p, 1.0); };
    const Point_2 b = CGAL::barycenter(
      boost::make_transform_iterator(vertices.begin(), lambda),
      boost::make_transform_iterator(vertices.end()  , lambda), Kernel());

    MatrixXd V(2, n);
    for (std::size_t i = 0; i < n; ++i) {
      V(0, i) = vertices[i].x() - b.x();
      V(1, i) = vertices[i].y() - b.y();
    }

    const auto A   = V.adjoint();
    const auto mat = V * A;
    const auto inv = mat.inverse();

    Point_2 diff; VectorXd vec(2);
    for (std::size_t i = 0; i < n; ++i) {
      const double x = query.x() - b.x();
      const double y = query.y() - b.y();
      diff = Point_2(x, y);

      vec(0) = V(0, i);
      vec(1) = V(1, i);
      const auto res = inv * vec;

      *(coordinates++) =
        diff.x() * res(0) + diff.y() * res(1) + 1.0 / double(n);
    }
  };

  // Compute affine coordinates for all query points.
  std::cout << std::endl << "affine coordinates (all queries): " << std::endl << std::endl;

  std::vector<double> coordinates;
  coordinates.reserve(4);
  for (const auto& query : queries) {
    coordinates.clear();
    affine(query, std::back_inserter(coordinates));
    for (std::size_t i = 0; i < coordinates.size() - 1; ++i) {
      std::cout << coordinates[i] << ", ";
    }
    std::cout << coordinates[coordinates.size() - 1] << std::endl;
  }
  std::cout << std::endl;

  return EXIT_SUCCESS;
}


#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <tuple>
#include <stdbool.h>
#include <bitset>
#include <string>
#include <boost/multiprecision/cpp_int.hpp>

namespace mp = boost::multiprecision;
using namespace std;

int main(void) {
    int ab, bc, ca;
    cin >> ab;
    cin >> bc;
    cin >> ca;

    // ヘロンの公式
    auto s = (ab + bc + ca) / 2;
    auto ans = sqrt(s * (s - ab) * (s - bc) * (s - ca));

    cout << ans << endl;

    return 0;
}


#include <Eigen/Geometry>
#include <iostream>

using namespace Eigen;
using namespace std;
int main()
{
        // scaling 矩阵为一个对角阵
        //2 0
        //0 1
        Matrix<float, 2, 2> t = Scaling(2.0f, 1.0f);
        std::cout << t.matrix() << std::endl;

        Affine3f aux(Affine3f::Identity());

        cout << aux.affine().matrix() << endl;  // aux是一个齐次矩阵，采用.affine()忽略了最后一行

        cout  << aux.matrix()<<endl;

        Transform<double, 3, Affine> Affine_transform;     // 仿射
        Affine_transform.setIdentity();
        Transform<double, 3, Isometry> Isometry_transform;   //等距
        Transform<double, 3, Projective> Projective_transform; // 射影变换
        Affine_transform.prerotate(AngleAxisd(3.14,Vector3d::UnitX()));

}


// #include <omi_for_c.h>
#include <Eigen/Eigen>

void CalcElaStiffMat(	Eigen::Ref<Eigen::Matrix<double, 6,6>> C,
						const double &G,
						const double &LAMBDA)
{
    C = Eigen::Matrix<double, 6,6>::Zero();
    // Kelvin Voigt
    for (int i = 0; i < 3; i++)
    {
		C(i,i) += 2*G;
        C(i+3,i+3) += G;
        for (int j = 0; j < 3; j++)
        {
            C(i,j) += LAMBDA;

        }
    }
}

extern "C" void umat(double *stress, double *statev, double *ddsdde, double *sse, double *spd,
		double *scd, double *rpl, double *ddsddt, double *drplde, double *drpldt,
		double *stran, double *dstran, double *time, double *dtime, double *temp,
		double *dtemp, double *predef, double *dpred, char *cmname, int *ndi,
		int *nshr, int *ntens, int *nstatv, double *props, int *nprops,
		double *coords, double *drot, double *pnewdt, double *celent, double *dfgrd0,
		double *dfgrd1, int *noel, int *npt, int *layer, int *kspt,
		int *kstep, int *kinc, short cmname_len)
{
	double E = props[0]; //210000
	double NU = props[1]; //0.3
	double G = E/2.0/(1.0 + NU); //80769,23
	double LAMBDA = 2.0*G*NU/(1.0 - 2.0*NU);//121153,85
	double eps [6];
	double eps_trace;

// Update strain
	for (int i = 0; i < 6; i++)
	{
		eps[i] = stran[i] + dstran[i];
	}

	eps_trace = eps[0] + eps[1] + eps[2];

//Calculation of the stress
	for(int i = 0; i < 3; i++)
	{
		stress[i] = LAMBDA*eps_trace + 2.0*G*eps[i];
		stress[i+3] = G*eps[i+3];
	}

// Calc Isotropic elastic stiffness matrix through Eigen
// (unnessary but informative)
	Eigen::Matrix<double, 6,6> C;
	CalcElaStiffMat(C, G, LAMBDA);

//	Isotropic elastic stiffness matrix ddsdde as a 36x1-Vector
//  But first it`s Initialization
	for (int i = 0; i < 6; i++)
	{
		for(int j = 0; j< 6; j++)
		{
			ddsdde[6*i+j] = 0.0;
		}
	}
	for(int i = 0; i < 3; i++)
	{
		ddsdde[6*i+0] 			= C(0,i);
		ddsdde[6*i+1] 			= C(1,i);
		ddsdde[6*i+2] 			= C(2,i);
		ddsdde[6*(i+3)+(i+3)] 	= C(i+3, i+3);
	}
}


#include <cmath>
#include <algorithm>

#include <sims/linkmodel.h>
#include <sims/cholesky.h>
#include <sims/svd.h>
#include <sims/qr.h>
#include <sims/ostr.h>
#include <Eigen/Eigenvalues>

std::vector<double> compute_link_distance(const std::vector<sims::Optics::CLink> &links) {
    std::vector<double> l_distance{};

    for (const auto &link : links) {
        l_distance.emplace_back(sims::math::distance_pathloss(link));
    }

    return l_distance;
}

sims::linalg::vecvec<double>
sims::linkmodel::nearest_SPD(const sims::linalg::vecvec<double> &matrix) {
    auto svd_res = sims::svd::svd(matrix, 20);

    auto h = std::get<2>(svd_res) * std::get<0>(svd_res) * sims::linalg::transpose(std::get<2>(svd_res));
    auto spd = (matrix + h) / 2.0;

    uint32_t scalar = 1;
    uint32_t multiplier = 1;
    while (!sims::cholesky::is_positive_definite(spd)) {
        auto eigen = sims::linalg::eig(spd, 30);
        auto min_eig = eigen.values.back();

        spd = spd + (-min_eig * sims::math::next_power_of_2(scalar) +
                     (std::numeric_limits<double>::epsilon() * std::abs(min_eig))) *
                    sims::linalg::identity(spd.size());

        scalar++;

    }

    return spd;
}

sims::linalg::Eigen calc_eigen(const sims::linalg::vecvec<double> &matrix) {
    auto s = matrix.size();
    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> x(s, s);
    ::std::vector<double> values(s);
    sims::linalg::vecvec<double> vectors;
    vectors.resize(s, ::std::vector<double>(s));

    for (auto row = 0; row < s; ++row) {
        for (auto column = 0; column < s; ++column) {
            x(row, column) = matrix[row][column];
        }
    }

    Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> es;
    es.compute(x);

    auto ve = es.eigenvectors();
    auto va = es.eigenvalues();

    for (auto row = 0; row < s; ++row) {
        for (auto column = 0; column < s; ++column) {
            vectors[row][column] = ve(row, column);
        }
    }
    for (auto row = 0; row < s; ++row) {
        values[row] = va(row);
    }

    std::sort(std::begin(values), std::end(values));
    return sims::linalg::Eigen{vectors, values, 0, 0};
}

sims::linalg::vecvec<double> sims::linkmodel::near_pd(const sims::linalg::vecvec<double> &matrix) {
    auto x = matrix;

    while (true) {
        auto y = x;
        //auto eigen = sims::linalg::eig(x, 10);
        //auto eigen = sims::qr::qr_algorithm(x);
        auto eigen = calc_eigen(x);
        auto q = eigen.vectors;
        auto d = eigen.values;

        std::vector<int> p;
        auto eigen_tolerance = 1e-06 * d.front();
        for (auto i = 0; i < d.size(); ++i) {
            if (d[i] > eigen_tolerance)
                p.emplace_back(i);
        }

        std::sort(p.begin(), p.end());
        q = sims::linalg::slice_column_from_index_list(q, p);
        auto q_t = q;

        for (auto i = 0; i < p.size(); ++i) {
            for (auto &row : q)
                row[i] = row[i] * d[i];
        }

        x = sims::linalg::crossprod(sims::linalg::transpose(q), q_t);
        x = sims::linalg::diag(x, 1.0);

        auto diff = y - x;
        auto conv = sims::linalg::infinity_norm(diff) / sims::linalg::infinity_norm(y);

        if (conv <= 1e-07) {
            return x;
        }
    }
}

std::vector<double> compute_link_fading(const std::vector<sims::Optics::CLink> &links, double time = 0.0) {
    auto corr = sims::math::generate_correlation_matrix(links);
    /*if (!sims::cholesky::is_positive_definite(corr)) {
        std::cout << "ensuring spd" << std::endl;
        corr = sims::linkmodel::near_pd(corr);
    }

    if (!sims::cholesky::is_positive_definite(corr)) {
        std::cout << "near PD failed" << std::endl;
    }*/

    auto std_deviation = std::pow(STANDARD_DEVIATION, 2);
    auto sigma = std_deviation * corr;

    /*if (!sims::cholesky::is_positive_definite(sigma)) {
        std::cout << "ensuring spd" << std::endl;
        sigma = sims::linkmodel::nearest_SPD(sigma);
    }*/

    auto autocorrelation_matrix = sims::cholesky::cholesky(sigma);

    auto l_fading = autocorrelation_matrix * sims::math::generate_gaussian_vector(0.0, 1.0, links.size());
    return common::is_equal(time, 0.0) ? l_fading : l_fading * time;
}

std::vector<double>
sims::linkmodel::compute_spatial_correlation(const std::vector<sims::Optics::CLink> &links, double time) {
    return compute_link_fading(links, time);

}

std::vector<double> sims::linkmodel::compute_temporal_correlation(const std::vector<sims::Optics::CLink> &links,
                                                                    const double time, const double delta_time) {
    /* TODO: Compute the temporal coefficient */
    auto d_t = 1_km;
    auto d_r = 1_km;

    auto temporal_coefficient = std::exp(-(std::log(2) * ((d_t + d_r) / 20)));

    /* compute l_fading */
    auto l_fading = compute_link_fading(links, time);

    return sqrt(1 - temporal_coefficient) + l_fading * temporal_coefficient;
}

::std::vector<double> sims::linkmodel::compute(const std::vector<sims::Optics::CLink> &links, double time) {
    return compute_link_distance(links);// + compute_link_fading(links, time); /* TODO: + temporal*/
}


/**
 * @file gradientflow.h
 * @brief NPDE homework GradientFlow code
 * @author Unknown, Oliver Rietmann
 * @date 04.04.2021
 * @copyright Developed at ETH Zurich
 */

#include "gradientflow.h"

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

namespace GradientFlow {

/* SAM_LISTING_BEGIN_0 */
Eigen::MatrixXd ButcherMatrix() {
  Eigen::MatrixXd A(6, 5);
  // clang-format off
  A <<       0.25,          0.,       0.,       0.,   0.,
    0.5,        0.25,       0.,       0.,   0.,
    17./50.,     -1./25.,     0.25,       0.,   0.,
    371./1360., -137./2720., 15./544.,     0.25,   0.,
    25./24.,    -49./48., 125./16., -85./12., 0.25,
    25./24.,    -49./48., 125./16., -85./12., 0.25;
  // clang-format on
  return A;
}
/* SAM_LISTING_END_0 */

/* SAM_LISTING_BEGIN_1 */
std::vector<Eigen::VectorXd> SolveGradientFlow(const Eigen::VectorXd &d,
                                               double lambda,
                                               const Eigen::VectorXd &y0,
                                               double T, unsigned int M) {
  // initialize solution vector
  std::vector<Eigen::VectorXd> sol(M + 1, Eigen::VectorXd::Zero(y0.size()));

#if SOLUTION
  // Define the right hand side of the ODE y' = f(y), and the Jacobian of f.
  auto f = [d, lambda](const Eigen::VectorXd &y) {
    Eigen::VectorXd val =
        -2. * std::cos(y.squaredNorm()) * y - 2. * lambda * d.dot(y) * d;
    return val;
  };
  auto df = [d, lambda](const Eigen::VectorXd &y) {
    int dim = y.size();
    Eigen::MatrixXd term1 = 4. * std::sin(y.squaredNorm()) * y * y.transpose();
    Eigen::MatrixXd term2 =
        -2. * std::cos(y.squaredNorm()) * Eigen::MatrixXd::Identity(dim, dim);
    Eigen::MatrixXd term3 = -2. * lambda * d * d.transpose();
    Eigen::MatrixXd dfval = term1 + term2 + term3;
    return dfval;
  };

  // Split the interval [0,T] into M intervals of size h.
  double h = T / M;
  Eigen::VectorXd y = y0;
  sol[0] = y;
  // Evolve up to time T:
  for (int i = 1; i <= M; i++) {
    y = DiscEvolSDIRK(f, df, y, h);
    sol[i] = y;
  }
#else
  //====================
  // Your code goes here
  //====================
#endif
  return sol;
}
/* SAM_LISTING_END_1 */

}  // namespace GradientFlow