// Copyright Christopher Kormanyos 2013.
// Copyright Paul A. Bristow 2013.
// Copyright John Maddock 2013.

// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or
// copy at http://www.boost.org/LICENSE_1_0.txt).

#ifdef _MSC_VER
#  pragma warning (disable : 4512) // assignment operator could not be generated.
#  pragma warning (disable : 4996) // assignment operator could not be generated.
#endif

#include <iostream>
#include <limits>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <iterator>

//[bessel_zeros_iterator_example_1

/*`[h5 Using Output Iterator to sum zeros of Bessel Functions]

This example demonstrates summing zeros of the Bessel functions.
To use the functions for finding zeros of the functions we need
 */

#include <boost/math/special_functions/bessel.hpp>

/*`We use the `cyl_bessel_j_zero` output iterator parameter `out_it`
to create a sum of ['1/zeros[super 2]] by defining a custom output iterator:
*/

template <class T>
struct output_summation_iterator
{
   output_summation_iterator(T* p) : p_sum(p)
   {}
   output_summation_iterator& operator*()
   { return *this; }
    output_summation_iterator& operator++()
   { return *this; }
   output_summation_iterator& operator++(int)
   { return *this; }
   output_summation_iterator& operator = (T const& val)
   {
     *p_sum += 1./ (val * val); // Summing 1/zero^2.
     return *this;
   }
private:
   T* p_sum;
};

//] [/bessel_zeros_iterator_example_1]

int main()
{
  try
  {
//[bessel_zeros_iterator_example_2

/*`The sum is calculated for many values, converging on the analytical exact value of `1/8`.
*/
    using boost::math::cyl_bessel_j_zero;
    double nu = 1.;
    double sum = 0;
    output_summation_iterator<double> it(&sum);  // sum of 1/zeros^2
    cyl_bessel_j_zero(nu, 1, 10000, it);

    double s = 1/(4 * (nu + 1)); // 0.125 = 1/8 is exact analytical solution.
    std::cout << std::setprecision(6) << "nu = " << nu << ", sum = " << sum
      << ", exact = " << s << std::endl;
    // nu = 1.00000, sum = 0.124990, exact = 0.125000
//] [/bessel_zeros_iterator_example_2]
   }
  catch (std::exception const& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }
  return 0;
  } // int_main()

/*
 Output:

 nu = 1, sum = 0.12499, exact = 0.125
*/


#include <Eigen/Dense>
#include <Eigen/IterativeLinearSolvers>

#include <algorithm>
#include <iostream>
#include <random>
#include <vector>

std::pair<Eigen::MatrixXf, Eigen::MatrixXf> GenerateData(size_t n) {
  std::vector<float> x_data(n);
  std::iota(x_data.begin(), x_data.end(), 0);
  std::vector<float> y_data(n);
  std::iota(y_data.begin(), y_data.end(), 0);

  // mutate data
  std::random_device rd;
  std::mt19937 re(rd());
  std::uniform_real_distribution<float> dist(-1.5f, 1.5f);

  for (auto& x : x_data) {
    x += dist(re);  // add noise
  }

  for (auto& y : y_data) {
    y += dist(re);  // add noise
  }

  // Make result
  Eigen::Map<Eigen::MatrixXf> x(x_data.data(), static_cast<Eigen::Index>(n), 1);
  Eigen::Map<Eigen::MatrixXf> y(y_data.data(), static_cast<Eigen::Index>(n), 1);

  return {x, y};
}

int main() {
  size_t n = 1000;
  // generate training data
  Eigen::MatrixXf x1, y;
  std::tie(x1, y) = GenerateData(n);
  Eigen::MatrixXf x0 = Eigen::MatrixXf::Ones(n, 1);
  // setup line coeficients y = b(4) + k(0.3)*x
  y.array() *= 0.3f;
  y.array() += 4.f;
  Eigen::MatrixXf x(n, 2);
  x << x0, x1;

  // train estimator
  Eigen::LeastSquaresConjugateGradient<Eigen::MatrixXf> gd;
  gd.setMaxIterations(100);
  gd.setTolerance(0.001f);
  gd.compute(x);
  Eigen::VectorXf b = gd.solve(y);
  std::cout << "Estimated parameters vector : " << b << std::endl;

  // normal equations
  Eigen::VectorXf b_norm = (x.transpose() * x).ldlt().solve(x.transpose() * y);
  std::cout << "Estimated with normal equation parameters vector : " << b_norm
            << std::endl;

  // predict
  Eigen::MatrixXf new_x(5, 2);
  new_x << 1, 1, 1, 2, 1, 3, 1, 4, 1, 5;
  auto new_y = new_x.array().rowwise() * b.transpose().array();
  std::cout << "Predicted values : \n" << new_y << std::endl;

  auto new_y_norm = new_x.array().rowwise() * b_norm.transpose().array();
  std::cout << "Predicted(norm) values : \n" << new_y_norm << std::endl;

  return 0;
};


/** \file matrix_utils.hpp
*  \brief Miscellaneous math functions
*
*  Miscellaneous math functions used in FDCL are defined here
*/

#ifndef FDCL_MATRIX_UTILS_HPP
#define FDCL_MATRIX_UTILS_HPP

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

#include "fdcl/common_types.hpp"

namespace fdcl
{

/** \fn Matrix3 hat(const Vector3 v)
* Returns the hat map of a given 3x1 vector. This is the inverse of vee map.
* @param v vector which the hat map is needed to be operated on
* @return hat map of the input vector
*/
Matrix3 hat(const Vector3 v);

/** \fn Vector3 vee(const Matrix3 V)
* Returns the vee map of a given 3x3 matrix. This is the inverse of hat map.
* @param V matrix which the vee map is needed to be operated on
* @return vee map of the input matrix
*/
Vector3 vee(const Matrix3 V);

/** \fn double sinx_over_x(const double x)
 * Calculates and returns the value of sin(x)/x, dealing with the case where
 * x = 0.
 * @param  x input value
 * @return   the value of sin(x)/x
 */
double sinx_over_x(const double x);

/** \fn Matrix3 expm_SO3(const Vector3 r)
 * Calculates and returns the rotation matrix in SO(3) from rotation vector.
 * This is the inverse of logm_som3.
 * @param  r rotation vector (angle * axis)
 * @return   rotation matrix in SO(3) which corresponds to the input vector
 */
Matrix3 expm_SO3(const Vector3 r);

/** \fn Vector3 logm_SO3(const Matrix3 R)
 * Calculates and returns the rotation vector from rotation matrix in SO(3).
 * This is the inverse of expm_SO3.
 * @param  R rotation matrix in SO(3)
 * @return rotation vector (angle * axis)
 */
Vector3 logm_SO3(const Matrix3 R);

/** \fn bool assert_SO3(Matrix3 R,const char *R_name)
 * Check and returns if a given matrix is in SO(3)
 * @param  R      rotation matrix
 * @param  R_name name of the rotation matrix
 * @return        true if the input matrix is true, false otherwise
 */
bool assert_SO3(Matrix3 R,const char *R_name);

/** \fn void saturate(Vector3 &x, const double x_min, const double x_max)
 * Saturate the elements of a given 3x1 vector between a minimum and a maximum
 * velue.
 * @param x     vector which the elements needed to be saturated
 * @param x_min minimum value for each element
 * @param x_max maximum value for each element
 */
void saturate(Vector3 &x, const double x_min, const double x_max);

/** \fn void saturate(Vector4 &x, const double x_min, const double x_max)
 * Saturate the elements of a given 4x1 vector between a minimum and a maximum
 * velue.
 * @param x     vector which the elements needed to be saturated
 * @param x_min minimum value for each element
 * @param x_max maximum value for each element
 */
void saturate(Vector4 &x, const double x_min, const double x_max);

/** \fn void saturate(Vector6 &x, const double x_min, const double x_max)
 * Saturate the elements of a given 6x1 vector between a minimum and a maximum
 * velue.
 * @param x     vector which the elements needed to be saturated
 * @param x_min minimum value for each element
 * @param x_max maximum value for each element
 */
void saturate(Vector6 &x, const double x_min, const double x_max);

/** \fn void saturate(int &x, const int x_min, const int x_max)
 * Saturate the elements of a given integer between a minimum and a maximum
 * velue.
 * @param x     integer which needed to be saturated
 * @param x_min minimum value for x
 * @param x_max maximum value for x
 */
void saturate(int &x, const int x_min, const int x_max);

/** \fn void saturate(double &x, const double x_min, const double x_max)
 * Saturate the elements of a given integer between a minimum and a maximum
 * velue.
 * @param x     double which needed to be saturated
 * @param x_min minimum value for x
 * @param x_max maximum value for x
 */
void saturate(double &x, const double x_min, const double x_max);

/** \fn void deriv_unit_vector(Vector3 B, Vector3 B_dot, Vector3 &q,
 * Vector3 &q_dot)
 * finds derivative q = -B/norm(B)
 */
void deriv_unit_vector(Vector3 B, Vector3 B_dot, Vector3 &q, Vector3 &q_dot);

/** \fn void deriv_unit_vector(Vector3 B, Vector3 B_dot, Vector3 B_ddot,
 * Vector3 &q, Vector3 &q_dot, Vector3 &q_ddot)
 * finds first and second derivatives of q = -B/norm(B)
 */
void deriv_unit_vector(Vector3 B, Vector3 B_dot, Vector3 B_ddot, Vector3 &q, \
    Vector3 &q_dot, Vector3 &q_ddot);

}  // end of namespace fdcl
#endif


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

using namespace std;

//Evaluate the Chebyshev polynomials up to order n in x.
vector<double> chebpolmult(const int &n,const double &x)
{
    vector<double> V={1,x};
    for (int k=1; k<n; k++)
        V.push_back(2*x*V[k]-V[k-1]);
    return V;
}

// Compute the best approximation of the function f with Chebyshev polynomials. alpha is the output vector of coefficients.
template <typename Function>
void bestpolchebnodes(const Function &f, Eigen::VectorXd &alpha) {
    int n=alpha.size()-1;
    Eigen::VectorXd fn(n+1);
    for (int k=0; k<n+1; k++) {
        double temp=cos(M_PI*(2*k+1)/2/(n+1));
        fn(k)=f(temp);
    }

    vector<double> V;
    Eigen::MatrixXd scal(n+1,n+1);
    for (int j=0; j<n+1; j++) {
        V=chebpolmult(n,cos(M_PI*(2*j+1)/2/(n+1)));
        for (int k=0; k<n+1; k++) scal(j,k)=V[k];
    }

    for (int k=0; k<n+1; k++) {
        alpha(k)=0;
        for (int j=0; j<n+1; j++) {
            alpha(k)+=2*fn(j)*scal(j,k)/(n+1);
        }
    }
        alpha(0)=alpha(0)/2;
}

// Test the implementation.
int main(){
    auto f = [] (double & x) {return 1/(pow(5*x,2)+1);};
    int n=20;
    Eigen::VectorXd alpha(n+1);
    bestpolchebnodes(f, alpha);

    //Compute the error
    Eigen::VectorXd X = Eigen::VectorXd::LinSpaced(1e6,-1,1);
    auto qn = [&alpha,&n] (double & x) {
        double temp;
        vector<double> V=chebpolmult(n,x);
        for (int k=0; k<n+1; k++) temp+=alpha(k)*V[k];
        return temp;
    };
    double err_max=abs(f(X(0))-qn(X(0)));
    for (int i=1; i<1e6; i++) err_max=std::max(err_max,abs(f(X(i))-qn(X(i))));
    cout<<"Error: "<< err_max <<endl;
}

Nummerical Methods for CSE/PS9/solutions_ps9/ChebBest.cpp


/**
 * Authors:
 *      Marcelo Jacinto (marcelo.jacinto@tecnico.ulisboa.pt)
 *      Andre Potes (andre.potes@tecnico.ulisboa.pt)
 * Maintained by: Marcelo Fialho Jacinto (marcelo.jacinto@tecnico.ulisboa.pt)
 * Last Update: 14/12/2021
 * License: MIT
 * File: rotations.hpp
 * Brief: Defines all functions related to angle wrapping, rotation matrices,
 * euler angles, convertion to quaternions, etc.
 */
