// Petter Strandmark 2014
// petter.strandmark@gmail.com
//
// [1] Chambolle, A., & Pock, T. (2011). A first-order primal-dual algorithm for convex
//     problems with applications to imaging. Journal of Mathematical Imaging and Vision,
//     40(1), 120-145.
//
// [2] Pock, T., & Chambolle, A. (2011, November). Diagonal preconditioning for first
//     order primal-dual algorithms in convex optimization. In Computer Vision (ICCV),
//     2011 IEEE International Conference on (pp. 1762-1769). IEEE.
//

#include <cstdio>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>

#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <first_order_solver.h>

double get_feasibility_error(const Eigen::VectorXd& x,
                             Eigen::VectorXd* temp_storage,
                             const Eigen::VectorXd& lb,
                             const Eigen::VectorXd& ub,
                             const Eigen::SparseMatrix<double>& A,
                             const Eigen::VectorXd& b,
                             const std::vector<LinearConstraintType>& constraint_types)
{
	using namespace std;
	const auto m = A.rows();
	const auto n = A.cols();
	attest(lb.rows() == n);
	attest(ub.rows() == n);
	attest(x.rows() == n);
	attest(b.rows() == m);
	attest(constraint_types.size() == m);

	double feasibility_error = 0;
	*temp_storage = A*x - b;

	for (ptrdiff_t i = 0; i < m; ++i) {
		if (constraint_types[i] == LinearConstraintType::Equality) {
			feasibility_error = max(feasibility_error, abs((*temp_storage)(i)));
		}
		else if (constraint_types[i] == LinearConstraintType::LessThan) {
			feasibility_error = max(feasibility_error, (*temp_storage)(i));
		}
		else if (constraint_types[i] == LinearConstraintType::GreaterThan) {
			feasibility_error = max(feasibility_error, -(*temp_storage)(i));
		}
	}

	for (ptrdiff_t j = 0; j < n; ++j) {
		feasibility_error = max(feasibility_error, lb(j) - x(j));
		feasibility_error = max(feasibility_error, x(j) - ub(j));
	}

	double denominator = max(x.maxCoeff(), -x.minCoeff());
	if (denominator <= 1e-10) {
		denominator = 1;
	}

	return feasibility_error / denominator;
}

// Will use x_prev as a temporary storage after
// examining it.
bool check_convergence_and_log(std::ptrdiff_t iteration,
                               const Eigen::VectorXd& x,
                               Eigen::VectorXd* x_prev,
                               const Eigen::VectorXd& y,
                               const Eigen::VectorXd& y_prev,
                               const Eigen::VectorXd& c,
                               const Eigen::VectorXd& lb,
                               const Eigen::VectorXd& ub,
                               const Eigen::SparseMatrix<double>& A,
                               const Eigen::VectorXd& b,
                               const std::vector<LinearConstraintType>& constraint_types,
                               const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	const auto n = x.size();
	const auto m = y.size();

	bool is_converged = false;

	//cerr << "x      = " << (*x).transpose() << endl;
	//cerr << "Ax     = " << (A*(*x)).transpose() << endl;
	//cerr << "Ax - b = " << (A*(*x) - b).transpose() << endl;

	auto get_relative_change = [iteration](const Eigen::VectorXd& x, const Eigen::VectorXd& x_prev) -> double
	{
		double relative_change;
		if (iteration <= 0) {
			relative_change = std::numeric_limits<double>::quiet_NaN();
		}
		else {
			relative_change = (x - x_prev).norm() / (x.norm() + x_prev.norm());
			if (relative_change != relative_change) {
				// Both x and x_prev were null vectors.
				relative_change = 0;
			}
		}
		return relative_change;
	};

	double relative_change_x = get_relative_change(x, *x_prev);
	double relative_change_y = get_relative_change(y, y_prev);
	double feasibility_error = get_feasibility_error(x, x_prev, lb, ub, A, b, constraint_types);

	if (relative_change_x < options.tolerance && relative_change_y < options.tolerance) {
		is_converged = true;
	}

	if (options.log_function) {
		ostringstream message;
		message << setw(9);
		if (iteration == -1) {
			message << "end";
		}
		else {
			message << iteration;
		}
		message << "   "
				<< setw(15) << setprecision(6) << scientific << c.dot(x) << " "
				<< setw(12) << setprecision(3) << scientific << relative_change_x << " "
				<< setw(12) << setprecision(3) << scientific << relative_change_y << " "
				<< setw(15) << setprecision(6) << scientific << feasibility_error;
		options.log_function(message.str());
	}

	return is_converged;
}

template<typename Int>
std::string to_string_with_separator(Int input)
{
	attest(input >= 0);
	std::string s;
	auto num = std::to_string(input);
	std::reverse(begin(num), end(num));
	for (std::size_t i = 0; i < num.size(); ++i) {
		s += num[i];
		if (i % 3 == 2 && i < num.size() - 1) {
			s += ',';
		}
	}
	std::reverse(begin(s), end(s));
	return s;
}

/// Solves the linear program
///
///   minimize c·x
///   such that Ax = b,
///             l ≤ x ≤ u.
bool first_order_primal_dual_solve(Eigen::VectorXd* x_ptr,    /// Primal variables (in/out).
                                   Eigen::VectorXd* y_ptr,    /// Dual variables (in/out).
                                   const Eigen::VectorXd& c,  /// Objective function.
                                   const Eigen::VectorXd& lb, /// Lower bound on x.
                                   const Eigen::VectorXd& ub, /// Upper bound on x.
                                   const Eigen::SparseMatrix<double>& A,   /// Equality constraint matrix.
                                   const Eigen::VectorXd& b,  /// Right-hand side of constraints.
                                   const std::vector<LinearConstraintType>& constraint_types,
                                   const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	VectorXd& x = *x_ptr;
	VectorXd& y = *y_ptr;

	const auto n = x.size();
	const auto m = y.size();
	attest(c.size() == n);
	attest(A.rows() == m);
	attest(A.cols() == n);
	attest(constraint_types.size() == m);

	VectorXd x_prev(n);
	VectorXd y_prev(m);

	//cerr << "m=" << m << ", n=" << n << endl;
	//cerr << "A = \n" << A << endl;
	//cerr << "b = \n" << b  << endl;
	//cerr << "lb = \n" << lb.transpose() << endl;
	//cerr << "ub = \n" << ub.transpose() << endl;

	const SparseMatrix<double> AT = A.transpose();

	if (options.log_function) {
		options.log_function("Problem size: " + to_string_with_separator(A.rows())
		                              + " x " + to_string_with_separator(A.cols())
		                              + " ("  + to_string_with_separator(A.nonZeros()) + " non-zeros)");
		options.log_function("   Iter         Objective     Rel. ch. x   Rel. ch. y   Infeasibility ");
		options.log_function("----------------------------------------------------------------------");
		x_prev.setConstant(std::numeric_limits<double>::quiet_NaN());
		y_prev.setConstant(std::numeric_limits<double>::quiet_NaN());
		check_convergence_and_log(0, x, &x_prev, y, y_prev, c, lb, ub, A, b, constraint_types, options);
	}

	// Compute preconditioners as in eq. (10) from [2], with alpha = 1.
	VectorXd Tvec(n);
	VectorXd Svec(m);
	Tvec.setZero();
	Svec.setZero();
	for (int k = 0; k < A.outerSize(); ++k) {
		for (SparseMatrix<double>::InnerIterator it(A, k); it; ++it) {
			auto i = it.row();
			auto j = it.col();
			auto value = abs(it.value());
			Tvec(j) += value;
			Svec(i) += value;
		}
	}

	for (ptrdiff_t j = 0; j < n; ++j) {
		Tvec(j) = 1.0 / Tvec(j);
	}

	for (ptrdiff_t i = 0; i < m; ++i) {
		Svec(i) = 1.0 / Svec(i);
	}

	size_t iteration;
	for (iteration = 1; iteration <= options.maximum_iterations; ++iteration) {
		bool should_check_convergence = options.print_interval <= 1 || iteration % options.print_interval == 1;

		x_prev = x;
		if (should_check_convergence) {
			y_prev = y;
		}

		// See eq. (18) from [2].

		x = x - Tvec.asDiagonal() * ( AT*y + c);

		for (ptrdiff_t j = 0; j < n; ++j) {
			x(j) = max(lb(j), min(ub(j), x(j)));
		}

		y = y + Svec.asDiagonal() * (A*(2 * x - x_prev) - b);

		for (size_t i = 0; i < m; ++i) {
			if (constraint_types[i] == LinearConstraintType::LessThan) {
				y(i) = max(y(i), 0.0);
			}
			else if (constraint_types[i] == LinearConstraintType::GreaterThan) {
				y(i) = min(y(i), 0.0);
			}
		}

		if (should_check_convergence) {
			if (check_convergence_and_log(iteration, x, &x_prev, y, y_prev, c, lb, ub, A, b, constraint_types, options)) {
				break;
			}
		}
	}

	check_convergence_and_log(-1, x, &x_prev, y, y_prev, c, lb, ub, A, b, constraint_types, options);

	double feasibility_error = get_feasibility_error(x, &x_prev, lb, ub, A, b, constraint_types);
	return feasibility_error < 100*options.tolerance;
}

bool EASY_IP_API first_order_admm_solve(Eigen::VectorXd* x_ptr,
                                        const Eigen::VectorXd& c,
                                        const Eigen::VectorXd& lb,
                                        const Eigen::VectorXd& ub,
                                        const Eigen::SparseMatrix<double>& A,
                                        const Eigen::VectorXd& b,
                                        const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	VectorXd& x = *x_ptr;

	const auto n = x.size();
	const auto m = A.rows();
	attest(c.size() == n);
	attest(A.cols() == n);

	VectorXd z(n);
	z.setZero();
	VectorXd u(n);
	u.setZero();

	const double rho = options.rho;

	std::vector<LinearConstraintType> constraint_types(m, LinearConstraintType::Equality);

	vector<Triplet<double>> triplets;

	for (auto j = decltype(n)(0); j < n; ++j) {
		triplets.emplace_back(j, j, rho);
	}

	for (int k = 0; k < A.outerSize(); ++k) {
		for (SparseMatrix<double>::InnerIterator it(A, k); it; ++it) {
			auto i = it.row();
			auto j = it.col();
			auto value = it.value();

			triplets.emplace_back(j    , i + n, value);
			triplets.emplace_back(n + i, j    , value);
		}
	}

	typedef SparseMatrix<double>::Index index;
	SparseMatrix<double, ColMajor> System(index(n + m), index(n + m));
	System.setFromTriplets(triplets.begin(), triplets.end());
	System.makeCompressed();

	/*cerr << "System = " << endl << System.toDense() << endl << endl;*/

	SparseLU<SparseMatrix<double, ColMajor>, COLAMDOrdering<SparseMatrix<double, ColMajor>::Index> >  solver;
	solver.analyzePattern(System);
	solver.factorize(System);
	auto computation_info = solver.info();
	if (computation_info != Success) {
		if (computation_info == NumericalIssue) {
			throw runtime_error("Eigen::NumericalIssue");
		}
		else if (computation_info == NoConvergence) {
			throw runtime_error("Eigen::NoConvergence ");
		}
		else if (computation_info == InvalidInput) {
			throw runtime_error("Eigen::InvalidInput ");
		}
		else {
			throw runtime_error("Unknown Eigen error.");
		}
	}

	VectorXd x_prev(n);
	VectorXd z_prev(m);

	VectorXd lhs(m + n);
	VectorXd xv(m + n);

	if (options.log_function) {
		options.log_function("   Iter         Objective     Rel. ch. x   Rel. ch. z   ||Ax - b||_inf");
		options.log_function("----------------------------------------------------------------------");
		x_prev.setConstant(std::numeric_limits<double>::quiet_NaN());
		z_prev.setConstant(std::numeric_limits<double>::quiet_NaN());
		check_convergence_and_log(0, x, &x_prev, z, z_prev, c, lb, ub, A, b, constraint_types, options);
	}

	size_t iteration;
	for (iteration = 1; iteration <= options.maximum_iterations; ++iteration) {
		bool should_check_convergence = options.print_interval <= 1 || iteration % options.print_interval == 1;

		if (should_check_convergence) {
			x_prev = x;
			z_prev = z;
		}

		lhs.block(0, 0, n, 1) = -c + rho*(z - u);
		lhs.block(n, 0, m, 1) = b;
		xv = solver.solve(lhs);
		x = xv.block(0, 0, n, 1);

		z = x + u;
		for (ptrdiff_t i = 0; i < n; ++i) {
			z(i) = max(lb(i), min(ub(i), z(i)));
		}

		u = u + x - z;

		if (should_check_convergence) {
			if (check_convergence_and_log(iteration, x, &x_prev, z, z_prev, c, lb, ub, A, b, constraint_types, options)) {
				// TODO
				break;
			}
		}
	}

	double feasibility_error = get_feasibility_error(x, &x_prev, lb, ub, A, b, constraint_types);
	return feasibility_error < 100 * options.tolerance;
}

