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

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

#include <Eigen/Dense>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>

#include "nn.h"

inline void swap(int &val)
{
	val = (val<<24) | ((val<<8) & 0x00ff0000) | ((val>>8) & 0x0000ff00) | (val>>24);
}

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

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

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

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

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

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

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

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

  std::string path = argv[1];

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

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

  // number of optimization steps
  int max_steps = 600;
  // regularization parameter
  double lambda = 0.0;

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

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

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

  // train the network
  std::cout << "starting training" << std::endl;
  std::cout << "iter        error" << std::endl;
  double err;
  for (int i = 0; i < max_steps; ++i) {
    err = nn.loss(X_train, Y_train, lambda);
    nn.rprop();
    printf("%4i   %10.7f\n", i, err);
  }

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

  std::cout << "test accuracy: " << correct*1.0/Y_test.rows() << std::endl;

  nn.write("mnist.nn");

  return 0;
}


/*
 * Copyright (c) 2016 Abhishek Agrawal (abhishek.agrawal@protonmail.com)
 * Distributed under the MIT License.
 * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT
 */

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cmath>
#include <limits>
#include <vector>

#include <boost/numeric/odeint.hpp>

#include "NAOS/constants.hpp"
#include "NAOS/basicMath.hpp"
#include "NAOS/basicAstro.hpp"
#include "NAOS/misc.hpp"
#include "NAOS/ellipsoidGravitationalAcceleration.hpp"

namespace naos
{

//! equations of motion (for a particle around the asteroid modelled as a spheroid)
/*!
 * first order differential equations describing the motion of a particle or spacecraft around a
 * central body modeled as a spheroid using ellipsoid gravitational model.
 */
class equationsOfMotionParticleAroundSpheroid
{
    // declare parameters, gravitational parameter and the radius of the spheroid
    const double gravParameter;
    const double alpha;
    const double zRotation;

public:
    // Default constructor with member initializer list, get the gravitational parameter
    equationsOfMotionParticleAroundSpheroid( const double aGravParameter,
                       const double aAlpha,
                       const double aZRotation )
                    : gravParameter( aGravParameter ),
                      alpha( aAlpha ),
                      zRotation( aZRotation )
    { }
    void operator() ( const std::vector< double > &stateVector,
                      std::vector< double > &dXdt,
                      const double currentTime )
    {
        // calculate the gravitational accelerations first
        std::vector< double > gravAcceleration( 3, 0.0 );

        computeEllipsoidGravitationalAcceleration( alpha,
                                                   alpha,
                                                   alpha,
                                                   gravParameter,
                                                   stateVector[ xPositionIndex ],
                                                   stateVector[ yPositionIndex ],
                                                   stateVector[ zPositionIndex ],
                                                   gravAcceleration );

        // now calculate the derivatives
        dXdt[ xPositionIndex ] = stateVector[ xVelocityIndex ];
        dXdt[ yPositionIndex ] = stateVector[ yVelocityIndex ];
        dXdt[ zPositionIndex ] = stateVector[ zVelocityIndex ];

        dXdt[ xVelocityIndex ] = gravAcceleration[ xPositionIndex ]
                                + 2.0 * zRotation * stateVector[ yVelocityIndex ]
                                + zRotation * zRotation * stateVector[ xPositionIndex ];

        dXdt[ yVelocityIndex ] = gravAcceleration[ yPositionIndex ]
                                - 2.0 * zRotation * stateVector[ xVelocityIndex ]
                                + zRotation * zRotation * stateVector[ yPositionIndex ];

        dXdt[ zVelocityIndex ] = gravAcceleration[ zPositionIndex ];
    }
};

//! Store intermediate state values and time( if needed )
/*!
 * This structure contains members that will save all intermediate state values and times when
 * an object of this structure is passed as an argument to the integrator function.
 */
struct pushBackStateAndTime
{
    // declare containers to store state and time
    std::vector< std::vector< double > > &stateContainer;
    std::vector< double > &timeContainer;

    //member initializer list
    pushBackStateAndTime( std::vector< std::vector< double > > &aState,
                          std::vector< double > &aTime )
                : stateContainer( aState ),
                  timeContainer( aTime )
    { }

    void operator() ( const std::vector< double > &singleStateVector, const double singleTime )
    {
        // store the intermediate state and time values in the containers
        stateContainer.push_back( singleStateVector );
        timeContainer.push_back( singleTime );
    }
};

//! particle around spheroid integration
/*!
 * integrate the equations of motion for a particle around a spheroid. The gravitational accelerations
 * calculated using the ellipsoid gravitational potential model.
 */
void executeParticleAroundSpheroid( const double alpha,
                                    const double gravParameter,
                                    std::vector< double > asteroidRotationVector,
                                    std::vector< double > &initialOrbitalElements,
                                    const double initialStepSize,
                                    const double startTime,
                                    const double endTime,
                                    std::ostringstream &outputFilePath,
                                    const int dataSaveIntervals )
{
    //! open the output csv file to save data. Declare file headers.
    std::ofstream outputFile;
    outputFile.open( outputFilePath.str( ) );
    outputFile << "x" << ",";
    outputFile << "y" << ",";
    outputFile << "z" << ",";
    outputFile << "vx" << ",";
    outputFile << "vy" << ",";
    outputFile << "vz" << ",";
    outputFile << "t" << std::endl;
    outputFile.precision( 16 );

    //! convert the initial orbital elements to cartesian state
    std::vector< double > initialStateInertial( 6, 0.0 );
    initialStateInertial = convertKeplerianElementsToCartesianCoordinates( initialOrbitalElements,
                                                                           gravParameter );

    std::vector< double > inertialPositionVector = { initialStateInertial[ xPositionIndex ],
                                                     initialStateInertial[ yPositionIndex ],
                                                     initialStateInertial[ zPositionIndex ] };
    std::vector< double > omegaCrossPosition( 3, 0.0 );
    omegaCrossPosition = crossProduct( asteroidRotationVector, inertialPositionVector );

    std::vector< double > initialState( 6, 0.0 );
    initialState[ xPositionIndex ] = initialStateInertial[ xPositionIndex ];
    initialState[ yPositionIndex ] = initialStateInertial[ yPositionIndex ];
    initialState[ zPositionIndex ] = initialStateInertial[ zPositionIndex ];

    initialState[ xVelocityIndex ]
                = initialStateInertial[ xVelocityIndex ] - omegaCrossPosition[ 0 ];

    initialState[ yVelocityIndex ]
                = initialStateInertial[ yVelocityIndex ] - omegaCrossPosition[ 1 ];

    initialState[ zVelocityIndex ]
                = initialStateInertial[ zVelocityIndex ] - omegaCrossPosition[ 2 ];

    // set up boost odeint
    const double absoluteTolerance = 1.0e-15;
    const double relativeTolerance = 1.0e-15;
    typedef boost::numeric::odeint::runge_kutta_fehlberg78< std::vector< double > > stepperType;

    // state step size guess (at each step this initial guess will be used)
    double stepSizeGuess = initialStepSize;

    // initialize the ode system
    const double zRotation = asteroidRotationVector[ zPositionIndex ];
    equationsOfMotionParticleAroundSpheroid particleAroundSpheroidProblem( gravParameter, alpha, zRotation );

    // initialize current state vector and time
    std::vector< double > currentStateVector = initialState;
    double currentTime = startTime;
    double intermediateEndTime = currentTime + dataSaveIntervals;

    // save the initial state vector
    outputFile << currentStateVector[ xPositionIndex ] << ",";
    outputFile << currentStateVector[ yPositionIndex ] << ",";
    outputFile << currentStateVector[ zPositionIndex ] << ",";
    outputFile << currentStateVector[ xVelocityIndex ] << ",";
    outputFile << currentStateVector[ yVelocityIndex ] << ",";
    outputFile << currentStateVector[ zVelocityIndex ] << ",";
    outputFile << currentTime << std::endl;

    // start the integration outer loop
    while( intermediateEndTime <= endTime )
    {
        // perform integration, integrated result stored in currentStateVector
        size_t steps = boost::numeric::odeint::integrate_adaptive(
                            make_controlled( absoluteTolerance, relativeTolerance, stepperType( ) ),
                            particleAroundSpheroidProblem,
                            currentStateVector,
                            currentTime,
                            intermediateEndTime,
                            stepSizeGuess );

        // update the time variables
        currentTime = intermediateEndTime;
        intermediateEndTime = currentTime + dataSaveIntervals;

        // save data
        outputFile << currentStateVector[ xPositionIndex ] << ",";
        outputFile << currentStateVector[ yPositionIndex ] << ",";
        outputFile << currentStateVector[ zPositionIndex ] << ",";
        outputFile << currentStateVector[ xVelocityIndex ] << ",";
        outputFile << currentStateVector[ yVelocityIndex ] << ",";
        outputFile << currentStateVector[ zVelocityIndex ] << ",";
        outputFile << currentTime << std::endl;

    } // end of outer while loop for integration

    outputFile.close( );
}

} // namespace naos


#include <algorithm>
#include <cmath>
#include <cstdint>
#include <limits>
#include <numeric>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include "losslessops.h"

using namespace crolol;
using namespace backend;
namespace mp = boost::multiprecision;
using std::int64_t;
using slims = std::numeric_limits<int64_t>;
using int128 = mp::int128_t;
using float128 = mp::cpp_bin_float_quad;

static constexpr int64_t slmax = slims::max();
static constexpr int64_t slmin = slims::min();
static constexpr int64_t scale = 1000;
static const float128 slmaxlog2 = mp::log2(static_cast<float128>(slmax) / scale);
static const float128 slminlog2 = mp::log2(-static_cast<float128>(slmax) / scale);

static saferet clamp(const int128& n)
{
	saferet out;
	out.val = static_cast<int64_t>(n);

	if (n > static_cast<int128>(slmax))
		out.flow = overflow;
	else if (n < static_cast<int128>(slmin))
		out.flow = underflow;

	return out;
}

static saferet make_error(const flowstatus flow)
{
	saferet out;
	out.flow = flow;

	return out;
}

static saferet make_badarg(const int64_t val)
{
	saferet out = make_error(badarg);
	out.val = val;

	return out;
}

saferet backend::multiply(int64_t n, int64_t m)
{
	return clamp((static_cast<int128>(n) * static_cast<int128>(m))
		/ static_cast<int128>(scale));
}

saferet backend::divide(int64_t n, int64_t m)
{
	if (m == 0) return make_badarg(n);
	else return clamp((static_cast<int128>(n) * scale)
		/ static_cast<int128>(m));
}

saferet backend::pow(int64_t n, int64_t m)
{
	if (n < 0 && m % scale != 0) return make_badarg(m);
	else if (n == 0 && m == 0) return clamp(scale);
	else if (n == 0 && m < 0) return make_badarg(m);
	else if (n == scale || m == 0) return clamp(scale);
	else if (m == scale) return clamp(n);

	const float128 nf = static_cast<float128>(n) / scale;
	const float128 mf = static_cast<float128>(m) / scale;
	const float128 size = mp::log2(mp::abs(nf)) * mf;

	if (size > slmaxlog2) return clamp(slmax);
	else if (mp::abs(size) > slminlog2) return clamp(slmin);
	else return clamp(static_cast<int128>(
		mp::llrint(mp::trunc(mp::pow(nf, mf) * scale))
	));
}

saferet backend::factorial(int64_t n)
{
	if (n < 0 or n % scale != 0) return make_badarg(n);

	saferet acc = clamp(scale);

	for (int64_t i = 0; i < n && acc.flow == noflow; i += scale)
		acc = multiply(acc.val, i);

	return acc;
}