#pragma once

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

namespace DSOR {

/**
 * @brief Function to convert from quaternion to (roll, pitch and yaw), according to Z-Y-X convention
 * This function is from: https://github.com/mavlink/mavros/issues/444
 * and the logic is also available at: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
 * @param q An eigen quaternion
 * @return A Vector<T, 3> with the [roll, pitch, yaw] obtained according to Z-Y-X convention
 */
template <typename T>
inline Eigen::Matrix<T, 3, 1> quaternion_to_euler(const Eigen::Quaternion<T> &q) {
    /* NOTE: The Eigen standard way of doing it is not used because for the order YPR the output range would be:
    [Eigen EulerAngles implementation] yaw, pitch, roll in the ranges [0:pi]x[-pi:pi]x[-pi:pi] */

    Eigen::Matrix<T, 3, 1> rpy;

    /* Compute roll */
    rpy.x() = std::atan2(2 * (q.w() * q.x() + q.y() * q.z()), 1 - 2 * (q.x() * q.x() + q.y()*q.y()));
    T sin_pitch = 2 * (q.w()*q.y() - q.z()*q.x());
    sin_pitch = sin_pitch >  1 ?  1 : sin_pitch;
    sin_pitch = sin_pitch < -1 ? -1 : sin_pitch;

    /* Compute pitch */
    rpy.y() = std::asin(sin_pitch);

    /* Compute yaw */
    rpy.z() = std::atan2(2 * (q.w() * q.z() + q.x() * q.y()), 1 - 2 * (q.y() * q.y() + q.z() * q.z()));

    return rpy;
}

/**
 * @brief Converts a vector of euler angles according to Z-Y-X convention
 * into a quaternion
 * @param v An eigen vector of either floats or doubles [roll, pitch, yaw]
 * @return An Eigen Quaternion
 */
template <typename T>
inline Eigen::Quaternion<T> euler_to_quaternion(const Eigen::Matrix<T, 3, 1> &v) {

    // Create the Eigen quaternion
    Eigen::Quaternion<T> orientation;

    // Obtain the orientation according to Z-Y-X convention
    orientation = Eigen::AngleAxis<T>(v.z(), Eigen::Matrix<T, 3, 1>::UnitZ()) *
            Eigen::AngleAxis<T>(v.y(), Eigen::Matrix<T, 3, 1>::UnitY()) *
            Eigen::AngleAxis<T>(v.x(), Eigen::Matrix<T, 3, 1>::UnitX());

    return orientation;
}

/**
 * @brief Gets the yaw angle from a quaternion (assumed a Z-Y-X rotation)
 * NOTE: this function is based on:
 * https://github.com/mavlink/mavros/blob/ros2/mavros/src/lib/ftf_quaternion_utils.cpp
 * which in turn has the theory explained in:
 * https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
 * @param q A eigen quaternion
 * @return The yaw angle in radians (assumed a Z-Y-X rotation)
 */
template <typename T>
inline T yaw_from_quaternion(const Eigen::Quaternion<T> &q) {
    return std::atan2(2 * (q.w() * q.z() + q.x() * q.y()), 1 - 2 * (q.y() * q.y() + q.z() * q.z()));
}

/**
 * @brief Wrap angle between [0, 2PI]
 *
 * @param angle angle in radians
 * @return The wraped angle
 */
template <typename T>
inline T wrapTo2pi(T angle) {

    double wrapped_angle = std::fmod(angle, 2 * M_PI);

    if(wrapped_angle < 0)
        wrapped_angle += 2 * M_PI;
    return wrapped_angle;
}

/**
 * @brief Wrap angle between [-PI, PI]
 *
 * @param angle angle in radians
 * @return The wraped angle
 */
template <typename T>
inline T wrapTopi(T angle) {

    double wrapped_angle = std::fmod(angle + M_PI, 2 * M_PI);

    if (wrapped_angle < 0)
        wrapped_angle += 2 * M_PI;

    return wrapped_angle - M_PI;
}

/**
 * @brief Convert an angle in radian to degrees
 *
 * @param angle in radians
 * @return angle in degrees
 */
template <typename T>
inline T radToDeg(T angle) {
    return angle * 180 / M_PI;
}

/**
 * @brief Convert an angle in degrees to radians
 *
 * @param angle in degrees
 * @return angle in radians
 */
template <typename T>
inline T degToRad(T angle) {
    return angle * M_PI / 180;
}

/**
 * @brief Method to calculate the diference between angles correctly even if they wrap between -pi and pi
 *
 * @param a angle 1 in radians
 * @param b angle 2 in radians
 * @return The minimum difference between the two angles
 */
template <typename T>
inline T angleDiff(T a, T b) {
    double aux = std::fmod(a - b + M_PI, 2 * M_PI);
    if (aux < 0) aux += (2 * M_PI);
    aux = aux - M_PI;
    return aux;
}

/**
 * @brief Compute the 3x3 skew-symmetric matrix from a vector 3x1
 * @param v A vector with 3 elements
 * @return A 3x3 skew-symmetric matrix
 */
template <typename T>
inline Eigen::Matrix<T, 3, 3> computeSkewSymmetric3(const Eigen::Matrix<T, 3, 1> &v) {

    Eigen::Matrix<T, 3, 3> skew_symmetric;
    skew_symmetric <<    0, -v(2),  v(1),
                      v(2),     0, -v(0),
                     -v(1),  v(0),     0;

    return skew_symmetric;
}

/**
 * @brief Compute the 2x2 skew-symmetric matrix from a constant (int, float or double)
 * @param v A constant
 * @return A 2x2 skew-symmetric matrix
 */
template <typename T>
inline Eigen::Matrix<T, 2, 2> computeSkewSymmetric2(T c) {

    Eigen::Matrix<T, 2, 2> skew_symmetric;
    skew_symmetric << 0, -c,
                      c,  0;

    return skew_symmetric;
}

/**
 * @brief Compute the rotation matrix that converts angular velocities expressed in the body frame
 * to angular velocities expressed in the inertial frame (according to Z-Y-X convention) - makes use of small angle approximation
 * @param v A vector with 3 elements (roll, pitch, yaw)
 * @return A 3x3 rotation matrix
 */
template <typename T>
inline Eigen::Matrix<T, 3, 3> rotationAngularBodyToInertial(const Eigen::Matrix<T, 3, 1> &v) {
    Eigen::Matrix<T, 3, 3> transformation_matrix;
    transformation_matrix << 1, sin(v(0)) * tan(v(1)), cos(v(0)) * tan(v(1)),
                             0, cos(v(0)), -sin(v(0)),
                             0, sin(v(0)) / cos(v(1)), cos(v(0)) / cos(v(1));
    return transformation_matrix;
}

/**
 * @brief Method that returns a rotation matrix from body frame to inertial frame, assuming a Z-Y-X convention
 * @param v A vector with euler angles (roll, pith, yaw) according to Z-Y-X convention
 * @return A 3x3 rotation matrix
 */
template <typename T>
inline Eigen::Matrix<T, 3, 3> rotationBodyToInertial(const Eigen::Matrix<T, 3, 1> &v) {

    // Create a quaternion
    Eigen::Matrix<T, 3, 3> m;

    // Obtain the orientation according to Z-Y-X convention
    m = (Eigen::AngleAxis<T>(v.z(), Eigen::Matrix<T, 3, 1>::UnitZ()) *
         Eigen::AngleAxis<T>(v.y(), Eigen::Matrix<T, 3, 1>::UnitY()) *
         Eigen::AngleAxis<T>(v.x(), Eigen::Matrix<T, 3, 1>::UnitX())).toRotationMatrix();

    return m;
}

}


#include <stdio.h>

#include <cmath>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::fixed;
using std::ifstream;
using std::left;
using std::pair;
using std::right;
using std::scientific;
using std::setw;
using std::setprecision;
using std::string;
using std::vector;

#include <boost/math/distributions/students_t.hpp>

using boost::math::students_t;

pair<double, double> get_mean_and_standard_deviation(const vector<double> &vv) {
  const double sum = std::accumulate(vv.begin(), vv.end(), 0.0);
  const double mean = sum / vv.size();
  double A = 0;
  std::for_each(vv.begin(), vv.end(), [&mean, &A](const double v) {
					A += (v - mean) * (v - mean);
				      });
  return std::make_pair(mean, std::sqrt(A / (vv.size() - 1)));
}

vector<double> get_data_set(const string &fn) {
  ifstream fin(fn);
  if (!fin.good()) {
    fprintf(stderr, "Open file error: %s\n", fn.c_str());
    return vector<double>();
  }
  vector<double> result;
  for (string line; std::getline(fin, line) ; ) {
    result.push_back(std::stof(line));
  }
  return result;
}

void two_samples_t_test_equal_sd(
        double Sm1, // Sm1 = Sample Mean 1.
        double Sd1,   // Sd1 = Sample Standard Deviation 1.
        unsigned Sn1,   // Sn1 = Sample Size 1.
        double Sm2,   // Sm2 = Sample Mean 2.
        double Sd2,   // Sd2 = Sample Standard Deviation 2.
        unsigned Sn2,   // Sn2 = Sample Size 2.
        double alpha)   // alpha = Significance Level.
{
   // A Students t test applied to two sets of data.
   // We are testing the null hypothesis that the two
   // samples have the same mean and that any difference
   // if due to chance.
   // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm
   //
   using namespace std;
   // using namespace boost::math;

   using boost::math::students_t;

   double v = (Sn1 + Sn2 - 2) ;
   double sp = sqrt(((Sn1-1) * Sd1 * Sd1 + (Sn2-1) * Sd2 * Sd2) / v);
   // t-statistic:
   double t_stat = (Sm1 - Sm2) / (sp * sqrt(1.0 / Sn1 + 1.0 / Sn2));
   cout << setw(20) << left << "T Statistic" << "=  " << t_stat << "\n";
   students_t dist(v);
   double q = cdf(complement(dist, fabs(t_stat)));
   cout << setw(20) << left << "P-value" << "=  "
	<< setprecision(3) << scientific << 2 * q << "\n";
   if(q < alpha / 2) {
      cout << "Sample 1 Mean != Sample 2 Mean\n";
   } else {
     printf("Sample 1 Mean = %.2f\n", Sm1);
     printf("Sample 2 Mean = %.2f\n", Sm2);
     cout << "Sample 1 Mean == Sample 2 Mean\n";
     return;
   }
   printf("Sample 1 Mean = %.2f\n", Sm1);
   printf("Sample 2 Mean = %.2f\n", Sm2);

   if(cdf(dist, t_stat) < alpha) {
     printf("Sample 1 Mean <  Sample 2 Mean\n");
     printf("Sample improvement = %.2f%%\n", (Sm2 - Sm1) / Sm1 * 100);
   }
   if(cdf(complement(dist, t_stat)) < alpha) {
     printf("Sample 1 Mean >  Sample 2 Mean\n");
     printf("Sample regression = %.2f%%\n", (Sm1 - Sm2) / Sm1 * 100);
   }
}