void FirstOrderProblem::check_invariants() const
{
	auto n = get_cost().size();
	attest(get_var_lb().size() == n);
	attest(get_var_ub().size() == n);

	attest(get_rows().size() == get_values().size());
	attest(get_cols().size() == get_values().size());

	auto m = get_rhs_lower().size();
	attest(get_rhs_upper().size() == m);

	attest(get_integer_variables().empty());
}

void FirstOrderProblem::convert_into_equality_constrained_problem()
{
	auto m = get_rhs_lower().size();

	size_t constraints_added = 0;
	for (size_t i = 0; i < m; ++i) {
		auto& lb = get_rhs_lower()[i];
		auto& ub = get_rhs_upper()[i];
		if (lb != ub) {
			auto slack = add_variable(IP::Real);
			set_bounds(0.0, slack, std::numeric_limits<double>::infinity());
			get_rows().push_back(int(i));
			get_cols().push_back(int(get_variable_index(slack)));

			if (ub < 1e100) {
				attest(lb <= -1e100); // Cannot convert if both lb and ub exists.
				lb = ub;
				get_values().push_back(1.0);
			}
			else {
				attest(lb > -1e100);
				ub = lb;
				get_values().push_back(-1.0);
			}
			constraints_added++;
		}
	}

	check_invariants();
}

void FirstOrderProblem::get_system_matrix(Eigen::SparseMatrix<double>* A,
                                          const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	auto n = get_cost().size();
	auto m = get_rhs_lower().size();
	check_invariants();

	typedef unsigned int index;
	vector<Triplet<double, index>> sparse_indices;
	for (size_t ind = 0; ind < get_rows().size(); ++ind) {
		size_t i = get_rows()[ind];
		size_t j = get_cols()[ind];
		auto value = get_values()[ind];
		attest(i < m);
		attest(j < n);
		sparse_indices.emplace_back(index(i), index(j), value);
	}

	A->resize(static_cast<int>(m), static_cast<int>(n));
	A->setFromTriplets(sparse_indices.begin(), sparse_indices.end());

	check_invariants();
}

bool FirstOrderProblem::solve_first_order(const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	SparseMatrix<double> A;
	get_system_matrix(&A, options);

	auto n = get_cost().size();
	auto m = get_rhs_lower().size();

	Map<const VectorXd> lb(get_var_lb().data(), n);
	Map<const VectorXd> ub(get_var_ub().data(), n);
	VectorXd            b(m);
	Map<const VectorXd> c(get_cost().data(), n);
	VectorXd x(n); x.setZero();
	VectorXd y(m); y.setZero();

	std::vector<LinearConstraintType> constraint_types;
	for (size_t i = 0; i < m; ++i) {
		auto& lb = get_rhs_lower()[i];
		auto& ub = get_rhs_upper()[i];
		if (lb == ub) {
			b[i] = lb;
			constraint_types.push_back(LinearConstraintType::Equality);
		}
		else if (ub < 1e100) {
			attest(lb <= -1e100); // Cannot convert if both lb and ub exists.
			b[i] = ub;
			constraint_types.push_back(LinearConstraintType::LessThan);
		}
		else {
			attest(lb > -1e100);
			b[i] = lb;
			constraint_types.push_back(LinearConstraintType::GreaterThan);
		}
	}

	bool feasible = first_order_primal_dual_solve(&x, &y, c, lb, ub, A, b, constraint_types, options);

	get_solution().resize(n);
	for (size_t j = 0; j < n; ++j) {
		get_solution()[j] = x(j);
	}

	return feasible;
}

bool FirstOrderProblem::solve_admm(const FirstOrderOptions& options)
{
	using namespace Eigen;
	using namespace std;

	auto n = get_cost().size();
	auto m = get_rhs_lower().size();

	// First, convert all inequality constraints to
	// equality constraints.
	convert_into_equality_constrained_problem();
	size_t constraints_added = get_cost().size() - n;
	n = get_cost().size();
	if (options.log_function && constraints_added > 0) {
		ostringstream sout;
		sout << constraints_added << " inequality constraints converted.";
		options.log_function(sout.str());
	}

	SparseMatrix<double> A;
	get_system_matrix(&A, options);

	Map<const VectorXd> lb(get_var_lb().data(), n);
	Map<const VectorXd> ub(get_var_ub().data(), n);
	Map<const VectorXd> b(get_rhs_upper().data(), m);
	Map<const VectorXd> c(get_cost().data(), n);
	VectorXd x(n); x.setZero();

	bool feasible = first_order_admm_solve(&x, c, lb, ub, A, b, options);

	get_solution().resize(n);
	for (size_t j = 0; j < n; ++j) {
		get_solution()[j] = x(j);
	}

	return feasible;
}


#include <hpx/hpx_init.hpp>
#include <hpx/runtime/threads/topology.hpp>
#include <boost/format.hpp>

#include <sys/time.h>

#include "matrix_block.h"

using hpx::lcos::shared_future;
using hpx::lcos::future;
using std::vector;
using std::cout;
using std::endl;
using std::chrono::high_resolution_clock;
using time_point = std::chrono::system_clock::time_point;

int blocksize;