static const int64_t cr2pi = std::llrintl(std::truncl(M_PI * 2.L * scale));
static constexpr long double radtodeg = 360.L / (M_PI * 2.L);
static constexpr long double degtorad = (M_PI * 2.L) / 360.L;

static long double trigmod(int64_t n)
{
	return static_cast<long double>(n % cr2pi) * degtorad / scale;
}

saferet backend::sin(int64_t n)
{
	return clamp(static_cast<int128>(
		std::truncl(std::sin(trigmod(n))) * scale
	));
}

saferet backend::cos(int64_t n)
{
	return clamp(static_cast<int128>(
		std::truncl(std::cos(trigmod(n))) * scale
	));
}

saferet backend::tan(int64_t n)
{
	return clamp(static_cast<int128>(
		std::truncl(std::tan(trigmod(n))) * scale
	));
}

saferet backend::asin(int64_t n)
{
	if (n > scale or n < -scale) return make_badarg(n);
	else return clamp(static_cast<int128>(
		std::truncl(std::asin(
			static_cast<long double>(n) / scale
		)) * scale * radtodeg
	));
}

saferet backend::acos(int64_t n)
{
	if (n > scale or n < -scale) return make_badarg(n);
	else return clamp(static_cast<int128>(
		std::truncl(std::acos(
			static_cast<long double>(n) / scale
		)) * scale * radtodeg
	));
}

saferet backend::atan(int64_t n)
{
	return clamp(static_cast<int128>(
		std::truncl(std::atan(
			static_cast<long double>(n) / scale
		)) * scale * radtodeg
	));
}


// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2019 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "rigid_alignment.h"
#include "polar_svd.h"
#include <Eigen/Sparse>
#include <Eigen/Cholesky>
#include <vector>
#include <iostream>

template <
  typename DerivedX,
  typename DerivedP,
  typename DerivedN,
  typename DerivedR,
  typename Derivedt