double confidence_interval(const vector<double> &data) {
  students_t dist(data.size() - 1);
  double t_star = quantile(complement(dist, 0.05 / 2));
  auto mean_and_standard_deviation = get_mean_and_standard_deviation(data);
  return t_star * mean_and_standard_deviation.second / sqrt(data.size());
}

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

  if (argc < 3) {
    fprintf(stderr, "Missing argument\n");
    return 1;
  }

   vector<double> data_1 = get_data_set(argv[1]);
   vector<double> data_2 = get_data_set(argv[2]);

   if (data_1.empty() || data_2.empty()) {
     fprintf(stderr, "Empty data set(s).\n");
     return 1;
   }

   if (data_1.size() != data_2.size()) {
     fprintf(stderr, "Data sets have different number of data points.\n");
     return 1;
   }

   vector<double> diff_set;
   for(vector<double>::iterator i = data_1.begin(),
	 j = data_2.begin(), e = data_1.end(); i != e; ++i, ++j)
     diff_set.push_back(*j - *i);

   auto p1 = get_mean_and_standard_deviation(data_1);
   auto p2 = get_mean_and_standard_deviation(data_2);
   auto p3 = get_mean_and_standard_deviation(diff_set);
   double diff_standard_error = p3.second / sqrt(diff_set.size());
   // T value
   double diff_t = p3.first / diff_standard_error;
   students_t dist(data_1.size() - 1);
   // P = 2 * q;
   double q = cdf(complement(dist, fabs(diff_t)));

   fprintf(stderr, "Group 1 mean = %.2f ± %.2f\n", p1.first, confidence_interval(data_1));
   fprintf(stderr, "Group 2 mean = %.2f ± %.2f\n", p2.first, confidence_interval(data_2));
   if (q * 2 <= 0.01) {
     fprintf(stderr, "P value      = %.2e\n", q * 2);
   } else {
     fprintf(stderr, "P value      = %.2f\n", q * 2);
   }
   if (q * 2 > 0.05) {
     fprintf(stderr, "Difference is not significant.\n");
     return 0;
   }
   double w = confidence_interval(diff_set);
   fprintf(stderr, "Diff mean (95%% CI)  = %.2f ± %.2f\n", p3.first, w);
   fprintf(stderr, "Percent   (95%% CI) = %.2f%% (± %.2f%%)\n", p3.first / p1.first * 100, w / p1.first * 100);

   return 0;
} // int main()


#ifndef MLT_UTILS_LOSS_FUNCTIONS_HPP
#define MLT_UTILS_LOSS_FUNCTIONS_HPP

#include <tuple>

#include <Eigen/Core>

#include "../defs.hpp"

namespace mlt {
namespace utils {
namespace loss_functions {
	class SquaredLoss {
	public:
		auto loss(MatrixXdRef pred, MatrixXdRef target) const {
			return (pred - target).array().pow(2).sum() / (2 * pred.cols());
		}

		auto gradient(MatrixXdRef pred, MatrixXdRef target) const {
			return MatrixXd{ (pred - target) / pred.cols() };
		}

		auto loss_and_gradient(MatrixXdRef pred, MatrixXdRef target) const {
			int size = pred.cols();
			auto residuals = (pred - target).eval();

			return make_tuple(residuals.array().pow(2).sum() / (2 * size), (residuals / size).eval());
		}
	};

	class HingeLoss {
	public:
		HingeLoss (double threshold = 1.0) : _threshold(threshold) {}

		auto loss(MatrixXdRef pred, MatrixXdRef target) const {
			return (((pred.rowwise() - pred.cwiseProduct(target).colwise().sum()) - target).array() + _threshold).max(0).sum() / pred.cols();
		}

		auto gradient(MatrixXdRef pred, MatrixXdRef target) const {
			auto margin_mask = ((((pred.rowwise() - pred.cwiseProduct(target).colwise().sum()) - target).array() + _threshold).max(0) > 0).cast<double>().eval();
			margin_mask = margin_mask + (target.array().rowwise() * -margin_mask.colwise().sum().array());
			return (margin_mask / pred.cols()).eval();
		}

		auto loss_and_gradient(MatrixXdRef pred, MatrixXdRef target) const {
			int size = pred.cols();
			auto hinge_loss = ((((pred.rowwise() - pred.cwiseProduct(target).colwise().sum()) - target).array() + _threshold).max(0)).eval();
			auto margin_mask = (hinge_loss.array() > 0).cast<double>().eval();
			margin_mask = margin_mask + (target.array().rowwise() * -margin_mask.colwise().sum().array());
			return make_tuple(hinge_loss.sum() / size, (margin_mask / size).eval());
		}
	protected:
		double _threshold;
	};

	class SoftmaxLoss {
	public:
		auto loss(MatrixXdRef pred, MatrixXdRef target) const {
			return -_softmax(pred).cwiseProduct(target).colwise().sum().array().log().sum() / pred.cols();
		}

		auto gradient(MatrixXdRef pred, MatrixXdRef target) const {
			return ((_softmax(pred) - target) / pred.cols()).eval();
		}

		auto loss_and_gradient(MatrixXdRef pred, MatrixXdRef target) const {
			int size = pred.cols();
			auto softmax_output = _softmax(pred);
			double l = softmax_output.cwiseProduct(target).colwise().sum().array().log().sum() / size;
			return make_tuple(l, ((_softmax(pred) - target) / size).eval());
		}

	protected:
		inline MatrixXd _softmax(MatrixXdRef x) const {
			auto result = (x.rowwise() - x.colwise().maxCoeff()).array().exp().eval();
			return (result.array().rowwise() / result.colwise().sum().array());
		}
	};
}
}
}
#endif


/*  Legendre polynomials

	An in-class exercise using equations for the Polynomials and solvers as
	shown in the lecture/manuscript for Numerical Methods for CSE
	by Prof. R. Hiptmair, ETH Zürich

	Include the Eigen3 library as shown in documentation for Eigen3.

	use piping to store the .m file. Example call:
	legendre >legendre.m

 	This program calculates
 	- Legendre Polynomials P0 to P8 and their derivatives in interval [-1,1]
 	  -> plots them using MatlabPlotter
 	- Gauss points / zero points for P1 to P8
 	  - using secant method as solver
 	  - using secant falsi method as solver
 	  -> plots them using MatlabPlotter
 	- uses these Gauss points to calculate the weights for GL quadrature
 	- applies this GL quadrature to a function f(x) = e^(x^2) over an interval [a,b] = [3,6]
 	- plots the relative error (comparison of P1 to P8 vs reference result by Wolfram|Alpha)

	v1.0.3 2015-11-22 / 2015-11-29 Pirmin Schmid
*/

//#define _USE_MATH_DEFINES
#include <cmath>
#include <vector>
#include <Eigen/Dense>
#include "matlab_plotter.h"

using namespace std;
using namespace Eigen;

//------------------------------------------------------------------------------

// 3-term recursion for sequences (Pn)n  and (Pn')n for n in 0 to (N-1)
// evaluation of multiple x_i values in parallel
// input:        vector x in R^n with x_0 to x_{n-1}
// input/output: Lx and DLx in R^Nxn
//               thus, number of given rows N eq. number of elements desired
//               of the sequences (Pn)n  and (Pn')n
void legvals(const VectorXd& x, MatrixXd& Lx, MatrixXd& DLx) {
	// check input
	long n = x.size();
	long N = Lx.rows();
	if(Lx.cols() != n || DLx.rows() != N || DLx.cols() != n) {
		cout << "Error in legvals(): Dimensions mismatch." << endl;
		exit(1);
	}

	double denominator_inv = 0.0;
	double numerator1 = 0.0;
	double numerator2 = 0.0;

	// we need a row vector for the calculations below (otherwise Eigen assertion fails)
	// this seemed the easiest way for me to get one.
	RowVectorXd xr = x;

	DLx.row(0) = MatrixXd::Zero(1, n);
	Lx.row(0) = MatrixXd::Ones(1, n);

	DLx.row(1) = MatrixXd::Ones(1, n);
	Lx.row(1) = x;

	for(long i = 2; i < N; i++) {
		// these values are calculated fresh for each iteration to avoid any accumulating rounding error
		// when calculated iteratively from prior values
		denominator_inv = 1.0 / (double)i; // one division here -> many much faster multiplications than divisions later
		numerator1 = (double)(2 * i - 1);
		numerator2 = (double)(i - 1);

		DLx.row(i) = denominator_inv * (numerator1 * (Lx.row(i-1) + DLx.row(i-1).cwiseProduct(xr)) - numerator2 * DLx.row(i-2));
		Lx.row(i)  = denominator_inv * (numerator1 * Lx.row(i-1).cwiseProduct(xr) - numerator2 * Lx.row(i-2));
	}
}

//------------------------------------------------------------------------------

using EvalFunction = function<double (const double, const int)>;

// computes Pk(x) for scalar x
double Pkx(const double x, const int k) {
	if(k < 2) {
		if(k == 0) {
			return 1.0;
		}

		if(k == 1) {
			return x;
		}

		cout << "Error in Pkx(): Negative k values are not valid." << endl;
		exit(1);
	}

	double denominator = 0.0;
	double numerator1 = 0.0;
	double numerator2 = 0.0;

	double result_minus2 = 1.0;
	double result_minus1 = x;
	double result = 0.0;

	for(int i = 2; i <= k; i++) {
		denominator = (double)i;
		numerator1 = (double)(2 * i - 1);
		numerator2 = (double)(i - 1);

		result = (numerator1 * result_minus1 * x - numerator2 * result_minus2) / denominator;
		result_minus2 = result_minus1;
		result_minus1 = result;
	}
	return result;
}

//------------------------------------------------------------------------------

using Solver = function<double (double, double, EvalFunction, int, const double, const double, const int)>;

// translation of the Matlab function secant 2.3.25 in the manuscript
// modified to include the additional parameter k
double secant(double x0, double x1, EvalFunction f, int k, const double rtol, const double atol, const int maxIterations) {
	double f0 = f(x0, k);
	double fn = 0.0;
	double s = 0.0;
	for(int i=0; i < maxIterations; i++) {
		fn = f(x1, k);
		s = fn * (x1-x0) / (fn-f0); // correction
		x0 = x1;
		x1 = x1 - s;
		if( abs(s) < max(atol, rtol * min(abs(x0), abs(x1))) ) {
			return x1;
		}
		f0 = fn;
	}

	// default, best guess after maxIterations
	return x1;
}

// translation of the Matlab function secant_falsi on the exercise sheet
// modified to include the additional parameter k
double secant_falsi(double x0, double x1, EvalFunction f, int k, const double rtol, const double atol, const int maxIterations) {
	double f0 = f(x0, k);
	double fn = 0.0;
	double s = 0.0;
	for(int i=0; i < maxIterations; i++) {
		fn = f(x1, k);
		s = fn * (x1-x0) / (fn-f0); // correction
		if(f(x1 - s, k) * fn < 0.0) {
			x0 = x1;
			f0 = fn;
		}
		x1 = x1 - s;
		if( abs(s) < max(atol, rtol * min(abs(x0), abs(x1))) ) {
			return x1;
		}
	}

	// default, best guess after maxIterations
	return x1;
}

//------------------------------------------------------------------------------

#define MAX_ITERATIONS 100

// calculate zeros of Pk, k in 1 to n using the secant rule for end points {-1, 1} of the interval [-1, 1] and the zeros
// of the previous Legendre polynomial as initial guesses. Correction based termination criterion
// input:  n size
//         rtol and atol relative and absolute tolerance
// return: nxn upper triangular matrix, to actually get such an upper triangular
//         I assume that row j indicates the j-th zero for j in 1 to k
//                       column k indicates the solutions for Pk (thus, we will have column vectors of solutions)
//         note: for C++, index 0 will refer to j=1 and k=1 respectively, and so on.
MatrixXd gaussPts(const int n, Solver z, const double rtol = 1e-10, const double atol = 1e-12) {
	MatrixXd zeros = MatrixXd::Zero(n, n);

	// find the first for P1 -> will be in [0,0]
	zeros(0,0) = z(-1.0, 1.0, Pkx, 1, rtol, atol, MAX_ITERATIONS);

	// get the zeros for P2 to Pn (will be in columns 1 to (n-1)
	for(int i = 1; i < n; i++) {
		// get first zero
		zeros(0, i) = z(-1.0, zeros(0, i-1), Pkx, i+1, rtol, atol, MAX_ITERATIONS);

		// get last zero
		zeros(i, i) = z(zeros(i-1, i-1), 1.0, Pkx, i+1, rtol, atol, MAX_ITERATIONS);

		// get the zeros in-between
		for(int j = 1; j < i; j++) {
			zeros(j, i) = z(zeros(j-1, i-1), zeros(j, i-1), Pkx, i+1, rtol, atol, MAX_ITERATIONS);
		}
	}

	return zeros;
}

//------------------------------------------------------------------------------

#define A 3
#define B 6

using Function = function<double (const double)>;

// just a simple function that does not have a primitive (Stammfunktion) that can be expressed
// in R space. thus: suitable for numerical integration / quadrature
double test_function_for_quadrature(const double x) {
	return exp(x * x);
}