void print(block A) {
    for(int i = 0; i < A.height; i++) {
        for(int j = 0; j < A.width; j++) {
            cout << A[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

block rec_mult(block A, block B, block C);

block serial_mult(block A, block B, block C) {
    for (int i = 0; i < C.height; i++) {
        for (int j = 0; j < C.width; j++) {
            for (int k = 0; k < A.width;k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
    return C;
}

block add_blocks(block A, block B, block result) {
    for(int i = 0; i < A.height; i++){
        for(int j = 0; j < A.width; j++) {
            result[i][j] = A[i][j] + B[i][j];
        }
    }
    return result;
}

block calc_c11(block A, block B, block C) {
    block tempC = C.block11();//scratch space
    tempC.add_scratch();
    block A11B11 = rec_mult(A.block11(), B.block11(), C.block11());
    block A12B21 = rec_mult(A.block12(), B.block21(), tempC);
    return add_blocks(A11B11, A12B21, C.block11());
}

block calc_c12(block A, block B, block C) {
    block tempC = C.block12();
    tempC.add_scratch();
    block A11B12 = rec_mult(A.block11(), B.block12(), C.block12());
    block A12B22 = rec_mult(A.block12(), B.block22(), tempC);
    return add_blocks(A11B12, A12B22, C.block12());
}

block calc_c21(block A, block B, block C) {
    block tempC = C.block21();
    tempC.add_scratch();
    block A21B11 = rec_mult(A.block21(), B.block11(), C.block21());
    block A22B21 = rec_mult(A.block22(), B.block21(), tempC);
    return add_blocks(A21B11, A22B21, C.block21());
}

block calc_c22(block A, block B, block C) {
    block tempC = C.block22();
    tempC.add_scratch();
    block A21B12 = rec_mult(A.block21(), B.block12(), C.block22());
    block A22B22 = rec_mult(A.block22(), B.block22(), tempC);
    return add_blocks(A21B12, A22B22, C.block22());
}

block rec_mult(block A, block B, block C) {
    if(C.width <= blocksize || C.height <= blocksize ) {
        return serial_mult(A, B, C);
    }
    block C11 = calc_c11(A, B, C);
    block C12 = calc_c12(A, B, C);
    block C21 = calc_c21(A, B, C);
    block C22 = calc_c22(A, B, C);

    return C;
}

int hpx_main(int argc, char **argv) {
    blocksize = 100;
    int niter = 1, N = 1000;
    time_point time1, time2;
    srand(1);
    if(argc > 1)
        N = atoi(argv[1]);
    if(argc > 2)
        blocksize = atoi(argv[2]);
    if(argc > 3)
        niter = atoi(argv[3]);
     cout << "Recursive matrix multiplication" << endl;
     cout << "size " << N << endl;
     cout << "block size " << blocksize << endl;
     cout << "Number of iterations " << niter << endl;

    block a(N);
    block b(N);
    block c(new double[N*N], N);

    time1 = high_resolution_clock::now();
    rec_mult(a, b, c);
    time2 = high_resolution_clock::now();

     auto time = std::chrono::duration_cast<std::chrono::microseconds>(time2 - time1).count();
     cout << "time "<< time << " microseconds" << endl;
    return hpx::finalize();
}

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

    hpx::init(argc, argv);

    return 0;
}


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

#include <cmath>
#include <cfloat>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <boost/math/ccmath/frexp.hpp>
#include <boost/math/ccmath/isnan.hpp>
#include <boost/math/ccmath/isinf.hpp>

#ifdef BOOST_HAS_FLOAT128
#include <boost/multiprecision/float128.hpp>
#endif

template <typename T>
inline constexpr T base_helper(const T val)
{
    int i = 0;
    const T ans = boost::math::ccmath::frexp(val, &i);

    return ans;
}

template <typename T>
inline constexpr int exp_helper(const T val)
{
    int i = 0;
    boost::math::ccmath::frexp(val, &i);

    return i;
}

template <typename T>
constexpr void test()
{
    if constexpr (std::numeric_limits<T>::has_quiet_NaN)
    {
        static_assert(boost::math::ccmath::isnan(base_helper(std::numeric_limits<T>::quiet_NaN())), "If the arg is NaN, NaN is returned");
    }

    static_assert(!base_helper(T(0)), "If the arg is +- 0 the value is returned");
    static_assert(!base_helper(T(-0)), "If the arg is +- 0 the value is returned");
    static_assert(boost::math::ccmath::isinf(base_helper(std::numeric_limits<T>::infinity())), "If the arg is +- inf the value is returned");
    static_assert(boost::math::ccmath::isinf(base_helper(-std::numeric_limits<T>::infinity())), "If the arg is +- inf the value is returned");

    // N[125/32, 30]
    // 3.90625000000000000000000000000
    // 0.976562500000000000000000000000 * 2^2
    constexpr T test_base = base_helper(T(125.0/32));
    static_assert(test_base == T(0.9765625));
    constexpr int test_exp = exp_helper(T(125.0/32));
    static_assert(test_exp == 2);
}

#if !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION) && !defined(BOOST_MATH_USING_BUILTIN_CONSTANT_P)
int main()
{
    test<float>();
    test<double>();

    #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
    test<long double>();
    #endif

    #ifdef BOOST_HAS_FLOAT128
    test<boost::multiprecision::float128>();
    #endif

    return 0;
}
#else
int main()
{
    return 0;
}
#endif


#include <vector>
#include <list>
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <iterator>

#include <boost/cstdlib.hpp>

double distance(const std::vector<std::size_t> &lhs, const std::vector<std::size_t> &rhs, const std::vector<std::vector<double>> &distances)
{
  double sum_d = 0.0;
  std::size_t n = 0;
  for(std::size_t x : lhs) {
    for(std::size_t y : rhs) {
      //std::cerr << "distances[" << x << "][" << y << "]=" << distances.at(x).at(y) << std::endl;
      sum_d += distances.at(x).at(y);
      ++n;
    }
  }
  //std::cerr << "sum_d=" << sum_d << std::endl;
  return sum_d / n;
}

int main()
{
  std::cerr.precision(3);
  //std::cerr << std::fixed;

  std::size_t n;
  std::cin >> n;
  //std::cerr << "n=" << n << std::endl;

  std::vector<std::vector<double>> distances(n, std::vector<double>(n, 0.0));
  std::string line;
  std::getline(std::cin, line);
  std::size_t l = 0;
  while(true) {
    std::getline(std::cin, line);
    if(!std::cin) {
      break;
    }

    std::istringstream linestream(line);
    for(std::size_t i = 0; i < n; ++i) {
      double x;
      linestream >> x;
      distances.at(l).at(i) = x;
    }
    ++l;
  }

  //std::cerr << "distances=[" << std::endl;
  //for(const std::vector<double> &row : distances) {
    //std::cerr << "  [ ";
    //std::copy(row.begin(), row.end(), std::ostream_iterator<double>(std::cerr, " "));
    //std::cerr << "]" << std::endl;
  //}
  //std::cerr << "]" << std::endl;

  std::list<std::vector<std::size_t>> clusters;
  typedef std::list<std::vector<std::size_t>>::iterator clusters_iterator;
  for(std::size_t i = 0; i < n; ++i) {
    clusters.push_back(std::vector<std::size_t>(1, i));
  }

  //for(const auto &cluster: clusters) {
    //std::cerr << "cluster=[ ";
    //std::copy(cluster.begin(), cluster.end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
    //std::cerr << "]" << std::endl;
  //}

  while(clusters.size() > 1) {
    const clusters_iterator c_end = clusters.end();
    double min_d = std::numeric_limits<double>::max(); // minimum distance
    std::pair<clusters_iterator, clusters_iterator> min_c = std::make_pair(c_end, c_end); // indices of two clusters with minimum distance
    for(clusters_iterator c_i = clusters.begin(); c_i != c_end; ++c_i) {
      for(clusters_iterator c_j = c_i; c_j != c_end; ++c_j) {
        if(c_i == c_j) {
          continue;
        }
        double d = distance(*c_i, *c_j, distances);
        if(d <= min_d) {
          min_d = d;
          min_c = std::make_pair(c_i, c_j);
        }
      }
    }
    //std::cerr << "min_d=" << min_d << std::endl;

    //std::cerr << "min_c.first=[ ";
    //std::copy(min_c.first->begin(), min_c.first->end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
    //std::cerr << "]" << std::endl;
    //std::cerr << "min_c.second=[ ";
    //std::copy(min_c.second->begin(), min_c.second->end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
    //std::cerr << "]" << std::endl;

    std::copy(min_c.second->begin(), min_c.second->end(), std::back_inserter(*min_c.first));
    //std::sort(min_c.first->begin(), min_c.first->end());

    //std::cerr << "min_c.first=[ ";
    //std::copy(min_c.first->begin(), min_c.first->end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
    //std::cerr << "]" << std::endl;
    //std::cerr << "min_c.second=[ ";
    //std::copy(min_c.second->begin(), min_c.second->end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
    //std::cerr << "]" << std::endl;

    clusters.erase(min_c.second);

    //for(const auto &cluster: clusters) {
      //std::cerr << "cluster=[ ";
      //std::copy(cluster.begin(), cluster.end(), std::ostream_iterator<std::size_t>(std::cerr, " "));
      //std::cerr << "]" << std::endl;
    //}
    for(std::size_t i: *min_c.first) {
      std::cout << (i + 1) << " ";
    }
    std::cout << std::endl;
    //std::cout << std::endl;
  }

  return boost::exit_success;
}

// vim: set ts=2 sw=2 et:


#pragma once

#include "perceive/foundation.hpp"
#include "perceive/utils/sdbm-hash.hpp"
#include <Eigen/Core>
#include <cmath>

namespace perceive
{
// --------------------------------------------------------------------- Vector2
#pragma pack(push, 1)
template<typename T> class Vector2T
{
 public:
   using value_type = T;

   T x, y;

   Vector2T()
       : x(T(0.0))
       , y(T(0.0))
   {}
   Vector2T(T x_, T y_)
       : x(x_)
       , y(y_)
   {}
   Vector2T(const float p[2])
   {
      x = p[0];
      y = p[1];
   }
   Vector2T(const double p[2])
   {
      x = p[0];
      y = p[1];
   }

   Vector2T& operator=(const Vector2T& v) = default;

   Vector2T& operator=(const Eigen::Vector2f& v)
   {
      for(int i = 0; i < 2; ++i) this->operator[](i) = v(i);
      return *this;
   }

   static Vector2T nan() { return Vector2T(T(NAN), T(NAN)); }
   static Vector2T range()
   {
      auto mmax = std::numeric_limits<T>::max();
      auto mmin = std::numeric_limits<T>::lowest();
      return Vector2T(mmax, mmin);
   }

   void union_value(T v)
   {
      if(v < this->x) this->x = v;
      if(v > this->y) this->y = v;
   }

   unsigned size() const { return 2; }

   Vector2T& normalise(T epsilon = 1e-9)
   {
      // Don't normalize if we don't have to
      T mag2 = x * x + y * y;
      if(std::fabs(mag2 - T(1.0)) > epsilon) {
         T mag_inv = T(1.0) / std::sqrt(mag2);
         x *= mag_inv;
         y *= mag_inv;
      }
      return *this;
   }
   Vector2T normalised(T epsilon = T(1e-9)) const
   {
      Vector2T res = *this;
      res.normalise(epsilon);
      return res;
   }
   Vector2T& normalize(T epsilon = T(1e-9)) { return normalise(epsilon); }
   Vector2T normalized(T epsilon = T(1e-9)) const
   {
      return normalised(epsilon);
   }
   T quadrance() const { return x * x + y * y; }
   T norm() const { return T(std::sqrt(quadrance())); }
   T dot(const Vector2T& rhs) const { return x * rhs.x + y * rhs.y; }
   T perp_dot(const Vector2T& rhs) const { return x * rhs.y - y * rhs.x; }
   T quadrance(const Vector2T& rhs) const
   {
      return (x - rhs.x) * (x - rhs.x) + (y - rhs.y) * (y - rhs.y);
   }
   T distance(const Vector2T& rhs) const { return (*this - rhs).norm(); }

   // As polar co-ordinates
   T& mag() { return x; }
   const T& mag() const { return x; }
   T& theta() { return y; }
   const T& theta() const { return y; }

   // As format
   T& width() { return x; }
   const T& width() const { return x; }
   T& height() { return y; }
   const T& height() const { return y; }

   Vector2T& set_to(const T& a, const T& b)
   {
      x = a;
      y = b;
      return *this;
   }
   Vector2T& set_to(T a[2])
   {
      set_to(a[0], a[1]);
      return *this;
   }

   T* copy_to(T a[2]) const
   {
      a[0] = x;
      a[1] = y;
      return a;
   }

   T* ptr()
   {
#ifdef DEBUG_BUILD
      assert(&x == reinterpret_cast<const T*>(this) + 0);
      assert(&y == reinterpret_cast<const T*>(this) + 1);
#endif
      return &x;
   }
   const T* ptr() const { return const_cast<Vector2T<T>*>(this)->ptr(); }

   T& operator[](int idx)
   {
#ifdef DEBUG_BUILD
      assert(idx >= 0 && idx < 2);
#endif
      return ptr()[idx];
   }
   const T& operator[](int idx) const
   {
#ifdef DEBUG_BUILD
      assert(idx >= 0 && idx < 2);
#endif
      return ptr()[idx];
   }

   T& operator()(int idx)
   {
#ifdef DEBUG_BUILD
      assert(idx >= 0 && idx < 2);
#endif
      return ptr()[idx];
   }

   const T& operator()(int idx) const
   {
#ifdef DEBUG_BUILD
      assert(idx >= 0 && idx < 2);
#endif
      return ptr()[idx];
   }

   Vector2T flip_x() const { return Vector2T(-x, y); }
   Vector2T flip_y() const { return Vector2T(x, -y); }
   Vector2T clockwise_90() const { return Vector2T(y, -x); }
   Vector2T counter_clockwise_90() const { return Vector2T(-y, x); }
   Vector2T rotate(T theta) const
   {
      auto sin_t = std::sin(theta);
      auto cos_t = std::cos(theta);
      return Vector2T<T>(x * cos_t - y * sin_t, x * sin_t + y * cos_t);
   }

   Vector2T round() const { return Vector2T(std::round(x), std::round(y)); }

   Vector2T& operator*=(T scalar)
   {
      x *= scalar;
      y *= scalar;
      return *this;
   }

   Vector2T& operator/=(T scalar)
   {
      x /= scalar;
      y /= scalar;
      return *this;
   }
   Vector2T operator*(T scalar) const
   {
      Vector2T res(*this);
      res *= scalar;
      return res;
   }

   Vector2T operator/(T scalar) const
   {
      Vector2T res(*this);
      res /= scalar;
      return res;
   }

   Vector2T& operator+=(const Vector2T& rhs)
   {
      x += rhs.x;
      y += rhs.y;
      return *this;
   }

   Vector2T& operator-=(const Vector2T& rhs)
   {
      x -= rhs.x;
      y -= rhs.y;
      return *this;
   }

   Vector2T operator+(const Vector2T& rhs) const
   {
      Vector2T res(*this);
      res += rhs;
      return res;
   }
   Vector2T operator-(const Vector2T& rhs) const
   {
      Vector2T res(*this);
      res -= rhs;
      return res;
   }

   Vector2T operator-() const { return Vector2T<T>(-x, -y); }

   bool operator==(const Vector2T& rhs) const
   {
      return x == rhs.x && y == rhs.y;
   }
   bool operator!=(const Vector2T& rhs) const { return !(*this == rhs); }

   bool operator<(const Vector2T& rhs) const
   {
      return x == rhs.x ? y < rhs.y : x < rhs.x;
   }
   bool operator<=(const Vector2T& rhs) const
   {
      return x == rhs.x ? y <= rhs.y : x <= rhs.x;
   }
   bool operator>(const Vector2T& rhs) const { return !(*this <= rhs); }
   bool operator>=(const Vector2T& rhs) const { return !(*this < rhs); }

   bool has_nan() const { return x != x || y != y; }
   bool is_nan() const { return std::isnan(x) || std::isnan(y); }
   bool is_finite() const { return std::isfinite(x) && std::isfinite(y); }
   bool is_unit_vector(T epsilon = 1e-9) const
   {
      return is_finite() && fabs(quadrance() - 1.0) < epsilon;
   }

   inline friend bool isfinite(const Vector2T& o) noexcept
   {
      return o.is_finite();
   }

   std::string to_string(const char* fmt = nullptr) const
   {
      if(fmt == nullptr) {
         if constexpr(std::is_floating_point<T>::value) {
            fmt = "[{:7.5f}, {:7.5f}]";
         } else {
            fmt = "[{}, {}]";
         }
      }
      return format(fmt, x, y);
   }
   std::string to_str() const { return format("[{}, {}]", x, y); }

   void print(const char* msg = NULL, bool newline = true) const
   {
      printf("%s%s%s%s",
             msg,
             (msg == NULL ? "" : " "),
             to_string().c_str(),
             (newline ? "\n" : ""));
      fflush(stdout);
   }

   size_t hash() const { return sdbm_hash(ptr(), sizeof(T) * size()); }

   friend std::string str(const Vector2T<T>& o) noexcept
   {
      return o.to_string();
   }
};
#pragma pack(pop)

// Scalar multiplication
template<typename T> Vector2T<T> operator*(float a, const Vector2T<T>& v)
{
   return v * T(a);
}
template<typename T> Vector2T<T> operator/(float a, const Vector2T<T>& v)
{
   return v / T(a);
}
template<typename T> Vector2T<T> operator*(double a, const Vector2T<T>& v)
{
   return v * T(a);
}
template<typename T> Vector2T<T> operator/(double a, const Vector2T<T>& v)
{
   return v / T(a);
}

// String shim
template<typename T> std::string str(const Vector2T<T>& v)
{
   return v.to_string();
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const Vector2T<T>& v)
{
   out << v.to_string();
   return out;
}

template<typename T> inline T perp_dot(T x1, T y1, T x2, T y2)
{
   return x1 * y2 - x2 * y1;
}

} // namespace perceive


//
// Copyright (c) 2015-2016,2018 CNRS
//

/* --- Unitary test symmetric.cpp This code tests and compares two ways of
 * expressing symmetric matrices. In addition to the unitary validation (test
 * of the basic operations), the code is validating the computation
 * performances of each methods.
 *
 * The three methods are:
 * - Eigen SelfAdjoint (a mask atop of a classical dense matrix) ==> the least efficient.
 * - Pinocchio rewritting of Metapod code with LTI factor as well and minor improvement.
 *
 * IMPORTANT: the following timings seems outdated.
 * Expected time scores on a I7 2.1GHz:
 * - Eigen: 2.5us
 * - Pinocchio: 6us
 */

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/spatial/skew.hpp"
#include "pinocchio/utils/timer.hpp"

#include <boost/random.hpp>
# include <eigen3/Eigen/Geometry>

#include "pinocchio/spatial/symmetric3.hpp"

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

# include <eigen3/Eigen/StdVector>
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Matrix3d)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(pinocchio::Symmetric3)

void timeSym3(const pinocchio::Symmetric3 & S,
        const pinocchio::Symmetric3::Matrix3 & R,
        pinocchio::Symmetric3 & res)
{
  res = S.rotate(R);
}

#ifdef WITH_METAPOD

#include <metapod/tools/spatial/lti.hh>
#include <metapod/tools/spatial/rm-general.hh>

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(metapod::Spatial::ltI<double>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(metapod::Spatial::RotationMatrixTpl<double>)

void timeLTI(const metapod::Spatial::ltI<double>& S,
       const metapod::Spatial::RotationMatrixTpl<double>& R,
       metapod::Spatial::ltI<double> & res)
{
  res = R.rotTSymmetricMatrix(S);
}

#endif

void timeSelfAdj( const Eigen::Matrix3d & A,
      const Eigen::Matrix3d & Sdense,
      Eigen::Matrix3d & ASA )
{
  typedef Eigen::SelfAdjointView<const Eigen::Matrix3d,Eigen::Upper> Sym3;
  Sym3 S(Sdense);
  ASA.triangularView<Eigen::Upper>()
    = A * S * A.transpose();
}

BOOST_AUTO_TEST_SUITE ( BOOST_TEST_MODULE )

/* --- PINOCCHIO ------------------------------------------------------------ */
/* --- PINOCCHIO ------------------------------------------------------------ */
/* --- PINOCCHIO ------------------------------------------------------------ */
BOOST_AUTO_TEST_CASE ( test_pinocchio_Sym3 )
{
  using namespace pinocchio;
  typedef Symmetric3::Matrix3 Matrix3;
  typedef Symmetric3::Vector3 Vector3;

  {
    // op(Matrix3)
    {
      Matrix3 M = Matrix3::Random(); M = M*M.transpose();
      Symmetric3 S(M);
      BOOST_CHECK(S.matrix().isApprox(M, 1e-12));
    }

    // S += S
    {
      Symmetric3
      S = Symmetric3::Random(),
      S2 = Symmetric3::Random();
      Symmetric3 Scopy = S;
      S+=S2;
      BOOST_CHECK(S.matrix().isApprox(S2.matrix()+Scopy.matrix(), 1e-12));
    }

    // S + M
    {
      Symmetric3 S = Symmetric3::Random();
      Matrix3 M = Matrix3::Random(); M = M*M.transpose();

      Symmetric3 S2 = S + M;
      BOOST_CHECK(S2.matrix().isApprox(S.matrix()+M, 1e-12));

      S2 = S - M;
      BOOST_CHECK(S2.matrix().isApprox(S.matrix()-M, 1e-12));
    }

    // S*v
    {
      Symmetric3 S = Symmetric3::Random();
      Vector3 v = Vector3::Random();
      Vector3 Sv = S*v;
      BOOST_CHECK(Sv.isApprox(S.matrix()*v, 1e-12));
    }

    // Random
    for(int i=0;i<100;++i )
    {
      Matrix3 M = Matrix3::Random(); M = M*M.transpose();
      Symmetric3 S = Symmetric3::RandomPositive();
      Vector3 v = Vector3::Random();
      BOOST_CHECK_GT( (v.transpose()*(S*v))[0] , 0);
    }

    // Identity
    {
      BOOST_CHECK(Symmetric3::Identity().matrix().isApprox(Matrix3::Identity(), 1e-12));
    }

    // Skew2
    {
      Vector3 v = Vector3::Random();
      Symmetric3 vxvx = Symmetric3::SkewSquare(v);

      Vector3 p = Vector3::UnitX();
      BOOST_CHECK((vxvx*p).isApprox(v.cross(v.cross(p)), 1e-12));

      p = Vector3::UnitY();
      BOOST_CHECK((vxvx*p).isApprox(v.cross(v.cross(p)), 1e-12));

      p = Vector3::UnitZ();
      BOOST_CHECK((vxvx*p).isApprox(v.cross(v.cross(p)), 1e-12));

      Matrix3 vx = skew(v);
      Matrix3 vxvx2 = (vx*vx).eval();
      BOOST_CHECK(vxvx.matrix().isApprox(vxvx2, 1e-12));

      Symmetric3 S = Symmetric3::RandomPositive();
      BOOST_CHECK((S-Symmetric3::SkewSquare(v)).matrix()
                                        .isApprox(S.matrix()-vxvx2, 1e-12));

      double m = Eigen::internal::random<double>()+1;
      BOOST_CHECK((S-m*Symmetric3::SkewSquare(v)).matrix()
                                        .isApprox(S.matrix()-m*vxvx2, 1e-12));

      Symmetric3 S2 = S;
      S -= Symmetric3::SkewSquare(v);
      BOOST_CHECK(S.matrix().isApprox(S2.matrix()-vxvx2, 1e-12));

      S = S2; S -= m*Symmetric3::SkewSquare(v);
      BOOST_CHECK(S.matrix().isApprox(S2.matrix()-m*vxvx2, 1e-12));

    }

    // (i,j)
    {
      Matrix3 M = Matrix3::Random(); M = M*M.transpose();
      Symmetric3 S(M);
      for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
          BOOST_CHECK_SMALL(S(i,j) - M(i,j), Eigen::NumTraits<double>::dummy_precision());
      }
    }

    // SRS
    {
      Symmetric3 S = Symmetric3::RandomPositive();
      Matrix3 R = (Eigen::Quaterniond(Eigen::Matrix<double,4,1>::Random())).normalized().matrix();

      Symmetric3 RSRt = S.rotate(R);
      BOOST_CHECK(RSRt.matrix().isApprox(R*S.matrix()*R.transpose(), 1e-12));

      Symmetric3 RtSR = S.rotate(R.transpose());
      BOOST_CHECK(RtSR.matrix().isApprox(R.transpose()*S.matrix()*R, 1e-12));
    }

  // Test operator vtiv
  {
    Symmetric3 S = Symmetric3::RandomPositive();
    Vector3 v = Vector3::Random();
    double kinetic_ref = v.transpose() * S.matrix() * v;
    double kinetic = S.vtiv(v);
    BOOST_CHECK_SMALL(kinetic_ref - kinetic, 1e-12);
  }

  // Test v x S3
  {
    Symmetric3 S = Symmetric3::RandomPositive();
    Vector3 v = Vector3::Random();
    Matrix3 Vcross = skew(v);
    Matrix3 M_ref(Vcross * S.matrix());

    Matrix3 M_res;
    Symmetric3::vxs(v,S,M_res);
    BOOST_CHECK(M_res.isApprox(M_ref));

    BOOST_CHECK(S.vxs(v).isApprox(M_ref));
  }

  // Test S3 vx
  {
    Symmetric3 S = Symmetric3::RandomPositive();
    Vector3 v = Vector3::Random();
    Matrix3 Vcross = skew(v);
    Matrix3 M_ref(S.matrix() * Vcross);

    Matrix3 M_res;
    Symmetric3::svx(v,S,M_res);
    BOOST_CHECK(M_res.isApprox(M_ref));

    BOOST_CHECK(S.svx(v).isApprox(M_ref));
  }

  // Test isZero
  {
    Symmetric3 S_not_zero = Symmetric3::Identity();
    BOOST_CHECK(!S_not_zero.isZero());

    Symmetric3 S_zero = Symmetric3::Zero();
    BOOST_CHECK(S_zero.isZero());
  }

  // Test isApprox
  {
    Symmetric3 S1 = Symmetric3::RandomPositive();
    Symmetric3 S2 = S1;

    BOOST_CHECK(S1.isApprox(S2));

    Symmetric3 S3 = S1;
    S3 += S3;
    BOOST_CHECK(!S1.isApprox(S3));
  }

    // Time test
    {
      const size_t NBT = 100000;
      Symmetric3 S = Symmetric3::RandomPositive();

      std::vector<Symmetric3> Sres (NBT);
      std::vector<Matrix3> Rs (NBT);
      for(size_t i=0;i<NBT;++i)
        Rs[i] = (Eigen::Quaterniond(Eigen::Matrix<double,4,1>::Random())).normalized().matrix();

      std::cout << "Pinocchio: ";
      PinocchioTicToc timer(PinocchioTicToc::US); timer.tic();
      SMOOTH(NBT)
      {
        timeSym3(S,Rs[_smooth],Sres[_smooth]);
      }
      timer.toc(std::cout,NBT);
    }
}

/* --- EIGEN SYMMETRIC ------------------------------------------------------ */
/* --- EIGEN SYMMETRIC ------------------------------------------------------ */
/* --- EIGEN SYMMETRIC ------------------------------------------------------ */

BOOST_AUTO_TEST_CASE ( test_eigen_SelfAdj )
{
  using namespace pinocchio;
  typedef Eigen::Matrix3d Matrix3;
  typedef Eigen::SelfAdjointView<Matrix3,Eigen::Upper> Sym3;

  Matrix3 M = Matrix3::Random();
  Sym3 S(M);
  {
    Matrix3 Scp = S;
    BOOST_CHECK((Scp-Scp.transpose()).isApprox(Matrix3::Zero(), 1e-16));
  }

  Matrix3 M2 = Matrix3::Random();
  M.triangularView<Eigen::Upper>() = M2;

  Matrix3 A = Matrix3::Random(), ASA1, ASA2;
  ASA1.triangularView<Eigen::Upper>() = A * S * A.transpose();
  timeSelfAdj(A,M,ASA2);

  {
    Matrix3 Masa1 = ASA1.selfadjointView<Eigen::Upper>();
    Matrix3 Masa2 = ASA2.selfadjointView<Eigen::Upper>();
    BOOST_CHECK(Masa1.isApprox(Masa2, 1e-16));
  }

  const size_t NBT = 100000;
  std::vector<Eigen::Matrix3d> Sres (NBT);
  std::vector<Eigen::Matrix3d> Rs (NBT);
  for(size_t i=0;i<NBT;++i)
    Rs[i] = (Eigen::Quaterniond(Eigen::Matrix<double,4,1>::Random())).normalized().matrix();

  std::cout << "Eigen: ";
  PinocchioTicToc timer(PinocchioTicToc::US); timer.tic();
  SMOOTH(NBT)
  {
    timeSelfAdj(Rs[_smooth],M,Sres[_smooth]);
  }
  timer.toc(std::cout,NBT);
}

BOOST_AUTO_TEST_CASE(comparison)
{
  using namespace pinocchio;
  Symmetric3 sym1(Symmetric3::Random());

  Symmetric3 sym2(sym1);
  sym2.data() *= 2;

  BOOST_CHECK(sym2 != sym1);
  BOOST_CHECK(sym1 == sym1);
}

BOOST_AUTO_TEST_CASE(cast)
{
  using namespace pinocchio;
  Symmetric3 sym(Symmetric3::Random());

  BOOST_CHECK(sym.cast<double>() == sym);
  BOOST_CHECK(sym.cast<long double>().cast<double>() == sym);

}
BOOST_AUTO_TEST_SUITE_END ()


//============================================================================
// Name        : autodiff.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <sstream>
#include <numeric>
#include <boost/foreach.hpp>
#include "autodiff.h"
#include "Stack.h"
#include "Tape.h"
#include "BinaryOPNode.h"
#include "UaryOPNode.h"

using namespace std;

namespace AutoDiff
{

#if FORWARD_ENABLED

unsigned int num_var = 0;

void hess_forward(Node* root, unsigned int nvar, double** hess_mat)
{
	assert(nvar == num_var);
	unsigned int len = (nvar+3)*nvar/2;
	root->hess_forward(len,hess_mat);
}

#endif

PNode* create_param_node(double value){
	return new PNode(value);
}
VNode* create_var_node(double v)
{
	return new VNode(v);
}
OPNode* create_binary_op_node(OPCODE code, Node* left, Node* right)
{
	return BinaryOPNode::createBinaryOpNode(code,left,right);
}
OPNode* create_uary_op_node(OPCODE code, Node* left)
{
	return UaryOPNode::createUnaryOpNode(code,left);
}
double eval_function(Node* root)
{
	assert(SD->size()==0);
	assert(SV->size()==0);
	root->eval_function();
	assert(SV->size()==1);
	double val = SV->pop_back();
	return val;
}

double grad_reverse(Node* root,vector<Node*>& vnodes, vector<double>& grad)
{
	grad.clear();
	BOOST_FOREACH(Node* node, vnodes)
	{
		assert(node->getType()==VNode_Type);
		static_cast<VNode*>(node)->adj = NaN_Double;
	}

	assert(SD->size()==0);
	root->grad_reverse_0();
	assert(SV->size()==1);
	root->grad_reverse_1_init_adj();
	root->grad_reverse_1();
	assert(SD->size()==0);
	double val = SV->pop_back();
	assert(SV->size()==0);
	//int i=0;
	BOOST_FOREACH(Node* node, vnodes)
	{
		assert(node->getType()==VNode_Type);
		grad.push_back(static_cast<VNode*>(node)->adj);
		static_cast<VNode*>(node)->adj = NaN_Double;
	}
	assert(grad.size()==vnodes.size());
	//all nodes are VNode and adj == NaN_Double -- this reset adj for this expression tree by root
	return val;
}

double grad_reverse(Node* root, vector<Node*>& vnodes, col_compress_matrix_row& rgrad)
{
	BOOST_FOREACH(Node* node, vnodes)
	{
		assert(node->getType()==VNode_Type);
		static_cast<VNode*>(node)->adj = NaN_Double;
	}
	assert(SD->size()==0);
	root->grad_reverse_0();
	assert(SV->size()==1);
	root->grad_reverse_1_init_adj();
	root->grad_reverse_1();
	assert(SD->size()==0);
	double val = SV->pop_back();
	assert(SV->size()==0);
	unsigned int i =0;
	BOOST_FOREACH(Node* node, vnodes)
	{
		assert((node)->getType()==VNode_Type);
		double diff = static_cast<VNode*>(node)->adj;
		if(!isnan(diff)){
			rgrad(i) = diff;
			static_cast<VNode*>(node)->adj = NaN_Double;
		}
		i++;
	}
	//all nodes are VNode and adj == NaN_Double -- this reset adj for this expression tree by root
	assert(i==vnodes.size());
	return val;
}

double hess_reverse(Node* root,vector<Node*>& vnodes,vector<double>& dhess)
{
	TT->clear();
	II->clear();
	assert(TT->empty());
	assert(II->empty());
	assert(TT->index==0);
	assert(II->index==0);
	dhess.clear();

//	for(vector<Node*>::iterator it=nodes.begin();it!=nodes.end();it++)
//	{
//		assert((*it)->getType()==VNode_Type);
//		(*it)->index = 0;
//	} //this work complete in hess-reverse_0_init_index

	assert(root->n_in_arcs == 0);
	root->hess_reverse_0_init_n_in_arcs();
	assert(root->n_in_arcs == 1);
	root->hess_reverse_0();
	double val = NaN_Double;
	root->hess_reverse_get_x(TT->index,val);
//	cout<<TT->toString();
//	cout<<endl;
//	cout<<II->toString();
//	cout<<"======================================= hess_reverse_0"<<endl;
	root->hess_reverse_1_init_x_bar(TT->index);
	assert(root->n_in_arcs == 1);
	root->hess_reverse_1(TT->index);
	assert(root->n_in_arcs == 0);
	assert(II->index==0);
//	cout<<TT->toString();
//	cout<<endl;
//	cout<<II->toString();
//	cout<<"======================================= hess_reverse_1"<<endl;

	for(vector<Node*>::iterator it=vnodes.begin();it!=vnodes.end();it++)
	{
		assert((*it)->getType()==VNode_Type);
		dhess.push_back(TT->get((*it)->index-1));
	}

	TT->clear();
	II->clear();
	root->hess_reverse_1_clear_index();
	return val;
}

double hess_reverse(Node* root,vector<Node*>& vnodes,col_compress_matrix_col& chess)
{
	TT->clear();
	II->clear();
	assert(TT->empty());
	assert(II->empty());
	assert(TT->index==0);
	assert(II->index==0);

//	for(vector<Node*>::iterator it=nodes.begin();it!=nodes.end();it++)
//	{
//		assert((*it)->getType()==VNode_Type);
//		(*it)->index = 0;
//	} //this work complete in hess-reverse_0_init_index

	assert(root->n_in_arcs == 0);
	//reset node index and n_in_arcs - for the Tape location
	root->hess_reverse_0_init_n_in_arcs();
	assert(root->n_in_arcs == 1);
	root->hess_reverse_0();
	double val = NaN_Double;
	root->hess_reverse_get_x(TT->index,val);
//	cout<<TT->toString();
//	cout<<endl;
//	cout<<II->toString();
//	cout<<"======================================= hess_reverse_0"<<endl;
	root->hess_reverse_1_init_x_bar(TT->index);
	assert(root->n_in_arcs == 1);
	root->hess_reverse_1(TT->index);
	assert(root->n_in_arcs == 0);
	assert(II->index==0);
//	cout<<TT->toString();
//	cout<<endl;
//	cout<<II->toString();
//	cout<<"======================================= hess_reverse_1"<<endl;

	unsigned int i =0;
	BOOST_FOREACH(Node* node, vnodes)
	{
		assert(node->getType() == VNode_Type);
		//node->index = 0 means this VNode is not in the tree
		if(node->index!=0)
		{
			double hess = TT->get(node->index -1);
			if(!isnan(hess))
			{
				chess(i) = chess(i) + hess;
			}
		}
		i++;
	}
	assert(i==vnodes.size());
	root->hess_reverse_1_clear_index();
	TT->clear();
	II->clear();
	return val;
}

unsigned int nzGrad(Node* root)
{
	unsigned int nzgrad,total = 0;
	boost::unordered_set<Node*> nodes;
	root->collect_vnodes(nodes,total);
	nzgrad = nodes.size();
	return nzgrad;
}

/*
 * number of non-zero gradient in constraint tree root that also belong to vSet
 */
unsigned int nzGrad(Node* root, boost::unordered_set<Node*>& vSet)
{
	unsigned int nzgrad=0, total=0;
	boost::unordered_set<Node*> vnodes;
	root->collect_vnodes(vnodes,total);
	//cout<<"nzGrad - vnodes size["<<vnodes.size()<<"] -- total node["<<total<<"]"<<endl;
	for(boost::unordered_set<Node*>::iterator it=vnodes.begin();it!=vnodes.end();it++)
	{
		Node* n = *it;
		if(vSet.find(n) != vSet.end())
		{
			nzgrad++;
		}
	}
	return nzgrad;
}

void nonlinearEdges(Node* root, EdgeSet& edges)
{
	root->nonlinearEdges(edges);
}

unsigned int nzHess(EdgeSet& eSet,boost::unordered_set<Node*>& set1, boost::unordered_set<Node*>& set2)
{
	list<Edge>::iterator i = eSet.edges.begin();
	for(;i!=eSet.edges.end();)
	{
		Edge e =*i;
		Node* a = e.a;
		Node* b = e.b;
		if((set1.find(a)!=set1.end() && set2.find(b)!=set2.end())
			||
			(set1.find(b)!=set1.end() && set2.find(a)!=set2.end()))
		{
			//e is connected between set1 and set2
			i++;
		}
		else
		{
			i = eSet.edges.erase(i);
		}
	}
	unsigned int diag=eSet.numSelfEdges();
	unsigned int nzHess = (eSet.size())*2 - diag;
	return nzHess;
}

unsigned int nzHess(EdgeSet& edges)
{
	unsigned int diag=edges.numSelfEdges();
	unsigned int nzHess = (edges.size())*2 - diag;
	return nzHess;
}

unsigned int numTotalNodes(Node* root)
{
	unsigned int total = 0;
	boost::unordered_set<Node*> nodes;
	root->collect_vnodes(nodes,total);
	return total;
}

string tree_expr(Node* root)
{
	ostringstream oss;
	oss<<"visiting tree == "<<endl;
	int level = 0;
	root->inorder_visit(level,oss);
	return oss.str();
}

void print_tree(Node* root)
{
	cout<<"visiting tree == "<<endl;
	int level = 0;
	root->inorder_visit(level,cout);
}

void autodiff_setup()
{
	Stack::diff = new Stack();
	Stack::vals = new Stack();
	Tape<unsigned int>::indexTape = new Tape<unsigned int>();
	Tape<double>::valueTape = new Tape<double>();
}

void autodiff_cleanup()
{
	delete Stack::diff;
	delete Stack::vals;
	delete Tape<unsigned int>::indexTape;
	delete Tape<double>::valueTape;
}

} //AutoDiff namespace end


/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology nor the names of its contributors
 *        may be used to endorse or promote products derived from this software without specific
 *        prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 *    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      100910    J. Melman         First creation of code.
 *      110111    J. Melman         Adapted to the offical Tudat standards.
 *      110124    J. Melman         Further adapted to the offical Tudat standards.
 *      110201    J. Melman         Made the tests for obliquity and astronomical unit more
 *                                  accurate.
 *      120127    D. Dirkx          Moved to Tudat core.
 *      120127    K. Kumar          Transferred unit tests over to Boost unit test framework.
 *      120128    K. Kumar          Changed BOOST_CHECK to BOOST_CHECK_CLOSE_FRACTION for unit test
 *                                  comparisons.
 *      121205    K. Kumar          Updated license in file header.
 *      150417    D. Dirkx          Added tests for floating ints.
 *
 *    References
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <iostream>
#include <iomanip>
#include <limits>

#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include "Tudat/Mathematics/BasicMathematics/mathematicalConstants.h"

namespace tudat
{
namespace unit_tests
{

// Define Boost test suite.
BOOST_AUTO_TEST_SUITE( test_mathematical_constants )

//! Check correct pi using PI = circumference / diameter:
BOOST_AUTO_TEST_CASE( test_PI )
{
    const double radius = 5.0;

    // Circumference circle with radius 5, 32 digits precision, see
    // http://www.wolframalpha.com/input/?i=Circumference+of+a+circle+with+radius+5
    // http://www.wolframalpha.com/input/?i=N[10*PI,66]
    double circumference = 31.4159265358979323846264338327950288419716939937510582097494459230;
    BOOST_CHECK_CLOSE(  mathematical_constants::PI,
                        circumference / ( 2.0 * radius ) ,
                        std::numeric_limits< double >::epsilon( ) );
}

//! Check correct E using E Wolfram alpha as reference
BOOST_AUTO_TEST_CASE( test_E )
{
    // Numerical value from:
    // http://www.wolframalpha.com/input/?i=e+72+digits
    BOOST_CHECK_CLOSE( mathematical_constants::E,
        2.71828182845904523536028747135266249775724709369995957496696762772407663,
        std::numeric_limits< double >::epsilon( ) );
}

//! Check correct GOLDEN_RATIO using GOLDEN_RATIO Wolfram alpha as reference
BOOST_AUTO_TEST_CASE( test_GOLDEN_RATIO )
{
    // Numerical value from:
    // http://www.wolframalpha.com/input/?i=golden+ratio+72+digits
    BOOST_CHECK_CLOSE(  mathematical_constants::GOLDEN_RATIO,
        1.618033988749894848204586834365638117720309179805762862135448622705260463,
        std::numeric_limits< double >::epsilon( ) );
}

//! Check correct NAN using boost Floating Point Classification (fpclassify)
BOOST_AUTO_TEST_CASE( test_NAN )
{
    // Numerical value from:
    // http://www.wolframalpha.com/input/?i=golden+ratio+72+digits
    BOOST_CHECK( boost::math::isnan( TUDAT_NAN ) );
}

BOOST_AUTO_TEST_CASE( test_TemplatedValues )
{
    double one = 1.0;
    long double longOne = 1.00000000000000000000L;

    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingInteger< double >( 1 ),
                        one, std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingInteger< long double >( 1 ),
                        longOne, std::numeric_limits< long  double >::epsilon( ) );

    BOOST_CHECK_SMALL(  mathematical_constants::getFloatingInteger< double >( 0 ),
                        std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_SMALL(  mathematical_constants::getFloatingInteger< long double >( 0 ),
                        std::numeric_limits< long  double >::epsilon( ) );

    double two = 2.0;
    long double longTwo = 2.00000000000000000000L;

    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingInteger< double >( 2 ),
                        two, std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingInteger< long double >( 2 ),
                        longTwo, std::numeric_limits< long  double >::epsilon( ) );

    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingFraction< double >( 1, 2 ),
                        mathematical_constants::getFloatingInteger< double >( 1 ) /
                        mathematical_constants::getFloatingInteger< double >( 2 ),
                        std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_CLOSE(  mathematical_constants::getFloatingFraction< long double >( 1, 2 ),
                        mathematical_constants::getFloatingInteger< long double >( 1 ) /
                        mathematical_constants::getFloatingInteger< long double >( 2 )
                        , std::numeric_limits< long double >::epsilon( ) );

    BOOST_CHECK_CLOSE(  mathematical_constants::getPi< double >( ),
                        mathematical_constants::PI, std::numeric_limits< double >::epsilon( ) );
    BOOST_CHECK_CLOSE(  mathematical_constants::getPi< long double >( ),
                        mathematical_constants::LONG_PI, std::numeric_limits< long  double >::epsilon( ) );

}

// Close Boost test suite.
BOOST_AUTO_TEST_SUITE_END( ) // End test_mathematical_constants

} // namespace unit_tests
} // namespace tudat


/*
   Copyright (C) 2015-2021 by Synge Todo <wistaria@phys.s.u-tokyo.ac.jp>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

// Critical temperature of hexagonal lattice Ising model

#include <iomanip>
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include "ising/mp_wrapper.hpp"
#include "options.hpp"
#include "hexagonal.hpp"

template<class T>
void calc(const std::string& Ja_in, const std::string& Jb_in, const std::string& Jc_in) {
  typedef T real_t;
  real_t Ja = convert<real_t>(Ja_in);
  real_t Jb = convert<real_t>(Jb_in);
  real_t Jc = convert<real_t>(Jc_in);
  auto tc = ising::tc::hexagonal(Ja, Jb, Jc);
  std::cout << std::scientific << std::setprecision(std::numeric_limits<real_t>::digits10)
            << "# lattice: hexagonal\n"
            << "# precision: " << std::numeric_limits<real_t>::digits10 << std::endl
            << "# Ja Jb Jc Tc 1/Tc" << std::endl
            << Ja << ' ' << Jb << ' ' << Jc << ' ' << tc << ' ' << (1 / tc) << std::endl;
}

int main(int argc, char **argv) {
  namespace mp = boost::multiprecision;
  options3 opt(argc, argv);
  if (!opt.valid) return 127;
  if (opt.prec <= std::numeric_limits<float>::digits10) {
    calc<float>(opt.Ja, opt.Jb, opt.Jc);
  } else if (opt.prec <= std::numeric_limits<double>::digits10) {
    calc<double>(opt.Ja, opt.Jb, opt.Jc);
  } else if (opt.prec <= std::numeric_limits<mp_wrapper<mp::cpp_dec_float_50>>::digits10) {
    calc<mp_wrapper<mp::cpp_dec_float_50>>(opt.Ja, opt.Jb, opt.Jc);
  } else if (opt.prec <= std::numeric_limits<mp_wrapper<mp::cpp_dec_float_100>>::digits10) {
    calc<mp_wrapper<mp::cpp_dec_float_100>>(opt.Ja, opt.Jb, opt.Jc);
  } else {
    std::cerr << "Error: Required precision is too high\n"; return 127;
  }
}


/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/math/CMatrixDynamic.h>
#include <Eigen/Dense>

TEST(CMatrixDynamic, GetSetEigen)
{
	{
		auto M = mrpt::math::CMatrixDynamic<double>::Identity(3);
		auto em = M.asEigen();
		em.setIdentity();
		for (int i = 0; i < 3; i++) EXPECT_EQ(M(i, i), 1.0);
	}
	{
		mrpt::math::CMatrixDynamic<double> M(3, 3);
		auto em = M.asEigen();
		for (int i = 0; i < 3; i++)
			for (int j = 0; j < 3; j++)
			{
				const auto n = ((i + 1) * 3) + (j * 1001);
				em(i, j) = n;
				EXPECT_NEAR(M(i, j), em(i, j), 1e-9)
					<< "(i,j)=(" << i << "," << j << ")\n";
			}
	}
}
TEST(CMatrixDynamic, asString)
{
	auto M = mrpt::math::CMatrixDynamic<double>::Identity(2);
	M.setIdentity();
	EXPECT_EQ(std::string("1 0\n0 1"), M.asString());
}

TEST(CMatrixDynamic, CtorFromArray)
{
	const double dat_R[] = {1., 2., 3., 4., 5., 6., 7., 8., 9.};
	mrpt::math::CMatrixDouble R(3, 3, dat_R);
	for (int r = 0; r < 3; r++)
	{
		for (int c = 0; c < 3; c++)
		{
			EXPECT_EQ(dat_R[c + r * 3], R(r, c))
				<< "(r,c)=(" << r << "," << c << ")\n";
		}
	}
}

// Added to run with valgrind to error checking.
TEST(CMatrixDynamic, Resizes)
{
	using mrpt::math::CMatrixDouble;
	{
		CMatrixDouble M(0, 0);
		M.resize(0, 0);
		M.resize(1, 1);
		M.resize(10, 10);
		M.resize(15, 10);
		M.resize(15, 12);
		M.resize(5, 12);
		M.resize(3, 2);
	}
	{
		CMatrixDouble M(40, 50);
		M.resize(3, 3);
	}
}


//
// $Id: Parabola.cpp 2051 2010-06-15 18:39:13Z chambm $
//
//
// Original author: Darren Kessner <darren@proteowizard.org>
//
// Copyright 2006 Louis Warschaw Prostate Cancer Center
//   Cedars Sinai Medical Center, Los Angeles, California  90048
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#define PWIZ_SOURCE

#include "Parabola.hpp"
#include "pwiz/utility/misc/Std.hpp"

#ifndef NDEBUG
#define NDEBUG
#endif // NDEBUG
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
namespace ublas = boost::numeric::ublas;

#if BOOST_UBLAS_TYPE_CHECK
goo; // need -DNDEBUG in makefile!
#endif

namespace pwiz {
namespace math {

PWIZ_API_DECL Parabola::Parabola(double a, double b, double c)
:   a_(3)
{
    a_[0] = a;
    a_[1] = b;
    a_[2] = c;
}

PWIZ_API_DECL Parabola::Parabola(vector<double> a)
:   a_(a)
{
    if (a_.size() != 3)
        throw logic_error("[Parabola::Parabola()] 3 coefficients required.");
}

namespace {

void solve(ublas::matrix<double>& A, ublas::vector<double>& a)
{
    ublas::permutation_matrix<size_t> pm(3);
    int singular = lu_factorize(A, pm);
    if (singular)
        throw runtime_error("[Parabola.cpp::solve()] Matrix is singular.");

    lu_substitute(A, pm, a); // may cause assertion without NDEBUG defined for ublas, probably due to roundoff errors
}

void fitExact(const vector< pair<double,double> >& samples, vector<double>& coefficients)
{
    if (samples.size() != 3)
        throw logic_error("[Parabola.cpp::fitExact()] Exactly 3 samples required.\n");

    // fit parabola to the 3 samples (xi,yi):
    //
    //   ( x1^2  x1  1 )( a[0] )   ( y1 )
    //   ( x2^2  x2  1 )( a[1] ) = ( y2 )
    //   ( x3^2  x3  1 )( a[2] )   ( y3 )

    ublas::matrix<double> A(3,3);
    ublas::vector<double> a(3);

    for (int i=0; i<3; i++)
    {
        double x = samples[i].first;
        double y = samples[i].second;
        A(i,0) = x*x;
        A(i,1) = x;
        A(i,2) = 1;
        a(i) = y;
    }

    solve(A, a);
    copy(a.begin(), a.end(), coefficients.begin());
}

void fitWeightedLeastSquares(const vector< pair<double,double> >& samples,
                             const vector<double>& weights,
                             vector<double>& coefficients)
{
    if (samples.size() != weights.size())
        throw logic_error("[Parabola.cpp::fitWeightedLeastSquares] Wrong weight count.");

    // given samples {(xi,yi)} and weights {wi}
    // minimize e(a) = sum[wi(p(a,xi)-yi)^2],
    // where p(a,xi) = a[0](xi)^2 + a[1](xi) + a[0]c
    //
    // de/da == 0 =>
    //   ( sum_wx4  sum_wx3  sum_wx2 )( a[0] )   ( sum_wyx2 )
    //   ( sum_wx3  sum_wx2  sum_wx1 )( a[1] ) = ( sum_wyx1 )
    //   ( sum_wx2  sum_wx1  sum_wx0 )( a[2] )   ( sum_wyx0 )
    //
    // where:
    //   sum_wxn means sum[wi*(xi)^n]
    //   sum_wyxn means sum[wi*yi*(xi)^n]

    double sum_wx4 = 0;
    double sum_wx3 = 0;
    double sum_wx2 = 0;
    double sum_wx1 = 0;
    double sum_wx0 = 0;
    double sum_wyx2 = 0;
    double sum_wyx1 = 0;
    double sum_wyx0 = 0;

    for (unsigned int i=0; i<samples.size(); i++)
    {
        double x = samples[i].first;
        double y = samples[i].second;
        double w = weights[i];

        sum_wx4 += w*pow(x,4);
        sum_wx3 += w*pow(x,3);
        sum_wx2 += w*x*x;
        sum_wx1 += w*x;
        sum_wx0 += w;
        sum_wyx2 += w*y*x*x;
        sum_wyx1 += w*y*x;
        sum_wyx0 += w*y;
    }

    ublas::matrix<double> A(3,3);
    ublas::vector<double> a(3);

    A(0,0) = sum_wx4;
    A(1,0) = A(0,1) = sum_wx3;
    A(2,0) = A(1,1) = A(0,2) = sum_wx2;
    A(1,2) = A(2,1) = sum_wx1;
    A(2,2) = sum_wx0;

    a(0) = sum_wyx2;
    a(1) = sum_wyx1;
    a(2) = sum_wyx0;

    solve(A, a);
    copy(a.begin(), a.end(), coefficients.begin());
}

} // namespace

PWIZ_API_DECL Parabola::Parabola(const vector< pair<double,double> >& samples)
:   a_(3)
{
    if (samples.size() < 3)
        throw logic_error("[Parabola::Parabola()] At least 3 samples required.");

    if (samples.size() == 3)
        fitExact(samples, a_);
    else
        fitWeightedLeastSquares(samples, vector<double>(samples.size(),1), a_);
}

// construct by weighted least squares
PWIZ_API_DECL
Parabola::Parabola(const std::vector< std::pair<double,double> >& samples,
                   const std::vector<double>& weights)
:   a_(3)
{
    fitWeightedLeastSquares(samples, weights, a_);
}

PWIZ_API_DECL ostream& operator<<(ostream& os, const Parabola& p)
{
    vector<double> a = p.coefficients();
    os << "[Parabola (" << a[0] << ", " << a[1] << ", " << a[2] << ")]";
    return os;
}

} // namespace math
} // namespace pwiz


static bool eigen_did_assert = false;
#define eigen_assert(X) if(!eigen_did_assert && !(X)){ std::cout << "### Assertion raised in " << __FILE__ << ":" << __LINE__ << ":\n" #X << "\n### The following would happen without assertions:\n"; eigen_did_assert = true;}

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

#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif

using namespace Eigen;
using namespace std;

int main(int, char**)
{
  cout.precision(3);
// intentionally remove indentation of snippet
{
ArrayXXi A = ArrayXXi::Random(4,4).abs();
cout << "Here is the initial matrix A:\n" << A << "\n";
for(auto row : A.rowwise())
  std::sort(row.begin(), row.end());
cout << "Here is the sorted matrix A:\n" << A << "\n";

}
  return 0;
}


#include "../Galerkin.hpp"
#include <iostream>

using namespace Galerkin;
using namespace Elements;
using namespace Rationals;
using namespace Polynomials;

#include <Eigen/Cholesky>
#include <Eigen/Core>

constexpr std::array<double, 5> scalings = {0.5, 1, 0.5, 0.25, 0.25};

constexpr std::array<double, 5> offsets = { 0.5, 2, 3.5, 4.25, 4.75 };

constexpr std::array<C1IntervalElement<double>, 5> elements = {
    C1IntervalElement(scalings[0], offsets[0]), C1IntervalElement(scalings[1], offsets[1]),
    C1IntervalElement(scalings[2], offsets[2]), C1IntervalElement(scalings[3], offsets[3]),
    C1IntervalElement(scalings[4], offsets[4])};

constexpr std::array<std::array<int, 4>, 5> dof_numbers = {
    std::array{0, 1, 2, 3}, std::array{3, 2, 4, 5}, std::array{5, 4, 6, 7}, std::array{7, 6, 8, 9},
    std::array{9, 8, 10, 11}};

constexpr std::size_t num_dofs = 12;

constexpr auto el_stiffness(const C1IntervalElement<double> &el)
{
    auto form = [&](auto f, auto g) { return el.template partial<0>(f) * el.template partial<0>(g); };

    return el.form_matrix(form);
}

Eigen::MatrixXd stiffness_matrix()
{
    Eigen::MatrixXd K = Eigen::MatrixXd::Zero(num_dofs, num_dofs);
    for (int i = 0; i < 5; ++i)
    {
        auto Ke = el_stiffness(elements[i]);
        for (int j = 0; j < 4; ++j)
        {
            for (int k = 0; k < 4; ++k)
            {
                K(dof_numbers[i][j], dof_numbers[i][k]) += Ke(j, k);
            }
        }
    }
    return K;
}

static_assert(elements[0].coordinate_map()(std::tuple(-1))[0] == 0);
static_assert(elements[0].coordinate_map()(std::tuple(1))[0] == 1);

constexpr auto u = make_poly(
    std::tuple(rational<3, 8>, rational<-47, 12>, rational<97, 8>, -rational<115, 12>),
    PowersList<Powers<4>, Powers<3>, Powers<2>, Powers<1>>{});

constexpr auto f = u.template partial<0>().template partial<0>();

Eigen::VectorXd forcing_vector()
{
    Eigen::VectorXd F = Eigen::VectorXd::Zero(num_dofs);
    for (int i = 0; i < 5; ++i)
    {
        const auto &el = elements[i];
        for (int j = 0; j < 4; ++j)
        {
            auto rule = el.coordinate_map().template quadrature_rule<6>();
            double detj = el.coordinate_map().detJ()();
            auto g = [&](auto xi) {
                return detj * f(el.coordinate_map()(std::tuple(xi))) * el.basis()[j](xi);
            };
            F[dof_numbers[i][j]] -= Quadrature::integrate(g, rule);
        }
    }

    return F;
}

void print_polynomial(const Polynomial<double, Powers<0>, Powers<1>, Powers<2>, Powers<3>> &p)
{
    printf("%f * x^3 + %f * x^2 + %f * x + %f", p.coeffs()[3], p.coeffs()[2], p.coeffs()[1], p.coeffs()[0]);
}

void eliminate_dirichlet_bc(Eigen::MatrixXd &K, Eigen::VectorXd &F, int which)
{
    for (int i = 0; i < K.rows(); ++i)
    {
        K(i, which) = 0;
        K(which, i) = 0;
    }
    K(which, which) = 1.0;
    F(which) = 0.0;
}

int main()
{
    auto K = stiffness_matrix();
    auto F = forcing_vector();
    eliminate_dirichlet_bc(K, F, 1);
    eliminate_dirichlet_bc(K, F, num_dofs - 2);
    std::cout << "K = " << K << '\n';
    std::cout << "F = " << F << '\n';
    Eigen::VectorXd U = K.ldlt().solve(F);

    for (int i = 0; i < 5; ++i)
    {
        const auto &el = elements[i];
        printf("Solution on element %d: ", i);
        auto p = 0.0 * el.basis()[0];
        for (int j = 0; j < 4; ++j)
        {
            p += el.basis()[j] * U[dof_numbers[i][j]];
        }
        print_polynomial(p);
        printf("\n");
    }

    return 0;
}


//////////////////////////////////////////////////////////////////////////////////
// statistics::survival::model::models::exponential::detail::log_likelihood.hpp //
//                                                                              //
//  Copyright 2009 Erwann Rogard. 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)            //
//////////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_SURVIVAL_MODEL_MODELS_EXPONENTIAL_DETAIL_LOG_LIKELIHOOD_HPP_ER_2009
#define BOOST_STATISTICS_SURVIVAL_MODEL_MODELS_EXPONENTIAL_DETAIL_LOG_LIKELIHOOD_HPP_ER_2009
#include <cmath>
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/statistics/survival/data/data/event.hpp>

namespace boost{
namespace statistics{

namespace survival{
namespace model{
namespace exponential{
namespace detail{

    template<typename T>
    T
    log_likelihood(
        const T& log_rate,
        const data::event<T>& e
    ){
        static const char* msg =
            "survival::model::exponential::log_unnromalized_pdf(%1%,%2%)";
        typedef T value_type;
        value_type result = exp(log_rate);
        result *= (- e.time());
        try{
            if( boost::math::isinf(result) ){
                throw std::runtime_error("isinf(result)");
            }
            if( boost::math::isnan(result) ){
                throw std::runtime_error("isnan(result)");
            }
        }catch(std::exception ex){
            std::string str = msg;
            str += ex.what();
            format f(str); f % log_rate % e;
            throw std::runtime_error(
                f.str()
            );
        }
        if(e.failure()){
            result += log_rate;
        }
        return result;
    }

}// detail
}// exponential
}// model
}// survival
}// statistics
}// boost

#endif


#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

int main()
  {
  mat A(4, 5, fill::randu);
  mat B(4, 5, fill::randu);

  cout << A*B.t() << endl;

  return 0;
  }


#pragma once
#include <cmath>
#include <iostream>
#include <exception>

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

using Eigen::ArrayXd;
using Eigen::MatrixXcd;
using Eigen::MatrixXd;
using Eigen::Vector3d;

namespace CPU
{
    struct closest_matrix_params
    {
        unsigned int dim;
        unsigned int np;
        unsigned int nm;
        const MatrixXd &p;
        const MatrixXd &m;
    };

    struct err_compute_params
    {
        unsigned int np;
        MatrixXd &p;
        double s;
        const MatrixXd &r;
        const MatrixXd &t;
        const MatrixXd &Y;
    };

    struct err_compute_alignment_params
    {
        unsigned int np;
        const MatrixXd &p;
        double s;
        const MatrixXd &r;
        const MatrixXd &t;
        const MatrixXd &y;
    };

    class ICP
    {
    public:
        ICP(MatrixXd m_, MatrixXd p_, int max_iter_)
            : m{m_},
              p{p_},
              new_p{p_},
              np{(unsigned int)p_.cols()},
              nm{(unsigned int)m_.cols()},
              dim{3},
              max_iter{max_iter_}
        {
            this->s = 1.;
            this->r = MatrixXd::Identity(m_.rows(), m_.rows());
            this->t = MatrixXd::Zero(m_.rows(), 1);
        }

        ~ICP()
        {
        }

        struct closest_matrix_params get_closest_matrix_params()
        {
            struct closest_matrix_params cmp
                {
                    dim, np, nm, new_p, m
                };
            return cmp;
        }

        struct err_compute_params get_err_compute_params(Eigen::MatrixXd &Y)
        {
            struct err_compute_params ecp
                {
                    np, new_p, s, r, t, Y
                };
            return ecp;
        }

        struct err_compute_alignment_params get_err_compute_alignment_params(Eigen::MatrixXd &Y)
        {
            struct err_compute_alignment_params ecap
                {
                    np, new_p, s, r, t, Y
                };
            return ecap;
        }

        void find_corresponding();
        void alignement_check();
        double find_alignment(MatrixXd y);

    public:
        MatrixXd new_p;

    private:
        double s;
        MatrixXd t;
        MatrixXd r;

        MatrixXd m;
        MatrixXd p;

        unsigned int np;
        unsigned int nm;
        unsigned int dim;

        int max_iter;
        const double threshold = 1e-5;
    };

    MatrixXd closest_matrix(struct closest_matrix_params pa);
    double err_compute(struct err_compute_params pa);
    double err_compute_alignment(struct err_compute_alignment_params pa);
    int max_element_index(Eigen::EigenSolver<Eigen::MatrixXd>::EigenvalueType &eigen_value);

} // namespace CPU


//
// Created by erik on 10/28/16.
//

#include "physics/units.h"
#include <boost/test/unit_test.hpp>
#include <type_traits>
#include <sstream>

using namespace spatacs;
namespace dim = physics::dimensions;

// check dimension multiplication
static_assert( std::is_same<dim::mul_t<dim::dimless_t, dim::length_t>, dim::length_t>::value,  "multiplication of dimensionless and length must yield length");
static_assert( std::is_same<dim::mul_t<dim::dimless_t, dim::energy_t>, dim::energy_t>::value,  "multiplication of dimensionless and energy must yield energy");

static_assert( std::is_same<dim::mul_t<dim::acceleration_t, dim::mass_t>, dim::force_t>::value,  "error in unit multiplication");
static_assert( std::is_same<dim::mul_t<dim::force_t, dim::length_t>, dim::energy_t>::value,  "error in unit multiplication");
static_assert( std::is_same<dim::div_t<dim::length_t, dim::time_t>, dim::velocity_t>::value,  "error in unit division");
static_assert( std::is_same<dim::div_t<dim::velocity_t, dim::time_t>, dim::acceleration_t>::value,  "error in unit division");
static_assert( std::is_same<dim::pow_t<dim::area_t, 1, 2>, dim::length_t>::value,  "error in unit division");

static_assert( std::ratio_equal<dim::energy_t::length, std::ratio<2, 1>>(), "unexpected meters in energy");
static_assert( std::ratio_equal<dim::energy_t::time,   std::ratio<-2, 1>>(), "unexpected meters in energy");
static_assert( std::ratio_equal<dim::energy_t::mass, std::ratio<1, 1>>(), "unexpected meters in energy");

static_assert( dim::dimensions_equal<dim::acceleration_t, dim::acceleration_t>(), "equality comparison is broken" );

#define STREAM_OUT_TEST(value, result)  \
{                                   \
    std::stringstream stream;       \
    stream << value;                \
    BOOST_CHECK_EQUAL(stream.str(), result); \
}

#define STREAM_IN_TEST(value, input)  \
{                                   \
    std::stringstream stream;       \
    stream << input;                \
    decltype(value) tmp;            \
    stream >> tmp;                  \
    BOOST_CHECK(!stream.fail());     \
    BOOST_CHECK_EQUAL(tmp, value);  \
}

BOOST_AUTO_TEST_SUITE(Units)
    BOOST_AUTO_TEST_CASE(ratio_stream)
    {
        STREAM_OUT_TEST((std::ratio<1, 3>{}), "1/3");
        STREAM_OUT_TEST((std::ratio<3, 1>{}), "3");
    }

    BOOST_AUTO_TEST_CASE(dimension_stream)
    {
        STREAM_OUT_TEST(dim::length_t{}, "m");
        STREAM_OUT_TEST(dim::area_t{},   "m^2");
        STREAM_OUT_TEST(dim::energy_t{}, "kgm^2s^-2");
    }

    BOOST_AUTO_TEST_CASE(units_stream)
    {
        STREAM_OUT_TEST(500.0_m, "500m");
        STREAM_OUT_TEST(150.0_kg, "150kg");
        STREAM_OUT_TEST(500.0_kJ, "500kJ");
        STREAM_OUT_TEST(3000.0_kg, "3t");
        STREAM_OUT_TEST(kilonewtons(5.5), "5.5kN");
        STREAM_OUT_TEST(5.0_km*5.0_km, "25km^2");
    }

    BOOST_AUTO_TEST_CASE(units_input)
    {
        STREAM_IN_TEST(500.0_m, "500m");
        STREAM_IN_TEST(150.0_kg, "150kg");
        STREAM_IN_TEST(500.0_kJ, "500kJ");
        STREAM_IN_TEST(3000.0_kg, "3t");
        STREAM_IN_TEST(kilonewtons(5.5), "5.5kN");
        STREAM_IN_TEST(5.0_km*5.0_km, "25km^2");
    }
BOOST_AUTO_TEST_SUITE_END()


#include "cmath"
#include "softmax.h"
#include <ctime>
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <fstream>

#include <Eigen/Dense>

using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::VectorXi;
using Eigen::MatrixXi;
using Eigen::ArrayXXd;

namespace lrprox {

  SOFTMAX::SOFTMAX(int num_dims, int num_classes)
    : num_dims_(num_dims), num_classes_(num_classes) {
    initWeight_();
  }

  double SOFTMAX::cost(const MatrixXd &X, const MatrixXi &Y) {
    // X: n * num_dims, y: n * num_classes
    // minimize negative log prob
    ArrayXXd term1 = (X * weight_).array();
    // do not take average
    return ((logsumexp(term1.matrix()).replicate(1, term1.cols()).array() - term1) * Y.cast<double>().array()).sum();
  }

  MatrixXd SOFTMAX::grad(const MatrixXd &X, const MatrixXi &Y) {
    MatrixXd term1 = (X * weight_).array().exp().matrix();
    ArrayXXd P = term1.array() / term1.rowwise().sum().replicate(1, term1.cols()).array();

    return X.transpose() * (P - Y.cast<double>().array()).matrix();
//    return weight_;
  }
//
//  VectorXi predict(const MatrixXd &X);
//
  const MatrixXd& SOFTMAX::getWeight() {
    return weight_;
  }
  void SOFTMAX::updateWeight(const std::vector<double>& weight) {
    for (int i = 0; i < weight_.cols(); i++) {
      weight_.col(i) = VectorXd::Map(&weight[i*weight_.rows()], weight_.rows());
    }
  }
  void SOFTMAX::updateWeight(const MatrixXd& weight) {
    weight_ = weight;
  }

  void SOFTMAX::outputWeight(std::vector<double>& weight) {
    weight.resize(weight_.rows() * weight_.cols());
    for (int i = 0; i < weight_.cols(); i++) {
       VectorXd::Map(&weight[i*weight_.rows()], weight_.rows()) = weight_.col(i);
    }
  }

  MatrixXi SOFTMAX::onehot_encoder(const VectorXi &y) {
    std::vector<int> labels;
    std::map<int, int> label_to_idx;
    for (int i = 0; i < y.size(); i++) {
      if (label_to_idx.count(y(i)) == 0) {
        label_to_idx[y(i)] = 1;
        labels.push_back(y(i));
      }
    }
    std::sort(labels.begin(), labels.end());
    for (int i = 0; i < labels.size(); i++) {
      label_to_idx[labels[i]] = i;
    }
    MatrixXi Y = MatrixXi::Zero(y.size(), labels.size());
    for (int i = 0; i < y.size(); i++) {
      Y(i, label_to_idx[y(i)]) = 1;
    }
    return Y;
  }

//
//  bool saveModel(std::string &filename);

  void SOFTMAX::initWeight_() {
//    weight_ = MatrixXd::Random(num_dims_, num_classes_);
    weight_ = MatrixXd::Ones(num_dims_, num_classes_);
  }

  MatrixXd SOFTMAX::logsumexp(const MatrixXd &X) {
    MatrixXd max_X = X.rowwise().maxCoeff();
    return max_X + (X - max_X.replicate(1, X.cols())).array().exp().matrix().rowwise().sum().array().log().matrix();
  }

//bool LR::SaveModel(std::string& filename) {
//  std::ofstream fout(filename.c_str());
//  fout << num_feature_dim_ << std::endl;
//  for (int i = 0; i < num_feature_dim_; ++i) {
//    fout << weight_[i] << ' ';
//  }
//  fout << std::endl;
//  fout.close();
//  return true;
//}

//std::string LR::DebugInfo() {
//  std::ostringstream out;
//  for (size_t i = 0; i < weight_.size(); ++i) {
//    out << weight_[i] << " ";
//  }
//  return out.str();
//}

//  float LR::Sigmoid_(std::vector<float> feature) {
//    float z = 0;
//    for (size_t j = 0; j < weight_.size(); ++j) {
//      z += weight_[j] * feature[j];
//    }
//    return 1. / (1. + exp(-z));
//  }

} // namespace lrprox