>
IGL_INLINE void igl::rigid_alignment(
  const Eigen::MatrixBase<DerivedX> & _X,
  const Eigen::MatrixBase<DerivedP> & P,
  const Eigen::MatrixBase<DerivedN> & N,
  Eigen::PlainObjectBase<DerivedR> & R,
  Eigen::PlainObjectBase<Derivedt> & t)
{
  typedef typename DerivedX::Scalar Scalar;
  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixXS;
  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
  typedef Eigen::Matrix<Scalar,3,3> Matrix3S;
  const int k = _X.rows();
  VectorXS Z = VectorXS::Zero(k,1);
  VectorXS I = VectorXS::Ones(k,1);

  DerivedX X = _X;
  R = DerivedR::Identity(3,3);
  t = Derivedt::Zero(1,3);
  // See gptoolbox, each iter could be O(1) instead of O(k)
  const int max_iters = 5;
  for(int iters = 0;iters<max_iters;iters++)
  {
    MatrixXS A(k*3,6);
    A <<
               Z, X.col(2),-X.col(1),I,Z,Z,
       -X.col(2),        Z, X.col(0),Z,I,Z,
        X.col(1),-X.col(0),        Z,Z,Z,I;
    VectorXS B(k*3,1);
    B<<
      P.col(0)-X.col(0),
      P.col(1)-X.col(1),
      P.col(2)-X.col(2);
    std::vector<Eigen::Triplet<Scalar> > NNIJV;
    for(int i = 0;i<k;i++)
    {
      for(int c = 0;c<3;c++)
      {
        NNIJV.emplace_back(i,i+k*c,N(i,c));
      }
    }
    Eigen::SparseMatrix<Scalar> NN(k,k*3);
    NN.setFromTriplets(NNIJV.begin(),NNIJV.end());
    A = (NN * A).eval();
    B = (NN * B).eval();
    VectorXS u = (A.transpose() * A).ldlt().solve(A.transpose() * B);
    Derivedt ti = u.tail(3).transpose();

    Matrix3S W;
    W<<
          0, u(2),-u(1),
      -u(2),    0, u(0),
       u(1),-u(0),    0;
    // strayed from a perfect rotation. Correct it.
    const double x = u.head(3).stableNorm();
    DerivedR Ri;
    if(x == 0)
    {
      Ri = DerivedR::Identity(3,3);
    }else
    {
      Ri =
        DerivedR::Identity(3,3) +
        sin(x)/x*W +
        (1.0-cos(x))/(x*x)*W*W;
    }

    R = (R*Ri).eval();
    t = (t*Ri + ti).eval();
    X = ((_X*R).rowwise()+t).eval();
  }
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::rigid_alignment<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
#endif


/* Copyright (c) 2015, Julian Straub <jstraub@csail.mit.edu>
 * Licensed under the MIT license. See the license file LICENSE.
 */

#pragma once

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

#include <boost/random/mersenne_twister.hpp>
#include <boost/math/special_functions/gamma.hpp>

#include <dpMM/global.hpp>

#ifndef PI
#  define PI 3.141592653589793
#endif
#define LOG_PI 1.1447298858494002
#define LOG_2 0.69314718055994529
#define LOG_2PI 1.8378770664093453

using namespace Eigen;

template<typename T>
class Distribution
{
public:
  Distribution(boost::mt19937* pRndGen) : pRndGen_(pRndGen)
  {};
  virtual ~Distribution()
  {};

//  virtual logProb()
  boost::mt19937* pRndGen_;
private:
};

template<typename T, typename T2>
inline Matrix<T,Dynamic,1> counts(const Matrix<T2,Dynamic,1> & z, T2 K)
{
  Matrix<T,Dynamic,1> N(K);
  N.setZero(K);
  for (T2 i=0; i<z.size(); ++i)
    N(z(i))++;
  return N;
};

//inline VectorXd counts(const VectorXu& z, uint32_t K)
//{
//  VectorXd N(K);
//  N.setZero(K);
//  for (uint32_t i=0; i<z.size(); ++i)
//    N(z(i))++;
//  return N;
//};

/* multivariate gamma function of dimension p */
inline double lgamma_mult(double x,uint32_t p)
{
  assert(x+0.5*(1.-p) > 0.);
  double lgam_p = p*(p-1.)*0.25*LOG_PI;
  for (uint32_t i=1; i<p+1; ++i)
  {
//    cout<<"digamma_mult of "<<(x + (1.0-double(i))/2)<<" = "<<digamma(x + (1.0-double(i))/2)<<endl;
    lgam_p += boost::math::lgamma(x + 0.5*(1.0-double(i)));
  }
  return lgam_p;
}

template<typename T>
inline T logsumexp(T x1, T x2)
{
   if (x1>x2)
      return x1 + log(1.+exp(x2-x1));
   else
      return x2 + log(1.+exp(x1-x2));
}


#include <iostream>

#include <deal.II/base/tensor.h>

int main(int argc, char* argv[])
{
    const unsigned int dim = 2;

    dealii::Tensor<2, dim> T;

    std::cout << "T = ";

    for (unsigned int i = 0; i < T.n_independent_components; ++i)
    {
        auto indices = T.unrolled_to_component_indices(i);

        std::cout << "T_{" << indices[0] + 1 << indices[1] + 1 << "}" << " ";

    }

    for (unsigned int i = 1; i < (dim + 1); ++i)
    {
        for (unsigned int j = 1; j < (dim + 1); ++j)
        {
            T[i - 1][j - 1] = 10*i + j;
        }
    }

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

    return 0;
}


/**
 * This code has been downloaded from the website of Bojan Nikolic
 * see http://www.bnikolic.co.uk/blog/cpp-khachiyan-min-cov-ellipsoid.html
 * the code implements Khachiyan's algorithm to compute the Minimum volume
 * enclosing ellipsoid approximately.
 *
 * Some parts were written inefficiently so have been changed.
 */

#include "MVE.h"
#include "RMSUtils.h"
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include "cholesky.h"

namespace ublas=boost::numeric::ublas;

template<class T>
bool InvertMatrix(const ublas::matrix<T> &input, ublas::matrix<T> &inverse) {
    using namespace boost::numeric::ublas;

    typedef permutation_matrix<std::size_t> pmatrix;
    matrix<T> A(input);
    pmatrix pm(A.size1());
    int res = lu_factorize(A, pm);
    if (res != 0) return false;
    inverse.assign(identity_matrix<T>(A.size1()));
    lu_substitute(A, pm, inverse);
    return true;
}

void InvertLP(const ublas::matrix<double> &Lambdap, ublas::matrix<double> &LpInv) {
    bool res = InvertMatrix(Lambdap, LpInv);
    if (not res) {
        throw std::runtime_error("Could not invert Matrix");
    }
}

void Lift(const ublas::matrix<double> &A, ublas::matrix<double> &Ap) {
    Ap.resize(A.size1() + 1,
              A.size2());
    ublas::matrix_range<ublas::matrix<double> >
            sub(Ap,
                ublas::range(0, A.size1()),
                ublas::range(0, A.size2()));
    sub.assign(A);
    ublas::row(Ap, Ap.size1() - 1) = ublas::scalar_vector<double>(A.size2(), 1.0);

}

void genDiag(const ublas::vector<double> &p,
             ublas::matrix<double> &res) {
    res.assign(ublas::zero_matrix<double>(p.size(),
                                          p.size()));
    for (size_t i = 0; i < p.size(); ++i) {
        res(i, i) = p(i);
    }
}

void KaLambda(const ublas::matrix<double> &Ap,
              const ublas::vector<double> &p,
              ublas::matrix<double> &Lambdap) {
    //cout << "KaLambda: Ap.size1() = " << Ap.size1() << ", Ap.size2() = "
    //	 << Ap.size2() << ", p.size() = " << p.size() << endl;
    assert(p.size() == Ap.size2());

    /**
        This code is very inefficient (It is trying to allocate a matrix
        of size m x m where m = # of points which is simply infeasible
        for large data sets

        It is basically trying to compute the sum of p_i q_i q_i^t for
        i in 1 to m where m is the number of points and p is a m dimensional
        vector p = (p_1, ...., p_m)^t. Since each q_i is a n x 1 vector
        the return value of this is a n x n matrix.
     **/
    /*
    ublas::matrix<double> dp(p.size(), p.size());
    genDiag(p, dp);

    dp=ublas::prod(dp, ublas::trans(Ap));
    Lambdap=ublas::prod(Ap,
                        dp);
    */

    /* Recall that Lambda(p) is a matrix of size n x n where it is simply
       defined as Lambda(p) = sum of p_i q_i q_i^t for i from 1 to m
       and q_i are the n x 1 vectors representing the (lifted points)
       The matrix Ap is (q_i .... q_m). It is a n x m matrix
    */
    size_t n = Ap.size1();
    ublas::matrix<double> sum(n, n);
    sum.assign(ublas::zero_matrix<double>(n, n));

    /* directly invoke the correct formula for matrix product */
    for (size_t i = 0; i < p.size(); i++) {
        for (size_t j = 0; j < n; j++)
            for (size_t k = 0; k < n; k++)
                sum(j, k) += p(i) * Ap(j, i) * Ap(k, i);
    }
    Lambdap = sum;
}

double KhachiyanIter(const ublas::matrix<double> &Ap,
                     ublas::vector<double> &p) {
    /// Dimensionality of the problem
    const size_t d = Ap.size1() - 1;

    ublas::matrix<double> Lp;
    KaLambda(Ap, p, Lp);
    ublas::matrix<double> ILp(Lp.size1(), Lp.size2());
    InvertLP(Lp, ILp);

    /**
        * This code is very inefficient as it is trying to allocate
        * a matrix of size m x m where m is the number of data
        * points simply to get the diagonal elements of M !!

        * Basically it is trying to do the following:
	* M = ILp * Ap where ILp is a n x n matrix and
	* Ap is a n x m matrix (n is dimension, m is number
	* of points). The needed output is a set of m numbers
	* where the i-th number is basically <Ap_i^t, M_i>
	* i.e. the dot product of the transpose of the i-th
	* column of Ap and the i-th column of M.

    ublas::matrix<double> M;
    M=ublas::prod(ILp, Ap);
    M=ublas::prod(ublas::trans(Ap), M);

    double maxval=0;
    size_t maxi=0;
    for(size_t i=0; i<M.size1(); ++i)
    {
        if (M(i,i) > maxval)
        {
            maxval=M(i,i);
            maxi=i;
        }
    }
    **/

    double maxval = 0;
    size_t maxi = 0;
    ublas::matrix<double> M = ublas::prod(ILp, Ap);
    ublas::matrix<double> Apt = ublas::trans(Ap);
    assert(M.size1() == Apt.size2());

    for (size_t i = 0; i < Ap.size2(); i++) {
        //evaluate the product c_i^t (ILp) c_i
        ublas::matrix_column<ublas::matrix<double> > mc(M, i);
        ublas::matrix_row<ublas::matrix<double> > mr(Apt, i);

        //evaluate the left product of row and column
        double prod = 0;
        for (size_t j = 0; j < mc.size(); j++)
            prod += mr(j) * mc(j);

        if (prod > maxval) {
            maxval = prod;
            maxi = i;
        }

    }

    const double step_size = (maxval - d - 1) / ((d + 1) * (maxval - 1));
    ublas::vector<double> newp = p * (1 - step_size);
    newp(maxi) += step_size;

    const double err = ublas::norm_2(newp - p);
    p = newp;
    return err;

}

void KaInvertDual(const ublas::matrix<double> &A,
                  const ublas::vector<double> &p,
                  ublas::matrix<double> &Q,
                  ublas::vector<double> &c
) {
    const size_t d = A.size1();
    /** This part of the code is not efficient. It is trying
        to allocate a matrix dp of size m x m where m is the
        number of points

	Basically it is trying to do the following:
	Here A is a n x m matrix (where n is dimension
	and m is number of points)

	The output of this code is PN a m x n matrix where
	the row i is the transpose of the i-th column of A
	multiplied by p_i where p is a m-vector.
    **/
/*
    ublas::matrix<double> dp(p.size(), p.size());
    genDiag(p, dp);

    ublas::matrix<double> PN=ublas::prod(dp, ublas::trans(A));
*/
    //========= Begin replacement code ===============
    ublas::matrix<double> PN = ublas::trans(A);
    assert(p.size() == PN.size1());
    for (size_t i = 0; i < PN.size1(); i++)
        for (size_t j = 0; j < PN.size2(); j++)
            PN(i, j) *= p(i);
    //======== End replacement code ===================

    PN = ublas::prod(A, PN);

    ublas::vector<double> M2 = ublas::prod(A, p);
    ublas::matrix<double> M3 = ublas::outer_prod(M2, M2);

    ublas::matrix<double> invert(PN.size1(), PN.size2());
    InvertLP(PN - M3, invert);

    Q.assign(1.0 / d * invert);
    c = ublas::prod(A, p);
}

double KhachiyanAlgo(const ublas::matrix<double> &A,
                     double eps,
                     size_t maxiter,
                     ublas::matrix<double> &Q,
                     ublas::vector<double> &c) {
    ublas::vector<double> p = ublas::scalar_vector<double>(A.size2(), 1.0) * (1.0 / A.size2());

    ublas::matrix<double> Ap;
    Lift(A, Ap);

    double ceps = eps * 2;
    for (size_t i = 0; i < maxiter && ceps > eps; ++i) {
        ceps = KhachiyanIter(Ap, p);
    }

    KaInvertDual(A, p, Q, c);

    return ceps;
}

void print_matrix(const ublas::matrix<double> &A) {
    for (size_t i = 0; i < A.size1(); i++) {
        for (size_t j = 0; j < A.size2(); j++)
            cout << A(i, j) << "  ";
        cout << endl;
    }
}

void print_vector(const ublas::vector<double> &v) {
    if (v.size() == 1) {
        cout << v(0) << endl;
        return;
    }

    cout << "---     ---" << endl;
    for (size_t i = 0; i < v.size(); i++) {
        cout << "||" << " " << v(i) << " " << "||" << endl;
    }

    cout << "---     ---" << endl;
}

void MVEUtil::GetNormalizedMVE(const vector<Point> &dataP,
                               float epsilon,
                               vector<Point> &normalizedP,
                               double &outer_rad,
                               double &inner_rad
) {
    using namespace boost::numeric::ublas;

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

    size_t d = dataP[0].get_dimension();

    ublas::matrix<double> A(d, dataP.size());

    size_t j = 0;

    for (size_t i = 0; i < dataP.size(); i++) {
        for (size_t k = 0; k < d; k++)
            A(k, j) = dataP[i].get_coordinate(k);
        ++j;
    }

    //try Khachiyans algorithm
    //cout << "Running Khachiyan algorithm " << endl;

    ublas::matrix<double> Q(d, d);
    ublas::vector<double> c(d);

    size_t maxiter = 1024 * dataP.size() * d;
    double ceps = KhachiyanAlgo(A, epsilon, maxiter, Q, c);
    if (ceps > epsilon) {
        throw std::runtime_error("Khachiyan failed ... ");
    }

    /** Only for debug
    cout << "Khachiyan returned " << ceps << endl;
    cout << "Printing the matrix Q " << endl;
    print_matrix(Q);
    **/

    /**
        The equation of the ellipse that is returned
	by Khachiyan algorithm is (x - c)^T Q (x - c) <= 1
        Unfortunately all the points of the data set
	do not satisfy it (but they do satisfy it
	approximately). Now we can put (1+epsilon) * dim
	on the right hand side and the points will
	still satisfy it, but this may be too loose
	an approximation. Instead, we find the maximum
	of (x-c)^T Q (x-c) over all the data points,
	add 0.01, and take that as the RHS.
	The square root of this gives the radius of
	the outer sphere, when we apply a linear
	transform to turn the ellipsoid into a ball
    **/
    double max_val = 0;
    for (size_t i = 0; i < dataP.size(); i++) {
        ublas::vector<double> ublasp = Point::to_ublas(dataP[i]);

        //compute p - c
        ublasp = ublasp - c;

        //compute Q (p - c)
        ublas::vector<double> prod1 = ublas::prod(Q, ublasp);

        //compute (p - c)^T
        ublas::matrix<double> ublasptr(1, d);
        for (size_t j = 0; j < d; j++)
            ublasptr(0, j) = ublasp[j];

        //compute (p-c)^T Q (p-c)
        ublas::vector<double> x = ublas::prod(ublasptr, prod1);

        if (x(0) > max_val) max_val = x(0);

        /** for debug
        cout << "Printing (p-c)^T Q (p -c ) " ;
        print_vector(x);
        cout << endl;
        **/
    }

    //the radius of the outer sphere
    outer_rad = sqrt(max_val + 0.01);

    //now compute the linear transformation
    ublas::matrix<double> L(d, d);
    //compute a Cholesky factorization
    int res = cholesky_decompose(Q, L);

    if (res != 0) {
        cout << "Cholesky decomposition failed " << res << endl;
        exit(1);
    }

    /** debug
    cout << "Printing cholesky decomposition " << endl;
    print_matrix(L);
    **/

    //get the transpose of L
    ublas::matrix<double> LTr(d, d);
    LTr = ublas::trans(L);

    //ublas::matrix<double> chprod = ublas::prod(L, LTr);
    //print_matrix(chprod);

    normalizedP = dataP;

    for (size_t i = 0; i < dataP.size(); i++) {
        ublas::vector<double> ublasp = Point::to_ublas(normalizedP[i]);

        //compute the linear transformation
        ublasp = ublasp - c;
        ublasp = ublas::prod(LTr, ublasp);
        normalizedP[i] = Point::from_ublas(ublasp);
    }

    inner_rad = 1 / ((1 + epsilon) * d);

    /* save this matrix into RandomUtil class for further use */
    /* the use requires the inverse of (matrix transpose) of Ltr */
    ublas::matrix<double> IL(d, d);
    InvertLP(L, IL);
    RMSUtils::dimension = d;
    RMSUtils::transformation_matrix = IL;
    RMSUtils::center = c;

    return;
}


/*****************************************************************************
*
* Copyright (C) 2015-2020 by Synge Todo <wistaria@phys.s.u-tokyo.ac.jp>
*
* 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)
*
*****************************************************************************/

// Calculating free energy, energy, and specific heat of triangular lattice Ising model

#include <iomanip>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include "triangle/infinite.hpp"

int main(int argc, char **argv) {
  typedef double real_t;
  real_t Ja, Jb, Jc, t_min, t_max, t_step;
  if (argc == 7) {
    Ja = boost::lexical_cast<real_t>(argv[1]);
    Jb = boost::lexical_cast<real_t>(argv[2]);
    Jc = boost::lexical_cast<real_t>(argv[3]);
    t_min = boost::lexical_cast<real_t>(argv[4]);
    t_max = boost::lexical_cast<real_t>(argv[5]);
    t_step = boost::lexical_cast<real_t>(argv[6]);
  } else if (argc == 1) {
    std::cin >> Ja >> Jb >> Jc >> t_min >> t_max >> t_step;
  } else {
    std::cerr << "Usage: " << argv[0] << " [Ja Jb Jc t_min t_max t_step]\n";
    return 127;
  }
  std::cout << std::scientific << std::setprecision(std::numeric_limits<real_t>::digits10);
  std::cout << "# triangular lattice Ising model\n";
  std::cout << "# Ja, Jb, Jc, T, free energy density, energy density, specific heat\n";
  for (real_t t = t_min; t <= t_max; t += t_step) {
    real_t beta = 1 / t;
    auto result = ising::triangle::infinite(beta, Ja, Jb, Jc);
    std::cout << Ja << ' ' << Jb << ' ' << Jc << ' ' << t << ' ' << std::get<0>(result) << ' '
              << std::get<1>(result) << ' ' << std::get<2>(result) << std::endl;
  }
}


/*
    Author: hauptmech <hauptmech@gmail.com>, Nov 2013

    This is free and unencumbered software released into the public domain.

    Anyone is free to copy, modify, publish, use, compile, sell, or
    distribute this software, either in source code form or as a compiled
    binary, for any purpose, commercial or non-commercial, and by any
    means.

    In jurisdictions that recognize copyright laws, the author or authors
    of this software dedicate any and all copyright interest in the
    software to the public domain. We make this dedication for the benefit
    of the public at large and to the detriment of our heirs and
    successors. We intend this dedication to be an overt act of
    relinquishment in perpetuity of all present and future rights to this
    software under copyright law.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

    For more information, please refer to <http://unlicense.org/>
*/

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

using namespace Eigen;

int main()
{
    // Init a fixed size 3x3 matrix
    Matrix3d m3 {{1.2,2.2,3.3},{4.2,2.5,6.3},{7.2,8.2,9.3}};
    std::cout << "\nm3:\n" << m3 << std::endl;

    // Initialize a variable length Matrix to 2x2
    MatrixXd mY {{1.2,2.2},{3.2,4.5}};
    std::cout << "\nmY:\n" << mY << std::endl;

    // Initialize a variable length Matrix (Vector) to 9x1
    // 2D Matrices are initialized column-wise
    MatrixXd mX {1.2,2.2,3.3, 4.2,2.5,6.3, 7.2,8.2,9.3};
    std::cout << "\nmX:\n" << mX << std::endl;

    // Init a 3 element vector
    Vector3d v3  {1,3,3};
    std::cout << "\nv3:\n" << v3 << std::endl;

    // Init a fixed size 3x3 array
    Array33d a3 {{1.2,2.2,3.3},{4.2,2.5,6.3},{7.2,8.2,9.3}};
    std::cout << "\na3:\n" << a3 << std::endl;

    // Initialize a variable length Array to 2x2
    ArrayXXd aY {{1.2,2.2},{3.2,4.5}};
    std::cout << "\naY:\n" << aY << std::endl;

    // Initialize a variable length Array to 9x1
    // 2D Arrays are initialized column-wise
    ArrayXXd aX {1.2,2.2,3.3, 4.2,2.5,6.3, 7.2,8.2,9.3};
    std::cout << "\naX:\n" << aX << std::endl;

    // Init a 3 element array
    Array3d w3  {1,3,3};
    std::cout << "\nw3:\n" << w3 << std::endl;
}


/**
 * @file
 * @brief NPDE homework "Handling degrees of freedom (DOFs) in LehrFEM++"
 * @author Julien Gacon
 * @date March 1st, 2019
 * @copyright Developed at ETH Zurich
 */

#include "lfppdofhandling.h"

#include <Eigen/Dense>
#include <array>
#include <memory>

#include "lf/assemble/assemble.h"
#include "lf/base/base.h"
#include "lf/geometry/geometry.h"
#include "lf/mesh/mesh.h"
#include "lf/mesh/utils/utils.h"

namespace LFPPDofHandling {

/* SAM_LISTING_BEGIN_1 */
std::array<std::size_t, 3> countEntityDofs(
    const lf::assemble::DofHandler &dofhandler) {
  std::array<std::size_t, 3> entityDofs;
  //====================
  // Your code goes here
  //====================
  for (int codim=0; codim<3; codim++){
    entityDofs[codim] = 0;
  }

  std::shared_ptr<const lf::mesh::Mesh> mesh = dofhandler.Mesh();

  for (int codim=0; codim<3; codim++){
    for (const auto *entity : mesh->Entities(codim)){
      if (entity->RefEl() == lf::base::RefEl::kQuad()){
        throw("Error");
      }
      entityDofs[codim] += dofhandler.NumInteriorDofs(*entity);
    }
  }
  return entityDofs;
}
/* SAM_LISTING_END_1 */

/* SAM_LISTING_BEGIN_2 */
std::size_t countBoundaryDofs(const lf::assemble::DofHandler &dofhandler) {
  std::shared_ptr<const lf::mesh::Mesh> mesh = dofhandler.Mesh();
  // given an entity, bd\_flags(entity) == true, if the entity is on the
  // boundary
  lf::mesh::utils::AllCodimMeshDataSet<bool> bd_flags(
      lf::mesh::utils::flagEntitiesOnBoundary(mesh));
  std::size_t no_dofs_on_bd = 0;
  //====================
  // Your code goes here
  //====================

  for (const auto *vertex : mesh->Entities(2)){
    if (bd_flags(*vertex)){
      no_dofs_on_bd+=1;
    }
  }
  return no_dofs_on_bd;
}
/* SAM_LISTING_END_2 */

// clang-format off
/* SAM_LISTING_BEGIN_3 */
double integrateLinearFEFunction(
    const lf::assemble::DofHandler& dofhandler,
    const Eigen::VectorXd& mu) {
  double I = 0;
  //====================
  // Your code goes here
  //====================

  std::shared_ptr<const lf::mesh::Mesh> mesh = dofhandler.Mesh();
  double area;
  for (const auto *cell : mesh->Entities(0)){
    lf::base::size_type cell_local_dofs = dofhandler.NumLocalDofs(*cell);
    if (cell_local_dofs!=3){
      throw("Error");
    }
    lf::geometry::Geometry *cell_geo = cell->Geometry();
    area = lf::geometry::Volume(*cell_geo);
    const auto global_idxs = dofhandler.GlobalDofIndices(*cell);
    for (auto idx_p=global_idxs.begin() ; idx_p<global_idxs.end() ; ++idx_p){
      I += area/3.0 * mu(*idx_p);
    }
  }
  return I;
}
/* SAM_LISTING_END_3 */
// clang-format on

/* SAM_LISTING_BEGIN_4 */
double integrateQuadraticFEFunction(const lf::assemble::DofHandler &dofhandler,
                                    const Eigen::VectorXd &mu) {
  double I = 0;
  //====================
  // Your code goes here
  //====================
  //
  std::shared_ptr<const lf::mesh::Mesh> mesh = dofhandler.Mesh();
  double area;
  for (const auto *cell : mesh->Entities(0)){
    lf::base::size_type cell_local_dofs = dofhandler.NumLocalDofs(*cell);
    if (cell_local_dofs!=6){
      throw("Error");
    }
    lf::geometry::Geometry *cell_geo = cell->Geometry();
    area = lf::geometry::Volume(*cell_geo);
    const auto global_idxs = dofhandler.GlobalDofIndices(*cell);
    for (int i=3; i<6; i++){
      I += (area/3.0 * mu[global_idxs[i]]);
    }
  }
  return I;
}
/* SAM_LISTING_END_4 */

/* SAM_LISTING_BEGIN_5 */
Eigen::VectorXd convertDOFsLinearQuadratic(
    const lf::assemble::DofHandler &dofh_Linear_FE,
    const lf::assemble::DofHandler &dofh_Quadratic_FE,
    const Eigen::VectorXd &mu) {
  if (dofh_Linear_FE.Mesh() != dofh_Quadratic_FE.Mesh()) {
    throw "Underlying meshes must be the same for both DOF handlers!";
  }
  std::shared_ptr<const lf::mesh::Mesh> mesh =
      dofh_Linear_FE.Mesh();                          // get the mesh
  Eigen::VectorXd zeta(dofh_Quadratic_FE.NumDofs());  // initialise empty zeta
  // safety guard: always set zero if you're not sure to set every entry later
  // on for us this shouldn't be a problem, but just to be sure
  zeta.setZero();

  for (const auto *cell : mesh->Entities(0)) {
    // check if the spaces are actually linear and quadratic
    //====================
    // Your code goes here
    //====================
    // get the global dof indices of the linear and quadratic FE spaces, note
    // that the vectors obey the LehrFEM++ numbering, which we will make use of
    // lin\_dofs will have size 3 for the 3 dofs on the nodes and
    // quad\_dofs will have size 6, the first 3 entries being the nodes and
    // the last 3 the edges
    //====================
    // Your code goes here
    // assign the coefficients of mu to the correct entries of zeta, use
    // the previous subproblem 2-9.a
    //====================

    if (dofh_Linear_FE.NumLocalDofs(*cell) != 3 ||
        dofh_Quadratic_FE.NumLocalDofs(*cell) != 6){
      throw("Error");
    }
    nonstd::span<const lf::assemble::gdof_idx_t> lin_idxs = dofh_Linear_FE.GlobalDofIndices(*cell);
    nonstd::span<const lf::assemble::gdof_idx_t> quad_idxs = dofh_Quadratic_FE.GlobalDofIndices(*cell);
    for (int i=0; i<3; i++){
      zeta(quad_idxs[i]) = mu(lin_idxs[i]);
      zeta(quad_idxs[i+3]) = 0.5*mu(lin_idxs[i])+0.5*mu(lin_idxs[(i+1)%3]);
    }
  }
  return zeta;
}
/* SAM_LISTING_END_5 */

}  // namespace LFPPDofHandling


/*
 * @file File for Eigen helper functions
 * Eigen_Utils.hpp
 *
 *  Created on: 25.07.2018
 *      Author: tomlucas
 */

#ifndef EIGEN_UTILS_HPP_
#define EIGEN_UTILS_HPP_

#include <Eigen/Geometry>
#include <math.h>
#include "ZaVI_Utils.hpp"
#include <ceres/ceres.h>
namespace zavi
::eigen_util {
	/**
	 * Rotates a vector with the given quaternion
	 * @param vector The vector to rotate
	 * @param quat The quaternion
	 * @return the rotatet vector
	 */
	inline ::Eigen::Vector3d rotateVector(const ::Eigen::Vector3d &vector, const ::Eigen::Quaterniond &quat) {
		::Eigen::Quaterniond vec(0, 0, 0, 0);
		vec.w() = 0;
		vec.vec() = vector;
		return (quat * vec * quat.conjugate()).vec();
	}
	/**
	 * Euler rodriguez formula
	 *
	 * Calculates a rotation matrix as if roll pitch and yaw happend simultaenously
	 * taken from C. Hertzberg 2013
	 * @param roll the roll angle
	 * @param pitch   the pitch angle
	 * @param yaw  the yaw angle
	 * @return a 3x3 rotation matrix
	 */
	template<typename T>
	::Eigen::Matrix<T, 3, 3> eulerRodriguez(const T & roll,const T & pitch,const T & yaw);

	/**
	 * Euler rodriguez formula
	 *
	 * Calculates a rotation matrix as if roll pitch and yaw happend simultaenously
	 * taken from C. Hertzberg 2013
	 * @param vec roll pitch and yaw as vector
	 * @return a 3x3 rotation matrix
	 */
	template<typename T>
	inline ::Eigen::Matrix<T, 3, 3> eulerRodriguez(const Eigen::Matrix<T, 3, 1> &vec) {
		return eulerRodriguez<T>(vec(0, 0), vec(1, 0), vec(2, 0));
	}

	/**
	 * Wraps an angle to -PI + PI
	 * @param angle the angle
	 * @return the wrapped angle
	 */
	template<typename T>
	T wrapAngle(const T & angle) {
		T temp=angle+M_PI;
		temp = fmod(temp,2*M_PI);
		if (temp < T(0.))
		temp += 2*M_PI;
		return temp - M_PI;
	}

	/**
	 * Wraps an angle to -PI + PI
	 * @param angle the angle
	 * @return the wrapped angle
	 */
	template<typename T,int size>
	ceres::Jet<T,size> wrapAngle(const ceres::Jet<T,size> & angle) {
		ceres::Jet<T,size> temp=angle;
		temp.a=wrapAngle(temp.a);
		return temp;
	}
	/**
	 * wraps the angles to -M_PI to M_PI
	 * @param matrix a eigen matrix or expression
	 * @return
	 */
	template<typename Derived>
	inline ::Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime, 1> wrapAngles(
			const ::Eigen::MatrixBase<Derived> & matrix) {
		::Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime, 1> temp = matrix;
		for (int i = 0; i < matrix.RowsAtCompileTime; i++) {
			temp(i) = wrapAngle(temp(i));
		}
		return temp;
	}
	/**
	 * retrieve the euler angles from an euler rodriguez rotation matrix
	 * @param rotation the rotation matrix
	 * @return euler angles as 3,1 matrix
	 */
	template<typename T>
	Eigen::Matrix<T, 3, 1> inverseEulerRodriguez(const ::Eigen::Matrix<T, 3, 3> & rotation);

	/**
	 * Generates an quaternion from euler angle
	 *
	 *taken from https://stackoverflow.com/questions/31589901/euler-to-quaternion-quaternion-to-euler-using-eigen
	 *
	 * @param roll  roll in radians
	 * @param pitch pitch in radians
	 * @param yaw  yaw in radians
	 * @return
	 */
	inline ::Eigen::Quaterniond eulerToQuaternion(double roll, double pitch, double yaw) {
		Eigen::Quaterniond q(eulerRodriguez<double>(roll, pitch, yaw));
		return q;
	}

	/**
	 * Transfers a vector to  a quaternion
	 * @param state the state vector
	 * @param startindex the start index of the euler angles
	 * @return an eigen Quaterniond
	 *
	 * state_dim dimension of the state
	 */
	template<int state_dim>
	inline ::Eigen::Quaterniond stateToQuaternion(Eigen::Matrix<double, state_dim, 1> & state, int startindex) {
		return ::Eigen::Quaterniond(state(startindex + 0), state(startindex + 1), state(startindex + 2),
				state(startindex + 3));
	}

	/**
	 * Object to call a function
	 *
	 * implements operator() to be called like a function and return a Eigen::Vector instead of a template pointer (ceres requirement)
	 *
	 * Implements an implicit type erasure so every function which needs a FuncCaller will accept snx objrvz ehivh implements the function (double * time, double * result, bool expand_noise)
	 */
	class FuncCaller {
	private:

		struct TypeErasure {
			virtual ~TypeErasure() {}
			virtual Eigen::Vector3d operator()(double time, bool expand_noise = false)const =0;

		};
		template<typename functor>
		struct FunctionWrapper: public TypeErasure {
			FunctionWrapper(const functor &function):function(function) {}

			virtual Eigen::Vector3d operator()(double time, bool expand_noise = false) const {
				double result[3];
				function(&time, result, expand_noise);
				return Eigen::Vector3d(result[0], result[1], result[2]);
			}
			functor function;
		};
	public:
		/**
		 * Calls the stored functor with parameters
		 * @param time time_point on wich the function es evaluated
		 * @param expand_noise whether to add a noisy increment
		 * @return a Eigen 3D Vector as the function result
		 */
		Eigen::Vector3d operator()(double time, bool expand_noise = false) const {
			return (*function)(time,expand_noise);
		}
		/**
		 * Create the funcCaller from an arbitrary object which implements the operator()((double * time, double * result, bool expand_noise)
		 * @param func function object
		 */
		template<typename functor>
		FuncCaller(const functor & func) :
		function(new FunctionWrapper<functor>(func)) {
		}
		/**
		 * Copy constructor
		 * @param func another FuncCaller
		 */
		FuncCaller(FuncCaller & func):
		function(func.function) {
		}

	protected:
		std::shared_ptr<TypeErasure> function;
	};

	/**
	 * First order numerical derivative
	 * @param time the time point
	 * @param function FunctionCaller   to derive
	 * @param itv the intervall for numeric derivation
	 * @return first order derivate at time
	 */

	inline Eigen::Vector3d diff1(double time,const FuncCaller & function, double itv = 1e-6) {
		return (function(time) - function(time - itv)) / itv;
	}
	/**
	 * Second order numerical derivative
	 * @param time the time point
	 * @param function  FunctionCaller   to derive
	 * @param itv the intervall for numeric derivation
	 * @return second order derivate at time
	 */
	inline Eigen::Vector3d diff2(double time,const FuncCaller & function, double itv = 1e-6) {
		return (diff1(time, function, itv) - diff1(time - itv, function, itv)) / itv;
	}
	/**
	 * Calculates the euler rotation angles of a function at a given time
	 *
	 * taken from https://stackoverflow.com/questions/18558910/direction-vector-to-rotation-matrix
	 *
	 * @param time  the time point
	 * @param function FunctionCaller   to calculate the orientation off
	 * @param itv the intervall for derivation purposes
	 * @param roll_function a function to determine roll, if not given roll is 0
	 * @return a vector with the 3 euler angles representing the orientation
	 */
	inline Eigen::Matrix3d orientationFromFunctor(double time,const FuncCaller & function, double itv,
			FuncCaller * ref_function = NULL) {
		Eigen::Vector3d vector_orient = diff1(time, function, itv);
		vector_orient.normalize();
		Eigen::Vector3d ref_axis =
		ref_function == NULL ? Eigen::Vector3d(0, 0, 1) : Eigen::Vector3d(ref_function->operator ()(time));
		Eigen::Vector3d xaxis = ref_axis.cross(vector_orient);
		xaxis.normalize();
		Eigen::Vector3d yaxis = vector_orient.cross(xaxis);
		yaxis.normalize();
		Eigen::Matrix3d orient;
		orient.col(1) = xaxis;
		orient.col(2) = yaxis;
		orient.col(0) = vector_orient;
		assert(abs(orient.determinant()-1)< 1e-3);
		return orient;
	}
	/**
	 * Wraps a rotation delta ( x,y,z) to -M_PI  + M_PI
	 * @param delta the vector to wrap
	 * @return a delta vector with values between -M_PI and + M_PI
	 */
	template<typename T>
	Eigen::Matrix<T,3,1> wrapRotDeltaVector(const Eigen::Matrix<T,3,1> & delta) {
		T sqnorm=delta.squaredNorm();
		if(sqnorm==T(0.)) {
			return delta;
		}
		T norm=sqrt(sqnorm);
		if(norm > M_PI) {
			T wrapped_norm=zavi::eigen_util::wrapAngle(norm);
			return delta*wrapped_norm/norm;
		}
		else
		return delta;
	}
	/**
	 * make s skew symmetric from w so that Q'=S(w)*Q  where Q is a rotation matrix and w its change
	 * @param w a 3 element vector
	 * @return a skew symmetric matrix of w
	 */
	template<typename T>
	Eigen::Matrix<T,3,3> makeSkewSymmetric(const Eigen::Matrix<T,3,1> & w) {
		Eigen::Matrix<T,3,3> S=S.Zero();
		S(0,1)=-w(2,0);
		S(0,2)=w(1,0);
		S(1,2)=-w(0,0);

		S(1,0)=w(2,0);
		S(2,0)=-w(1,0);
		S(2,1)=w(0,0);
		return S;
	}
	/**
	 * Determine whether a line intersects a plane
	 *
	 * where the line is l+t*l_d
	 *
	 * and the plane is p+u*p_d1 +v*p_d2
	 *
	 * with t,u,v variables in [0,1]
	 *
	 * length of vectors determines the line length / plane width/height
	 *
	 * @param line_base line start point
	 * @param line_dir  line direction vector
	 * @param plane_base plane start point
	 * @param plane_dir1  first plane direction vector
	 * @param plane_dir2  second plane direction vector
	 * @return
	 */
	template<typename T>
	bool lineIntersectsPlane(const Eigen::Matrix<T,3,1> &line_base,const Eigen::Matrix<T,3,1> &line_dir, const Eigen::Matrix<T,3,1> &plane_base, const Eigen::Matrix<T,3,1> &plane_dir1,const Eigen::Matrix<T,3,1> &plane_dir2 ) {
		Eigen::Matrix<T,3,3> A;
		A << -line_dir,plane_dir1 , plane_dir2;
		if(A.determinant() == 0.) {
			LOG(WARNING)<< "Unhandled Special case in lineIntersectsPlane. Line may be inside plane.";
			return false;
		}
		Eigen::Matrix<T,3,1> tuv=A.inverse()*(line_base-plane_base);
		bool intersects=true;
		for(unsigned int i=0; i < 3; i++) {
			if(tuv(i) < T(0.) or tuv(i) > T(1.))
			intersects=false;
		}
		return intersects;
	}

	/**
	 * For use from other functions
	 * @param a 3d Orientation matrix
	 * @param b 3d orientation matrix
	 * @return b boxminus a
	 */
	template<typename T, typename T2>
	inline static auto boxMinusOrientation(const Eigen::Matrix<T, 3, 3> &a,
			const Eigen::Matrix<T2, 3, 3> &b) ->Eigen::Matrix<decltype(a(0,0)*b(0,0)),3,1> {
		Eigen::Matrix<decltype(a(0,0)*b(0,0)), 3, 3> product= a.inverse() * b;
		return zavi::eigen_util::inverseEulerRodriguez<decltype(a(0,0)*b(0,0))>(product);
	}

	/**
	 * For use from other functions
	 * @param a Angle Axis vector
	 * @param b Angle Axis vector
	 * @return b boxminus a
	 */
	template<typename T, typename T2>
	inline static auto boxMinusEuler(const Eigen::Matrix<T, 3, 1> &a,
			const Eigen::Matrix<T2, 3, 1> &b) ->Eigen::Matrix<decltype(a(0,0)*b(0,0)),3,1> {
		return wrapAngles(b-a);
	}

	/**
	 * For use from other functions
	 * @param a Angle Axis vector
	 * @param b Angle Axis vector
	 * @return a boxplus b
	 */
	template<typename T, typename T2>
	inline static auto boxPlusEuler(const Eigen::Matrix<T, 3, 1> &state,
			const Eigen::Matrix<T2, 3, 1> &delta) ->Eigen::Matrix<decltype(state(0,0)*delta(0,0)),3,1> {
		return wrapAngles(state+delta);
	}

	/**
	 * boxplus operator for rotations
	 * @param state  the rotation matrix
	 * @param delta  the rotation change axis angle
	 * @return state boxplus delta
	 */
	template<typename T>
	inline static Eigen::Matrix<T, 3, 3> boxPlusOrientation(const Eigen::Matrix<T, 3, 3> &state,
			const Eigen::Matrix<T, 3, 1> &delta) {
		//assert(abs(state.determinant() - T(1.)) < T(1e-2));
		Eigen::Matrix<T, 3, 3> product = state* eigen_util::eulerRodriguez(wrapRotDeltaVector(delta));
		//assert(abs(product.determinant() - T(1.)) < T(1e-6));
		return product;

	}

	inline static Eigen::Matrix3d normaliseRotation(const Eigen::Matrix3d & rotation) {
		Eigen::Matrix3d Q= rotation.householderQr().householderQ();
		for(int i=0; i < 3 ; i ++){
			if(Q(i,i)<0.){
				Q.col(i)=-(Q.col(i));
			}
		}
		return Q;
	}

	inline double norm(const double a, const double b, const double c) {
		return sqrt(pow(a, 2) + pow(b, 2) + pow(c, 2));
	}

	template <typename T, int N> inline
	ceres::Jet<T, N> norm(const ceres::Jet<T, N>& a, const ceres::Jet<T, N>& b, const ceres::Jet<T, N>& c) {
		ceres::Jet<T, N> out;

		T const temp1 =sqrt(pow(a.a, 2) + pow(b.a, 2) + pow(c.a, 2));
		T const multiplier= 1./(temp1);
		T const temp2 = temp1==T(0.)? T(1./sqrt(3.)): multiplier*(a.a);
		T const temp3 = temp1==T(0.)? T(1./sqrt(3.)): multiplier*(b.a);
		T const temp4 = temp1==T(0.)? T(1./sqrt(3.)): multiplier*(c.a);

		out.a = temp1;
		out.v = temp2 * a.v + temp3 * b.v+temp4*c.v;
		return out;
	}

}
//zavi::eigen_util

#include "Eigen_Utils.tpp"
#endif /* EIGEN_UTILS_HPP_ */


// Includes
// ========
#include <iostream>
// BGL includes
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/cycle_canceling.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
#include <boost/graph/find_flow_cost.hpp>

// Graph Type with nested interior edge properties for Cost Flow Algorithms
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> traits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property,
    boost::property<boost::edge_capacity_t, long,
        boost::property<boost::edge_residual_capacity_t, long,
            boost::property<boost::edge_reverse_t, traits::edge_descriptor,
                boost::property <boost::edge_weight_t, long> > > > > graph; // new! weightmap corresponds to costs

typedef boost::graph_traits<graph>::edge_descriptor             edge_desc;
typedef boost::graph_traits<graph>::out_edge_iterator           out_edge_it; // Iterator

// Custom edge adder class
class edge_adder {
 graph &G;

 public:
  explicit edge_adder(graph &G) : G(G) {}
  void add_edge(int from, int to, long capacity, long cost) {
    auto c_map = boost::get(boost::edge_capacity, G);
    auto r_map = boost::get(boost::edge_reverse, G);
    auto w_map = boost::get(boost::edge_weight, G); // new!
    const edge_desc e = boost::add_edge(from, to, G).first;
    const edge_desc rev_e = boost::add_edge(to, from, G).first;
    c_map[e] = capacity;
    c_map[rev_e] = 0; // reverse edge has no capacity!
    r_map[e] = rev_e;
    r_map[rev_e] = e;
    w_map[e] = cost;   // new assign cost
    w_map[rev_e] = -cost;   // new negative cost
  }
};

void testcase() {

    int c, g, b, k, a;
    std::cin >> c >> g >> b >> k >> a;
    // Create graph, edge adder class and propery maps
    graph G(c + g);
    edge_adder adder(G);
    auto c_map = boost::get(boost::edge_capacity, G);
    auto r_map = boost::get(boost::edge_reverse, G);
    auto rc_map = boost::get(boost::edge_residual_capacity, G);

    const int v_source = boost::add_vertex(G);

    int sum_elephants = 0;
    for(int i = 0; i < g; i++) {
        int x, y, d, e;
        std::cin >> x >> y >> d >> e;
        sum_elephants += e;
        adder.add_edge(x, c + i, e, d);
        adder.add_edge(c + i, y, e, 0);
    }

    // source
    adder.add_edge(v_source, k, sum_elephants, 0);

    int l = 0;
    int s_flow = 0;
    out_edge_it e, eend;
    boost::successive_shortest_path_nonnegative_weights(G, v_source, a);
    int cost = boost::find_flow_cost(G);

    for(boost::tie(e, eend) = boost::out_edges(boost::vertex(v_source,G), G); e != eend; ++e) {
        s_flow += c_map[*e] - rc_map[*e];
    }

    // this is a simple heuristic: we save the binary search
    // if cost is not the bottleneck anyway
    if(cost <= b) {
        std::cout << s_flow << std::endl;
        return;
    }

    int r = s_flow;
    while(l <= r) {
        int mid = (l + r) / 2;
        // change capacity
        const edge_desc e_s = boost::edge(v_source, k, G).first;
        const edge_desc rev_e = r_map[e_s];
        c_map[e_s] = mid;
        c_map[rev_e] = 0; // reverse edge has no capacity!
        boost::successive_shortest_path_nonnegative_weights(G, v_source, a);
        int cost = boost::find_flow_cost(G);
        out_edge_it e, eend;
        if(cost <= b) { // cost is okay, i.e. go higher
            l = mid + 1;
        } else {
            r = mid;
            if(l == r) break;
        }
    }
    std::cout << l - 1 << std::endl;
}
int main() {
    std::ios_base::sync_with_stdio(false);

    int t;
    std::cin >> t;
    for (int i = 0; i < t; ++i)
        testcase();
}


/**
 * @date Mon May 16 21:45:27 2011 +0200
 * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
 * @author Andre Anjos <andre.anjos@idiap.ch>
 *
 * Copyright (C) Idiap Research Institute, Martigny, Switzerland
 */

#include <stdexcept>
#include <algorithm>
#include <vector>
#include <boost/shared_array.hpp>

#include <bob.math/eig.h>

#include <bob.core/assert.h>
#include <bob.core/check.h>
#include <bob.core/array_copy.h>

// Generalized eigenvalue decomposition of a real matrix
//   (dgeev)
extern "C" void dgeev_( const char *jobvl, const char *jobvr,
  const int *N, double *A, const int *lda, double *wr, double *wi,
  double *vl, const int *ldvl, double *vr, const int *ldvr,
  double *work, const int *lwork, int *info);

// Declaration of the external LAPACK functions
// Eigenvalue decomposition of a real symmetric matrix (dsyevd)
//   (Divide and conquer version which is supposed to be faster than dsyev)
extern "C" void dsyevd_( const char *jobz, const char *uplo, const int *N,
  double *A, const int *lda, double *W, double *work, const int *lwork,
  int *iwork, const int *liwork, int *info);

// Generalized eigenvalue decomposition of a real symmetric definite matrix
//   (dsygvd)
//   (Divide and conquer version which is supposed to be faster than dsygv)
extern "C" void dsygvd_( const int *itype, const char *jobz, const char *uplo,
  const int *N, double *A, const int *lda, double *B, const int *ldb,
  double *W, double *work, const int *lwork, const int *iwork,
  const int *liwork, int *info);

void bob::math::eig(const blitz::Array<double,2>& A,
  blitz::Array<std::complex<double>,2>& V,
  blitz::Array<std::complex<double>,1>& D)
{
  // Size variable
  const int N = A.extent(0);
  const blitz::TinyVector<int,1> shape1(N);
  const blitz::TinyVector<int,2> shape2(N,N);

  // Check
  bob::core::array::assertZeroBase(A);
  bob::core::array::assertZeroBase(V);
  bob::core::array::assertZeroBase(D);

  bob::core::array::assertSameShape(A,shape2);
  bob::core::array::assertSameShape(V,shape2);
  bob::core::array::assertSameShape(D,shape1);

  bob::math::eig_(A, V, D);
}

void bob::math::eig_(const blitz::Array<double,2>& A,
  blitz::Array<std::complex<double>,2>& V,
  blitz::Array<std::complex<double>,1>& D)
{
  // Size variable
  const int N = A.extent(0);

  // Prepares to call LAPACK function
  // Initialises LAPACK variables
  const char jobvl = 'N'; // Do NOT compute left eigen-vectors
  const char jobvr = 'V'; // Compute right eigen-vectors
  int info = 0;
  const int lda = N;
  const int ldvr = N;
  double VL = 0; // notice we don't compute the left eigen-values
  const int ldvl = 1;

  // Initialises LAPACK arrays
  blitz::Array<double,2> A_lapack = bob::core::array::ccopy(const_cast<blitz::Array<double,2>&>(A).transpose(1,0));

  // temporary arrays to receive LAPACK's eigen-values and eigen-vectors
  blitz::Array<double,1> WR(D.shape()); //real part
  blitz::Array<double,1> WI(D.shape()); //imaginary part
  blitz::Array<double,2> VR(A.shape()); //right eigen-vectors

  // Calls the LAPACK function
  // A/ Queries the optimal size of the working arrays
  const int lwork_query = -1;
  double work_query;
  dgeev_( &jobvl, &jobvr, &N, A_lapack.data(), &lda, WR.data(), WI.data(),
      &VL, &ldvl, VR.data(), &ldvr, &work_query, &lwork_query, &info);

  // B/ Computes the eigenvalue decomposition
  const int lwork = static_cast<int>(work_query);
  boost::shared_array<double> work(new double[lwork]);
  dgeev_( &jobvl, &jobvr, &N, A_lapack.data(), &lda, WR.data(), WI.data(),
      &VL, &ldvl, VR.data(), &ldvr, work.get(), &lwork, &info);

  // Checks info variable
  if (info != 0) {
    throw std::runtime_error("the QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed.");
  }

  // Copy results back from WR, WI => D
  blitz::real(D) = WR;
  blitz::imag(D) = WI;

  // Copy results back from VR => V, with two rules:
  // 1) If the j-th eigenvalue is real, then v(j) = VR(:,j), the j-th column of
  //    VR.
  // 2) If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
  // then v(j) = VR(:,j) + i*VR(:,j+1) and v(j+1) = VR(:,j) - i*VR(:,j+1).
  blitz::Range a = blitz::Range::all();
  int i=0;
  while (i<N) {
    if (std::imag(D(i)) == 0.) { //real eigen-value, consume 1
      blitz::real(V(a,i)) = VR(i,a);
      blitz::imag(V(a,i)) = 0.;
      ++i;
    }
    else { //complex eigen-value, consume 2
      blitz::real(V(a,i)) = VR(i,a);
      blitz::imag(V(a,i)) = VR(i+1,a);
      blitz::real(V(a,i+1)) = VR(i,a);
      blitz::imag(V(a,i+1)) = -VR(i+1,a);
      i += 2;
    }
  }
}

void bob::math::eigSym(const blitz::Array<double,2>& A,
  blitz::Array<double,2>& V, blitz::Array<double,1>& D)
{
  // Size variable
  const int N = A.extent(0);
  const blitz::TinyVector<int,1> shape1(N);
  const blitz::TinyVector<int,2> shape2(N,N);

  // Check
  bob::core::array::assertZeroBase(A);
  bob::core::array::assertZeroBase(V);
  bob::core::array::assertZeroBase(D);

  bob::core::array::assertSameShape(A,shape2);
  bob::core::array::assertSameShape(V,shape2);
  bob::core::array::assertSameShape(D,shape1);

  bob::math::eigSym_(A, V, D);
}

void bob::math::eigSym_(const blitz::Array<double,2>& A,
  blitz::Array<double,2>& V, blitz::Array<double,1>& D)
{
  // Size variable
  const int N = A.extent(0);

  // Prepares to call LAPACK function
  // Initialises LAPACK variables
  const char jobz = 'V'; // Get both the eigenvalues and the eigenvectors
  const char uplo = 'U';
  int info = 0;
  const int lda = N;

  // Initialises LAPACK arrays
  blitz::Array<double,2> A_blitz_lapack;
  // Tries to use V directly
  blitz::Array<double,2> Vt = V.transpose(1,0);
  const bool V_direct_use = bob::core::array::isCZeroBaseContiguous(Vt);
  if (V_direct_use)
  {
    A_blitz_lapack.reference(Vt);
    // Ugly fix for non-const transpose
    A_blitz_lapack = const_cast<blitz::Array<double,2>&>(A).transpose(1,0);
  }
  else
    // Ugly fix for non-const transpose
    A_blitz_lapack.reference(
      bob::core::array::ccopy(const_cast<blitz::Array<double,2>&>(A).transpose(1,0)));
  double *A_lapack = A_blitz_lapack.data();
  blitz::Array<double,1> D_blitz_lapack;
  const bool D_direct_use = bob::core::array::isCZeroBaseContiguous(D);
  if (D_direct_use)
    D_blitz_lapack.reference(D);
  else
    D_blitz_lapack.resize(D.shape());
  double *D_lapack = D_blitz_lapack.data();

  // Calls the LAPACK function
  // A/ Queries the optimal size of the working arrays
  const int lwork_query = -1;
  double work_query;
  const int liwork_query = -1;
  int iwork_query;
  dsyevd_( &jobz, &uplo, &N, A_lapack, &lda, D_lapack, &work_query,
    &lwork_query, &iwork_query, &liwork_query, &info);
  // B/ Computes the eigenvalue decomposition
  const int lwork = static_cast<int>(work_query);
  boost::shared_array<double> work(new double[lwork]);
  const int liwork = static_cast<int>(iwork_query);
  boost::shared_array<int> iwork(new int[liwork]);
  dsyevd_( &jobz, &uplo, &N, A_lapack, &lda, D_lapack, work.get(), &lwork,
    iwork.get(), &liwork, &info);

  // Checks info variable
  if (info != 0)
    throw std::runtime_error("The LAPACK function 'dsyevd' returned a non-zero value.");

  // Copy singular vectors back to V if required
  if (!V_direct_use)
    Vt = A_blitz_lapack;

  // Copy result back to sigma if required
  if (!D_direct_use)
    D = D_blitz_lapack;
}

void bob::math::eigSym(const blitz::Array<double,2>& A, const blitz::Array<double,2>& B,
  blitz::Array<double,2>& V, blitz::Array<double,1>& D)
{
  // Size variable
  const int N = A.extent(0);
  const blitz::TinyVector<int,1> shape1(N);
  const blitz::TinyVector<int,2> shape2(N,N);
  bob::core::array::assertZeroBase(A);
  bob::core::array::assertZeroBase(B);
  bob::core::array::assertZeroBase(V);
  bob::core::array::assertZeroBase(D);

  bob::core::array::assertSameShape(A,shape2);
  bob::core::array::assertSameShape(B,shape2);
  bob::core::array::assertSameShape(V,shape2);
  bob::core::array::assertSameShape(D,shape1);

  bob::math::eigSym_(A, B, V, D);
}

void bob::math::eigSym_(const blitz::Array<double,2>& A, const blitz::Array<double,2>& B,
  blitz::Array<double,2>& V, blitz::Array<double,1>& D)
{
  // Size variable
  const int N = A.extent(0);

  // Prepares to call LAPACK function
  // Initialises LAPACK variables
  const int itype = 1;
  const char jobz = 'V'; // Get both the eigenvalues and the eigenvectors
  const char uplo = 'U';
  int info = 0;
  const int lda = N;
  const int ldb = N;

  // Initialises LAPACK arrays
  blitz::Array<double,2> A_blitz_lapack;
  // Tries to use V directly
  blitz::Array<double,2> Vt = V.transpose(1,0);
  const bool V_direct_use = bob::core::array::isCZeroBaseContiguous(Vt);
  if (V_direct_use)
  {
    A_blitz_lapack.reference(Vt);
    // Ugly fix for non-const transpose
    A_blitz_lapack = const_cast<blitz::Array<double,2>&>(A).transpose(1,0);
  }
  else
    // Ugly fix for non-const transpose
    A_blitz_lapack.reference(
      bob::core::array::ccopy(const_cast<blitz::Array<double,2>&>(A).transpose(1,0)));
  double *A_lapack = A_blitz_lapack.data();
  // Ugly fix for non-const transpose
  blitz::Array<double,2> B_blitz_lapack(
    bob::core::array::ccopy(const_cast<blitz::Array<double,2>&>(B).transpose(1,0)));
  double *B_lapack = B_blitz_lapack.data();
  blitz::Array<double,1> D_blitz_lapack;
  const bool D_direct_use = bob::core::array::isCZeroBaseContiguous(D);
  if (D_direct_use)
    D_blitz_lapack.reference(D);
  else
    D_blitz_lapack.resize(D.shape());
  double *D_lapack = D_blitz_lapack.data();

  // Calls the LAPACK function
  // A/ Queries the optimal size of the working arrays
  const int lwork_query = -1;
  double work_query;
  const int liwork_query = -1;
  int iwork_query;
  dsygvd_( &itype, &jobz, &uplo, &N, A_lapack, &lda, B_lapack, &ldb, D_lapack,
    &work_query, &lwork_query, &iwork_query, &liwork_query, &info);
  // B/ Computes the generalized eigenvalue decomposition
  const int lwork = static_cast<int>(work_query);
  boost::shared_array<double> work(new double[lwork]);
  const int liwork = static_cast<int>(iwork_query);
  boost::shared_array<int> iwork(new int[liwork]);
  dsygvd_( &itype, &jobz, &uplo, &N, A_lapack, &lda, B_lapack, &ldb, D_lapack,
    work.get(), &lwork, iwork.get(), &liwork, &info);

  // Checks info variable
  if (info != 0)
    throw std::runtime_error("The LAPACK function 'dsygvd' returned a non-zero value. This might be caused by a non-positive definite B matrix.");

  // Copy singular vectors back to V if required
  if (!V_direct_use)
    V = A_blitz_lapack.transpose(1,0);

  // Copy result back to sigma if required
  if (!D_direct_use)
    D = D_blitz_lapack;
}


/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Hidekazu Ikeno
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

///
/// \file aak_reduction.hpp
///
/// Sparse approximation of exponential sum using modified Prony method.
///
#ifndef MXPFIT_MODIFIED_PRONY_REDUCTION_HPP
#define MXPFIT_MODIFIED_PRONY_REDUCTION_HPP

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/QR>

#include <mxpfit/exponential_sum.hpp>

namespace mxpfit
{
///
/// ### ModifiedPronyReduction
///
/// \brief Find a truncated exponential sum function with smaller number of
///        terms by the modified balanced truncation method.
///
/// \tparam T  Scalar type of exponential sum function.
///
/// Let us consider an exponential sum function, in which the weights and
/// exponetns are strictly positive, i.e.,
///
/// \f[
///   f(t)=\sum_{j=1}^{n} w_{j}^{} e^{-a_{j}^{} t}, \quad
///   (a_{j} > 0, \, w_{j} > 0).
/// \f]
///
/// This class calculates truncated exponential \f$\hat{f}(t)\f$ sum such that
///
/// \f[
///   \hat{f}(t)=\sum_{j=1}^{k} \hat{w}_{j}^{}e^{-\hat{a}_{j}^{} t}, \quad
///   \left| f(t)-\hat{f}(t) \right| < \epsilon, \, (k < n)
/// \f]
///
/// where \f$\epsilon > 0\f$ is the prescribed accuracy. The weights
/// \f$\hat{w}_{j}\f$ and exponents \f$\hat{w}_{j}\f$ in the trucated sum are
/// all positive.
///
/// The modified Prony method proposed by Beylkin and Monzon are adopted. We
/// refer to the literature listed below for the detial about the method.
///
/// #### References
///
/// 1. G. Beylkin and L. Monz\'{o}n, "Approximation by exponential sums
///    revisited", Appl. Comput. Harmon. Anal. 28 (2010) 131-149.
///    [DOI: https://doi.org/10.1016/j.acha.2009.08.011]
/// 2. W. McLean, "Exponential sum approximations for \f$t^{-\beta}\f$",
///    arXiv:1606.00123 [math]
///
template <typename T>
class ModifiedPronyReduction
{
public:
    using Scalar        = T;
    using RealScalar    = typename Eigen::NumTraits<Scalar>::Real;
    using ComplexScalar = std::complex<RealScalar>;
    using Index         = Eigen::Index;

    using VectorType = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
    using MatrixType = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
    using ResultType = ExponentialSum<Scalar, Scalar>;

    ///
    /// Compute truncated exponential sum \f$ \hat{f}(t) \f$
    ///
    /// \tparam DerivedF type of exponential sum inheriting ExponentialSumBase
    ///
    /// \param[in] orig original exponential sum function, \f$ f(t) \f$
    /// \param[in] n_target Index smaller than `orig.size()`, which denotes
    ///            number of terms to be target for reduction.
    /// \param[in] threshold  prescribed accuracy \f$0 < \epsilon \ll 1\f$
    ///
    /// \pre The weights \f$w_{j}\f$ and exponents \f${a_{j}}\f$ are strictly
    /// positive and \f$a_{j}\f$ must be sorted in ascending order.
    ///
    /// \remark The exponents \f$\hat{a}_{j}\f$ of truncated sum are obtained as
    /// a root of Prony polynomials, which might not be real and positive.
    /// Internaly, obtaind roots of polynomial is casted to be a real number,
    /// which might introduce significant errors in the approximation.
    ///
    /// \return An instance of ExponentialSum represents \f$\hat{f}(t)\f$
    ///
    template <typename DerivedF>
    ResultType compute(const ExponentialSumBase<DerivedF>& orig, Index n_target,
                       RealScalar threshold);
};

template <typename T>
template <typename DerivedF>
typename ModifiedPronyReduction<T>::ResultType
ModifiedPronyReduction<T>::compute(const ExponentialSumBase<DerivedF>& orig,
                                   Index n_target, RealScalar eps)
{
    using Eigen::numext::abs;
    using Eigen::numext::real;
    assert(Index(0) <= n_target && n_target <= orig.size());
    assert(eps > RealScalar());

    if (n_target == Index())
    {
        ResultType ret(orig);
        return ret; // quick return
    }

    //
    // Compute a sequence
    //
    // \f[
    //   h_{j} = \sum_{k=1}^{n} w_{k} a_{k}^{j}
    // \f]
    //
    VectorType h(2 * n_target);
    const auto w_target = orig.weights().head(n_target);
    const auto a_target = orig.exponents().head(n_target);
    VectorType a_pow(a_target);

    h(0) = w_target.sum();
    h(1) = -(w_target * a_pow.array()).sum();

    Index m        = 1;
    auto factorial = RealScalar(1);
    for (; m < n_target; ++m)
    {
        a_pow.array() *= a_target;
        h(2 * m + 0) = (w_target * a_pow.array()).sum();
        a_pow.array() *= a_target;
        h(2 * m + 1) = -(w_target * a_pow.array()).sum();
        factorial *= RealScalar(2 * m * (2 * m + 1));

        if (abs(h(2 * m + 1)) / factorial < eps)
        {
            // Taylor expansion converges with the tolerance eps.
            ++m;
            break;
        }
    }

    if (m == n_target)
    {
        // no further reduction
        ResultType ret(orig);
        return ret;
    }

    //
    // Construct a Hankel matrix from the sequence h, and solve the linear
    // equation, H q = b, with b = -h(m:2m-1).
    //
    MatrixType H(m, m);
    for (Index i = 0; i < m; ++i)
    {
        H.col(i) = h.segment(i, m);
    }
    VectorType q(H.colPivHouseholderQr().solve(-h.segment(m, m)));

    //
    // Find the roots of the Prony polynomial,
    //
    // q(z) = \sum_{k=0}^{m-1} q_k z^{k}.
    //
    // The roots of q(z) can be obtained as the eigenvalues of the companion
    // matrix,
    //
    //     (0  0  ...  0 -p[0]  )
    //     (1  0  ...  0 -p[1]  )
    // C = (0  1  ...  0 -p[2]  )
    //     (.. .. ...  .. ..    )
    //     (0  0  ...  1 -p[m-1])
    //

    MatrixType companion(MatrixType::Zero(m, m));
    companion.diagonal(-1).setOnes();
    companion.col(m - 1) = -q;
    VectorType gamma(companion.eigenvalues().real());

    // --- Update exponents & weights
    const Index keep = orig.size() - n_target;
    ResultType ret(keep + m);
    ret.exponents().head(m)    = -gamma;
    ret.exponents().tail(keep) = orig.exponents().tail(keep);

    //
    // Construct Vandermonde matrix from Prony roots
    //
    MatrixType V(2 * m, m);
    for (Index i = 0; i < m; ++i)
    {
        const RealScalar z = gamma(i);
        V(0, i)            = RealScalar(1);
        for (Index j = 1; j < V.rows(); ++j)
        {
            V(j, i) = V(j - 1, i) * z; // z[i]**j
        }
    }

    //
    // Solve overdetermined Vandermonde system,
    //
    // V(0:2m-1,0:m-1) w(0:m-1) = h(0:2m-1)
    //
    // by the least square method.
    //
    ret.weights().head(m)    = V.colPivHouseholderQr().solve(h.head(2 * m));
    ret.weights().tail(keep) = orig.weights().tail(keep);

    return ret;
}

} // namespace mxpfit

#endif /* MXPFIT_MODIFIED_PRONY_REDUCTION_HPP */


#pragma once

#include <cmath>

#include <Eigen/Dense>

#define D2R(x) (x * (M_PI/180))
#define R2D(x) (x * (180/M_PI))

class Geodesy{
public:
	/**WGS84 ellipsoid semi-major axis*/
	static constexpr double a = 6378137.0;

	/**WGS84 ellipsoid first eccentricity squared*/
	static constexpr double e2 = 0.081819190842622 * 0.081819190842622;

	static void getPositionECEF(Eigen::Vector3d & positionECEF, double longitude, double latitude,double ellipsoidalHeight) {
		double clat = cos(latitude);
		double slat = sin(latitude);
		double clon = cos(longitude);
		double slon = sin(longitude);

		double N = a / (sqrt(1 - e2 * slat * slat));
		double xTRF = (N + ellipsoidalHeight) * clat * clon;
		double yTRF = (N + ellipsoidalHeight) * clat * slon;
		double zTRF = (N * (1 - e2) + ellipsoidalHeight) * slat;

		positionECEF << xTRF, yTRF, zTRF;
	}
};


///
// ALGOLAB BGL Tutorial 3
// Flow example demonstrating
// - breadth first search (BFS) on the residual graph

// Compile and run with one of the following:
// g++ -std=c++11 -O2 bgl_residual_bfs.cpp -o bgl_residual_bfs ./bgl_residual_bfs
// g++ -std=c++11 -O2 -I path/to/boost_1_58_0 bgl_residual_bfs.cpp -o bgl_residual_bfs; ./bgl_residual_bfs

// Includes
// ========
// STL includes
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
// BGL includes
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/cycle_canceling.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
#include <boost/graph/find_flow_cost.hpp>

// BGL graph definitions
// =====================
// Graph Type with nested interior edge properties for Cost Flow Algorithms
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> traits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property,
    boost::property<boost::edge_capacity_t, long,
        boost::property<boost::edge_residual_capacity_t, long,
            boost::property<boost::edge_reverse_t, traits::edge_descriptor,
                boost::property <boost::edge_weight_t, long> > > > > graph; // new! weightmap corresponds to costs

typedef boost::graph_traits<graph>::edge_descriptor             edge_desc;
typedef boost::graph_traits<graph>::out_edge_iterator           out_edge_it; // Iterator

// Custom edge adder class
class edge_adder {
 graph &G;

 public:
  explicit edge_adder(graph &G) : G(G) {}
  void add_edge(int from, int to, long capacity, long cost) {
    auto c_map = boost::get(boost::edge_capacity, G);
    auto r_map = boost::get(boost::edge_reverse, G);
    auto w_map = boost::get(boost::edge_weight, G); // new!
    const edge_desc e = boost::add_edge(from, to, G).first;
    const edge_desc rev_e = boost::add_edge(to, from, G).first;
    c_map[e] = capacity;
    c_map[rev_e] = 0; // reverse edge has no capacity!
    r_map[e] = rev_e;
    r_map[rev_e] = e;
    w_map[e] = cost;   // new assign cost
    w_map[rev_e] = -cost;   // new negative cost
  }
};

// Main
void testcase() {
  // build graph
  int n;
  std::cin >> n;
  graph G(n);
  edge_adder adder(G);
  // auto rc_map = boost::get(boost::edge_residual_capacity, G);
  const int v_source = boost::add_vertex(G);
  const int v_sink = boost::add_vertex(G);

  std::vector<int> a_and_c(2*n);
  for(int i = 0; i < n; i++) {
    int a, c;
    std::cin >> a >> c;
    a_and_c[2 * i] = a;
    a_and_c[2 * i + 1] = c;
    // adder.add_edge(v_source, i, a, c);
  }

  int sum_students = 0;
  int max_price = 0;
  std::vector<int> s_and_p(2*n);
  for(int i = 0; i < n; i++) {
    int s, p;
    std::cin >> s >> p;
    sum_students += s;
    s_and_p[2 * i] = s;
    s_and_p[2 * i + 1] = p;
    max_price = std::max(max_price, p);
  }

  for(int i = 0; i < n; i++) {
    int a = a_and_c[2 * i];
    int c = a_and_c[2 * i + 1];
    adder.add_edge(v_source, i, a, c);
  }

  for(int i = 0; i < n; i++) {
    int s = s_and_p[2 * i];
    int p = s_and_p[2 * i + 1];
    adder.add_edge(i, v_sink, s, - p + max_price);
  }

  for(int i = 0; i < n - 1; i++) {
    int v, e;
    std::cin >> v >> e;
    adder.add_edge(i, i + 1, v, e);
  }

  // int flow = boost::push_relabel_max_flow(G, v_source, v_sink);
  // boost::cycle_canceling(G);
  // int cost = boost::find_flow_cost(G);

  boost::successive_shortest_path_nonnegative_weights(G, v_source, v_sink);
  int cost = boost::find_flow_cost(G);
  // Iterate over all edges leaving the source to sum up the flow values.
  int flow = 0;
  out_edge_it e, eend;
  auto c_map = boost::get(boost::edge_capacity, G);
  auto rc_map = boost::get(boost::edge_residual_capacity, G);
  for(boost::tie(e, eend) = boost::out_edges(boost::vertex(v_source,G), G); e != eend; ++e) {
      // std::cout << "edge from " << boost::source(*e, G) << " to " << boost::target(*e, G)
      //     << " with capacity " << c_map[*e] << " and residual capacity " << rc_map[*e] << "\n";
      flow += c_map[*e] - rc_map[*e];
  }
  if(flow == sum_students) {
    std::cout << "possible ";
  } else {
    std::cout << "impossible ";
  }
  std::cerr << flow * max_price << std::endl;
  std::cout << flow << " " << -(cost - (flow * max_price)) << "\n";
  // std::cerr << std::endl;
  // // Retrieve the capacity map and reverse capacity map
  // const auto c_map = boost::get(boost::edge_capacity, G);
  // const auto rc_map = boost::get(boost::edge_residual_capacity, G);

  // // Iterate over all the edges to print the flow along them
  // auto edge_iters = boost::edges(G);
  // for (auto edge_it = edge_iters.first; edge_it != edge_iters.second; ++edge_it) {
  //   const edge_desc edge = *edge_it;
  //   const long flow_through_edge = c_map[edge] - rc_map[edge];
  //   std::cerr << "edge from " << boost::source(edge, G) << " to " << boost::target(edge, G)
  //             << " runs " << flow_through_edge
  //             << " units of flow (negative for reverse direction). \n";
  // }
}

int main() {
  std::ios_base::sync_with_stdio(false);
  std::size_t t;
  for (std::cin >> t; t > 0; --t) testcase();
  return 0;
}


#include <iostream>
#include <array>
#include <string>
#include <cstring>
#include <fstream>
#include <exception>
#define _USE_MATH_DEFINES
#include <cmath>
#include <vector>
#include "port_authority.hpp"

using namespace std;
using namespace pauth;

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/tokenizer.hpp>
#include <boost/token_functions.hpp>

using namespace boost;
using namespace boost::program_options;

#include "mpi.h"

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

  int taskid, numtasks;
  MPI_Init(nullptr, nullptr);
  MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
  MPI_Comm_rank(MPI_COMM_WORLD, &taskid);

  options_description desc("\nMetropolis simulation of a harmonic oscillator."
                           "\n\nAllowed arguments");

  double delta_max, x0, dx, sk;
  unsigned long nsteps;

  desc.add_options()
    ("help,h", "Produce this help message.")
    ("x0,x", value<double>(&x0)->default_value(0.0), "Initial position.")
    ("spring-const,k", value<double>(&sk)->default_value(1.0), "Spring constant.")
    ("beta,b", value<double>()->default_value(1.0), "1 / kT")
    ("delta,d", value<double>(&delta_max)->default_value(2.0), "Maximum step size.")
    ("num-steps,n", value<size_t>(&nsteps)->default_value(100000), "Number of steps.")
    ("dx,e", value<double>(&dx)->default_value(0.1), "Threshold size for "
      "approximating <dirac_delta(x - x0)> which is used to approximate Z.")
    ("plot-histogram,p", "Plot histogram.");

  variables_map vm;
  try {
    store(command_line_parser(argc, argv).options(desc).run(), vm);
    notify(vm);
  } catch(std::exception &e) {
    cout << endl << e.what() << endl;
    cout << desc << endl;
  }

  if (vm.count("help")) {
    if(taskid == 0) {
      cout << "--help specified" << endl;
      cout << desc << endl;
    }
    MPI_Finalize();
    return EXIT_SUCCESS;
  }

  const double T = 1.0;
  const double kB = 1.0 / vm["beta"].as<double>();

  const molecular_id id = molecular_id::Test1;
  const size_t N = 1;
  const size_t D = 1;
  const double L = 1.0;
  const metric m = euclidean;
  const bc boundary = no_bc;
  const_k_spring_potential pot(sk);
  vector<double> xs;

  metropolis sim(id, N, D, L, continuous_trial_move(delta_max),
                 &pot, T, kB, m, boundary, metropolis_acc,
                 hardware_entropy_seed_gen, true);
  sim.positions()(0, 0) = x0;
  const double u0 = accessors::U(sim);

  if (vm.count("plot-histogram")) {
    sim.add_callback([&](const metropolis &sim) -> void {
      xs.push_back(sim.positions()(0, 0));
    });
  }

  metropolis_suite msuite(sim, 0, 1, info_lvl_flag::VERBOSE);

  msuite.add_variable_to_average("x", [](const metropolis &sim) {
    return sim.positions()(0, 0);
  });
  msuite.add_variable_to_average("x^2", [](const metropolis &sim) {
    return sim.positions()(0, 0) * sim.positions()(0, 0);
  });
  msuite.add_variable_to_average("U", accessors::U);
  msuite.add_variable_to_average("delta(x - x0)", [=](const metropolis &sim) {
    const double x = sim.positions()(0, 0);
    return (x < x0 + dx && x > x0 - dx) ? 1 : 0;
  });

  msuite.simulate(nsteps);

  if(taskid == 0) {
    auto averages = msuite.averages();

    const double exp_x = averages["x"];
    const double exp_xsq = averages["x^2"];
    cout << "<x>      =     " << exp_x << '\n';
    cout << "<x^2>    =     " << exp_xsq << '\n';
    cout << "kT/k     =     " << kB * T / sk << '\n';
    cout << "Delta x  =     " << sqrt(exp_xsq - exp_x*exp_x) << '\n';
    cout << "<E>      =     " << averages["U"] << '\n';
    cout << "kT / 2   =     " << kB * T / 2.0 << '\n';
    cout << "Z        =     " << (2.0 * dx * exp(-u0 / (kB * T))
                                  / averages["delta(x - x0)"]) << '\n';
    cout << "Z (an)   =     " << sqrt(2.0 * M_PI * kB * T / sk) << '\n';

    if (vm.count("plot-histogram")) {
      throw "Not yet implemented.";
    }
  }

  MPI_Finalize();

  return 0;
}