// Wolfram|Alpha calculated the quadrature of this function in [3,6] to be
// 3.644831077835569048422984645481051411815484722480248338949090926023254915628803401963716304967305392 10^14
// change this reference value if you change the function or A, B

#define REFERENCE_RESULT 3.6448310778355690e14

// applies the Gauss-Legendre quadrature for the given function over a defined interval [a,b]
// input:  f     a function that fits the type definition of Function
//         a, b  define interval [a,b]
//         w, x  weights and Gauss points for the given Legendre Polynomial in standard interval [-1,1]
//               size of both arrays must match, of course
// return: quadrature approximation for this function in interval [a,b]
double GLquadrature(const Function f, const double a, const double b, const ArrayXd& w, const ArrayXd& x) {
	int n = w.size();
	if(n != x.size()) {
		cout << "vectors of weights and Gauss points must have the same size" << endl;
		exit(1);
	}

	double half_delta = 0.5 * (b-a);
	double avg = 0.5 * (a+b);
	ArrayXd weights = half_delta * w;
	ArrayXd xs = half_delta * x;
	xs += avg;

	ArrayXd ys = xs.unaryExpr(f);
	ys *= weights;
	return ys.sum();
}

//------------------------------------------------------------------------------

#define MIN -1
#define MAX 1
#define MAX_K 8
#define N_X 600

int main() {
	// initialization
	MatlabPlotter p;
	p.comment("Legendre polynomials");
	p.comment("Code generated by legendre.cpp");

	vector<string> colors = {"k-", "b-", "g-", "r-", "c-", "m-", "y-"};
	vector<string> colors2 = {"ko", "bo", "go", "ro", "co", "mo", "yo"};
	int n_colors = colors.size();

	vector<string> description = {"P_{0}", "P_{1}", "P_{2}", "P_{3}", "P_{4}", "P_{5}", "P_{6}", "P_{7}", "P_{8}"};

	// (1) get a visual impression -> plot the Legendre polynomials up to k = MAX_K
	VectorXd xx = VectorXd::LinSpaced(N_X, MIN, MAX);
	MatrixXd Lx(MAX_K+1, N_X);
	MatrixXd DLx(MAX_K+1, N_X);
	legvals(xx, Lx, DLx);

	p.figure("Legendre polynomials 0 to 8");
	VectorXd yy = Lx.row(0);
	p.plot(xx, yy, colors[0]);
	p.hold();
	p.title("Legendre polynomials 0 to 8");
	for(int i=1; i <= MAX_K; i++) {
		yy = Lx.row(i);
		p.plot(xx, yy, colors[i % n_colors]);
	}
	p.xylabels("x", "P_{i}(x) for i={0, 1, ..., 8}");
	p.legend("P_{0}", "P_{1}", "P_{2}", "P_{3}", "P_{4}", "P_{5}", "P_{6}", "P_{7}", "P_{8}");
	p.hold(false);

	// (2) get a visual impression -> plot the derivatives of the Legendre polynomials up to k = MAX_K
	p.figure("Derivatives of Legendre polynomials 0 to 8");
	yy = DLx.row(0);
	p.plot(xx, yy, colors[0]);
	p.hold();
	p.title("Derivatives of Legendre polynomials 0 to 8");
	for(int i=1; i <= MAX_K; i++) {
		yy = DLx.row(i);
		p.plot(xx, yy, colors[i % n_colors]);
	}
	p.xylabels("x", "dP_{i}(x)/dx for i={0, 1, ..., 8}");
	p.legend("dP_{0}/dx", "dP_{1}/dx", "dP_{2}/dx", "dP_{3}/dx", "dP_{4}/dx", "dP_{5}/dx", "dP_{6}/dx", "dP_{7}/dx", "dP_{8}/dx");
	p.hold(false);

	// (3) Find zeros with secant and secant falsi methods
	//     and since we are iterating thru the Legendre polynomials and their Gauss points
	//     -> use the gained insight to apply GL quadrature to a given function and interval
	//        and measure the error of approximation
	MatrixXd zeros_x = gaussPts(MAX_K, secant);
	MatrixXd zeros_x_falsi = gaussPts(MAX_K, secant_falsi);
	VectorXd zeros_y = VectorXd::Zero(MAX_K);

	vector<double> x = {MIN, MAX};
	vector<double> y = {0.0, 0.0};

	ArrayXd i_values(MAX_K+1);
	i_values[0] = 0.0;
	ArrayXd areas(MAX_K+1);
	areas[0] = 0.0; // P0 is not tested

	for(int i=1; i <= MAX_K; i++) {
		p.figure("Legendre polynomial " + description[i] + " Zeros / Gauss points by secant and secant falsi methods.");
		yy = Lx.row(i);
		p.plot(xx, yy, colors[i % n_colors]);
		p.hold();
		p.title("Legendre polynomial " + description[i] + " Zeros / Gauss points by secant and secant falsi methods.");
		// secant
		VectorXd gyy = zeros_y.head(i);
		VectorXd gxx = zeros_x.col(i-1);
		gxx = gxx.head(i);
		p.plot(gxx, gyy, "ko");
		// true position of these "zeros"
		MatrixXd Lgx(i+1, i);
		MatrixXd DLgx(i+1, i);
		legvals(gxx, Lgx, DLgx);
		VectorXd true_gyy = Lgx.row(i);
		p.plot(gxx, true_gyy, "b*"); // note: This may not be visible if secant falsi gets the same result
		                             // but P8 shows a clear difference
		p.comment("zeros for " + description[i] + " by secant method");
		for(int j=0; j < i; j++) {
			p.comment("x = " + to_string(gxx[j]) + " y = " + to_string(true_gyy[j]) + " expected 0.0");
		}

		// falsi
		gxx = zeros_x_falsi.col(i-1);
		gxx = gxx.head(i);
		p.plot(gxx, gyy, "r*");
		// true position of these "zeros"
		legvals(gxx, Lgx, DLgx);
		true_gyy = Lgx.row(i);
		p.comment("zeros for " + description[i] + " by secant falsi method");
		for(int j=0; j < i; j++) {
			p.comment("x = " + to_string(gxx[j]) + " y = " + to_string(true_gyy[j]) + " expected 0.0");
		}
		// calculation of weights for GL-quadrature on standard interval [-1,1]
		p.comment("");
		p.comment(description[i] + ": Weights w_i and gauss points x_i needed for Gauss-Legendre quadrature");
		p.comment("(integration approximation) on interval [-1, 1]. Use appropriate scaling for other intervals.");
		ArrayXd DLgx_squared = DLgx.row(i).array();
		DLgx_squared *= DLgx_squared;
		ArrayXd gww = gxx.cwiseProduct(gxx).array();
		gww = -gww; // intermediary step since - seems not to be defined in combination with scalars
		gww = gww + 1.0;
		gww = gww.cwiseProduct(DLgx_squared);
		gww = 2.0 / gww;
		for(int j=0; j < i; j++) {
			string index = to_string(j);
			p.comment("w_" + index + " = " + to_string(gww[j]) +" x_" + index + " = " + to_string(gxx[j]) );
		}

		// let's test this on an effective quadrature
		double area = GLquadrature(test_function_for_quadrature, A, B, gww, gxx.array());
		p.comment("-> quadrature of f(x)=e^(x^2) in [" + to_string(A) + "," + to_string(B) + "] approx. = " + to_string(area));
		areas[i] = area;
		i_values[i] = (double)i;

		// null line
		p.plot(x, y, "k:");
		// info
		p.xylabels("x", description[i] + "(x)");
		p.legend(description[i], "zeros by secant", "true y value of these zeros", "zeros by secant falsi");
		p.hold(false);
	}

	// show relative errors (P1 to P8 vs reference result)
	double negReference = -REFERENCE_RESULT;
	ArrayXd error = areas + negReference; // workaround since - is not accepted with scalars (while + is)
	error = error.cwiseAbs() / REFERENCE_RESULT;

	// do not show P0
	i_values = i_values.tail(MAX_K);
	error = error.tail(MAX_K);

	p.figure("Relative errors of P1 to P8 vs reference result from Wolfram|Alpha", MatlabPlotter::LINEAR);
	p.plot(i_values, error, "r*-");
	p.xylabels("P_{i}", "Relative error vs reference result (lin scale)");
	p.title("Relative errors of P1 to P8 vs reference result from Wolfram|Alpha");

	p.figure("Relative errors of P1 to P8 vs reference result from Wolfram|Alpha", MatlabPlotter::SEMILOGY);
	p.plot(i_values, error, "r*-");
	p.xylabels("P_{i}", "Relative error vs reference result (log scale)");
	p.title("Relative errors of P1 to P8 vs reference result from Wolfram|Alpha");

	return 0;
}


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

const static Eigen::IOFormat CSVFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, "\t", "\n");

int main()
{
	// Initialization of vectors and matrices
    Eigen::VectorXd a_1(3), a_2(3), a_3(3), x(3), y(3);
	Eigen::MatrixXd matA(3,3);

	// Definition of vectors and matrices
    a_1 << 1./2., sqrt(3.)/2., 0.;
    a_2 << -1./2., sqrt(3.)/2., 0.;
    a_3 << 0., 0., 1.;
    matA << a_1, a_2, a_3;

    // b), c)
    x << 2., 0., 2.;
    y << 1., 2.*sqrt(3.), 3;

	// Use PartialPivLU as it was told in the exercise.
	Eigen::PartialPivLU<Eigen::MatrixXd> matPivLU(matA);
	Eigen::VectorXd x_new = matPivLU.solve(x);
	Eigen::VectorXd y_new = matPivLU.solve(y);

	// Produce U, L, P matrices and check if everything works as expected.
	Eigen::MatrixXd U = matPivLU.matrixLU().triangularView<Eigen::Upper>();
    Eigen::MatrixXd L = matPivLU.matrixLU().triangularView<Eigen::UnitLower>();
    Eigen::MatrixXd P = matPivLU.permutationP();
    Eigen::MatrixXd P_inv = P.inverse();
    Eigen::MatrixXd matA_new = P_inv * L * U;

	// d) Do the same with the reversed (rev) basis vectors in the matrix.
	Eigen::MatrixXd matA_rev(3,3);
    matA_rev << a_3, a_2, a_1;

	// Everything is done as before.
	Eigen::PartialPivLU<Eigen::MatrixXd> matPivLU_rev(matA_rev);
	Eigen::VectorXd x_new_rev = matPivLU_rev.solve(x);
	Eigen::VectorXd y_new_rev = matPivLU_rev.solve(y);

	Eigen::MatrixXd U_rev = matPivLU_rev.matrixLU().triangularView<Eigen::Upper>();
    Eigen::MatrixXd L_rev = matPivLU_rev.matrixLU().triangularView<Eigen::UnitLower>();
    Eigen::MatrixXd P_rev = matPivLU_rev.permutationP();
    Eigen::MatrixXd P_inv_rev = P_rev.inverse();
    Eigen::MatrixXd matA_new_rev = P_inv_rev * L_rev * U_rev;

	std::ofstream output;
	output.open("bin/Aufgabe1.txt", std::ofstream::out | std::ofstream::trunc);
	output << "Matrix U:\n" << U << std::endl;
	output << "Matrix L:\n" <<L << std::endl;
	output << "Matrix P:\n" << P.format(CSVFormat) << std::endl;
	output << "Matrix A:\n" << matA.format(CSVFormat) << std::endl;
	output << "Matrix A_new:\n" << matA_new.format(CSVFormat) << std::endl;
	output << "Vector x:\n" << x.format(CSVFormat) << std::endl;
	output << "Vector x_new:\n" << x_new.format(CSVFormat) << std::endl;
	output << "Vector y:\n" << y.format(CSVFormat) << std::endl;
	output << "Vector y_new:\n" << y_new.format(CSVFormat) << std::endl;

	output << "Matrix U_rev:\n" << U_rev.format(CSVFormat) << std::endl;
	output << "Matrix L_rev:\n" <<L_rev.format(CSVFormat) << std::endl;
	output << "Matrix P_rev:\n" << P_rev.format(CSVFormat) << std::endl;
	output << "Matrix A_rev:\n" << matA_rev.format(CSVFormat) << std::endl;
	output << "Matrix A_new_rev:\n" << matA_new_rev.format(CSVFormat) << std::endl;
	output << "Vector x_rev:\n" << x.format(CSVFormat) << std::endl;
	output << "Vector x_new_rev:\n" << x_new_rev.format(CSVFormat) << std::endl;
	output << "Vector y_rev:\n" << y.format(CSVFormat) << std::endl;
	output << "Vector y_new_rev:\n" << y_new_rev.format(CSVFormat) << std::endl;
	output.close();

	// Aufgabe 2

	// Initialization of the vector and the matrix.
	Eigen::VectorXd x2(10), y2(10);
	Eigen::MatrixXd A(10, 2);

	// x2 and y2 are the input vectors. A is the matrix resulting from the original minimization problem.
	x2 <<  0., 2.5, -6.3, 4., -3.2, 5.3, 10.1, 9.5, -5.4, 12.7;
	A << x2, Eigen::VectorXd::Ones(10);
	y2 << 4., 4.3, -3.9, 6.5, 0.7, 8.6, 13., 9.9, -3.6, 15.1;

	// Transform A to a pseudo quadratic matrix as explained in the lecture and transform y2 as well.
	Eigen::MatrixXd mat = A.transpose() * A;
	Eigen::VectorXd b = A.transpose() * y2;

	// Use the same calculation as in Exercise 1 to solve the problem.
	Eigen::PartialPivLU<Eigen::MatrixXd> matPivLU2(mat);
	Eigen::Vector2d alpha = matPivLU2.solve(b);

	Eigen::VectorXd result = A * alpha;
	// Save everything in a file to copy the results into an output file and to use it as input for a visualization script in python.

	Eigen::MatrixXd xy(10, 2);
	xy << x2, y2;
	std::ofstream file;
	file.open("bin/python_Aufgabe2.txt", std::ofstream::out | std::ofstream::trunc);
	file << "# x, y\n" << xy.format(CSVFormat) << std::endl;
	file << "#m, n\n " << alpha.transpose().format(CSVFormat);
	file.close();

	// std::ofstream file2;
	// file2.open("bin/python_result.txt", std::ofstream::out | std::ofstream::trunc);

	// file2.close();
    return 0;
}


