/**
 * \file libs/numeric/ublasx/test/cond.cpp
 *
 * \brief Test suite for the \c cond operation.
 *
 * Copyright (c) 2011, Marco Guazzone
 *
 * 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)
 *
 * \author Marco Guazzone, marco.guazzone@gmail.com
 */

//ATTENTION: test fails
//TODO: fix it

//#include <boost/numeric/ublas/banded.hpp>
#include <boost/numeric/ublas/fwd.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix.hpp>
//#include <boost/numeric/ublas/symmetric.hpp>
//#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublasx/operation/cond.hpp>
#include <complex>
#include <cmath>
#include <cstddef>
#include <limits>
#include "libs/numeric/ublasx/test/utils.hpp"

namespace ublas = boost::numeric::ublas;
namespace ublasx = boost::numeric::ublasx;

static const double tol = 1.0e-5;

BOOST_UBLASX_TEST_DEF( norm_1_real_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_1(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_1(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_1_real_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_1(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_1(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_1_complex_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_1(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_1(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_1_complex_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_1(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_1(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_1_real_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_1(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_1_real_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_1(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_1_complex_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_1(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_1_complex_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_1(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_2_real_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Real Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 4;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 49026176493774648;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_real_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Real Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 4;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 49026176493774648;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_complex_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Complex Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 4;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 20994351988002824;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_complex_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Complex Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 4;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 20994351988002824;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_real_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Real Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type Well(nr,nc);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;
	Well(3,0) =  1; Well(3,1) =  2; Well(3,2) = -1;

	matrix_type Ill(nr,nc);
	Ill(0,0) =  1; Ill(0,1) =  2; Ill(0,2) =  3;
	Ill(1,0) =  4; Ill(1,1) =  5; Ill(1,2) =  6;
	Ill(2,0) =  7; Ill(2,1) =  8; Ill(2,2) =  9;
	Ill(3,0) = 10; Ill(3,1) = 11; Ill(3,2) = 12;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 3.41990480101429;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 14259982749169812;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_real_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Real Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type Well(nr,nc);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;
	Well(3,0) =  1; Well(3,1) =  2; Well(3,2) = -1;

	matrix_type Ill(nr,nc);
	Ill(0,0) =  1; Ill(0,1) =  2; Ill(0,2) =  3;
	Ill(1,0) =  4; Ill(1,1) =  5; Ill(1,2) =  6;
	Ill(2,0) =  7; Ill(2,1) =  8; Ill(2,2) =  9;
	Ill(3,0) = 10; Ill(3,1) = 11; Ill(3,2) = 12;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 3.41990480101429;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 14259982749169812;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_complex_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Complex Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type Well(nr,nc);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);
	Well(3,0) = value_type( 1, 0); Well(3,1) = value_type( 2,-1); Well(3,2) = value_type(-1, 2);

	matrix_type Ill(nr,nc);
	Ill(0,0) = value_type( 1,10); Ill(0,1) = value_type( 2,14); Ill(0,2) = value_type( 3,18);
	Ill(1,0) = value_type( 4,11); Ill(1,1) = value_type( 5,15); Ill(1,2) = value_type( 6,19);
	Ill(2,0) = value_type( 7,12); Ill(2,1) = value_type( 8,16); Ill(2,2) = value_type( 9,20);
	Ill(3,0) = value_type(10,13); Ill(3,1) = value_type(11,17); Ill(3,2) = value_type(12,21);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 3.67416702058981;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 37955084752566112;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_2_complex_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 2-Norm - Complex Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type Well(nr,nc);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);
	Well(3,0) = value_type( 1, 0); Well(3,1) = value_type( 2,-1); Well(3,2) = value_type(-1, 2);

	matrix_type Ill(nr,nc);
	Ill(0,0) = value_type( 1,10); Ill(0,1) = value_type( 2,14); Ill(0,2) = value_type( 3,18);
	Ill(1,0) = value_type( 4,11); Ill(1,1) = value_type( 5,15); Ill(1,2) = value_type( 6,19);
	Ill(2,0) = value_type( 7,12); Ill(2,1) = value_type( 8,16); Ill(2,2) = value_type( 9,20);
	Ill(3,0) = value_type(10,13); Ill(3,1) = value_type(11,17); Ill(3,2) = value_type(12,21);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 3.67416702058981;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_2(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = 37955084752566112;
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_2(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );
}

BOOST_UBLASX_TEST_DEF( norm_inf_real_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: inf-Norm - Real Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_inf(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_inf(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_inf_real_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: inf-Norm - Real Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_inf(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_inf(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_inf_complex_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_inf(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_inf(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_inf_complex_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_inf(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	res = ublasx::cond_inf(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_inf_real_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_inf(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_inf_real_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Real Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_inf(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_inf_complex_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_inf(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_inf_complex_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: 1-Norm - Complex Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_inf(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_real_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Real Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5.25;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_frobenius(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	//res = 456177073660509760;
	res = ublasx::cond_frobenius(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_real_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Real Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) =  2; Well(0,1) = -1; Well(0,2) =  0;
	Well(1,0) = -1; Well(1,1) =  3; Well(1,2) = -1;
	Well(2,0) =  0; Well(2,1) = -1; Well(2,2) =  2;

	matrix_type Ill(n,n);
	Ill(0,0) = 1; Ill(0,1) = 2; Ill(0,2) = 3;
	Ill(1,0) = 4; Ill(1,1) = 5; Ill(1,2) = 6;
	Ill(2,0) = 7; Ill(2,1) = 8; Ill(2,2) = 9;

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5.25;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_frobenius(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	//res = 456177073660509760;
	res = ublasx::cond_frobenius(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_complex_square_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-norm - Complex Square Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5.25;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_frobenius(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	//res = 54418634865903768;
	res = ublasx::cond_frobenius(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_complex_square_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Complex Square Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef real_type result_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t n = 3;

	matrix_type Well(n,n);
	Well(0,0) = value_type( 2, 2); Well(0,1) = value_type(-1,-1); Well(0,2) = value_type( 0, 0);
	Well(1,0) = value_type(-1,-1); Well(1,1) = value_type( 3, 3); Well(1,2) = value_type(-1,-1);
	Well(2,0) = value_type( 0, 0); Well(2,1) = value_type(-1,-1); Well(2,2) = value_type( 2, 2);

	matrix_type Ill(n,n);
	Ill(0,0) = value_type(1,10); Ill(0,1) = value_type(2,13); Ill(0,2) = value_type(3,16);
	Ill(1,0) = value_type(4,11); Ill(1,1) = value_type(5,14); Ill(1,2) = value_type(6,17);
	Ill(2,0) = value_type(7,12); Ill(2,1) = value_type(8,15); Ill(2,2) = value_type(9,18);

	result_type res;
	result_type expect_res;

	// Well-conditioned matrix
	expect_res = 5.25;
	BOOST_UBLASX_DEBUG_TRACE("Well-conditioned Matrix = " << Well);
	res = ublasx::cond_frobenius(Well);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect_res, tol );

	// Ill-conditioned matrix
	expect_res = std::numeric_limits<result_type>::infinity();
	BOOST_UBLASX_DEBUG_TRACE("Ill-conditioned Matrix = " << Ill);
	//res = 54418634865903768;
	res = ublasx::cond_frobenius(Ill);
	BOOST_UBLASX_DEBUG_TRACE("res = " << res);
	BOOST_UBLASX_TEST_CHECK( std::isinf(res) );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_real_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Real Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_frobenius(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_real_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Real Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef real_type value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) =  1; A(0,1) =  2; A(0,2) =  3;
	A(1,0) =  4; A(1,1) =  5; A(1,2) =  6;
	A(2,0) =  7; A(2,1) =  8; A(2,2) =  9;
	A(3,0) = 10; A(3,1) = 11; A(3,2) = 12;

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_frobenius(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_complex_rectangular_dense_matrix_column_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Complex Rectangular Dense Matrix - Column Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::column_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_frobenius(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

BOOST_UBLASX_TEST_DEF( norm_frobenius_complex_rectangular_dense_matrix_row_major )
{
	BOOST_UBLASX_DEBUG_TRACE("Test Case: frobenius-Norm - Complex Rectangular Dense Matrix - Row Major");

	typedef double real_type;
	typedef std::complex<real_type> value_type;
	typedef ublas::matrix<value_type,ublas::row_major> matrix_type;

	const std::size_t nr = 4;
	const std::size_t nc = 3;

	matrix_type A(nr,nc);
	A(0,0) = value_type( 1,13); A(0,1) = value_type( 2,17); A(0,2) = value_type( 3,21);
	A(1,0) = value_type( 4,14); A(1,1) = value_type( 5,18); A(1,2) = value_type( 6,22);
	A(2,0) = value_type( 7,15); A(2,1) = value_type( 8,19); A(2,2) = value_type( 9,23);
	A(3,0) = value_type(10,16); A(3,1) = value_type(11,20); A(3,2) = value_type(12,24);

	bool res;

	// Condition number for rectangular matrix only available with the 2-norm
	BOOST_UBLASX_DEBUG_TRACE("Matrix = " << A);
	try
	{
		ublasx::cond_frobenius(A);
		res = false;
	}
	catch (...)
	{
		res = true;
	}
	BOOST_UBLASX_TEST_CHECK( res );
}

int main()
{
	BOOST_UBLASX_DEBUG_TRACE("Test Suite: 'cond' operation");

	BOOST_UBLASX_TEST_BEGIN();

	BOOST_UBLASX_TEST_DO( norm_1_real_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_1_real_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_1_complex_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_1_complex_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_1_real_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_1_real_rectangular_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_1_complex_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_1_complex_rectangular_dense_matrix_row_major );

	BOOST_UBLASX_TEST_DO( norm_2_real_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_2_real_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_2_complex_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_2_complex_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_2_real_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_2_real_rectangular_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_2_complex_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_2_complex_rectangular_dense_matrix_row_major );

	BOOST_UBLASX_TEST_DO( norm_inf_real_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_inf_real_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_inf_complex_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_inf_complex_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_inf_real_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_inf_real_rectangular_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_inf_complex_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_inf_complex_rectangular_dense_matrix_row_major );

	BOOST_UBLASX_TEST_DO( norm_frobenius_real_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_real_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_complex_square_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_complex_square_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_real_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_real_rectangular_dense_matrix_row_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_complex_rectangular_dense_matrix_column_major );
	BOOST_UBLASX_TEST_DO( norm_frobenius_complex_rectangular_dense_matrix_row_major );

	BOOST_UBLASX_TEST_END();
}


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_EXPM1_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_EXPM1_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-exponential
    Function object implementing expm1 capabilities

    exponential function minus one:\f$e^{x}-1\f$

    @par Semantic:

    For every parameter of floating type T

    @code
    T r = expm1(x);
    @endcode

    is similar to:

    @code
    T r = minusone(exp(x));
    @endcode

    @par Notes:

    - result is accurate even for x of small modulus

    @par Decorators

    std_ for floating entries

    @see exp

  **/
  const boost::dispatch::functor<tag::expm1_> expm1 = {};
} }
#endif

#include <boost/simd/function/scalar/expm1.hpp>
#include <boost/simd/function/simd/expm1.hpp>

#endif


///////////////////////////////////////////////////////////////////////////////
// numbers.cpp
//
//  Copyright 2008 David Jenkins. 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)

#if defined(_MSC_VER)
//disbale warning C4996: 'std::xxx' was declared deprecated
# pragma warning(disable:4996)
#endif

#include <iostream>
#include <string>
#include <map>
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/xpressive/xpressive.hpp>
#include <boost/xpressive/regex_actions.hpp>

///////////////////////////////////////////////////////////////////////////////
// Match all named numbers in a string and return their integer values
//
// For example, given the input string:
//      "one two sixty three thousand ninety five eleven"
// the program will output:
//      "one = 1"
//      "two = 2"
//      "sixty three thousand ninety five = 63095"
//      "eleven = 11"

void example1()
{
    using namespace boost::xpressive;
    using namespace boost::assign;

    // initialize the maps for named numbers
    std::map< std::string, int > ones_map =
        map_list_of("one",1)("two",2)("three",3)("four",4)("five",5)
        ("six",6)("seven",7)("eight",8)("nine",9);

    std::map< std::string, int > teens_map =
        map_list_of("ten",10)("eleven",11)("twelve",12)("thirteen",13)
        ("fourteen",14)("fifteen",15)("sixteen",16)("seventeen",17)
        ("eighteen",18)("nineteen",19);

    std::map< std::string, int > tens_map =
        map_list_of("twenty",20)("thirty",30)("fourty",40)
        ("fifty",50)("sixty",60)("seventy",70)("eighty",80)("ninety",90);

    std::map< std::string, int > specials_map =
        map_list_of("zero",0)("dozen",12)("score",20);

    // n is the integer result
    local<long> n(0);
    // temp stores intermediate values
    local<long> temp(0);

    // initialize the regular expressions for named numbers
    sregex tens_rx =
        // use skip directive to skip whitespace between words
        skip(_s)
        (
            ( a3 = teens_map )
            |
            ( a2 = tens_map ) >> !( a1 = ones_map )
            |
            ( a1 = ones_map )
        )
        [ n += (a3|0) + (a2|0) + (a1|0) ];

    sregex hundreds_rx =
        skip(_s)
        (
            tens_rx >>
            !(
                as_xpr("hundred")  [ n *= 100 ]
                >> !tens_rx
             )
        )
        ;

    sregex specials_rx =    // regex for special number names like dozen
        skip(_s)
        (
            // Note: this uses two attribues, a1 and a2, and it uses
            // a default attribute value of 1 for a1.
            ( !( a1 = ones_map ) >> ( a2 = specials_map ) )
                [ n = (a1|1) * a2 ]
            >> !( "and" >> tens_rx )
        )
        ;

    sregex number_rx =
        bow
        >>
        skip(_s|punct)
        (
            specials_rx // special numbers
            |
            (   // normal numbers
                !( hundreds_rx >> "million" ) [ temp += n * 1000000, n = 0 ]
                >>
                !( hundreds_rx >> "thousand" ) [ temp += n * 1000, n = 0 ]
                >>
                !hundreds_rx
            )
            [n += temp, temp = 0 ]
        );

    // this is the input string
    std::string str( "one two three eighteen twenty two "
        "nine hundred ninety nine twelve "
        "eight hundred sixty three thousand ninety five "
        "sixty five hundred ten "
        "two million eight hundred sixty three thousand ninety five "
        "zero sixty five hundred thousand "
        "extra stuff "
        "two dozen "
        "four score and seven");

    // the MATCHING results of iterating through the string are:
    //      one  = 1
    //      two  = 2
    //      three  = 3
    //      eighteen  = 18
    //      twenty two  = 22
    //      nine hundred ninety nine  = 999
    //      twelve  = 12
    //      eight hundred sixty three thousand ninety five  = 863095
    //      sixty five hundred ten  = 6510
    //      two million eight hundred sixty three thousand ninety five  = 2863095
    //      zero = 0
    //      sixty five hundred thousand = 6500000
    //      two dozen = 24
    //      four score and seven = 87
    sregex_token_iterator cur( str.begin(), str.end(), number_rx );
    sregex_token_iterator end;

    for( ; cur != end; ++cur )
    {
        if ((*cur).length() > 0)
            std::cout << *cur << " = " << n.get() << '\n';
        n.get() = 0;
    }
    std::cout << '\n';
    // the NON-MATCHING results of iterating through the string are:
    //      extra = unmatched
    //      stuff = unmatched
    sregex_token_iterator cur2( str.begin(), str.end(), number_rx, -1 );
    for( ; cur2 != end; ++cur2 )
    {
        if ((*cur2).length() > 0)
            std::cout << *cur2 << " = unmatched" << '\n';
    }
}

///////////////////////////////////////////////////////////////////////////////
// main
int main()
{
    std::cout << "\n\nExample 1:\n\n";
    example1();

    std::cout << "\n\n" << std::flush;

    return 0;
}


#include "GaussianMixture.h"

#include <Eigen/Core>
#include <Eigen/Dense>
#include <fstream>
#include <iostream>
#include <cmath>

#include "Util.h"

namespace ark {
    void GaussianMixture::load(const std::string & path)
    {
        std::ifstream ifs(path);
        if (!ifs) {
            std::cerr << "Warning: pose prior file at " << path << " does not exist or cannot be read\n";
            nComps = -1;
            return;
        }
        ifs >> nComps >> nDims;

        // compute constants
        double sqrt_2_pi_n = std::pow(2 * M_PI, nDims * 0.5 );
        double log_sqrt_2_pi_n = nDims * 0.5 * std::log(2 * M_PI);
        weight.resize(nComps);
        consts.resize(nComps);
        consts_log.resize(nComps);
        for (int i = 0; i < nComps; ++i) {
            // load weights
            ifs >> weight[i];
            consts_log[i] = log(weight[i]) - log_sqrt_2_pi_n;
            consts[i] = weight[i] / sqrt_2_pi_n;
        }

        mean.resize(nComps, nDims);
        for (int i = 0; i < nComps; ++i) {
            for (int j = 0; j < nDims; ++j) {
                // load mean vectors
                ifs >> mean(i, j);
            }
        }

        /** Cholesky decomposition */
        typedef Eigen::LLT<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> Cholesky;

        cov.resize(nComps);
        cov_cho.resize(nComps);
        prec_cho.resize(nComps);
        double minDet = std::numeric_limits<double>::max();
        for (int i = 0; i < nComps; ++i) {
            auto & m = cov[i];
            m.resize(nDims, nDims);
            for (int j = 0; j < nDims; ++j) {
                for (int k = 0; k < nDims; ++k) {
                    // load covariance matrices
                    ifs >> m(j, k);
                }
            }
            Cholesky chol(cov[i]);
            if (chol.info() != Eigen::Success) throw "Decomposition failed!";
            cov_cho[i] = chol.matrixL();
            Cholesky chol_prec(cov[i].inverse());
            prec_cho[i] = chol_prec.matrixL();
            double det = cov_cho[i].determinant();
            minDet = std::min(det, minDet);

            // update constants
            consts[i] /= det;
            consts_log[i] -= log(det);
        }

        for (int i = 0; i < nComps; ++i) {
            // normalize constants
            consts[i] *= minDet;
            consts_log[i] += log(minDet);
        }
    }

    int GaussianMixture::numComponents() const {
        return nComps;
    };

    /** Compute PDF at 'input' */
    double GaussianMixture::pdf(const Eigen::VectorXd & x) const {
        double prob(0.0);
        typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Mattype;
        for (int i = 0; i < nComps; ++i) {
            Eigen::TriangularView<Eigen::MatrixXd, Eigen::Lower> L(prec_cho[i]);
            auto residual = (L * (x - mean.row(i).transpose()));
            prob += consts[i] * std::exp(-0.5 * residual.squaredNorm());
        }
        return prob;
    }

    Eigen::VectorXd GaussianMixture::residual(const Eigen::VectorXd & x, int* comp_idx) const {
        double bestProb = std::numeric_limits<double>::max();
        Eigen::VectorXd ans;
        for (int i = 0; i < nComps; ++i) {
            Eigen::TriangularView<Eigen::MatrixXd, Eigen::Lower> L(prec_cho[i]);
            Eigen::VectorXd residual(nDims + 1);
            residual[nDims] = 0.;
            residual.head(nDims) = L.transpose() * (x - mean.row(i).transpose()) * sqrt(0.5);
            double p = residual.squaredNorm() - consts_log[i];
            if (p < bestProb) {
                bestProb = p;
                residual[nDims] = sqrt(-consts_log[i]);
                ans = residual;
                if (comp_idx != nullptr) {
                    *comp_idx = i;
                }
            }
        }
        return ans;
    }

    Eigen::VectorXd GaussianMixture::sample() const {
        // Pick random GMM component
        double randf = random_util::uniform(0.0f, 1.0f);
        int component;
        for (size_t i = 0 ; i < nComps; ++i) {
            randf -= weight[i];
            if (randf <= 0) component = i;
        }
        Eigen::VectorXd r(nDims);
        // Sample from Gaussian
        for (int i = 0; i < nDims; ++i) {
            r(i) = random_util::randn();
        }
        r *= cov_cho[component];
        r += mean.row(component);
        return r;
    }

}  // namespace ark


#ifndef CWT1D_WAVELETS
#define CWT1D_WAVELETS
#include "cwt1d.hpp"
#include <boost/math/special_functions/gamma.hpp>

namespace cwt1d
{
  template <typename T>
  class dog
    :public wavelet_func<T>
  {
  private:
    int m;
    T norm;
    T coi_factor;
    bool coi_calculated;
  public:
    dog()
      :m(2),coi_calculated(false)
    {
      norm=boost::math::tgamma(m+1/2.);
    }

    dog(int m1)
      :m(m1),coi_calculated(false)
    {
      norm=boost::math::tgamma(m+1/2.);
    }

    T do_cone_of_influence_factor()const
    {
      if(!coi_calculated)
	{
	  blitz::Array<T,1> signal(1024);
	  signal=0;
	  signal(signal.extent(0)/2)=1;
	  blitz::Array<T,1> scales(1);
	  scales(0)=1;
	  blitz::Array<std::complex<T>,2> signal_cwt(cwt(signal,scales,*this));
	  int max_idx=0;
	  for(int i=0;i<signal.extent(0)/2;++i)
	    {
	      if(abs(signal_cwt(0,i))>abs(signal_cwt(0,signal.extent(0)/2))/5)
		{
		  max_idx=i;
		  break;
		}
	    }
	  const_cast<T&>(coi_factor)=signal.extent(0)/2-max_idx;
	  const_cast<bool&>(coi_calculated)=true;
	}
      return coi_factor*.85;
    }

  private:
    std::complex<T> do_wavelet_f(T w,T s)const
    {
      const T ws=w*s;
      const T pi=4*std::atan(1);
      return -pow(std::complex<T>(0,1),T(m))*pow(ws,T(m))*exp(-(ws*ws)/2)/norm;
    }
  };

  template <typename T>
  class morlet
    :public wavelet_func<T>
  {
  private:
    T omega_0;
    T coi_factor;
    bool coi_calculated;
  public:
    morlet()
      :omega_0(1),coi_calculated(false)
    {}

    morlet(T w1)
      :omega_0(w1),coi_calculated(false)
    {}

    T do_cone_of_influence_factor()const
    {
      if(!coi_calculated)
	{
	  blitz::Array<T,1> signal(1024);
	  signal=0;
	  signal(signal.extent(0)/2)=1;
	  blitz::Array<T,1> scales(1);
	  scales(0)=8;
	  blitz::Array<std::complex<T>,2> signal_cwt(cwt(signal,scales,*this));
	  int max_idx=0;
	  for(int i=0;i<signal.extent(0)/2;++i)
	    {
	      if(abs(signal_cwt(0,i))>abs(signal_cwt(0,signal.extent(0)/2))/1e2)
		{
		  max_idx=i;
		  break;
		}
	    }
	  const_cast<T&>(coi_factor)=(signal.extent(0)/2-max_idx)/8.;
	  const_cast<bool&>(coi_calculated)=true;
	}
      return coi_factor*.85;
    }

  private:
    std::complex<T> do_wavelet_f(T w,T s)const
    {
      static const T pi=atan(1)*4;
      if(w<=0)
	{
	  return 0;
	}
      else
	{
	  return pow(T(pi),T(-.25))*exp(-pow(s*w-omega_0,2)/2);
	}
    }
  };

  template <typename T>
  class paul
    :public wavelet_func<T>
  {
  private:
    int m;
    T norm;
    T coi_factor;
    bool coi_calculated;

  public:
    paul()
      :m(4),coi_calculated(false)
    {
      norm=calc_norm();
    }

    paul(T m1)
      :m(m1),coi_calculated(false)
    {
      norm=calc_norm();
    }

    T do_cone_of_influence_factor()const
    {
      if(!coi_calculated)
	{
	  blitz::Array<T,1> signal(1024);
	  signal=0;
	  signal(signal.extent(0)/2)=1;
	  blitz::Array<T,1> scales(1);
	  scales(0)=1;
	  blitz::Array<std::complex<T>,2> signal_cwt(cwt(signal,scales,*this));
	  int max_idx=0;
	  for(int i=0;i<signal.extent(0)/2;++i)
	    {
	      if(abs(signal_cwt(0,i))>abs(signal_cwt(0,signal.extent(0)/2))/25)
		{
		  max_idx=i;
		  break;
		}
	    }
	  const_cast<T&>(coi_factor)=(signal.extent(0)/2-max_idx)/4.;
	  const_cast<bool&>(coi_calculated)=true;
	}
      return coi_factor;
    }

    T calc_norm()
    {
      return pow(T(2.),(T)m)/sqrt(m*factorial(2*m-1));
    }

    int factorial(int n)
    {
      if(n==0)
	{
	  return 1;
	}
      else
	{
	  return n*factorial(n-1);
	}
    }

  private:
    std::complex<T> do_wavelet_f(T w,T s)const
    {
      if(w<=0)
	{
	  return 0;
	}
      else
	{
	  return norm*pow(s*w,(T)m)*exp(-s*w);
	}
    }
  };
}

#endif
//EOF


// Petter Strandmark 2012.

#include <cstdio>
#include <iostream>
#include <limits>
#include <stdexcept>

#include <Eigen/Dense>

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

namespace spii {

void PatternSolver::solve(const Function& function,
                          SolverResults* results) const
{
	double global_start_time = wall_time();

	// Dimension of problem.
	size_t n = function.get_number_of_scalars();

	if (n == 0) {
		results->exit_condition = SolverResults::FUNCTION_TOLERANCE;
		return;
	}

	// Current point, gradient and Hessian.
	double fval   = std::numeric_limits<double>::quiet_NaN();
	double fprev  = std::numeric_limits<double>::quiet_NaN();

	Eigen::VectorXd x;
	// Copy the user state to the current point.
	function.copy_user_to_global(&x);
	Eigen::VectorXd dx(n);

	// Size of the pattern.
	double pattern_size = 1.0;
	double x_inf = std::max(x.maxCoeff(), -x.minCoeff());
	if (x_inf > 1e-6) {
		pattern_size = x_inf /= 2.0;
	}
	double pattern_size0 = pattern_size;

	// Sufficient decrease.
	auto rho = [](double t) -> double { return 1e-4 * std::pow(t ,1.5); };

	//
	// START MAIN ITERATION
	//
	results->startup_time   += wall_time() - global_start_time;
	results->exit_condition = SolverResults::INTERNAL_ERROR;
	int iter = 0;
	while (true) {

		//
		// Search along all coordinate directions
		//
		double start_time = wall_time();

		if (iter == 0) {
			fval = function.evaluate(x);
		}

		bool success = false;
		for (size_t i = 0; i < n; ++i) {
			dx.setZero();
			//for d in {-1, 1}
			for (double d = -1; d <= 1; d += 2) {
				// Search along this coordinate axis in
				// direction d.
				dx[i] = d * pattern_size;
				// Evaluate function in new point.
				double fval_new = function.evaluate(x + dx);

				// If we have sufficient decrease.
				if (fval_new < fval - rho(pattern_size)) {
					success = true;
					x = x + dx;
					fval = fval_new;
					break;
				}
			}

			if (success) {
				break;
			}
		}

		// If no point was found, decrease pattern size.
		if (! success) {
			pattern_size /= 2.0;
		}

		results->function_evaluation_time += wall_time() - start_time;

		//
		// Test stopping criteriea
		//
		start_time = wall_time();
		if (pattern_size / pattern_size0 < this->area_tolerance) {
			results->exit_condition = SolverResults::GRADIENT_TOLERANCE;
			break;
		}
		if (success &&
			std::fabs(fval - fprev) / (std::fabs(fval) + this->function_improvement_tolerance) <
			                                             this->function_improvement_tolerance) {
			results->exit_condition = SolverResults::FUNCTION_TOLERANCE;
			break;
		}
		if (iter >= this->maximum_iterations) {
			results->exit_condition = SolverResults::NO_CONVERGENCE;
			break;
		}
		results->stopping_criteria_time += wall_time() - start_time;

		//
		// Log the results of this iteration.
		//
		start_time = wall_time();

		int log_interval = 1;
		if (iter > 30) {
			log_interval = 10;
		}
		if (iter > 200) {
			log_interval = 100;
		}
		if (iter > 2000) {
			log_interval = 1000;
		}
		if (iter > 20000) {
			log_interval = 10000;
		}
		if (iter > 200000) {
			log_interval = 100000;
		}
		if (this->log_function && iter % log_interval == 0) {
			char str[1024];
				if (iter == 0) {
					this->log_function("Itr         f       deltaf   gamma   success");
				}
				std::sprintf(str, "%7d %+10.3e %9.3e %9.3e %s",
					iter, fval, std::fabs(fval - fprev), pattern_size, success ? "yes" : "no");
			this->log_function(str);
		}
		results->log_time += wall_time() - start_time;

		fprev = fval;
		iter++;
	}

	function.copy_global_to_user(x);
	results->total_time += wall_time() - global_start_time;

	if (this->log_function) {
		char str[1024];
		std::sprintf(str, "    end %+10.3e %9.3e %9.3e", fval, std::fabs(fval - fprev), pattern_size);
		this->log_function(str);
	}
}

}  // namespace spii


#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
#include <vector>

using namespace std;
using namespace boost::multiprecision;

void printvector(vector<int> n); // imprime un vector
void dec2bin(cpp_int n); // transforma a binario
vector<int> twoscomplement(vector<int> &negative); // complemento del 2 del numero

int main() {
  cpp_int n;
  while (cin >> n) {
    dec2bin(n);
  }
  return 0;
}

void printvector(vector<int> n) {
  int bitcount = 0;
  for (size_t i = 0; i < n.size(); ++i) {
    cout << n[i];
    bitcount += n[i] == 1 ? 1 : 0;
  }
  cout << endl << "Bitcount: " << bitcount << endl;
}

void dec2bin(cpp_int n) {
  vector<int> resultado;
  resultado.clear();
  int counter = 31;
  bool isNegative = 0;
  if (n < 1) { // si es negativo, se calcula el valor absoluto
    n = -n;
    isNegative = 1;
  }
  for (int i = 0; i < 32; ++i) { // transforma el numero a binario al reves
    resultado.push_back(n % 2 == 1 ? 1 : 0);
	n /= 2;
  }
  for (int i = 0; i < 16; ++i) { // reordena el numero al reves
    swap(resultado[i], resultado[counter]);
    --counter;
  }
  printvector((isNegative == 1) ? twoscomplement(resultado) : resultado);
}

vector<int> twoscomplement(vector<int> &negative) {
  for (int i = 0; i < 32; ++i) { // cambia 1 por 0 y vice-versa
    negative[i] = (negative[i] == 0) ? 1 : 0;
  }
  for (int i = 31; i >= 0; --i) { // suma 1 al numero
    if (negative[i] != 0) {
      negative[i] = 0;
    } else {
      negative[i] = 1;
      break;
    }
  }
  return negative;
}


// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// 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 "main.h"
#include <limits>
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

template<typename MatrixType> bool find_pivot(typename MatrixType::Scalar tol, MatrixType &diffs, Index col=0)
{
  bool match = diffs.diagonal().sum() <= tol;
  if(match || col==diffs.cols())
  {
    return match;
  }
  else
  {
    Index n = diffs.cols();
    std::vector<std::pair<Index,Index> > transpositions;
    for(Index i=col; i<n; ++i)
    {
      Index best_index(0);
      if(diffs.col(col).segment(col,n-i).minCoeff(&best_index) > tol)
        break;

      best_index += col;

      diffs.row(col).swap(diffs.row(best_index));
      if(find_pivot(tol,diffs,col+1)) return true;
      diffs.row(col).swap(diffs.row(best_index));

      // move current pivot to the end
      diffs.row(n-(i-col)-1).swap(diffs.row(best_index));
      transpositions.push_back(std::pair<Index,Index>(n-(i-col)-1,best_index));
    }
    // restore
    for(Index k=transpositions.size()-1; k>=0; --k)
      diffs.row(transpositions[k].first).swap(diffs.row(transpositions[k].second));
  }
  return false;
}

/* Check that two column vectors are approximately equal upto permutations.
 * Initially, this method checked that the k-th power sums are equal for all k = 1, ..., vec1.rows(),
 * however this strategy is numerically inacurate because of numerical cancellation issues.
 */
template<typename VectorType>
void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2)
{
  typedef typename VectorType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  VERIFY(vec1.cols() == 1);
  VERIFY(vec2.cols() == 1);
  VERIFY(vec1.rows() == vec2.rows());

  Index n = vec1.rows();
  RealScalar tol = test_precision<RealScalar>()*test_precision<RealScalar>()*numext::maxi(vec1.squaredNorm(),vec2.squaredNorm());
  Matrix<RealScalar,Dynamic,Dynamic> diffs = (vec1.rowwise().replicate(n) - vec2.rowwise().replicate(n).transpose()).cwiseAbs2();

  VERIFY( find_pivot(tol, diffs) );
}

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  /* this test covers the following files:
     ComplexEigenSolver.h, and indirectly ComplexSchur.h
  */
  Index rows = m.rows();
  Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  MatrixType a = MatrixType::Random(rows,cols);
  MatrixType symmA =  a.adjoint() * a;

  ComplexEigenSolver<MatrixType> ei0(symmA);
  VERIFY_IS_EQUAL(ei0.info(), Success);
  VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());

  ComplexEigenSolver<MatrixType> ei1(a);
  VERIFY_IS_EQUAL(ei1.info(), Success);
  VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
  // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
  // another algorithm so results may differ slightly
  verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());

  ComplexEigenSolver<MatrixType> ei2;
  ei2.setMaxIterations(ComplexSchur<MatrixType>::m_maxIterationsPerRow * rows).compute(a);
  VERIFY_IS_EQUAL(ei2.info(), Success);
  VERIFY_IS_EQUAL(ei2.eigenvectors(), ei1.eigenvectors());
  VERIFY_IS_EQUAL(ei2.eigenvalues(), ei1.eigenvalues());
  if (rows > 2) {
    ei2.setMaxIterations(1).compute(a);
    VERIFY_IS_EQUAL(ei2.info(), NoConvergence);
    VERIFY_IS_EQUAL(ei2.getMaxIterations(), 1);
  }

  ComplexEigenSolver<MatrixType> eiNoEivecs(a, false);
  VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
  VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());

  // Regression test for issue #66
  MatrixType z = MatrixType::Zero(rows,cols);
  ComplexEigenSolver<MatrixType> eiz(z);
  VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());

  MatrixType id = MatrixType::Identity(rows, cols);
  VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));

  if (rows > 1 && rows < 20)
  {
    // Test matrix with NaN
    a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
    ComplexEigenSolver<MatrixType> eiNaN(a);
    VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
  }

  // regression test for bug 1098
  {
    ComplexEigenSolver<MatrixType> eig(a.adjoint() * a);
    eig.compute(a.adjoint() * a);
  }

  // regression test for bug 478
  {
    a.setZero();
    ComplexEigenSolver<MatrixType> ei3(a);
    VERIFY_IS_EQUAL(ei3.info(), Success);
    VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(),RealScalar(1));
    VERIFY((ei3.eigenvectors().transpose()*ei3.eigenvectors().transpose()).eval().isIdentity());
  }
}

template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m)
{
  ComplexEigenSolver<MatrixType> eig;
  VERIFY_RAISES_ASSERT(eig.eigenvectors());
  VERIFY_RAISES_ASSERT(eig.eigenvalues());

  MatrixType a = MatrixType::Random(m.rows(),m.cols());
  eig.compute(a, false);
  VERIFY_RAISES_ASSERT(eig.eigenvectors());
}

void test_eigensolver_complex()
{
  int s = 0;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( eigensolver(Matrix4cf()) );
    s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
    CALL_SUBTEST_2( eigensolver(MatrixXcd(s,s)) );
    CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
    CALL_SUBTEST_4( eigensolver(Matrix3f()) );
    TEST_SET_BUT_UNUSED_VARIABLE(s)
  }
  CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) );
  s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
  CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(s,s)) );
  CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()) );
  CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) );

  // Test problem size constructors
  CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf> tmp(s));

  TEST_SET_BUT_UNUSED_VARIABLE(s)
}


// SPDX-FileCopyrightText: 2015 - 2021 Marcin Łoś <marcin.los.91@gmail.com>
// SPDX-License-Identifier: MIT

#ifndef ADS_SIMULATION_DIMENSION_HPP
#define ADS_SIMULATION_DIMENSION_HPP

#include <boost/range/counting_range.hpp>

#include "ads/basis_data.hpp"
#include "ads/bspline/bspline.hpp"
#include "ads/form_matrix.hpp"
#include "ads/lin/band_matrix.hpp"
#include "ads/lin/band_solve.hpp"
#include "ads/simulation/config.hpp"
#include "ads/solver.hpp"
#include "ads/util.hpp"

namespace ads {

class dimension {
public:
    using element_range_type = decltype(boost::counting_range(0, 0));

    int p;
    int elements;
    double a;
    double b;
    bspline::basis B;
    lin::band_matrix M;
    basis_data basis;
    lin::solver_ctx ctx;

    dimension(bspline::basis basis, int quad_order, int derivatives, int elem_division = 1);

    dimension(const dim_config& config, int derivatives);

    int dofs() const { return B.dofs(); }

    element_range_type element_indices() const { return boost::counting_range(0, elements); }

    dim_data data() { return {M, ctx}; }

    void fix_dof(int k);

    void fix_left() { fix_dof(0); }

    void fix_right() {
        int last = dofs() - 1;
        fix_dof(last);
    }

    void factorize_matrix() { lin::factorize(M, ctx); }

private:
    static bspline::basis bspline_basis(const dim_config& config) {
        return bspline::create_basis(config.a, config.b, config.p, config.elements,
                                     config.repeated_nodes);
    }
};

}  // namespace ads

#endif  // ADS_SIMULATION_DIMENSION_HPP


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

  This source file is part of the Avogadro project.

  Copyright 2011-2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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.

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

#include <gtest/gtest.h>

#include <Eigen/Core>

TEST(EigenTest, vector3d)
{
  Eigen::Vector3d vec;
  vec.setZero();
  EXPECT_EQ(vec.x(), 0);
  EXPECT_EQ(vec.y(), 0);
  EXPECT_EQ(vec.z(), 0);
}


#define BOOST_TEST_MODULE cnnefTestMarray

#include <boost/test/unit_test.hpp>

#include <iostream>

#include "cnnef/tools/runtime_check.hxx"
#include "cnnef/marray/marray.hxx"

BOOST_AUTO_TEST_CASE(StridesTest)
{
    std::vector<size_t> shape({10,20});
    cnnef::marray::Marray<int> a(shape.begin(), shape.end());
    CNNEF_TEST_OP(a.strides(1),==,1);
    CNNEF_TEST_OP(a.strides(0),==,20);
}


#include "block.hpp"
#include <iostream>
#include <Eigen/Dense>
#include <ostream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace Eigen;

TetrisBlock::TetrisBlock(std::string name, int value, Matrix4f mask, Vector2f pivot){
    this_name = name;
    this_pivot = pivot;
    this_mask = mask;
    this_rotation_matrix << 0, -1, 1, 0;
    this_value = value;
};

Vector2f TetrisBlock::rotate_point(Vector2f point){
    return (this_rotation_matrix * (point - this_pivot)) + this_pivot;
}

Matrix4f TetrisBlock::rotate_mask(){
    Matrix4f new_mask = Matrix4f::Zero();
    int newx;
    int newy;
    auto handle_negative_index = [](int index){
			    if (index < 0){
			      index = 4 + index;
			    }
			    return index;
			  };

    for (int i=0; i < 4; i++){
      for (int j=0; j < 4; j++){
	if (this_mask(i, j) != 0){
	    Vector2f point;
	    point << i, j;
	    auto position = rotate_point(point);
	    newx = handle_negative_index(position(0));
	    newy = handle_negative_index(position(1));
	    new_mask(newx, newy) = this_value;
	  }
      }
    }
    return new_mask;
  }

void TetrisBlock::rotate(){
  this_mask = rotate_mask();
}

std::ostream & operator<<(std::ostream & flux, TetrisBlock const & block ){
  return flux << "\n" <<  "block : " << block.this_name << "\n" << "----------\n" << block.this_mask << "\n";
}

bool block_position_possible(int x, int y, const TetrisBlock &block, const MatrixXf &grid){
  /* Check if the block can be placed in the position (x,y), with (x,y) reprenting the left corner of the mask*/

  auto mask_block = block.this_mask.block(0, 0, 4, 4);
  auto grid_block = grid.block(y, x,  4, 4);
  auto bool_block = (mask_block.array() * grid_block.array()) != 0.0;
  return !(bool_block.any());
}

void add_block_to_grid(int x, int y, const TetrisBlock &block, MatrixXf &grid){
  /* Add the block to the grid. This function do some side effects on grid
   */
  auto mask_block = block.this_mask.block(0, 0, 4, 4);
  auto grid_block = grid.block(y, x,  4, 4);
  grid_block = mask_block + grid_block;
}

MatrixXf get_visualGrid(int x, int y, int visualNrows, int visualNcols, const TetrisBlock &block, MatrixXf grid, int top_padding, int left_padding){
  /* Return the visual grid wich is used to display the game to the player without showing the paddings blocks, it doesn't do any side effects*/
  auto mask_block = block.this_mask.block(0, 0, 4, 4);
  auto grid_block = grid.block(y, x,  4, 4);
  grid_block = mask_block + grid_block;

  auto visualGridBlock = grid.block(3, 3, visualNrows, visualNcols);
  MatrixXf newGrid (visualNrows, visualNcols);
  newGrid = visualGridBlock;
  return newGrid;
}

int next_one_index(int index, VectorXf col){
  for (int i =0; i < col.size(); i++){
    if (i > index){
      if (col(i) != 0){
	return i;
      }
    }
  }
  // if no values are found return a negative value;
  return -1;
}

bool is_line(VectorXf row) { return row.array().all(); }

std::vector<int> find_lines(const MatrixXf & grid, int padding){
  /* Return a vector of row indexes of completed lines*/
  std::vector<int> indexes;
  for (int i = 0; i < grid.rows() - padding; i++){

    if (is_line(grid.row(i))){
      indexes.push_back(i);
    }
  }
  return indexes;
}

VectorXf refactor_col(int line_index, VectorXf col){
  /* Construct a new column by destroying the line value and shifting the values to the next non-zero value (make the block "fall").*/

  int inext = next_one_index(line_index, col);
  VectorXf new_col(col.size());
  new_col << VectorXf::Zero(inext - line_index), col.head(line_index), col.tail(col.size() - inext);
  return new_col;
}

void delete_line(int line_index, MatrixXf &grid, int padding){
  /* Delete a line by refactoring all the columns of the grid who are not padding columns*/
  for (int j = padding; j < grid.cols() - padding; j++){
    auto col = grid.col(j);
    col = refactor_col(line_index, col);
  }
}

std::unordered_map<std::string, TetrisBlock> get_block_map(){
  std::unordered_map<std::string, TetrisBlock> map;

  // I, cyan
  Matrix4f Imask;
  Vector2f Ipivot;
  Imask << 0, 0, 0, 0,
    0, 0, 0, 0,
    1, 1, 1, 1,
    0, 0, 0, 0;

  Ipivot << 2, 1;
  map.insert({"I", TetrisBlock("I", 1, Imask, Ipivot)});

  //
  Matrix4f Omask;
  Vector2f Opivot;
  Omask << 0, 0, 0, 0,
    0, 0, 0, 0,
    0, 2, 2, 0,
    0, 2, 2, 0;

  Opivot << 2.5, 1.5;
  map.insert({"O", TetrisBlock("O", 2, Omask, Opivot)});

  Matrix4f Tmask;
  Vector2f Tpivot;
  Tmask << 0, 0, 0, 0,
    0, 0, 0, 0,
    3, 3, 3, 0,
    0, 3, 0, 0;

  Tpivot << 2, 1;
  map.insert({"T", TetrisBlock("T", 3, Tmask, Tpivot)});

  Matrix4f Lmask;
  Vector2f Lpivot;
  Lmask << 0, 0, 0, 0,
    0, 0, 0, 0,
    4, 4, 4, 0,
    4, 0, 0, 0;

  Lpivot << 2, 1;
  map.insert({"L", TetrisBlock("L", 4, Lmask, Lpivot)});

  Matrix4f Jmask;
  Vector2f Jpivot;
  Jmask << 0, 0, 0, 0,
    0, 0, 0, 0,
    5, 5, 5, 0,
    0, 0, 5, 0;

  Jpivot << 2, 1;
  map.insert({"J", TetrisBlock("J", 5, Jmask, Jpivot)});

  Matrix4f Zmask;
  Vector2f Zpivot;
  Zmask << 0, 0, 0, 0,
    6, 6, 0, 0,
    0, 6, 6, 0,
    0, 0, 0, 0;

  Zpivot << 2, 1;
  map.insert({"Z", TetrisBlock("Z", 6, Zmask, Zpivot)});

  Matrix4f Smask;
  Vector2f Spivot;
  Smask << 0, 0, 0, 0,
    0, 7, 7, 0,
    7, 7, 0, 0,
    0, 0, 0, 0;

  Spivot << 2, 1;
  map.insert({"S", TetrisBlock("S", 7, Smask, Spivot)});

  return map;

}


#include <boost/math/quadrature/sinh_sinh.hpp>


// Copyright (c) Dewetron 2017
#include "otfft.h"
#include "otfft_test_utils.h"

#include <boost/test/unit_test.hpp>

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <vector>

namespace
{
    std::size_t findPeak(const std::size_t fft_length, const double sample_rate, const double signal_frequency)
    {
        OTFFT::test::SineGenerator generator(sample_rate);
        generator.setAmplitude(64).setFrequency(signal_frequency).generate(fft_length);

        std::vector<OTFFT::complex_t> spectrum(fft_length);
        {
            auto fft = OTFFT::Factory::createRealFFT(static_cast<int>(fft_length));
            OTFFT::double_vector fft_in{generator.data()};
            OTFFT::complex_vector fft_out{spectrum.data()};
            fft->fwd(fft_in, fft_out);
        }

        auto peakPos = std::max_element(
                           std::begin(spectrum),
                           std::begin(spectrum) + fft_length / 2,
                           [] (OTFFT::complex_t x, OTFFT::complex_t y) -> bool
                           {
                               return std::sqrt(OTFFT::norm(x)) < std::sqrt(OTFFT::norm(y));
                           }
                       );

        std::size_t d = std::distance(std::begin(spectrum), peakPos);

        return d;
    }
}

BOOST_AUTO_TEST_SUITE(otfft_find_peak_test)

BOOST_AUTO_TEST_CASE(TestSinePeakDetect1)
{
    const auto peak_position = findPeak(64, 10000, 1000);
    BOOST_CHECK_EQUAL(6u, peak_position);
}

BOOST_AUTO_TEST_CASE(TestSinePeakDetect2)
{
    const auto peak_position = findPeak(1024, 10000, 50);
    BOOST_CHECK_EQUAL(5u, peak_position);
}

BOOST_AUTO_TEST_CASE(TestSinePeakDetect3)
{
    const auto peak_position = findPeak(8192, 50000, 4999);
    BOOST_CHECK_EQUAL(819u, peak_position);
}

BOOST_AUTO_TEST_CASE(TestSinePeakDetect4)
{
    const auto peak_position = findPeak(262144, 1000000, 60000);
    BOOST_CHECK_EQUAL(15729u, peak_position);
}

BOOST_AUTO_TEST_CASE(TestSinePeakDetect5)
{
    const auto peak_position = findPeak(32, 512, 1);
    BOOST_CHECK_EQUAL(0u, peak_position);
}

BOOST_AUTO_TEST_SUITE_END()


/*
// Copyright 2018 University of Liege
//
// 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.
//
// Authors:
// - Adrien Crovato
*/

//// Surface variables computation
// Compute flow physical properties such as body velocity, mach number, pressure and forces coefficients.
//
// I/O:
// - symY: defines symmetry about Y axis
// - sRef: reference surface of the full wing
// - alpha: freestream angle of attack
// - Minf: freestream Mach number
// - vInf: freestream velocity vector
// - vSigma: field source induced body velocity
// - bPan: (network of) body panels (structure)
// - cL: lift coefficient
// - cD: drag coefficient

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

#include "compute_sVars.h"

#define NDIM 3
#define GAMMA 1.4

using namespace std;
using namespace Eigen;

void compute_sVars(bool symY, double sRef, double alpha, double Minf, Vector3d &vInf,
               MatrixX3d &vSigma, Network &bPan, double &cL, double &cD) {

    // Temporary variables
    int panIdx = 0;
    double deltaL1, deltaL2, deltaT1, deltaT2;
    double u = 0, v = 0, w = 0;
    double cX = 0, cZ = 0;

    //// Begin
    cout << "Computing surface variables... ";

    // Resize matrices
    bPan.U = MatrixX3d::Zero(bPan.nP, NDIM);
    bPan.cP.resize(bPan.nP);

    //// Velocity computation
    // Surface induced velocity
    for (int j = 0; j < bPan.nS_; ++j) {
        for (int i = 0; i < bPan.nC_; ++i) {

            // Longitudinal
            if (i == 0) { // Forward differencing
                deltaL2 = (bPan.CG.row(panIdx + 1) - bPan.CG.row(panIdx)).norm();
                u = (bPan.mu(panIdx + 1) - bPan.mu(panIdx)) / deltaL2;
            }
            else if (i == bPan.nC_ - 1) { // Backward differencing
                deltaL1 = (bPan.CG.row(panIdx) - bPan.CG.row(panIdx - 1)).norm();
                u = (bPan.mu(panIdx) - bPan.mu(panIdx - 1)) / deltaL1;
            }
            else { // Central differencing
                deltaL1 = (bPan.CG.row(panIdx) - bPan.CG.row(panIdx - 1)).norm();
                deltaL2 = (bPan.CG.row(panIdx + 1) - bPan.CG.row(panIdx)).norm();
                u = 0.5 * ((bPan.mu(panIdx + 1) - bPan.mu(panIdx)) / deltaL2 +
                           (bPan.mu(panIdx) - bPan.mu(panIdx - 1)) / deltaL1);
            }
            // Transverse
            if (j == 0) { // Forward differencing
                deltaT2 = (bPan.CG.row(panIdx + bPan.nC_) - bPan.CG.row(panIdx)).norm();
                v = (bPan.mu(panIdx + bPan.nC_) - bPan.mu(panIdx)) / deltaT2;
            }
            else if (j == bPan.nS_ - 1) { // Backward differencing
                deltaT1 = (bPan.CG.row(panIdx) - bPan.CG.row(panIdx - bPan.nC_)).norm();
                v = (bPan.mu(panIdx) - bPan.mu(panIdx - bPan.nC_)) / deltaT1;
            }
            else { // Central differencing
                deltaT1 = (bPan.CG.row(panIdx) - bPan.CG.row(panIdx - bPan.nC_)).norm();
                deltaT2 = (bPan.CG.row(panIdx + bPan.nC_) - bPan.CG.row(panIdx)).norm();
                v = 0.5 * ((bPan.mu(panIdx + bPan.nC_) - bPan.mu(panIdx)) / deltaT2 +
                           (bPan.mu(panIdx) - bPan.mu(panIdx - bPan.nC_)) / deltaT1);
            }

            // Transverse to perpendicular velocity
            v = (bPan.t(panIdx, 0) * bPan.p(panIdx, 0)
                 + bPan.t(panIdx, 1) * bPan.p(panIdx, 1)
                 + bPan.t(panIdx, 2) * bPan.p(panIdx, 2)) * v;
            // Normal velocity
            w = bPan.tau(panIdx);

            // Transformation to global axis
            bPan.U(panIdx, 0) = u * bPan.l(panIdx, 0) - v * bPan.p(panIdx, 0) + w * bPan.n(panIdx, 0);
            bPan.U(panIdx, 1) = u * bPan.l(panIdx, 1) - v * bPan.p(panIdx, 1) + w * bPan.n(panIdx, 1);
            bPan.U(panIdx, 2) = u * bPan.l(panIdx, 2) - v * bPan.p(panIdx, 2) + w * bPan.n(panIdx, 2);

            panIdx++;
        }
    }
    // Freestream velocity
    for (int i = 0; i < bPan.nP; ++i) {
        bPan.U(i, 0) += vInf(0);
        bPan.U(i, 1) += vInf(1);
        bPan.U(i, 2) += vInf(2);
    }
    // Source induced velocity
    if (Minf != 0)
        bPan.U += vSigma;
    // Mach number
    if (Minf == 0)
        bPan.M = VectorXd::Zero(bPan.nP);
    else {
        bPan.M.resize(bPan.nP);
        for (int i = 0; i < bPan.nP; ++i)
            bPan.M(i) = bPan.U.row(i).norm()
                        / (1 / (Minf * Minf)
                           + (GAMMA - 1) / 2 - (GAMMA - 1) / 2 * bPan.U.row(i).dot(bPan.U.row(i)));
    }
    //// Aerodynamic forces
    // Pressure coefficient
    if (Minf == 0) {
        for (int i = 0; i < bPan.nP; ++i)
            bPan.cP(i) = 1 - bPan.U.row(i).dot(bPan.U.row(i)) / vInf.dot(vInf);
    }
    else {
        for (int i = 0; i < bPan.nP; ++i)
            bPan.cP(i) = 2 / (GAMMA * Minf * Minf) *
                (pow(1 + (GAMMA - 1) / 2 * Minf * Minf *
                                 (1 - bPan.U.row(i).dot(bPan.U.row(i))), GAMMA / (GAMMA - 1)) - 1);
    }
    // Forces (x,y,z)
    for (int i = 0; i < bPan.nP; ++i) {
        cX += -bPan.cP(i) * bPan.S(i) / sRef * bPan.n(i,0);
        cZ += -bPan.cP(i) * bPan.S(i) / sRef * bPan.n(i,2);
    }
    if (symY) {
        cX = 2*cX;
        cZ = 2*cZ;
    }
    // Forces (l,d,y)
    cD = cos(alpha)*cX + sin(alpha)*cZ;
    cL = -sin(alpha)*cX + cos(alpha)*cZ;

    //// Control display
    cout << "Done!" << endl;
    #ifdef VERBOSE
        cout << "Surface velocities: " << bPan.U.rows() << "X" << bPan.U.cols() << endl;
        for (int i = 0; i < bPan.nP; ++i)
            cout << i << ' ' << bPan.U(i,0) << ' ' << bPan.U(i,1) << ' ' << bPan.U(i,2) << endl;
        cout << "Pressure coefficients: " << bPan.cP.rows() << "X" << bPan.cP.cols() << endl;
        for (int i = 0; i < bPan.nP; ++i)
            cout << i << ' ' << bPan.cP(i) << endl;
    #endif
    cout << "Aerodynamic forces:" << endl;
    cout << "Cx = " << cX << endl;
    cout << "Cz = " << cZ << endl;
    cout << "Cl = " << cL << endl;
    cout << "Cd = " << cD << endl;
    cout << "L/D = " << cL/cD << endl << endl;
}


//  Copyright (c) 2015 John Maddock
//  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)

#ifndef BOOST_MATH_ELLINT_HL_HPP
#define BOOST_MATH_ELLINT_HL_HPP

#ifdef _MSC_VER
#pragma once
#endif

#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/jacobi_zeta.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>

// Elliptic integral the Jacobi Zeta function.

namespace boost { namespace math {

namespace detail{

// Elliptic integral - Jacobi Zeta
template <typename T, typename Policy>
T heuman_lambda_imp(T phi, T k, const Policy& pol)
{
    BOOST_MATH_STD_USING
    using namespace boost::math::tools;
    using namespace boost::math::constants;

    const char* function = "boost::math::heuman_lambda<%1%>(%1%, %1%)";

    if(fabs(k) > 1)
       return policies::raise_domain_error<T>(function, "We require |k| <= 1 but got k = %1%", k, pol);

    T result;
    T sinp = sin(phi);
    T cosp = cos(phi);
    T s2 = sinp * sinp;
    T k2 = k * k;
    T kp = 1 - k2;
    T delta = sqrt(1 - (kp * s2));
    if(fabs(phi) <= constants::half_pi<T>())
    {
       result = kp * sinp * cosp / (delta * constants::half_pi<T>());
       result *= ellint_rf_imp(T(0), kp, T(1), pol) + k2 * ellint_rj(T(0), kp, T(1), T(1 - k2 / (delta * delta)), pol) / (3 * delta * delta);
    }
    else
    {
       T rkp = sqrt(kp);
       T ratio;
       if(rkp == 1)
       {
          return policies::raise_domain_error<T>(function, "When 1-k^2 == 1 then phi must be < Pi/2, but got phi = %1%", phi, pol);
       }
       else
          ratio = ellint_f_imp(phi, rkp, pol) / ellint_k_imp(rkp, pol);
       result = ratio + ellint_k_imp(k, pol) * jacobi_zeta_imp(phi, rkp, pol) / constants::half_pi<T>();
    }
    return result;
}

} // detail

template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type heuman_lambda(T1 k, T2 phi, const Policy& pol)
{
   typedef typename tools::promote_args<T1, T2>::type result_type;
   typedef typename policies::evaluation<result_type, Policy>::type value_type;
   return policies::checked_narrowing_cast<result_type, Policy>(detail::heuman_lambda_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::heuman_lambda<%1%>(%1%,%1%)");
}

template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type heuman_lambda(T1 k, T2 phi)
{
   return boost::math::heuman_lambda(k, phi, policies::policy<>());
}

}} // namespaces

#endif // BOOST_MATH_ELLINT_D_HPP


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

#include "irls.h"
#include "input_validation.h"
#include "disclap_family.h"
#include "beta.h"

using namespace Eigen;

void check_input(const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w, VectorXd& beta, size_t maxit, bool use_deviance, double eps_deviance, bool use_beta, double eps_beta) {
  check_common_input(maxit, use_deviance, eps_deviance, use_beta, eps_beta);
  check_d_w(d, w);
  check_beta(beta, d, w);
}

void update_lin_pred(VectorXd& lin_pred, const VectorXd& beta_ext, size_t individuals, size_t clusters, size_t loci) {
  size_t idx = 0;

  for (size_t k = 0; k < loci; k++) {
    double b_k = beta_ext[clusters + k];

    for (size_t j = 0; j < clusters; j++) {
      double b_j = beta_ext[j];

      double bj_bk = b_j + b_k;

      for (size_t i = 0; i < individuals; i++) {
        lin_pred[idx] = bj_bk;
        idx += 1;
      }
    }
  }
}

bool deviance_converged(const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w,
  bool& deviance_calculated,
  VectorXd& lin_pred, const VectorXd& beta, double& deviance, double& old_deviance, double eps_deviance,
  size_t individuals, size_t clusters, size_t loci, bool verbose) {

  VectorXd beta_ext = get_beta_extended(beta);

  update_lin_pred(lin_pred, beta_ext, individuals, clusters, loci);

  double dev = 0;

  for (size_t i = 0; i < individuals; i++) {
    MatrixXi d_i = d[i];
    MatrixXd w_i = w[i];

    for (size_t j = 0; j < clusters; j++) {
      double b_j = beta_ext[j];

      for (size_t k = 0; k < loci; k++) {
        double b_k = beta_ext[clusters + k];

        double eta = b_j + b_k;
        double mu = linkinv(eta);
        int d_ele = d_i(j, k);

        double dev_contrib = 0.0;

        if (d_ele == 0) {
          // y == 0: dev = 2*log((1+p)/(1-p))
          double p = (mu < 1e-6) ? 0.5 * mu : (sqrt(1.0 + mu * mu) - 1.0) / mu;
          dev_contrib = 2 * log((1.0 + p) / (1.0 - p));
        } else {
          // y != 0
          double d_ele_double = (double)d_ele;
          dev_contrib = 2 * (loglikeh(d_ele_double, d_ele_double) - loglikeh(mu, d_ele_double));
        }

        dev_contrib *= w_i(j, k);
        dev += dev_contrib;
      }
    }
  }

  old_deviance = deviance;
  deviance = dev;
  deviance_calculated = true;

  double c = std::abs(dev - old_deviance)/(0.1 + std::abs(dev));

  if (verbose) {
    OUTPUT << "      Deviance convergence investigation:" << std::endl;
    OUTPUT << "        deviance     = " << dev << std::endl;
  }

  if (c < eps_deviance) {
    if (verbose) {
      OUTPUT << "        criteria     = " << c << " < " << eps_deviance << " [CONVERGENCE]" << std::endl;
    }

    return true;
  }

  if (verbose) {
    OUTPUT << "        criteria     = " << c << " >= " << eps_deviance << std::endl;
  }

  return false;
}

bool beta_converged(const VectorXd& beta, const VectorXd& old_beta, double eps_beta, bool verbose) {
  VectorXd den = 0.1 + beta.cwiseAbs().array();
  VectorXd diff = beta - old_beta;

  double c = diff.cwiseAbs().cwiseQuotient(den).maxCoeff();

  if (verbose) {
    OUTPUT << "      Beta convergence investigation:" << std::endl;
    OUTPUT << "        beta         = " << beta.transpose() << std::endl;
  }

  if (c < eps_beta) {
    if (verbose) {
      OUTPUT << "        criteria     = " << c << " < " << eps_beta << " [CONVERGENCE]" << std::endl;
    }

    return true;
  }

  if (verbose) {
    OUTPUT << "        criteria     = " << c << " >= " << eps_beta << std::endl;
  }

  return false;
}

void fill_generics(size_t clusters, size_t loci, VectorXd& beta_ext,
  MatrixXd& lin_pred_generic, MatrixXd& mu_generic) {

  for (size_t j = 0; j < clusters; j++) {
    double beta_j = beta_ext[j];

    for (size_t k = 0; k < loci; k++) {
      double eta = beta_j + beta_ext[clusters + k];
      lin_pred_generic(j, k) = eta;
      mu_generic(j, k) = linkinv(eta);
    }
  }
}

void fill_H_ab(size_t individuals, size_t clusters, size_t loci,
  const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w,
  const MatrixXd& mu_generic,
  MatrixXd& H, MatrixXd& ab) {

  for (size_t i = 0; i < individuals; i++) {
    MatrixXi d_i = d[i];
    MatrixXd w_i = w[i];

    for (size_t j = 0; j < clusters; j++) {
      for (size_t k = 0; k < loci; k++) {
        double mu_generic_jk = mu_generic(j, k);
        double w_ijk = w_i(j, k);

        // H
        double psi_jk = w_ijk * varfunc(mu_generic_jk);
        H(j, k) += psi_jk;

        // ab
        double d_mu_res = d_i(j, k) - mu_generic_jk;
        ab(j, k) += w_ijk * d_mu_res;
      }
    }
  }
}

/*
void fill_H_ab(size_t individuals, size_t clusters, size_t loci,
  const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w,
  const MatrixXd& mu_generic,
  MatrixXd& H, MatrixXd& ab) {

  // varfunc(double mu) = mu * sqrt(1.0 + mu*mu)
  MatrixXd mu_1_sq = mu_generic.array().square() + 1;
  MatrixXd mu_sqrt_1_sq = mu_1_sq.cwiseSqrt();
  MatrixXd mu_varfunc = mu_generic.cwiseProduct(mu_sqrt_1_sq);

  for (size_t i = 0; i < individuals; i++) {
    MatrixXi d_i = d[i];
    MatrixXd w_i = w[i];
    MatrixXd d_mu = d_i.cast<double>().array() - mu_generic.array();

    H = H.array() + w_i.cwiseProduct(mu_varfunc).array();
    ab = ab.array() + w_i.cwiseProduct(d_mu).array();
  }
}
*/

void update_beta(const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w, VectorXd& beta,
  MatrixXd& vcov,
  size_t individuals, size_t clusters, size_t loci, bool verbose) {

  VectorXd beta_ext = get_beta_extended(beta);
  MatrixXd lin_pred_generic(clusters, loci);
  MatrixXd mu_generic(clusters, loci);
  fill_generics(clusters, loci, beta_ext, lin_pred_generic, mu_generic);

  MatrixXd H = MatrixXd::Zero(clusters, loci);
  MatrixXd ab = MatrixXd::Zero(clusters, loci);
  fill_H_ab(individuals, clusters, loci, d, w, mu_generic, H, ab);

  VectorXd Drvec_raw = H.colwise().sum();
  VectorXd Drvec(loci - 1);
  for (size_t k = 0; k < (loci - 1); k++) {
    Drvec[k] = Drvec_raw[k];
  }
  MatrixXd Dr = Drvec.asDiagonal();

  VectorXd Dcinvvec(clusters);
  for (size_t j = 0; j < clusters; j++) {
    Dcinvvec[j] = 1 / H.row(j).sum();
  }
  MatrixXd Dcinv = Dcinvvec.asDiagonal();

  H.conservativeResize(NoChange, loci - 1);

  MatrixXd E = Dr - H.transpose() * Dcinv * H;
  MatrixXd Einv = E.lu().solve(MatrixXd::Identity(loci - 1, loci - 1));
  MatrixXd F = Dcinv * H;
  MatrixXd Ft = F.transpose();

  /*
  OUTPUT << "H:" << std::endl << H << std::endl;
  OUTPUT << "Dr:" << std::endl << Dr << std::endl;
  OUTPUT << "Dcinv:" << std::endl << Dcinv << std::endl;
  OUTPUT << "E:" << std::endl << E << std::endl;
  OUTPUT << "Einv:" << std::endl << Einv << std::endl;
  OUTPUT << "F:" << std::endl << F << std::endl;
  OUTPUT << "Ft:" << std::endl << Ft << std::endl;
  */

  MatrixXd P = MatrixXd::Zero(clusters + loci - 1, clusters + loci - 1);
  P.topLeftCorner(clusters, clusters) = Dcinv + (F * Einv) * Ft;
  P.topRightCorner(clusters, loci - 1) = -F * Einv;
  P.bottomLeftCorner(loci - 1, clusters) = -Einv * Ft;
  P.bottomRightCorner(loci - 1, loci - 1) = Einv;

  vcov = P;

  VectorXd a = ab.rowwise().sum();
  VectorXd b = ab.colwise().sum();
  VectorXd gamma(clusters + loci - 1);

  for (size_t j = 0; j < clusters; j++) {
    gamma[j] = a[j];
  }

  for (size_t k = 0; k < (loci - 1); k++) {
    gamma[clusters + k] = b[k];
  }

  VectorXd beta_correction = P * gamma;

  beta = beta + beta_correction;
}

/*
// iter >= ensures old_deviance has been calculated
if (deviance_calculated && iter >= 2 && !isinf(old_deviance) && old_deviance < dev) {
  OUTPUT << "old_deviance = " << old_deviance << std::endl;
  OUTPUT << "dev          = " << dev << std::endl;
  throw "Deviance increased! Normally step-halving would be tried, but it has yet to be implemented...";
}
*/

/*
Returns true if converged, false otherwise
*/
bool irls(const std::vector<MatrixXi>& d, const std::vector<MatrixXd>& w,
  VectorXd& beta, VectorXd& lin_pred,
  MatrixXd& vcov,
  double& deviance, size_t& iterations,
  bool verbose = true, size_t maxit = 25,
  bool use_deviance = true, double eps_deviance = 1e-6,
  bool use_beta = true, double eps_beta = 1e-6,
  bool force_calculate_deviance = false) {

  check_input(d, w, beta, maxit, use_deviance, eps_deviance, use_beta, eps_beta);

  assert(maxit > 0);
  assert(!use_deviance || (use_deviance && eps_deviance > 0));
  assert(!use_beta || (use_beta && eps_beta > 0));

  size_t individuals = d.size();
  assert(individuals > 0);
  assert(w.size() == individuals);

  size_t clusters = d.at(0).rows();
  size_t loci = d.at(0).cols();

  bool converged = false;

  bool deviance_calculated = false;
  double dev = std::numeric_limits<double>::infinity();
  double old_deviance = std::numeric_limits<double>::infinity();

  VectorXd start_beta = VectorXd(beta);

  VectorXd old_beta(beta.size());
  for (size_t idx = 0; idx < old_beta.size(); idx++) {
    old_beta[idx] = std::numeric_limits<double>::infinity();
  }

  if (verbose) {
    OUTPUT << "    Initial coefficients = " << beta.transpose() << std::endl;
  }

  iterations = 0;

  for (size_t iter = 0; iter < maxit; iter++) {
    iterations = iterations + 1;

    if (verbose) {
      OUTPUT << "    IRLS iteration " << (iter + 1) << std::endl;
    }

    if (use_deviance && use_beta) {
      bool beta_conv = beta_converged(beta, old_beta, eps_beta, verbose);

      if (beta_conv) {
        bool dev_conv = deviance_converged(d, w, deviance_calculated, lin_pred, beta, dev, old_deviance, eps_deviance, individuals, clusters, loci, verbose);

        if (dev_conv) {
          converged = true;
          break;
        }
      }
    } else if (use_deviance) {
      bool dev_conv = deviance_converged(d, w, deviance_calculated, lin_pred, beta, dev, old_deviance, eps_deviance, individuals, clusters, loci, verbose);

      if (dev_conv) {
        converged = true;
        break;
      }
    } else if (use_beta) {
      bool beta_conv = beta_converged(beta, old_beta, eps_beta, verbose);

      if (beta_conv) {
        converged = true;
        break;
      }
    } else {
      throw "Unexpected error (!use_deviance && !use_beta)";
    }

    old_beta = beta;
    update_beta(d, w, beta, vcov, individuals, clusters, loci, verbose);

    #if defined(DISCLAPMIX_USED_IN_R)
    R_CheckUserInterrupt();
    #endif
  }

  if (!deviance_calculated) {
    if (force_calculate_deviance) {
      deviance_converged(d, w, deviance_calculated, lin_pred, beta, dev, old_deviance, eps_deviance, individuals, clusters, loci, false);
    }
  }

  deviance = dev;

  return converged;
}