//
// Created by Vlad Argunov on 13/11/2021.
//

#include "nonuniform_grid.h"

#include <Eigen/Dense>
#include <string>

void create_nonuniform_grid(Eigen::VectorXd & x_range, double x_min, double x_max, double alpha, double beta, int m) {
    /*The function transforms the grid in the non-uniform manner concentrating around the beta.
     * Parameter alpha is responsible for the fraction of points lying in the neighbourhood of the beta.
     * Important! The length of x_range must be of m + 1 exactly.*/

    double xi;
    double dxi = (asinh((x_max - beta)/alpha) - asinh((x_min - beta)/alpha)) / m;

    for (int i = 0; i < m + 1; ++i) {
        xi = asinh(- beta / alpha) + i * dxi;
        x_range(i,0) = beta + alpha * sinh(xi);
    }
}


/**
 * @file contourplot.cc
 * @brief NPDE homework ContourPlot code
 * @author Unknown, Oliver Rietmann
 * @date 25.03.2021
 * @copyright Developed at ETH Zurich
 */

#include "contourplot.h"

#include <Eigen/Core>

namespace ContourPlot {

/* SAM_LISTING_BEGIN_0 */
Eigen::Matrix<double, 2, Eigen::Dynamic> crookedEgg() {
#if SOLUTION
  auto gradF = [](Eigen::Vector2d x) -> Eigen::Vector2d {
    return 4.0 * x.squaredNorm() * x - 3.0 * x.cwiseAbs2();
  };
  Eigen::Vector2d y0(1.0, 0.0);
  double T = 4.0;
  return computeIsolinePoints(gradF, y0, T);
#else
  //====================
  // Your code goes here
  // Replace the following dummy return value
  // by the matrix containing the isoline points:
  return Eigen::Matrix<double, 2, 42>::Zero();
  //====================
#endif
}
/* SAM_LISTING_END_0 */

}  // namespace ContourPlot


#include <Eigen/Dense>
#include <iostream>
// Solves an eigenvalue problem, print out the solution plus some checks:

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

  Eigen::VectorXd Y(2);
  Y(0)= 1.0;
  Y(1)= 3.0;

  Eigen::MatrixXd A(2,2);
  A(0,0)= 1.0; A(0,1)=2.0;
  A(1,0)= 2.0; A(1,1)=9.0;

  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> s(A);
  Eigen::VectorXd  val=s.eigenvalues();
  Eigen::MatrixXd  vec=s.eigenvectors();

  std::cout << "Eigenvalues:\n "  << val << std::endl;
  std::cout << std::endl;

  std::cout << "Eigenvectors A:\n " << vec << std::endl;
  std::cout << std::endl;

  std::cout << "Aᵀ⋅A:\n" << vec.transpose()*vec << std::endl;
  std::cout << std::endl;

  std::cout << "Reconstituted original matrix:\n" <<  vec*val.asDiagonal()*vec.transpose() << std::endl;
  std::cout << std::endl;

}


// compile with: g++ template_structured_matrix_vector.cpp -I/usr/include/eigen3 -lmgl

//#include <chrono>
#include <iostream>
#include <iomanip>
//#include <limits>
//#include <ratio>
#include <vector>

#include <Eigen/Dense>
#include <mgl2/mgl.h>

using namespace Eigen;

/* \brief compute $\mathbf{A}\mathbf{x}$
 * \mathbf{A} is defined by $(\mathbf{A})_{i,j} := \min {i,j}$
 * \param[in] x vector x for computation of A*x = y
 * \param[out] y = A*x
 */
void multAminSlow(const VectorXd & x, VectorXd & y) {
    unsigned int n = x.size();

    VectorXd one = VectorXd::Ones(n);
    VectorXd linsp = VectorXd::LinSpaced(n,1,n);
    y = ( ( one * linsp.transpose() )
          .cwiseMin( linsp * one.transpose()) ) * x;
}

/* \brief compute $\mathbf{A}\mathbf{x}$
 * \mathbf{A} is defined by $(\mathbf{A})_{i,j} := \min {i,j}$
 * Instead of a "Matlab style" construcion of the product,
 * we use simple loops.
 * \param[in] x vector x for computation of A*x = y
 * \param[out] y = A*x
 */
void multAminLoops(const VectorXd & x, VectorXd & y) {
    unsigned int n = x.size();

    MatrixXd A(n,n);

    for(unsigned int i = 0; i < n; ++i) {
        for(unsigned int j = 0; j < n; ++j) {
            A(i,j) = std::min(i+1,j+1);
        }
    }
    y = A * x;
}

/* \brief compute $\mathbf{A}\mathbf{x}$
 * This function has optimal complexity.
 * \mathbf{A} is defined by $(\mathbf{A})_{i,j} := \min {i,j}$
 * \param[in] x vector x for computation of A*x = y
 * \param[out] y = A*x
 */
void multAmin(const VectorXd & x, VectorXd & y) {
    unsigned int n = x.size();
    y = VectorXd::Zero(n);

    VectorXd sum_left(n);
    VectorXd sum_right(n);

    sum_left(0) = 0;
    for(int i = 1; i < n; i++) {
      sum_left(i) = sum_left(i - 1) + i * x(i - 1);
    }

    sum_right(n - 1) = x(n - 1);
    for(int i = n - 2; i >= 0; i--) {
      sum_right(i) = sum_right(i + 1) + x(i);
    }

    for(int i = 0; i < n; i++) {
      y(i) = sum_left(i) + (i + 1) * sum_right(i);
    }
}

int main(void) {
    // Testing correctness of the code
    unsigned int M = 10;
    VectorXd xa = VectorXd::Random(M);
    VectorXd ys, yf;

    multAmin(xa, yf);
    multAminSlow(xa, ys);
    // Error should be small
    std::cout << "||ys-yf|| = " << (ys - yf).norm() << std::endl;

    unsigned int nLevels = 9;
  	unsigned int *n = new unsigned int[nLevels];
  	double *minTime = new double[nLevels];
  	double *minTimeLoops = new double[nLevels];
  	double *minTimeEff = new double[nLevels];

  	n[0] = 4;
  	for (unsigned int i=1; i<nLevels; i++)
  		n[i] = 2*n[i-1];

  	//TODO: Point (c)

    // Plotting with MathGL
    double nMgl[nLevels];
    double ref1[nLevels], ref2[nLevels];
    for (int i=0; i<nLevels; i++) {
    	nMgl[i] = n[i];
    	ref1[i] = 1e-8*pow(n[i],2);
    	ref2[i] = 1e-7*n[i];
    }

    mglData matSize;
    matSize.Link(nMgl, nLevels);

    mglData data1, data2;
    mglData dataRef1, dataRef2;
  	data1.Link(minTime, nLevels);
  	data2.Link(minTimeEff, nLevels);
  	dataRef1.Link(ref1,nLevels);
  	dataRef2.Link(ref2,nLevels);

  	mglGraph *gr = new mglGraph;
    gr->Title("Runtime of multAmin");
  	gr->SetRanges(n[0],n[0]*pow(2,nLevels-1),1e-6,1e+1);  gr->SetFunc("lg(x)","lg(y)");
  	gr->Axis();
  	gr->Plot(matSize,data1,"k +"); gr->AddLegend("slow","k +");
  	gr->Plot(matSize,data2,"r +"); gr->AddLegend("efficient","r +");
  	gr->Plot(matSize,dataRef1,"k"); gr->AddLegend("O(n^2)","k");
  	gr->Plot(matSize,dataRef2,"r"); gr->AddLegend("O(n)","r");
  	gr->Label('x',"Matrix size [n]",0);
  	gr->Label('y', "Runtime [s]",0);
    gr->Legend(2);
	  gr->WriteFrame("multAmin_comparison.eps");

    // The following code is just for demonstration purposes.
    // Build Matrix B with dimension 10x10
    unsigned int nn = 10;
    MatrixXd B = MatrixXd::Zero(nn,nn);
    for(unsigned int i = 0; i < nn; ++i) {
        B(i,i) = 2;
        if(i < nn-1) B(i+1,i) = -1;
        if(i > 0) B(i-1,i) = -1;
    }
    B(nn-1,nn-1) = 1;

    // Point (e)
    MatrixXd A(nn, nn);
    for(unsigned int i = 0; i < nn; ++i) {
        for(unsigned int j = 0; j < nn; ++j) {
            A(i,j) = std::min(i + 1, j + 1);
        }
    }

    // We observe that A is the Inverse of B since AB = I
    std::cout << A * B << std::endl;
}


// Copyright Christopher Kormanyos 2013.
// Copyright Paul A. Bristow 2013.
// Copyright John Maddock 2013.

// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or
// copy at http://www.boost.org/LICENSE_1_0.txt).

#ifdef _MSC_VER
#  pragma warning (disable : 4512) // assignment operator could not be generated.
#  pragma warning (disable : 4996) // assignment operator could not be generated.
#endif

#include <iostream>
#include <limits>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <iterator>

//[neumann_zeros_example_1

/*`[h5 Calculating zeros of the Neumann function.]
This example also shows how Boost.Math and Boost.Multiprecision can be combined to provide
a many decimal digit precision. For 50 decimal digit precision we need to include
*/

  #include <boost/multiprecision/cpp_dec_float.hpp>

/*`and a `typedef` for `float_type` may be convenient
(allowing a quick switch to re-compute at built-in `double` or other precision)
*/
  typedef boost::multiprecision::cpp_dec_float_50 float_type;

//`To use the functions for finding zeros of the `cyl_neumann` function we need:

  #include <boost/math/special_functions/bessel.hpp>
//] [/neumann_zerso_example_1]

int main()
{
  try
  {
    {
//[neumann_zeros_example_2
/*`The Neumann (Bessel Y) function zeros are evaluated very similarly:
*/
    using boost::math::cyl_neumann_zero;
    double zn = cyl_neumann_zero(2., 1);
    std::cout << "cyl_neumann_zero(2., 1) = " << zn << std::endl;

    std::vector<float> nzeros(3); // Space for 3 zeros.
    cyl_neumann_zero<float>(2.F, 1, nzeros.size(), nzeros.begin());

    std::cout << "cyl_neumann_zero<float>(2.F, 1, ";
    // Print the zeros to the output stream.
    std::copy(nzeros.begin(), nzeros.end(),
              std::ostream_iterator<float>(std::cout, ", "));

    std::cout << "\n""cyl_neumann_zero(static_cast<float_type>(220)/100, 1) = "
      << cyl_neumann_zero(static_cast<float_type>(220)/100, 1) << std::endl;
    // 3.6154383428745996706772556069431792744372398748422

//] //[/neumann_zeros_example_2]
    }
  }
  catch (std::exception ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }
} // int main()

/*
 Output:

cyl_neumann_zero(2., 1) = 3.38424
cyl_neumann_zero<float>(2.F, 1,
3.38424
6.79381
10.0235
3.61544
*/


#include <Eigen/Dense>
#include <iostream>
#include <ctime>
#define     N   7

//! \brief Compute an ONB of the space orthogonal to $v$
//! \param[in] v vector $ v \in \mathbb{R}^n \setminus \{ 0 \} $
//! \param[out] Z matrix $ Z \in \mathbb{R}^{n-1 \times n} $
void houserefl(const Eigen::VectorXd & v, Eigen::MatrixXd & Z)
{
    unsigned int n = v.size();
    Eigen::VectorXd w = v.normalized();
    Eigen::VectorXd u=w;
    u(0) += 1;
    Eigen::VectorXd  q=u.normalized();
    Eigen::MatrixXd X = Eigen::MatrixXd::Identity(n, n) - 2*q*q.transpose();
    Z = X.rightCols(n-1);
}

int main(int argc, char ** argv) {
    // Check what houserefl does to random vector
    srand((unsigned int) time(0));
    unsigned int n = N;
    if(argc >= 2) n = std::atoi(argv[1]);

    Eigen::VectorXd v = Eigen::VectorXd::Random(n); // Not truly random if missing srand
    Eigen::MatrixXd Z;

    houserefl(v, Z);

    std::cout << "v = " << v << std::endl;
    std::cout << "Z = " << Z << std::endl;
}

Nummerical Methods for CSE/solutions/solution_0/houserefl.cpp


#include <iostream>
#include <armadillo>
#include <stdlib.h>

#define CLOSE_TO_ZERO 0.00001

using namespace std;
using namespace arma;

/**
 * Gauss Elimination Without Pivoting
 * @param  aug_mat Augmented Matrix
 * @return         Solution Vector
 */
vec gauss_elimination(mat aug_mat) {
    //: Check for Singularity
    mat coeff_matrix = aug_mat.submat(0, 0, aug_mat.n_rows - 1, aug_mat.n_cols - 2);
    double determinant_coeff_mat = det(coeff_matrix);

    if (abs(determinant_coeff_mat) < CLOSE_TO_ZERO) {
        cout << "[ERR] Singular Coeffecient Matrix.";
        exit (EXIT_FAILURE);
    }

    //: Row Eliminations
    for (int i = 0; i < aug_mat.n_rows - 1; ++i) {
        for (int j = i+1; j < aug_mat.n_rows; ++j) {
            double ratio = aug_mat(j, i) / aug_mat(i, i);
            aug_mat.row(j) = aug_mat.row(j) - ratio * aug_mat.row(i);
        }
    }

    for (int i = aug_mat.n_rows - 1; i > 0; --i) {
        for (int j = i-1; j >= 0; --j) {
            double ratio = aug_mat(j, i) / aug_mat(i, i);
            aug_mat.row(j) = aug_mat.row(j) - ratio * aug_mat.row(i);
        }
    }

    // Calculating the X. Divide the last column (B) of the Augmented Matrix by the
    // Diagonal of the Augmenterd matrix.
    vec x = aug_mat.col(aug_mat.n_cols - 1) / aug_mat.diag();

    return x;
}

/**
 * Gauss Elimination With Pivoting
 * @param  aug_mat Augmented Matrix
 * @return         Solution Vector
 */
vec gauss_elimination_pivoted(mat aug_mat) {
    //: Check for Singularity
    mat coeff_matrix = aug_mat.submat(0, 0, aug_mat.n_rows - 1, aug_mat.n_cols - 2);
    double determinant_coeff_mat = det(coeff_matrix);

    if (abs(determinant_coeff_mat) < CLOSE_TO_ZERO) {
        cout << "[ERR] Singular Coeffecient Matrix.";
        exit (EXIT_FAILURE);
    }

    //: Pivoting
    for (int i = 0; i < aug_mat.n_cols-1; ++i) {
        uword r;
        aug_mat.col(i).max(r);
        aug_mat.swap_rows(r, i);
    }

    //: Row Eliminations
    for (int i = 0; i < aug_mat.n_rows - 1; ++i) {
        for (int j = i+1; j < aug_mat.n_rows; ++j) {
            double ratio = aug_mat(j, i) / aug_mat(i, i);
            aug_mat.row(j) = aug_mat.row(j) - ratio * aug_mat.row(i);
        }
    }

    for (int i = aug_mat.n_rows - 1; i > 0; --i) {
        for (int j = i-1; j >= 0; --j) {
            double ratio = aug_mat(j, i) / aug_mat(i, i);
            aug_mat.row(j) = aug_mat.row(j) - ratio * aug_mat.row(i);
        }
    }

    // Calculating the X. Divide the last column (B) of the Augmented Matrix by the
    // Diagonal of the Augmenterd matrix.
    vec x = aug_mat.col(aug_mat.n_cols - 1) / aug_mat.diag();

    return x;
}

/**
 * L U Decomposition
 * @param  aug_mat Augmented Matrix
 * @return         Solution Vector
 */
vec l_u_decomposition(mat aug_mat) {
    mat coeff_matrix = aug_mat.submat(0, 0, aug_mat.n_rows - 1, aug_mat.n_cols - 2);

    //: Declare l and u matrices.
    mat l(size(coeff_matrix)), u(size(coeff_matrix));

    //: Declare column vectors.
    colvec b, x, y;

    //: Decompose B from Augmented Matrix.
    b = aug_mat.col(aug_mat.n_cols - 1);

    //: Check for Singularity
    double determinant_coeff_mat = det(coeff_matrix);

    if (abs(determinant_coeff_mat) < CLOSE_TO_ZERO) {
        cout << "[ERR] Singular Coeffecient Matrix.";
        exit (EXIT_FAILURE);
    }

    //: Identity matrix
    l.eye();
    //: Prepare U
    u = coeff_matrix;

    //: Calculate L and U
    for (int i = 0; i < coeff_matrix.n_rows-1; ++i) {
        for (int j = i+1; j < coeff_matrix.n_rows; ++j) {
            double ratio = u(j, i) / u(i, i);

            u.row(j) = u.row(j) - ratio*u.row(i);
            l(j, i) = ratio;
        }
    }

    //: b is B vector for y
    y = (l.i()) * b;

    //: y is B vector for x
    x = (u.i()) * y;

    return x;
}

/**
 * Gauss Jacobi Method
 * NOTE: This method does NOT guarantee a solution.
 * @param  aug_mat Augmented Matrix
 * @return         Solution Vector
 */
vec gauss_jacobi(mat aug_mat) {
    mat coeff_matrix = aug_mat.submat(0, 0, aug_mat.n_rows - 1, aug_mat.n_cols - 2);

    //: Declare column vectors.
    colvec x, xi, b;

    x.resize(coeff_matrix.n_cols);
    x.zeros();
    xi.resize(coeff_matrix.n_cols);
    xi.zeros();

    //: Decompose B from Augmented Matrix.
    b = aug_mat.col(aug_mat.n_cols - 1);

    //: Check for Singularity
    double determinant_coeff_mat = det(coeff_matrix);

    if (abs(determinant_coeff_mat) < CLOSE_TO_ZERO) {
        cout << "[ERR] Singular Coeffecient Matrix.";
        exit (EXIT_FAILURE);
    }

    int count=0;
    while(++count < 50) {
        for (int i = 0 ; i < coeff_matrix.n_cols ; ++i) {
            double sigma = 0;
            for (int j = 0; j < coeff_matrix.n_cols ; ++j) {
                if (i != j) {
                    sigma = sigma + coeff_matrix(i, j) * x(j);
                }
            }
            xi(i) = (b(i) - sigma) / coeff_matrix(i, i);
        }
        //: Update X
        x = xi;
    }

    return x;
}

/**
 * Gauss Seidel Method
 * NOTE: This method does NOT guarantee a solution.
 * @param  aug_mat Augmented Matrix
 * @return         Solution Vector
 */
vec gauss_seidel(mat aug_mat) {
    mat coeff_matrix = aug_mat.submat(0, 0, aug_mat.n_rows - 1, aug_mat.n_cols - 2);

    //: Declare column vectors.
    colvec x, xi, b;

    x.resize(coeff_matrix.n_cols);
    x.zeros();
    xi.resize(coeff_matrix.n_cols);
    xi.zeros();

    //: Decompose B from Augmented Matrix.
    b = aug_mat.col(aug_mat.n_cols - 1);

    //: Check for Singularity
    double determinant_coeff_mat = det(coeff_matrix);

    if (abs(determinant_coeff_mat) < CLOSE_TO_ZERO) {
        cout << "[ERR] Singular Coeffecient Matrix.";
        exit (EXIT_FAILURE);
    }

    int count=0;
    while(++count < 50) {
        for (int i = 0 ; i < coeff_matrix.n_cols ; ++i) {
            double sigma = 0;
            for (int j = 0; j < coeff_matrix.n_cols ; ++j) {
                if (i != j) {
                    sigma = sigma + coeff_matrix(i, j) * xi(j);
                }
            }
            xi(i) = (b(i) - sigma) / coeff_matrix(i, i);
        }
        //: Update X
        x = xi;
    }

    return x;
}

/**
 * Main Function
 * @param  argc Commandline Argument Counts
 * @param  argv Commandline Argument Vectors
 * @return      Exit Status
 */
int main(int argc, char** argv) {

    //: The Augmented Matrix needs to be put here.
    mat aug_mat = {
        {2, 1, 11},
        {5, 7, 13}
    };

    gauss_elimination(aug_mat).print("Gauss Elimination Without Pivoting:");
    gauss_elimination_pivoted(aug_mat).print("Pivoted Gaussian Elimination");
    l_u_decomposition(aug_mat).print("L U Decomposition");
    gauss_jacobi(aug_mat).print("Gauss Jacobi");
    gauss_seidel(aug_mat).print("Gauss Seidel");

    return 0;
}


// arcsine_example.cpp

// Copyright John Maddock 2014.
// Copyright  Paul A. Bristow 2014.

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

// Example for the arcsine Distribution.

// Note: Contains Quickbook snippets in comments.

//[arcsine_snip_1
#include <boost/math/distributions/arcsine.hpp> // For arcsine_distribution.
//] [/arcsine_snip_1]

#include <iostream>
#include <exception>
#include <boost/math/tools/assert.hpp>

int main()
{
  std::cout << "Examples of Arcsine distribution." << std::endl;
  std::cout.precision(3);  // Avoid uninformative decimal digits.

  using boost::math::arcsine;

  arcsine as; // Construct a default `double` standard [0, 1] arcsine distribution.

//[arcsine_snip_2
  std::cout << pdf(as, 1. / 2) << std::endl; // 0.637
  // pdf has a minimum at x = 0.5
//]  [/arcsine_snip_2]

//[arcsine_snip_3
  std::cout << pdf(as, 1. / 4) << std::endl; // 0.735
//]  [/arcsine_snip_3]

//[arcsine_snip_4
  std::cout << cdf(as, 0.05) << std::endl; // 0.144
//] [/arcsine_snip_4]

//[arcsine_snip_5
  std::cout << 2 * cdf(as, 1 - 0.975) << std::endl; // 0.202
//] [/arcsine_snip_5]

//[arcsine_snip_6
  std::cout << 2 * cdf(complement(as, 0.975)) << std::endl; // 0.202
//] [/arcsine_snip_6]

//[arcsine_snip_7
  std::cout << quantile(as, 1 - 0.2 / 2) << std::endl; //  0.976

  std::cout << quantile(complement(as, 0.2 / 2)) << std::endl; // 0.976
//] [/arcsine_snip_7]

{
//[arcsine_snip_8
  using boost::math::arcsine_distribution;

  arcsine_distribution<> as(2, 5); // Constructs a double arcsine distribution.
  BOOST_MATH_ASSERT(as.x_min() == 2.);  // as.x_min() returns 2.
  BOOST_MATH_ASSERT(as.x_max() == 5.);   // as.x_max()  returns 5.
//] [/arcsine_snip_8]
}
    return 0;

} // int main()

/*
[arcsine_output

Example of Arcsine distribution
0.637
0.735
0.144
0.202
0.202
0.976
0.976

] [/arcsine_output]
*/


#include <iostream>

using namespace std;

#include <ctime>
// Eigen core
#include <Eigen/Core>
// For operations on dense matrices (inverse, eigenvals, etc)
#include <Eigen/Dense>

using namespace Eigen;

#define MATRIX_SIZE 50

/****************************
 * This program demonstrates the use of basic Eigen types
 ****************************/

int main(int argc, char **argv) {
  // All vectors and matrices in Eigen are Eigen::Matrix, which is a template
  // class. Its first three parameters are: data type, row, column Declare a 2∗3
  // float matrix
  Matrix<float, 2, 3> matrix_23;

  // At the same time, Eigen provides many built−in types via typedef, but the
  // bottom layer is still Eigen::Matrix. For example, Vector3d is essentially
  // Eigen::Matrix<double, 3, 1>, which is a three−dimensional vector.
  Vector3d v_3d;
  // This is the same as above
  Matrix<float, 3, 1> vd_3d;

  // Matrix3d is essentially Eigen::Matrix<double, 3, 3>
  Matrix3d matrix_33 = Matrix3d::Zero();  // Initialized to 0
  // If you are not sure about the size of the matrix, you can use a matrix of
  // dynamic size
  Matrix<double, Dynamic, Dynamic> matrix_dynamic;
  // Simpler way to define the same
  MatrixXd matrix_x;
  // There are still many types of this kind. We don't list them one by one.

  // Here is the operation of the Eigen matrix
  // input data (initialization)
  matrix_23 << 1, 2, 3, 4, 5, 6;
  // Initialize
  cout << "matrix 2x3 from 1 to 6: \n" << matrix_23 << endl;

  // Use () to access the elements
  cout << "print matrix 2x3: " << endl;
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) cout << matrix_23(i, j) << "\t";
    cout << endl;
  }

  // We can easily multiply a matrix with a vector (but actually still matrices and
  // matrices)
  v_3d << 3, 2, 1;
  vd_3d << 4, 5, 6;

  // In Eigen you can't mix two different types of matrices, like this is
  // wrong Matrix<double, 2, 1> result_wrong_type = matrix_23 ∗ v_3d;
  // It should be explicitly converted
  Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;
  cout << "[1,2,3;4,5,6]*[3,2,1]=" << result.transpose() << endl;

  Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;
  cout << "[1,2,3;4,5,6]*[4,5,6]: " << result2.transpose() << endl;

  // Also you can't misjudge the dimensions of the matrix
  // Try canceling the comments below to see what Eigen will report.
  // Eigen::Matrix<double, 2, 3> result_wrong_dimension =
  // matrix_23.cast<double>() ∗ v_3d;

  // Basic operations
  matrix_33 = Matrix3d::Random();  // Random
  cout << "random matrix: \n" << matrix_33 << endl;
  cout << "transpose: \n" << matrix_33.transpose() << endl;  // Transpose
  cout << "sum: " << matrix_33.sum() << endl;                // Sum of the elements
  cout << "trace: " << matrix_33.trace() << endl;            // Trace
  cout << "times 10: \n" << 10 * matrix_33 << endl;          // Scalar
  cout << "inverse: \n" << matrix_33.inverse() << endl;      // Inverse
  cout << "det: " << matrix_33.determinant() << endl;        // Matrix determinant

  // Eigenvalues
  // Real symmetric matrix can guarantee successful diagonalization
  Matrix3d sym_mat = matrix_33.transpose() * matrix_33;
  SelfAdjointEigenSolver<Matrix3d> eigen_solver(sym_mat);
  cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;
  cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;

  // Solving equations
  // We solve the equation of matrix_NN ∗ x = v_Nd
  // The size of N is defined in the previous macro, which is generated by a
  // random number Direct inversion is the most direct, but the amount of
  // inverse operations is large.

  Matrix<double, MATRIX_SIZE, MATRIX_SIZE> matrix_NN =
      MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
  matrix_NN = matrix_NN * matrix_NN.transpose();  // Guarantee semi−positive definite
  Matrix<double, MATRIX_SIZE, 1> v_Nd = MatrixXd::Random(MATRIX_SIZE, 1);

  clock_t time_stt = clock();  // timing
  // Direct inversion
  Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse() * v_Nd;
  cout << "time of normal inverse is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC
       << "ms" << endl;
  cout << "x = " << x.transpose() << endl;

  // Usually solved by matrix decomposition, such as QR decomposition, the speed
  // will be much faster
  time_stt = clock();
  x = matrix_NN.colPivHouseholderQr().solve(v_Nd);
  cout << "time of Qr decomposition is "
       << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;
  cout << "x = " << x.transpose() << endl;

  // For positive definite matrices, you can also use cholesky decomposition to
  // solve equations.
  time_stt = clock();
  x = matrix_NN.ldlt().solve(v_Nd);
  cout << "time of ldlt decomposition is "
       << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;
  cout << "x = " << x.transpose() << endl;

  return 0;
}


#include <Eigen/Dense>

double mse(Eigen::MatrixXd X, Eigen::VectorXd W, Eigen::VectorXd Y);

Eigen::VectorXd _derivative(Eigen::MatrixXd X, Eigen::VectorXd W,
                            Eigen::VectorXd Y) {
  /*
  Computes the jth derivative given W, X, Y
  by following gradient descent where
       D_j J(W,X) = (Y - X * W) * X_j
  */
  return -1 * X.transpose() * (Y - X * W);
}

Eigen::VectorXd _gradient_descent_step(Eigen::MatrixXd X, Eigen::VectorXd W,
                                       Eigen::VectorXd Y, double alpha) {
  /*
  Runs gradient descent for each row in the dataset X
  */
  Eigen::VectorXd W_temp = W;
  for (int j = 0; j < X.rows(); j++) {
    W_temp -= alpha * _derivative(X, W, Y);
  }

  return W_temp;
}

Eigen::VectorXd gradient_descent(Eigen::MatrixXd X, Eigen::MatrixXd Y,
                                 int *iter, bool *converged,
                                 int max_iterations, double threshold,
                                 double learning_rate) {
  Eigen::VectorXd W;
  /*
    Starting from a random set of weights W, use
    gradient descent to determine the optimal W. Stop
    when either the max iterations (not converged)
    or the error threshold (converged) is reached.
  */
  *converged = true;
  W = Eigen::MatrixXd::Random(X.cols(), 1);

  for (*iter = 0; *iter < max_iterations; *iter = *iter + 1) {
    W = _gradient_descent_step(X, W, Y, learning_rate);

    double error = mse(X, W, Y);
    if (error < threshold) {
      *converged = true;
      break;
    }
  }

  return W;
}


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

struct point
{
    int x, y;
};

int orientation(point p, point q, point r)
{
    int val = (q.y - p.y) * (r.x - q.x) -
              (q.x - p.x) * (r.y - q.y);

    if (val == 0) return 0;  // colinear
    return (val > 0)? 1: 2; // clock or counterclock wise
}

int pointLocation(point A, point B, point P)
    {
        int cp1 = (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x);
        if (cp1 > 0)
            return 1;
        else if (cp1 == 0)
            return 0;
        else
            return -1;
    }

 int distance(point A, point B, point C)
    {
        int ABx = B.x - A.x;
        int ABy = B.y - A.y;
        int num = ABx * (A.y - C.y) - ABy * (A.x - C.x);
        if (num < 0)
            num = -num;
        return num;
    }

  void hullSet(point A, point B, vector<point>set,vector<point>&hull)
  {
  	vector<point>::iterator it;
  	point alpha=B;
  	 it=find_if(hull.begin(),hull.end(),boost::bind (&point::x, _1 ) == alpha.x );

  	if (set.size() == 0)
            return;

    if (set.size() == 1)
        {
            point p = set[0];
            set.erase(set.begin()+0);
            hull.insert(it, p);
            return;
        }

    int dist = INT_MIN;
        int furthestPoint = -1;
        for (int i = 0; i <set.size(); i++)
        {
            point p = set[i];
            int distan = distance(A, B, p);
            if (distan > dist)
            {
                dist = distan;
                furthestPoint = i;
            }
        }

     point P = set[furthestPoint];
        set.erase(set.begin()+furthestPoint-1);
        hull.insert(it, P);

    // Determine who's to the left of AP
        vector<point>leftSetAP;
        for (int i = 0;i < set.size(); i++)
        {
            point M = set[i];
            if (pointLocation(A, P, M) == 1)
            {
                leftSetAP.push_back(M);
            }
        }

        // Determine who's to the left of PB
        vector<point>leftSetPB;
        for (int i = 0; i < set.size(); i++)
        {
            point M = set[i];
            if (pointLocation(P, B, M) == 1)
            {
                leftSetPB.push_back(M);
            }
        }
        hullSet(A, P, leftSetAP, hull);
        hullSet(P, B, leftSetPB, hull);

  }

void convexHull(point sample[], int n)
{

	if(n<3) return;
	// Initialize Result
    vector<point> hull;
    vector<point> Lefthull;
    vector<point> Righthull;

	 int minPoint = -1, maxPoint = -1;
        int minX = INT_MAX;
        int maxX = INT_MIN;
        for (int i=0;i<n; i++)
        {
            if (sample[i].x < minX)
            {
                minX = sample[i].x;
                minPoint = i;
            }
            if (sample[i].x > maxX)
            {
                maxX =sample[i].x;
                maxPoint = i;
            }
        }

         hull.push_back(sample[minPoint]);
         hull.push_back(sample[maxPoint]);

        point A = sample[minPoint];
        point B = sample[maxPoint];

          for(int i=0;i<n; i++)
        {
            point p = sample[i];
            if (pointLocation(A, B, p) == -1)
               Lefthull.push_back(p);
            else if (pointLocation(A, B, p) == 1)
                 Righthull.push_back(p);
        }

        hullSet(A, B, Righthull, hull);
        hullSet(B, A, Lefthull, hull);

    // Print Result
    for (int i = 0; i < hull.size(); i++)
        cout << "(" << hull[i].x << ", "
              << hull[i].y << ")\n";

}

int main() {
	 int N;
cout << "Enter no of points N "<<endl;
cin>>N;
point sample[N];

for (int i = 0; i < N; i++)
{
  cin>>sample[i].x>>sample[i].y;
}
//add timer here to calculate execution time
clock_t start;
double duration;
start = clock();

cout << "The points in the convex hull are: "<<endl;
convexHull(sample, N);

duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
cout<<"time: "<<duration <<" seconds"<<endl;
return 0;
}


#include <armadillo>

using namespace arma;

const static double π = 3.141592653589793238463;
const static float h = 0.74;
const static float l = 2.83;
const static float a = 0.95 + l;
const static float b = 0.50;

double measure(double θ){
  double tmp = std::fmod(θ,2*π);
  return tmp - ((int) (tmp/π))*2*π;
}

mat inverse(mat q){
  double d = q(0,0)*q(1,1)-q(0,1)*q(1,0);
  return {{q(1,1)/d,-q(0,1)/d},{-q(1,0)/d,q(0,0)/d}};
}

mat jacobian_motion(float θ, float v, float α, float dt){
  return {{1, 0, -dt*(v*std::sin(θ)+v/l*std::tan(α)*(a*std::cos(θ)-b*std::sin(θ)))},
          {0, 1,  dt*(v*std::cos(θ)-v/l*std::tan(α)*(a*std::sin(θ)+b*std::cos(θ)))},
          {0, 0,  1}};
}

vec equation_motion(float θ, float v1, float α, float dt){
  float v = v1/(1-std::tan(α)*h/l);
  return {dt*(v*std::cos(θ)-v/l*std::tan(α)*(a*std::sin(θ)+b*std::cos(θ))),
          dt*(v*std::sin(θ)+v/l*std::tan(α)*(a*std::cos(θ)-b*std::sin(θ))),
          dt*v/l*std::tan(α)};
}

mat jacobian_measurement(vec μ, vec m){
  //pb converting Col<uint> to uvec = Col<long long int>
  vec δ = m-μ(span(0,1));
  vec δ1 = sum(square(δ),0);
  double q = δ1(0);

  mat jcb = {{-δ(0),-δ(1),0,δ(0),δ(1)},
             {δ(1),-δ(0),-q,-δ(1),δ(0)}};
  jcb.row(0) *= (1/sqrt(q));
  jcb.row(1) *= (1/q);

  return jcb;
}

vec equation_measurement(vec μ, vec m){

  vec δ = m-μ(span(0,1));
  vec δ1 = sqrt(sum(square(δ),0));
  double q = δ1(0);
  double ϕ = atan2(δ(1),δ(0)) - μ(2) + π/2;
  return {q,ϕ};
}

mat inverse_measurement(vec μ, mat z){
  rowvec c = cos(z.row(1)+μ(2));
  rowvec s = sin(z.row(1)+μ(2));

  return mat(join_vert(z.row(0)%s,-z.row(0)%c)).each_col() + μ(span(0,1));
}


// Boost.Geometry
// QuickBook Example

// Copyright (c) 2020, Aditya Mohan

// Use, modification and distribution is 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)

//[dot_product
//` Calculate the dot product of two points

#include <iostream>

#include <boost/geometry.hpp>
#include <boost/geometry/arithmetic/dot_product.hpp>
#include <boost/geometry/geometries/adapted/boost_array.hpp>

namespace bg = boost::geometry; /*< Convenient namespace alias >*/

BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CS(cs::cartesian)

int main()
{
     double dp1,dp2,dp3,dp4;
     bg::model::point<double, 3, bg::cs::cartesian> point1(1.0, 2.0, 3.0);
     bg::model::point<double, 3, bg::cs::cartesian> point2(4.0, 5.0, 6.0);

     //Example 1
     dp1 = bg::dot_product(point1, point2);

     std::cout << "Dot Product 1: "<< dp1 << std::endl;

     bg::model::point<double, 2, bg::cs::cartesian> point3(3.0, 2.0);
     bg::model::point<double, 2, bg::cs::cartesian> point4(4.0, 7.0);

     //Example 2
     dp2 = bg::dot_product(point3, point4);

     std::cout << "Dot Product 2: "<< dp2 << std::endl;

     boost::array<double, 2> a =  {1, 2};
     boost::array<double, 2> b =  {2, 3};

     //Example 3
     dp3 = bg::dot_product(a, b);

     std::cout << "Dot Product 3: "<< dp3 << std::endl;

     return 0;

}

//]

//[dot_product_output
/*`
Output:
[pre
Dot Product 1: 32
Dot Product 2: 26
Dot Product 3: 8
]
*/
//]


#include <iostream>
#include <cstdio>
#include <armadillo>
#include <ctime>
#include <unistd.h>

#include "comp_eig.hh"

using namespace std;
using namespace arma;

const double rmin = 0;
const double rmax = 6;
const double epsilon = 1e-10;

struct program_output {
  size_t steps;
  double step_time;
  double arma_time;
  double err;
};

// potential function
static constexpr double V(double r) {
  return r * r;
}

// calculate maximal off-diagonal element with respect to absolute value
// return square of maximal off-diagonal element
static double maxoff(const mat &A, size_t &i, size_t &j) {
  i = 1; j = 0; // indices of maximal lement
  double a = 0; // square of maximal element

  SizeMat s = size(A);

  for(size_t k = 0; k < s.n_rows; k++) {
    for(size_t l = 0; l < s.n_cols; l++) {
      if(k == l) continue;

      const double x = A(k, l);
      const double y = x * x;
      if(y > a)
        i = k, j = l, a = y;
    }
  }

  return a;
}

static void apply_rot_col(size_t k, size_t l, double t, mat &M) {
  if(k == l) return;

  const double c = 1 / sqrt( 1 + t * t );
  const double s = t * c;

  colvec kvec = c * M.col(k) - s * M.col(l);
  colvec lvec = s * M.col(k) + c * M.col(l);

  M.col(k) = kvec;
  M.col(l) = lvec;
}

static void apply_rot_row(size_t k, size_t l, double t, mat &M) {
  if(k == l) return;

  const double c = 1 / sqrt( 1 + t * t );
  const double s = t * c;

  rowvec kvec = c * M.row(k) - s * M.row(l);
  rowvec lvec = s * M.row(k) + c * M.row(l);

  M.row(k) = kvec;
  M.row(l) = lvec;
}

// single step with Jacobi's method
static bool jacobi_step(mat &B, mat &P) {
  // calculate maximal off-diagonal element with respect to absolute value
  size_t k, l;
  const double a = maxoff(B, k, l); // square of maximal element

  // if less than epsilon, stop
  if(a < epsilon)
    return false;

  // calculate sin θ and cos θ
  const double tau = (B(l, l) - B(k, k)) / (2 * B(k, l));
  const double t = (tau >= 0 ? - tau - sqrt( 1 + tau * tau ) : - tau + sqrt( 1 + tau * tau ));

  // apply similarity transform
  //   B = S.t() * B * S;
  apply_rot_col(k, l, t, B);
  apply_rot_row(k, l, t, B);

  // apply S^T to P
  //   P = P * S;
  apply_rot_col(k, l, t, P);

  return true;
}

// solve with Jacobi's method
// A is input matrix, P is eigenvector matrix (with column vector eigenvectors), L is eigenvalue vector
static void jacobi_solve(const mat &A, mat &P, vec &L, size_t &steps, double &step_time) {
  // get N from A matrix
  const size_t N = A.n_rows;
  assert(A.n_cols == N);

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

  // B is similar matrix to A through matrix transforms
  mat B = A;

  // set P matrix (that will contain eigenvectors) to the identity matrix
  P.eye(size(A));

  clock_t time_start, time_end;
  double time_total = 0;
  steps = 0;
  while(true) {
    // timing
    time_start = clock();

    if(!jacobi_step(B, P))
      break;

    // timing
    time_end = clock();
    time_total += (double)(time_end - time_start) / CLOCKS_PER_SEC;
    steps++;
  }

  // export steps and time per step
  step_time = time_total / steps;

  std::cout << "JACOBI DONE (N = " << N << ", steps = " << steps << ", time per step = " << (1000 * step_time) << "ms)" << std::endl;

  // find eigenvalues
  L.set_size(N);
  for(size_t i = 0; i < N; i++)
    L(i) = B(i, i);
}

int run_program(size_t N, struct program_output &out) {
  const double h = (rmax - rmin) / N;

  // array of ρ valuses
  vec r(N);
  for(size_t i = 0; i < N; i++)
    r(i) = rmin + h * i;

  // calculate e_i, which are all the same
  double e = - 1 / (h * h);

  // calculate d_i, which depend on V(ρ_i)
  vec d(N);
  for(size_t i = 0; i < N; i++)
    d(i) = 2 / (h * h) + V(r[i]);

  // calculate matrix A
  mat A(N, N, arma::fill::zeros);
  for(size_t i = 0; i < N; i++) {
    A(i, i) = d(i);

    if(i > 0)
      A(i, i-1) = e;
    if(i < N - 1)
      A(i, i+1) = e;
  }

  // solve with Jacobi method
  vec eigenvalues;
  mat eigenvectors;
  jacobi_solve(A, eigenvectors, eigenvalues, out.steps, out.step_time);

  // solve with Armadillo's eig_sym
  clock_t arma_start, arma_finish;
  vec arma_eigenvalues;
  mat arma_eigenvectors;
  arma_start = clock();
  eig_sym(arma_eigenvalues, arma_eigenvectors, A);
  arma_finish = clock();
  out.arma_time = (double)(arma_finish - arma_start)/CLOCKS_PER_SEC;

  out.err = comp_eig(eigenvalues, eigenvectors, arma_eigenvalues, arma_eigenvectors);
}

#ifndef NO_MAIN
int main(int argc, char **argv) {
  const size_t Nvalues[] = { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100 };
  const size_t Nlen = sizeof(Nvalues) / sizeof(*Nvalues);

  FILE *fp = fopen("b.dat", "w");
  fprintf(fp, "N          epsilon    steps      step_time  arma_time  error\n");

  for(size_t i = 0; i < Nlen; i++) {
    size_t N = i[Nvalues]; // aww yeah abusing valid C++ syntax for no reason

    struct program_output out;

    std::cout << "running with N = " << N << std::endl;

    run_program(N, out);

    // write result row
    fprintf(fp, "%-10ld %-10.5g %-10ld %-10.5g %-10.5g %-10.5g\n", N, epsilon, out.steps, out.step_time, out.arma_time, out.err);
    fflush(fp);
  }

  fclose(fp);
}
#endif


/*****************************************************************************
 * reduce.cpp     Blitz++ array reduction example
 *
 * This example illustrates the array reduction functions provided by
 * Blitz++.  These functions reduce an N dimensional array (or array
 * expression) to an N-1 dimensional array expression by summing, taking
 * the mean, etc.  These array reductions are currently provided: sum,
 * mean, min, max, minIndex, maxIndex, product, count, any and all.
 *****************************************************************************/

#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

int main()
{
    Array<int, 2> A(4,4);

    A = 3,  1,  2,  4,
        8, -1, -5,  3,
        0,  9, -1,  4,
        1,  3,  1,  2;

    cout << "A = " << A << endl;

    /*
     * Reduce the array A to a one-dimensional array, by summing/taking
     * the mean/etc. of each row.
     */

    Array<int, 1> z(4);
    Array<float, 1> z2(4);
    secondIndex j;

    z = sum(A, j);
    cout << "sum(A,j) = " << endl << z << endl;

    z2 = mean(A, j);
    cout << "mean(A,j) = " << endl << z2 << endl;

    z = min(A, j);
    cout << "min(A,j) = " << endl << z << endl;

    z = minIndex(A, j);
    cout << "minIndex(A, j) = " << endl << z << endl;

    z = max(A, j);
    cout << "max(A, j) = " << endl << z << endl;

    z = maxIndex(A, j);
    cout << "maxIndex(A, j) = " << endl << z << endl;

    z = first((A < 0), j);
    cout << "first((A < 0), j) = " << endl << z << endl;

    z = product(A, j);
    cout << "product(A, j) = " << endl << z << endl;

    z = count( (A > 0), j);
    cout << "count((A > 0), j) = " << endl << z << endl;

    z = any((abs(A) > 4), j);
    cout << "any((abs(A) > 4), j) = " << endl << z << endl;

    z = all(A > 0, j);
    cout << "all(A > 0, j) = " << endl << z << endl;

    return 0;
}

/*
 * Output
 */
#if 0
A = 4 x 4
         3         1         2         4
         8        -1        -5         3
         0         9        -1         4
         1         3         1         2

sum(A,j) =
[         10         5        12         7 ]
mean(A,j) =
[        2.5      1.25         3      1.75 ]
min(A,j) =
[          1        -5        -1         1 ]
minIndex(A, j) =
[          1         2         2         0 ]
max(A, j) =
[          4         8         9         3 ]
maxIndex(A, j) =
[          3         0         1         1 ]
product(A, j) =
[         24       120         0         6 ]
count((A > 0), j) =
[          4         2         2         4 ]
any((abs(A) > 4), j) =
[          0         1         1         0 ]
all(A > 0, j) =
[          1         0         0         1 ]

#endif