/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */

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

#include <boost/numeric/ublas/fwd.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_expression.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_expression.hpp>
#include <boost/numeric/ublasx/operation/max.hpp>
#include <boost/numeric/ublasx/tags.hpp>
#include <complex>
#include <cstddef>
#include <functional>
#include <iostream>
#include "libs/numeric/ublasx/test/utils.hpp"

static const double tol = 1.0e-5;

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

BOOST_UBLASX_TEST_DEF( real_vector )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Real Vector" );

    typedef double value_type;
    typedef ublas::vector<value_type> vector_type;

    vector_type v(5);

    v(0) = 0.0;
    v(1) = 0.108929;
    v(2) = 0.0;
    v(3) = 0.0;
    v(4) = 1.023787;

    value_type expect(0);
    value_type res(0);
    ublas::vector<value_type> vexpect(0);
    ublas::vector<value_type> vres(0);

    // max(v)
    expect = value_type(1.023787);
    res = ublasx::max(v);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << v << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max<1>(v)
    vexpect = ublas::vector<value_type>(1, 1.023787);
    vres = ublasx::max<1>(v);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << v << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, 1, tol );
}

BOOST_UBLASX_TEST_DEF( complex_vector )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Complex Vector" );

    typedef double real_type;
    typedef ::std::complex<real_type> value_type;
    typedef ublas::vector<value_type> vector_type;

    vector_type v(5);

    v(0) = value_type( 0.000000,-0.54000);
    v(1) = value_type(-0.108929, 2.43000);
    v(2) = value_type( 0.000000, 1.00030);
    v(3) = value_type(-0.050000, 1.00030);
    v(4) = value_type( 1.023787,-4.24959);

    value_type expect(0);
    value_type res(0);
    ublas::vector<value_type> vexpect(0);
    ublas::vector<value_type> vres(0);

    // max(v)
    expect = value_type(1.023787,-4.24959);
    res = ublasx::max(v);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << v << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max<1>(v)
    vexpect = ublas::vector<value_type>(1, value_type( 1.023787,-4.24959));
    vres = ublasx::max<1>(v);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << v << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, 1, tol );
}

BOOST_UBLASX_TEST_DEF( vector_container )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Vector Container" );

    typedef double value_type;
    typedef ublas::vector<value_type> vector_type;
    typedef ublas::zero_vector<value_type> zero_vector_type;

    vector_type v(5);

    v(0) = 0.0;
    v(1) = 0.108929;
    v(2) = 0.0;
    v(3) = 0.0;
    v(4) = 1.023787;

    zero_vector_type z(5);

    value_type expect(0);
    value_type res(0);
    ublas::vector<value_type> vexpect(0);
    ublas::vector<value_type> vres(0);

    // max(z)
    expect = value_type(0);
    res = ublasx::max(z);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << z << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK( res == expect );

    // max(v)
    expect = value_type(1.023787);
    res = ublasx::max(v);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << v << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max<1>(v)
    vexpect = ublas::vector<value_type>(1, 1.023787);
    vres = ublasx::max<1>(v);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << v << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, 1, tol );
}

BOOST_UBLASX_TEST_DEF( vector_expression )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Vector Expression" );

    typedef double value_type;
    typedef ublas::vector<value_type> vector_type;

    vector_type v(5);

    v(0) = 0.0;
    v(1) = 0.108929;
    v(2) = 0.0;
    v(3) = 0.0;
    v(4) = 1.023787;

    value_type expect(0);
    value_type res(0);
    ublas::vector<value_type> vexpect(0);
    ublas::vector<value_type> vres(0);

    // max(-v)
    expect = value_type(0);
    res = ublasx::max(-v);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << -v << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max<1>(-v)
    vexpect = ublas::vector<value_type>(1, 0);
    vres = ublasx::max<1>(-v);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << -v << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, 1, tol );
}

BOOST_UBLASX_TEST_DEF( vector_reference )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Vector Reference" );

    typedef double value_type;
    typedef ublas::vector<value_type> vector_type;
    typedef ublas::vector_reference<vector_type> vector_reference_type;

    vector_type v(5);

    v(0) = 0.0;
    v(1) = 0.108929;
    v(2) = 0.0;
    v(3) = 0.0;
    v(4) = 1.023787;

    value_type expect(0);
    value_type res(0);
    ublas::vector<value_type> vexpect(0);
    ublas::vector<value_type> vres(0);

    // max(ref(v))
    expect = value_type(1.023787);
    res = ublasx::max(vector_reference_type(v));
    BOOST_UBLASX_DEBUG_TRACE( "max(" << vector_reference_type(v) << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max<1>(ref(v))
    vexpect = ublas::vector<value_type>(1, 1.023787);
    vres = ublasx::max<1>(vector_reference_type(v));
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << vector_reference_type(v) << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, 1, tol );
}

BOOST_UBLASX_TEST_DEF( real_matrix )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Real Matrix" );

    typedef double value_type;
    typedef ublas::matrix<value_type> matrix_type;
    typedef ublas::vector<value_type> vector_type;

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = 0.0;      A(0,1) = 0.274690; A(0,2) = 0.0;      A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.0;      A(1,2) = 0.891726; A(1,3) = 0.0;
    A(2,0) = 0.0;      A(2,1) = 0.0;      A(2,2) = 0.0;      A(2,3) = 0.0;
    A(3,0) = 0.0;      A(3,1) = 0.675382; A(3,2) = 0.0;      A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.0;      A(4,2) = 1.231751; A(4,3) = 1.0;

    vector_type max_rows(nr);
    max_rows(0) = 0.798938;
    max_rows(1) = 0.891726;
    max_rows(2) = 0;
    max_rows(3) = 0.675382;
    max_rows(4) = 1.231751;

    vector_type max_cols(nc);
    max_cols(0) = 1.023787;
    max_cols(1) = 1.0;
    max_cols(2) = 1.231751;
    max_cols(3) = 1.0;

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(A)
    expect = value_type(1.231751);
    res = ublasx::max(A);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << A << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max_rows(A)
    vexpect = max_rows;
    vres = ublasx::max_rows(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(A)
    vexpect = max_cols;
    vres = ublasx::max_columns(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(A)
    vexpect = max_rows;
    vres = ublasx::max<1>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(A)
    vexpect = max_cols;
    vres = ublasx::max<2>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(A)
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::major>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );
}

BOOST_UBLASX_TEST_DEF( complex_matrix )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Complex Matrix" );

    typedef double real_type;
    typedef ::std::complex<real_type> value_type;
    typedef ublas::matrix<value_type> matrix_type;
    typedef ublas::vector<value_type> vector_type;

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = value_type( 0.000000,-1.000000); A(0,1) = value_type(0.274690, 1.231751); A(0,2) = value_type(0.090000, 0.108929); A(0,3) = value_type(0.798938,1.000000);
    A(1,0) = value_type( 0.108929, 0.450332); A(1,1) = value_type(0.000000, 1.400000); A(1,2) = value_type(0.891726, 1.023787); A(1,3) = value_type(0.000000,1.230000);
    A(2,0) = value_type(-0.500000, 0.500000); A(2,1) = value_type(0.000000, 2.100000); A(2,2) = value_type(0.090000,-1.230000); A(2,3) = value_type(0.000000,0.675382);
    A(3,0) = value_type( 0.000000,-0.500000); A(3,1) = value_type(0.675382,-1.230000); A(3,2) = value_type(0.090000, 1.231751); A(3,3) = value_type(0.450332,0.891726);
    A(4,0) = value_type( 1.023787, 0.798938); A(4,1) = value_type(1.000000, 0.891726); A(4,2) = value_type(1.231751, 0.000000); A(4,3) = value_type(1.000000,0.500000);

    vector_type max_rows(nr);
    max_rows(0) = value_type(0.798938, 1.000000);
    max_rows(1) = value_type(0.000000, 1.400000);
    max_rows(2) = value_type(0.000000, 2.100000);
    max_rows(3) = value_type(0.675382,-1.230000);
    max_rows(4) = value_type(1.000000, 0.891726);

    vector_type max_cols(nc);
    max_cols(0) = value_type(1.023787,0.798938);
    max_cols(1) = value_type(0.000000,2.100000);
    max_cols(2) = value_type(0.891726,1.023787);
    max_cols(3) = value_type(0.798938,1.000000);

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(A)
    expect = value_type(0.000000,2.100000);
    res = ublasx::max(A);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << A << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max_rows(A)
    vexpect = max_rows;
    vres = ublasx::max_rows(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(A)
    vexpect = max_cols;
    vres = ublasx::max_columns(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(A)
    vexpect = max_rows;
    vres = ublasx::max<1>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(A)
    vexpect = max_cols;
    vres = ublasx::max<2>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(A)
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::major>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );
}

BOOST_UBLASX_TEST_DEF( row_major_matrix_container )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Row-major Matrix Container" );

    typedef double value_type;
    typedef ublas::matrix<value_type, ublas::row_major> matrix_type;
    typedef ublas::zero_matrix<value_type> zero_matrix_type;
    typedef ublas::vector<value_type> vector_type;

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = 0.0;      A(0,1) = 0.274690; A(0,2) = 0.0;      A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.0;      A(1,2) = 0.891726; A(1,3) = 0.0;
    A(2,0) = 0.0;      A(2,1) = 0.0;      A(2,2) = 0.0;      A(2,3) = 0.0;
    A(3,0) = 0.0;      A(3,1) = 0.675382; A(3,2) = 0.0;      A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.0;      A(4,2) = 1.231751; A(4,3) = 1.0;

    zero_matrix_type Z(nr, nc);

    vector_type max_rows(nr);
    max_rows(0) = 0.798938;
    max_rows(1) = 0.891726;
    max_rows(2) = 0;
    max_rows(3) = 0.675382;
    max_rows(4) = 1.231751;

    vector_type max_cols(nc);
    max_cols(0) = 1.023787;
    max_cols(1) = 1.0;
    max_cols(2) = 1.231751;
    max_cols(3) = 1.0;

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(Z)
    expect = value_type(0);
    res = ublasx::max(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << Z << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK( res == expect );

    // max_rows(Z)
    vexpect = ublas::vector<value_type>(nr, 0);
    vres = ublasx::max_rows(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(Z)
    vexpect = ublas::vector<value_type>(nc, 0);
    vres = ublasx::max_columns(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(Z)
    vexpect = ublas::vector<value_type>(nr, 0);
    vres = ublasx::max<1>(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(Z)
    vexpect = ublas::vector<value_type>(nc, 0);
    vres = ublasx::max<2>(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(Z)
    vexpect = ublas::vector<value_type>(nr, 0);
    vres = ublasx::max_by_tag<ublasx::tag::major>(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(Z)
    vexpect = ublas::vector<value_type>(nc, 0);
    vres = ublasx::max_by_tag<ublasx::tag::minor>(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(Z)
    vexpect = ublas::vector<value_type>(nc, 0);
    vres = ublasx::max_by_tag<ublasx::tag::leading>(Z);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << Z << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max(A)
    expect = value_type(1.231751);
    res = ublasx::max(A);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << A << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max_rows(A)
    vexpect = max_rows;
    vres = ublasx::max_rows(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(A)
    vexpect = max_cols;
    vres = ublasx::max_columns(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(A)
    vexpect = max_rows;
    vres = ublasx::max<1>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(A)
    vexpect = max_cols;
    vres = ublasx::max<2>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(A)
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::major>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );
}

BOOST_UBLASX_TEST_DEF( col_major_matrix_container )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Column-major Matrix Container" );

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

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = 0.0;      A(0,1) = 0.274690; A(0,2) = 0.0;      A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.0;      A(1,2) = 0.891726; A(1,3) = 0.0;
    A(2,0) = 0.0;      A(2,1) = 0.0;      A(2,2) = 0.0;      A(2,3) = 0.0;
    A(3,0) = 0.0;      A(3,1) = 0.675382; A(3,2) = 0.0;      A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.0;      A(4,2) = 1.231751; A(4,3) = 1.0;

    vector_type max_rows(nr);
    max_rows(0) = 0.798938;
    max_rows(1) = 0.891726;
    max_rows(2) = 0;
    max_rows(3) = 0.675382;
    max_rows(4) = 1.231751;

    vector_type max_cols(nc);
    max_cols(0) = 1.023787;
    max_cols(1) = 1.0;
    max_cols(2) = 1.231751;
    max_cols(3) = 1.0;

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(A)
    expect = value_type(1.231751);
    res = ublasx::max(A);
    BOOST_UBLASX_DEBUG_TRACE( "max(" << A << ") = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max_rows(A)
    vexpect = max_rows;
    vres = ublasx::max_rows(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(A)
    vexpect = max_cols;
    vres = ublasx::max_columns(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(A)
    vexpect = max_rows;
    vres = ublasx::max<1>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(A)
    vexpect = max_cols;
    vres = ublasx::max<2>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(A)
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::major>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::minor>(A)
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::leading>(A)
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(A);
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << A << ") = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );
}

BOOST_UBLASX_TEST_DEF( matrix_expression )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Matrix Expression" );

    typedef double value_type;
    typedef ublas::matrix<value_type> matrix_type;
    typedef ublas::vector<value_type> vector_type;

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = 0.0;      A(0,1) = 0.274690; A(0,2) = 0.0;      A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.0;      A(1,2) = 0.891726; A(1,3) = 0.0;
    A(2,0) = 0.0;      A(2,1) = 0.0;      A(2,2) = 0.0;      A(2,3) = 0.0;
    A(3,0) = 0.0;      A(3,1) = 0.675382; A(3,2) = 0.0;      A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.0;      A(4,2) = 1.231751; A(4,3) = 1.0;

    vector_type max_rows(nr);
    max_rows(0) = 0.798938;
    max_rows(1) = 0.891726;
    max_rows(2) = 0;
    max_rows(3) = 0.675382;
    max_rows(4) = 1.231751;

    vector_type max_cols(nc);
    max_cols(0) = 1.023787;
    max_cols(1) = 1.0;
    max_cols(2) = 1.231751;
    max_cols(3) = 1.0;

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(A')
    expect = value_type(1.231751);
    res = ublasx::max(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max(" << A << "') = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK_CLOSE( res, expect, tol );

    // max_rows(A')
    vexpect = max_cols;
    vres = ublasx::max_rows(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max_columns(A')
    vexpect = max_rows;
    vres = ublasx::max_columns(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<1>(A')
    vexpect = max_cols;
    vres = ublasx::max<1>(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<2>(A')
    vexpect = max_rows;
    vres = ublasx::max<2>(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::major>(A')
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::major>(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(A')
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(A')
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(ublas::trans(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(" << A << "') = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );
}

BOOST_UBLASX_TEST_DEF( matrix_reference )
{
    BOOST_UBLASX_DEBUG_TRACE( "Test Case: Matrix Reference" );

    typedef double value_type;
    typedef ublas::matrix<value_type> matrix_type;
    typedef ublas::matrix_reference<matrix_type> matrix_reference_type;
    typedef ublas::vector<value_type> vector_type;

    std::size_t nr = 5;
    std::size_t nc = 4;

    matrix_type A(nr, nc);

    A(0,0) = 0.0;      A(0,1) = 0.274690; A(0,2) = 0.0;      A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.0;      A(1,2) = 0.891726; A(1,3) = 0.0;
    A(2,0) = 0.0;      A(2,1) = 0.0;      A(2,2) = 0.0;      A(2,3) = 0.0;
    A(3,0) = 0.0;      A(3,1) = 0.675382; A(3,2) = 0.0;      A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.0;      A(4,2) = 1.231751; A(4,3) = 1.0;

    vector_type max_rows(nr);
    max_rows(0) = 0.798938;
    max_rows(1) = 0.891726;
    max_rows(2) = 0;
    max_rows(3) = 0.675382;
    max_rows(4) = 1.231751;

    vector_type max_cols(nc);
    max_cols(0) = 1.023787;
    max_cols(1) = 1.0;
    max_cols(2) = 1.231751;
    max_cols(3) = 1.0;

    value_type expect(0);
    value_type res(0);
    vector_type vexpect(0);
    vector_type vres(0);

    // max(ref(A))
    expect = value_type(1.231751);
    res = ublasx::max(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max(reference(" << A << ")) = " << res << " ==> " << expect );
    BOOST_UBLASX_TEST_CHECK( res == expect );

    // max_rows(ref(A))
    vexpect = max_rows;
    vres = ublasx::max_rows(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_rows(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max_columns(ref(A))
    vexpect = max_cols;
    vres = ublasx::max_columns(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_columns(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<1>(ref(A))
    vexpect = max_rows;
    vres = ublasx::max<1>(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max<1>(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<2>(ref(A))
    vexpect = max_cols;
    vres = ublasx::max<2>(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max<2>(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::major>(ref(A))
    vexpect = max_rows;
    vres = ublasx::max_by_tag<ublasx::tag::major>(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::major>(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nr, tol );

    // max<tag::minor>(ref(A))
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::minor>(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::minor>(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );

    // max<tag::leading>(ref(A))
    vexpect = max_cols;
    vres = ublasx::max_by_tag<ublasx::tag::leading>(matrix_reference_type(A));
    BOOST_UBLASX_DEBUG_TRACE( "max_by_tag<tag::leading>(reference(" << A << ")) = " << vres << " ==> " << vexpect );
    BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( vres, vexpect, nc, tol );
}

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

    BOOST_UBLASX_TEST_BEGIN();

    BOOST_UBLASX_TEST_DO( real_vector );
    BOOST_UBLASX_TEST_DO( complex_vector );
    BOOST_UBLASX_TEST_DO( vector_container );
    BOOST_UBLASX_TEST_DO( vector_expression );
    BOOST_UBLASX_TEST_DO( vector_reference );
    BOOST_UBLASX_TEST_DO( real_matrix );
    BOOST_UBLASX_TEST_DO( complex_matrix );
    BOOST_UBLASX_TEST_DO( row_major_matrix_container );
    BOOST_UBLASX_TEST_DO( col_major_matrix_container );
    BOOST_UBLASX_TEST_DO( matrix_expression );
    BOOST_UBLASX_TEST_DO( matrix_reference );

    BOOST_UBLASX_TEST_END();
}


/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include <boost/test/unit_test.hpp>
#include <ored/portfolio/schedule.hpp>
#include <oret/toplevelfixture.hpp>

using namespace boost::unit_test_framework;
using namespace ore::data;
using namespace QuantLib;

BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)

BOOST_AUTO_TEST_SUITE(ScheduleDataTests)

BOOST_AUTO_TEST_CASE(testScheduleData) {

    BOOST_TEST_MESSAGE("Testing ScheduleData...");

    ScheduleDates dates1("TARGET", "", "", {"2015-01-09", "2015-02-09", "2015-03-09", "2015-04-09"});

    ScheduleDates dates2("TARGET", "", "",
                         {"2015-04-09",
                          "2016-04-11", // 9th = Saturday
                          "2017-04-10", // 9th = Sunday
                          "2018-04-09"});

    ScheduleRules rules1("2015-01-09", "2015-04-09", "1M", "TARGET", "MF", "MF", "Forward");

    ScheduleRules rules2("2015-04-09", "2018-04-09", "1Y", "TARGET", "MF", "MF", "Forward");

    // Test <Dates> and <Dates>
    ScheduleData data(dates1);
    data.addDates(dates2);
    QuantLib::Schedule s = makeSchedule(data);
    BOOST_CHECK_EQUAL(s.size(), 7UL); // 7 dates, 6 coupons
    BOOST_CHECK_EQUAL(s.startDate(), Date(9, Jan, 2015));
    BOOST_CHECK_EQUAL(s.endDate(), Date(9, Apr, 2018));

    // Test <Rules> and <Rules>
    data = ScheduleData(rules1);
    data.addRules(rules2);
    QuantLib::Schedule s2 = makeSchedule(data);
    BOOST_CHECK_EQUAL(s2.size(), s.size());
    for (Size i = 0; i < s.size(); i++)
        BOOST_CHECK_EQUAL(s[i], s2[i]);

    // Test <Dates> and <Rules>
    data = ScheduleData(dates1);
    data.addRules(rules2);
    QuantLib::Schedule s3 = makeSchedule(data);
    BOOST_CHECK_EQUAL(s3.size(), s.size());
    for (Size i = 0; i < s.size(); i++)
        BOOST_CHECK_EQUAL(s[i], s3[i]);
}

// The original reason for adding the LastWednesday date generation rule was to generate the AU CPI publication dates
// using a rules based schedule. Here, we compare the dates for a number of years against the release dates from
// https://www.abs.gov.au/statistics/economy/price-indexes-and-inflation/consumer-price-index-australia
BOOST_AUTO_TEST_CASE(testLastWednesdayDateGenerationRule) {

    vector<Date> expected{
        Date(30, Oct, 2018),
        Date(30, Jan, 2019), Date(24, Apr, 2019), Date(31, Jul, 2019), Date(30, Oct, 2019), // 2019
        Date(29, Jan, 2020), Date(29, Apr, 2020), Date(29, Jul, 2020), Date(28, Oct, 2020), // 2020
        Date(27, Jan, 2021), Date(28, Apr, 2021), Date(28, Jul, 2021), Date(27, Oct, 2021), // 2021
        Date(25, Jan, 2022)
    };

    // AU CPI publication dates are the last Wednesday of Jan, Apr, Jul and Oct. If that is not a good AU business
    // day, it is the preceding good AU business day.
    Schedule s = makeSchedule(ScheduleData(ScheduleRules("2018-10-30", "2022-01-25", "3M", "AUD",
        "Preceding", "Unadjusted", "LastWednesday")));

    // Check
    BOOST_CHECK_EQUAL_COLLECTIONS(s.dates().begin(), s.dates().end(), expected.begin(), expected.end());
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


//==============================================================================
//         Copyright 2015 J.T. Lapreste
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_LINALG_FUNCTIONS_TIED_CDF2RDF_HPP_INCLUDED
#define NT2_LINALG_FUNCTIONS_TIED_CDF2RDF_HPP_INCLUDED

#include <nt2/linalg/functions/cdf2rdf.hpp>
#include <boost/dispatch/attributes.hpp>
#include <nt2/core/container/table/table.hpp>
#include <nt2/include/functions/cons.hpp>
#include <nt2/include/functions/ctranspose.hpp>
#include <nt2/include/functions/diag_of.hpp>
#include <nt2/include/functions/eye.hpp>
#include <nt2/include/functions/find.hpp>
#include <nt2/include/functions/imag.hpp>
#include <nt2/include/functions/isempty.hpp>
#include <nt2/include/functions/is_real.hpp>
#include <nt2/include/functions/length.hpp>
#include <nt2/include/functions/linsolve.hpp>
#include <nt2/include/functions/plus.hpp>
#include <nt2/include/functions/real.hpp>
#include <nt2/include/constants/one.hpp>
#include <nt2/include/constants/i.hpp>
#include <nt2/sdk/meta/as_real.hpp>
#include <nt2/linalg/options.hpp>
#include <nt2/core/container/dsl/as_terminal.hpp>
#include <nt2/core/container/colon/colon.hpp>
#include <nt2/core/utility/of_size.hpp>

namespace nt2 { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT  ( cdf2rdf_, tag::cpu_
                            , (A0)(A1)
                            , (scalar_<unspecified_<A0> >)
                              (scalar_<unspecified_<A1> >)
                            )
  {
    typedef typename meta::as_real<A0>::type result_type;

    BOOST_FORCEINLINE result_type operator()(const A0& a0, const A1& ) const
    {
      BOOST_ASSERT_MSG(is_real(a0), "diagonal is not valid");
      return real(a0);
    }
  };

  BOOST_DISPATCH_IMPLEMENT  ( cdf2rdf_, tag::cpu_
                            , (A0)(N0)(A1)(N1)
                            , ((node_<A0, nt2::tag::cdf2rdf_
                                    , N0, nt2::container::domain
                                      >
                              ))
                              ((node_<A1, nt2::tag::tie_
                                    , N1, nt2::container::domain
                                     >
                              ))
                            )
  {
    typedef void  result_type;
    typedef typename boost::proto::result_of::child_c<A0&,0>::value_type    child0;
    typedef typename child0::value_type                                     type_t;
    typedef typename nt2::meta::as_real<type_t>::type                      rtype_t;
    typedef typename nt2::meta::as_complex<rtype_t>::type                  ctype_t;
    typedef nt2::memory::container<tag::table_, rtype_t, nt2::_2D> desired_semantic;

    BOOST_FORCEINLINE result_type operator()( A0& a0, A1& a1 ) const
    {
      eval(a0, a1, N0(), N1());
    }

    //==========================================================================
    /// INTERNAL ONLY - [v, w] = cdf2rdf(cv, cw)
    BOOST_FORCEINLINE
    void eval ( A0& a0, A1& a1
              , boost::mpl::long_<2> const&
              , boost::mpl::long_<2> const&
              ) const
    {
       auto& cv = boost::proto::child_c<0>(a0);
       auto& cw = boost::proto::child_c<1>(a0);
       auto i = find(imag(diag_of(cw)));
       container::table<std::size_t> index =
         cast<std::size_t>(i(_(std::size_t(1), std::size_t(2), length(i))));
       if (isempty(index))
       {
         boost::proto::child_c<0>(a1) = real(cv);
         boost::proto::child_c<1>(a1) = real(cw);
         return;
       }
       container::table<ctype_t> ct = eye(length(cw), meta::as_<ctype_t>());
       container::table<ctype_t> twobytwo = cons<ctype_t>(of_size(2, 2), One<ctype_t>()
                                                         , I<ctype_t>(), One<ctype_t>()
                                                         , -I<ctype_t>());
       auto i2 = _(std::size_t(0), std::size_t(1));
       for(auto j : index)
       {
         ct(i2+j, i2+j) = twobytwo;
       }
       boost::proto::child_c<0>(a1) = trans(real(linsolve(ctrans(ct), ctrans(cv))));
       boost::proto::child_c<1>(a1) = real(mtimes(ct, ctrans(linsolve(ctrans(ct), ctrans(cw)))));
    }

  };
} }

#endif


#ifndef __solver_Up_h__
#define __solver_Up_h__

#include <Eigen/Dense>
#include <vector>
#include <iostream>
#include "weighted_hqp/HCod.hpp"
#include "weighted_hqp/givens.hpp"

namespace hcod{
    class Up{
        public:
            Up(){
                given_ = new Givens();
            };
            ~Up(){};

        private:

        public:
            bool compute(const int kup, const int cup, const int bound, const std::vector<h_structure> & h, const Eigen::MatrixXd & Y, const bool & isweighted = true);
            std::vector<h_structure> geth(){
                return h_;
            };
            Eigen::MatrixXd getY(){
                return Y_;
            };

        private:
            Eigen::MatrixXd Y_, Yup_, Wi_, Yi_;
            std::vector<H_structure> h_;
            bool _isweighted;
            Givens* given_;
            int nh_, p_;

    };
}

#endif


/**
 * @file   Image2DStatistics.cpp
 * @author Sebastian Maisch <sebastian.maisch@uni-ulm.de>
 * @date   2015.09.18
 *
 * @brief  Implements a class to create statistics of 2D images.
 */

#include "Image2DStatistics.h"
#include "gfx/glrenderer/GLTexture2D.h"
#include "gfx/glrenderer/GLTexture.h"
#include "app/ApplicationBase.h"
#include <boost/assign.hpp>
#include <glm/gtx/log_base.hpp>
#undef max
#undef min

namespace cgu {
    namespace eval {

        Image2DStatistics::Image2DStatistics(const std::string& origImage, ApplicationBase* app) :
            origTex_(new GLTexture2D(origImage, app)),
            diffProgram_(app->GetGPUProgramManager()->GetResource("shader/eval/diffImage.cp")),
            diffUniformIds_(diffProgram_->GetUniformLocations({ "origTex", "cmpTex", "resultTex", "statsTex" })),
            reduceProgram_(app->GetGPUProgramManager()->GetResource("shader/eval/reductionRMS.cp")),
            reduceUniformIds_(reduceProgram_->GetUniformLocations({ "reduceTex" })),
            application_(app)
        {
            auto diffTexDesc = origTex_->GetTexture()->GetDescriptor();
            assert(diffTexDesc.bytesPP == 4);
            assert(diffTexDesc.format == GL_RGBA || diffTexDesc.format == GL_BGRA);
            imgDimensions_ = origTex_->GetTexture()->GetDimensions();
            diffTex_.reset(new GLTexture(imgDimensions_.x, imgDimensions_.y, diffTexDesc, nullptr));

            TextureDescriptor statsTexDesc{ 16 , GL_RGBA32F, GL_RGBA, GL_FLOAT };
            statsTex_.reset(new GLTexture(imgDimensions_.x, imgDimensions_.y, statsTexDesc, nullptr));
        }

        Image2DStatistics::~Image2DStatistics() = default;

        EvalStatistics Image2DStatistics::CreateDiffImage(const std::string& compareImage, const std::string& diffImage) const
        {
            const auto workGroupSize = glm::vec2(32.0f, 16.0f);
            auto compareTex = std::make_unique<GLTexture2D>(compareImage, application_);
            diffProgram_->UseProgram();
            diffProgram_->SetUniform(diffUniformIds_[0], 0);
            diffProgram_->SetUniform(diffUniformIds_[1], 1);
            diffProgram_->SetUniform(diffUniformIds_[2], 2);
            diffProgram_->SetUniform(diffUniformIds_[3], 3);
            auto numGroups = glm::ivec2(glm::ceil(glm::vec2(imgDimensions_) / workGroupSize));
            origTex_->GetTexture()->ActivateImage(0, 0, GL_READ_ONLY);
            compareTex->GetTexture()->ActivateImage(1, 0, GL_READ_ONLY);
            diffTex_->ActivateImage(2, 0, GL_WRITE_ONLY);
            statsTex_->ActivateImage(3, 0, GL_WRITE_ONLY);
            OGL_CALL(glDispatchCompute, numGroups.x, numGroups.y, 1);
            OGL_CALL(glMemoryBarrier, GL_ALL_BARRIER_BITS);
            OGL_SCALL(glFinish);

            diffTex_->SaveTextureToFile(application_->GetConfig().evalDirectory + "/" + diffImage);

            while (numGroups.x > 1 || numGroups.y > 1) {
                reduceProgram_->UseProgram();
                reduceProgram_->SetUniform(reduceUniformIds_[0], 0);
                statsTex_->ActivateImage(0, 0, GL_READ_WRITE);
                OGL_CALL(glDispatchCompute, numGroups.x, numGroups.y, 1);
                OGL_CALL(glMemoryBarrier, GL_ALL_BARRIER_BITS);
                OGL_SCALL(glFinish);
                numGroups = glm::ivec2(glm::ceil(glm::vec2(numGroups) / workGroupSize));
            }

            OGL_CALL(glUseProgram, 0);

            std::vector<uint8_t> statResults;
            statsTex_->DownloadData(statResults, 0, 16);
            auto statResultsFlt = reinterpret_cast<float*>(statResults.data());
            auto numPixels = static_cast<float>(imgDimensions_.x * imgDimensions_.y);
            EvalStatistics result;
            result.errorMax_ = statResultsFlt[2];
            result.numErrorPixels_ = statResultsFlt[3];
            result.errorRMSAvg_ = glm::sqrt(statResultsFlt[0] / result.numErrorPixels_);
            result.errorRMSAvgAll_ = glm::sqrt(statResultsFlt[0] / numPixels);
            result.errorRMSMax_ = glm::sqrt(statResultsFlt[1] / result.numErrorPixels_);
            result.errorRMSMaxAll_ = glm::sqrt(statResultsFlt[1] / numPixels);
            result.psnrAvg_ = 20.0f * glm::log(1.0f / result.errorRMSAvg_, 10.0f);
            result.psnrAvgAll_ = 20.0f * glm::log(1.0f / result.errorRMSAvgAll_, 10.0f);
            result.psnrMax_ = 20.0f * glm::log(1.0f / result.errorRMSMax_, 10.0f);
            result.psnrMaxAll_ = 20.0f * glm::log(1.0f / result.errorRMSMaxAll_, 10.0f);
            return result;
        }
    }
}


//------------------------------------------------------------------------------
//                           UserPathFunctionManager
//------------------------------------------------------------------------------
// GMAT: General Mission Analysis Tool
//
// Copyright (c) 2002 - 2020 United States Government as represented by the
// Administrator of The National Aeronautics and Space Administration.
// All Other Rights Reserved.
//
// Author: Wendy Shoan / NASA
// Created: 2015.12.10
//
/**
 * From original MATLAB prototype:
 *  Author: S. Hughes.  steven.p.hughes@nasa.gov
 */
//------------------------------------------------------------------------------

#ifndef UserPathFunctionManager_hpp
#define UserPathFunctionManager_hpp

#include "csaltdefs.hpp"
#include "UserFunctionManager.hpp"
#include "UserFunctionProperties.hpp"
#include "Rmatrix.hpp"
#include "BoundData.hpp"
#include "PathFunctionContainer.hpp"
#include "FunctionInputData.hpp"
#include "FunctionOutputData.hpp"
// YK mod for hessian
#include <boost/numeric/ublas/symmetric.hpp>

class UserPathFunctionManager : public UserFunctionManager
{
public:
   // YK mod for hessian

   UserPathFunctionManager();
   UserPathFunctionManager(const UserPathFunctionManager &copy);
   UserPathFunctionManager& operator=(const UserPathFunctionManager &copy);
   virtual ~UserPathFunctionManager();

   virtual void Initialize(UserPathFunction          *uData,
                           FunctionInputData         *pData,
                           PathFunctionContainer     *fData,
                           BoundData                 *bData);

   virtual void WriteDebugData();

   virtual PathFunctionContainer* EvaluateUserFunction(
               FunctionInputData   *pData,
               PathFunctionContainer  *fData,
               UserFunction::FunctionType fType = UserFunction::ALLFUNCTIONS);
   virtual PathFunctionContainer* EvaluateUserJacobian(
               FunctionInputData   *pData,
               PathFunctionContainer  *fData,
               UserFunction::FunctionType fType = UserFunction::ALLFUNCTIONS,
               bool isComputingFunctions = false);

   // should these return const UserFunctionProperties& (need class data)?
   virtual UserFunctionProperties GetDynFunctionProperties();
   virtual UserFunctionProperties GetAlgFunctionProperties();
   virtual UserFunctionProperties GetCostFunctionProperties();

   virtual bool           HasDynFunctions();
   virtual bool           HasAlgFunctions();

   virtual Integer        GetNumAlgFunctions();
   virtual const Rvector& GetAlgFunctionsUpperBounds();
   virtual const Rvector& GetAlgFunctionsLowerBounds();

   virtual void           SetParamData(FunctionInputData *pData);
   virtual void           SetFunctionData(PathFunctionContainer *fData);

protected:

   /*
   /// Number of algebraic functions
   Integer      numAlgFunctions;
   /// Number of dynamics functions
   Integer      numDynFunctions;
   /// Number of integral functions
   Integer      numIntFunctions;
   */
   std::vector<Integer> numFunctions;

   // YK mod static vars: num variables vector.
   /// in the future, the root class's numStateVars,... are removed
   std::vector<Integer> numVars;

   /* YK mod for hessian
   /// Indicates if user has algebraic functions
   bool         hasAlgFunctions;
   /// Indicates if user has dynamics functions
   bool         hasDynFunctions;
   /// Indicates if user has integral functions
   bool         hasIntFunctions;
   */
   std::vector<bool> hasFunctions;

   /* YK mod for hessian
   /// The jacobian of dynamics wrt time
   Rmatrix      dynFuncTimeJacobian;
   /// The jacobian of dynamics wrt state
   Rmatrix      dynFuncStateJacobian;
   /// The jacobian of dynamics wrt control
   Rmatrix      dynFuncControlJacobian;
   /// The jacobian of algebraic functions wrt time
   Rmatrix      algFuncTimeJacobian;
   /// The jacobian of algebraic functions wrt state
   Rmatrix      algFuncStateJacobian;
   /// The jacobian of algebraic functions wrt control
   Rmatrix      algFuncControlJacobian;
   /// The jacobian of integral cost function wrt time
   Rmatrix      costFuncTimeJacobian;
   /// The jacobian of integral cost function wrt state
   Rmatrix      costFuncStateJacobian;
   /// The jacobian of integral cost function wrt control
   Rmatrix      costFuncControlJacobian;
   */
   std::vector<std::vector<Rmatrix>> jacobian;

   /*
   /// Sparsity of Jacobian of dynamics wrt time
   Rmatrix      dynFuncTimeJacobianPattern;
   /// Sparsity of Jacobian of dynamics wrt state
   Rmatrix      dynFuncStateJacobianPattern;
   /// Sparsity of Jacobian of dynamics wrt control
   Rmatrix      dynFuncControlJacobianPattern;
   /// Sparsity of Jacobian of algebraic functions wrt time
   Rmatrix      algFuncTimeJacobianPattern;
   /// Sparsity of Jacobian of algebraic functions wrt state
   Rmatrix      algFuncStateJacobianPattern;
   /// Sparsity of Jacobian of algebraic functions wrt control
   Rmatrix      algFuncControlJacobianPattern;
   /// Sparsity of Jacobian of cost function wrt time
   Rmatrix      costFuncTimeJacobianPattern;
   /// Sparsity of Jacobian of cost function wrt state
   Rmatrix      costFuncStateJacobianPattern;
   /// Sparsity of Jacobian of cost function wrt control
   Rmatrix      costFuncControlJacobianPattern;
   */

   // The sparsity patterns of the Jacobians
   std::vector<std::vector<Rmatrix>> jacPattern;

   /// Upper bound on algebraic function values
   Rvector      algFuncUpperBound;
   /// Lower bound on algebraic function values
   Rvector      algFuncLowerBound;

   /// Pointer to a FunctionInputData object
   FunctionInputData     *paramData;
   /// Pointer to the function container
   // funcData in ML NOTE: does this need to be stored sicne it is passed
   // in each time
   PathFunctionContainer *pfContainer;

   /*
   /// Indicates if there are any state Jacobians that must be finite
   /// differenced
   bool         needsStateJacobianFiniteDiff;
   /// Indicates if there are any control Jacobians that must be finite
   /// differenced
   bool         needsControlJacobianFiniteDiff;
   /// Indicates if there are any time Jacobians that must be finite
   /// differenced
   bool         needsTimeJacobianFiniteDiff;
   */
   boost::numeric::ublas::matrix<bool> needsJacobianFiniteDiff;

   /// protected methods
   /// Initialize member data
   virtual void CheckIfNeedsFiniteDiffJacobian();
   virtual void InitFunctionData(PathFunctionContainer *toData);

   /*
   virtual void InitDynFunctionsData(PathFunctionContainer *toData);
   virtual void InitAlgFunctionsData(PathFunctionContainer *toData);
   virtual void InitCostFunctionData(PathFunctionContainer *toData);
   */
   virtual void InitFunctionsData(UserFunction::FunctionType fType, PathFunctionContainer *toData);

   /// Compute function Jacobians
   /*
   virtual void ComputeStateJacobian(FunctionInputData     *pData,
                                     PathFunctionContainer *fData);
   virtual void ComputeControlJacobian(FunctionInputData     *pData,
                                       PathFunctionContainer *fData);
   virtual void ComputeTimeJacobian(FunctionInputData        *pData,
                                    PathFunctionContainer    *fData);
   */
   virtual void ComputeAll(UserFunction::FunctionType fType,
                           FunctionInputData        *pData,
                           PathFunctionContainer    *fData, bool isComputingHess = false);

   /// Compute sparsity patterns
   virtual void ComputeSparsityPatterns(FunctionInputData     *pData,
                                        PathFunctionContainer *fData,
                                        BoundData             *bData,
                                        bool isComputingHess = false);
   /*
   virtual void ComputeStateSparsity(FunctionInputData       *pData,
                                     PathFunctionContainer   *uData,
                                     const Rvector           &tUpper,
                                     const Rvector           &tLower,
                                     const Rvector           &stUpper,
                                     const Rvector           &stLower,
                                     const Rvector           &ctrUpper,
                                     const Rvector           &ctrLower);
   virtual void ComputeControlSparsity(FunctionInputData      *pData,
                                       PathFunctionContainer  *uData,
                                       const Rvector           &tUpper,
                                       const Rvector           &tLower,
                                       const Rvector           &stUpper,
                                       const Rvector           &stLower,
                                       const Rvector           &ctrUpper,
                                       const Rvector           &ctrLower);
   virtual void ComputeTimeSparsity(FunctionInputData      *pData,
                                    PathFunctionContainer  *uData,
                                    const Rvector           &tUpper,
                                    const Rvector           &tLower,
                                    const Rvector           &stUpper,
                                    const Rvector           &stLower,
                                    const Rvector           &ctrUpper,
                                    const Rvector           &ctrLower);
   */

   virtual void ComputeSparsity(UserFunction::FunctionType fType,
                                       FunctionInputData      *pData,
                                       PathFunctionContainer  *uData,
                                       const Rvector           &tUpper,
                                       const Rvector           &tLower,
                                       const Rvector           &stUpper,
                                       const Rvector           &stLower,
                                       const Rvector           &ctrUpper,
                                       const Rvector           &ctrLower,
                                       const Rvector           &stcUpper,
                                       const Rvector           &stcLower,
                                       bool isComputingHess = false);

   /*
   virtual void UpdateStateSparsityPattern();
   virtual void UpdateControlSparsityPattern();
   virtual void UpdateTimeSparsityPattern();
   */
   virtual void UpdateSparsityPattern(UserFunction::FunctionType fType,
                                      FunctionInputData *pData,
                                      PathFunctionContainer *uData,
                                      const Rvector &randTime,
                                      const Rvector &randState,
                                      const Rvector &randControl,
                                      const Rvector &randStatic,
                                      bool isComputingHess = false);
};
#endif // UserPathFunctionManager_hpp


#ifndef MPLLIBS_METAMONAD_TEST_IS_EMPTY_HPP
#define MPLLIBS_METAMONAD_TEST_IS_EMPTY_HPP

// Copyright Abel Sinkovics (abel@sinkovics.hu) 2013.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <mpllibs/metamonad/metafunction.hpp>
#include <mpllibs/metamonad/is_exception.hpp>

#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/int.hpp>

MPLLIBS_METAFUNCTION(is_empty, (S))
((
  boost::mpl::and_<
    typename boost::mpl::not_<
      typename mpllibs::metamonad::is_exception<S>::type
    >::type,
    typename boost::mpl::equal_to<
      boost::mpl::int_<0>,
      typename boost::mpl::distance<
        typename boost::mpl::begin<S>::type,
        typename boost::mpl::end<S>::type
      >::type
    >::type
  >
));

#endif


#include <qubus/value_set_analysis.hpp>

#include <qubus/isl/map.hpp>

#include <boost/range/adaptor/transformed.hpp>

#include <qubus/util/assert.hpp>

namespace qubus
{

value_set_analysis_result::value_set_analysis_result(
    const axiom_analysis_result& axiom_analysis_,
    const task_invariants_analysis_result& task_invariants_analysis_, isl::context& isl_ctx_)
: axiom_analysis_(&axiom_analysis_),
  task_invariants_analysis_(&task_invariants_analysis_),
  isl_ctx_(&isl_ctx_)
{
}

std::vector<value_set> value_set_analysis_result::determine_value_sets(
    boost::any_range<const expression&, boost::forward_traversal_tag> expressions,
    const expression& context) const
{
    QUBUS_ASSERT(axiom_analysis_ != nullptr, "Invalid value_set_analysis_result object.");

    auto ctx = std::make_shared<affine_expr_context>([this, &context](const expression& expr) {
        return task_invariants_analysis_->is_invariant(expr, context);
    });

    std::vector<value_set> value_sets;

    for (const auto& expr : expressions)
    {
        auto axioms = axiom_analysis_->get_valid_axioms(expr);

        auto analyzed_expr = try_construct_affine_expr(expr, *ctx);

        if (analyzed_expr)
        {
            std::vector<affine_constraint> affine_axioms;

            for (const auto& axiom : axioms)
            {
                auto expr = try_extract_affine_constraint(axiom.as_expr(), *ctx);

                if (expr)
                {
                    affine_axioms.push_back(*std::move(expr));
                }
            }

            auto domain = isl::set::universe(ctx->construct_corresponding_space(*isl_ctx_));

            for (const auto& axiom : affine_axioms)
            {
                auto constraint = axiom.convert(*isl_ctx_);

                domain = intersect(std::move(domain), constraint);
            }

            domain = simplify(std::move(domain));

            auto map = isl::map::from_affine_expr(analyzed_expr->convert(*isl_ctx_));

            auto value_set = apply(map, domain);

            value_sets.emplace_back(std::move(value_set), ctx);
        }
        else
        {
            value_sets.emplace_back(isl::set::universe(isl::space(*isl_ctx_, 0, 1)), ctx);
        }
    }

    return value_sets;
}

namespace
{
struct unwrap_reference
{
    template <typename T>
    T& operator()(const std::reference_wrapper<T>& wrapper) const
    {
        return wrapper.get();
    }
};
}

value_set value_set_analysis_result::determine_value_set(const expression& expr,
                                                         const expression& context) const
{
    std::vector<std::reference_wrapper<const expression>> expressions{expr};

    using boost::adaptors::transformed;

    auto value_sets = determine_value_sets(expressions | transformed(unwrap_reference()), context);

    QUBUS_ASSERT(value_sets.size() == 1, "Expecting only one value set.");

    return value_sets[0];
}

value_set_analysis_result
value_set_analysis_pass::run(const expression& root, analysis_manager& manager,
                             pass_resource_manager& resource_manager) const
{
    return value_set_analysis_result(manager.get_analysis<axiom_analysis_pass>(root),
                                     manager.get_analysis<task_invariants_analysis_pass>(root),
                                     resource_manager.get_isl_ctx());
}

std::vector<analysis_id> value_set_analysis_pass::required_analyses() const
{
    return {get_analysis_id<axiom_analysis_pass>()};
}

QUBUS_REGISTER_ANALYSIS_PASS(value_set_analysis_pass);
}


#include "edge_core.h"
#include <unordered_map>
#include <cmath>
#include <iostream>
#include <boost/functional/hash/hash.hpp>
using namespace std;
using namespace Eigen;
const float PI = 3.14159265359;
namespace marvel{

struct pair_hash{
  size_t operator ()(const pair<size_t,size_t>& a) const{
    size_t seed = 0;
    boost::hash_combine(seed, a.first);
    boost::hash_combine(seed, a.second);
    return seed ;
  }
};

float edge_core::get_beta(const size_t& valence){
  return  (0.625 - pow((0.375 + 0.25 * cos(2 * PI / valence)), 2) ) / valence;
}

int edge_core::construct_core(const MatrixXi& tris, const MatrixXf& nods){
  //init
  num_faces_ = tris.cols();
  num_vertices_ = nods.cols();
  edges_.clear();
  valences_.clear();
  edges_ .resize(0);
  valences_.resize(num_vertices_);

  unordered_map<pair<size_t, size_t>, size_t, pair_hash> edge_pair2id;
  size_t edge_id = 0;
  for(size_t i = 0; i < tris.cols(); ++i){
    for(size_t j = 0; j < 3; ++j){
      // one <another
      size_t one, another;{
        if (tris(j%3, i) < tris((j + 1)%3, i)){
          one = tris(j%3, i);
          another = tris((j + 1)%3, i);
        }
        else{
          one = tris((j + 1)%3, i);
          another = tris(j%3, i);
        }

      }

      auto res_ins = edge_pair2id.insert({{one, another}, edge_id});
      if( res_ins.second ){
        assert(edges_.size() == edge_id);

        edges_.push_back({static_cast<int>(i), -1, tris(j%3, i), tris((j + 1)%3, i), tris((j + 2)%3, i), -1});

        ++(valences_[one]);
        ++(valences_[another]);

        ++edge_id;
      }
      else{
        assert(edges_[res_ins.first->second].f2 == -1);
        edges_[res_ins.first->second].f2 = i;
        edges_[res_ins.first->second].v4 = tris((j + 2)%3, i);
      }
    }

  }
  num_edges_ = edges_.size();
  if_construct_ = true;
  return 0;

}

int edge_core::calculate_odd_points(C_MF_ptr& ori_verts, MF_ptr& new_verts){
#pragma omp parallel for
  for(size_t i = 0; i < num_edges_; ++i){
    size_t v1 = edges_[i].v1, v2 = edges_[i].v2;
    if(edges_[i].f2 != -1){
      new_verts->col(num_vertices_ + i) = 0.375 * ( ori_verts->col(v1) + ori_verts->col(v2) )
          + 0.125 * ( ori_verts->col(edges_[i].v3) + ori_verts->col(edges_[i].v4) );
    }
    else
      new_verts->col(num_vertices_ + i) = 0.5 * ( ori_verts->col(v1) + ori_verts->col(v2) );
  }

  return 0;
}

int edge_core::calculate_even_points(C_MF_ptr& ori_verts, MF_ptr& new_verts){

#pragma omp parallel for
  for(size_t i = 0; i < num_vertices_; ++i){
    new_verts->col(i) = (1 - valences_[i] * get_beta(valences_[i])) * ori_verts->col(i);
  }

  for(size_t i = 0; i < num_edges_; ++i){

    size_t v1 = edges_[i].v1, v2 = edges_[i].v2;
    //add even weight // TODO::  handle boundary in even points

    new_verts->col(v1) += get_beta(valences_[v1]) * ori_verts->col(v2);
    new_verts->col(v2) += get_beta(valences_[v2]) * ori_verts->col(v1);

  }

  return 0;
}

int edge_core::set_odds_to_new_tris(C_MI_ptr& ori_tris, MI_ptr& new_tris){
  #pragma omp parallel for
  for(size_t i = 0; i < num_edges_; ++i){
    //get order
    size_t order1, order2;{
      for(size_t j = 0; j < 3; ++j){

        if(edges_[i].v1 == (*ori_tris)(j, edges_[i].f1)){
          order1 = j;
          break;
        }
      }
      for(size_t j = 0; j < 3; ++j){
        if(edges_[i].v2 == (*ori_tris)(j, edges_[i].f2)){
          order2 = j;
          break;
        }
      }
    }

    size_t vert_id = i + num_vertices_;
    assert(vert_id >= num_vertices_);
    size_t f1_1st = edges_[i].f1 * 4 ;
    assert(vert_id < num_vertices_ + num_edges_);
    (*new_tris)(1, f1_1st + order1 % 3) = vert_id;
    (*new_tris)(2, f1_1st + (order1 + 1) %3) = vert_id;
    (*new_tris)(order1, f1_1st + 3) = vert_id;

    size_t f2_1st = edges_[i].f2 * 4;
    (*new_tris)(1, f2_1st + order2 % 3) = vert_id;
    (*new_tris)(2, f2_1st + (order2 + 1) %3) = vert_id;
    (*new_tris)(order2, f2_1st + 3) = vert_id;
  }
  return 0;
}
int edge_core::set_evens_to_new_tris(C_MI_ptr& ori_tris, MI_ptr& new_tris){
  #pragma omp parallel for
  for(size_t i = 0; i < num_faces_; ++i){
    new_tris->block(0, i*4, 1, 3) = ori_tris->col(i).transpose();
   }
  return 0;
}

int edge_core::operator ()(C_MI_ptr& ori_tris, C_MF_ptr& ori_verts, MI_ptr& new_tris, MF_ptr& new_verts){
  if(!if_construct_ || !if_update_)
    construct_core(*ori_tris, *ori_verts);

  //construct new lookup table
  new_tris->resize(3, 4 * num_faces_);
  new_verts->resize(3, num_vertices_+ num_edges_);

  calculate_even_points(ori_verts, new_verts);
  calculate_odd_points(ori_verts, new_verts);

  set_odds_to_new_tris(ori_tris, new_tris);
  set_evens_to_new_tris(ori_tris, new_tris);

  if(if_update_)
    update_edges_and_valence(ori_tris, new_tris);
  return 0;

}

//>>>>>>>>>>>>>>>>TODO : update edges after each loop<<<<<<<<<<<<<<<<<<<<<<<<<
int edge_core::update_edges_and_valence(C_MI_ptr& ori_tris, C_MI_ptr& new_tris){

  valences_.resize(num_vertices_ + num_edges_);
  fill(valences_.begin() + num_vertices_, valences_.begin() + num_vertices_ + num_edges_, 6);
  edges_.resize(2 * num_edges_ + 3 * num_faces_);
  #pragma omp parallel for
  for(size_t i = 0; i < num_edges_; ++i){
      size_t order1 = get_order(edges_[i].v1, (*ori_tris).col(edges_[i].f1));
      size_t order2 = get_order(edges_[i].v2, (*ori_tris).col(edges_[i].f2));

      edges_[num_edges_ + i].f1 = edges_[i].f1 * 4 + (order1 + 1)%3;
      edges_[num_edges_ + i].v1 = num_vertices_ + i;
      edges_[num_edges_ + i].v2 = edges_[i].v2;
      edges_[num_edges_ + i].v3 = (*new_tris)(1, edges_[num_edges_ + i].f1);

      edges_[i].f1 = edges_[i].f1 * 4 + order1%3;
      edges_[i].v2 = num_vertices_ + i;
      edges_[i].v3 = (*new_tris)(2, edges_[i].f1);

    if(edges_[i].f2 != -1){
      edges_[num_edges_ + i].f2 = edges_[i].f2 * 4 + order2%3;
      edges_[num_edges_ + i].v4 = (*new_tris)(2, edges_[num_edges_ + i].f2);

      edges_[i].f2 = edges_[i].f2 * 4 + (order2 + 1)%3;
      edges_[i].v4 = (*new_tris)(1, edges_[i].f2);

    }
    else{
      edges_[num_edges_ + i].f2 = -1;
      edges_[num_edges_ + i].v4 = -1;

      edges_[i].f2 = -1;
      edges_[i].v4 = -1;

    }
  }

  size_t begin = 2 * num_edges_;
  #pragma omp parallel for
  for(size_t i = 0; i < num_faces_; ++i){
    for(size_t j = 0; j < 3; ++j){
      edges_[begin + i * 3 + j].f1 = i*4 + 3;
      edges_[begin + i * 3 + j].f2 = i*4 + (j + 1) %3;
      edges_[begin + i * 3 + j].v1 = (*new_tris)(j%3, i*4 + 3);
      edges_[begin + i * 3 + j].v2 = (*new_tris)((j + 1)%3, i*4 + 3);
      edges_[begin + i * 3 + j].v3 = (*new_tris)((j + 2)%3, i*4 + 3);
      edges_[begin + i * 3 + j].v4 = (*new_tris)(0, i*4 + (j + 1) %3);
    }

  }

  num_faces_ *= 4;
  num_vertices_ += num_edges_;
  num_edges_ = edges_.size();
  return 0;
}

int edge_core::get_order(const size_t& v_id, const Vector3i& f){
  for(size_t i = 0; i < 3; ++i){
    if(v_id == f(i))
      return i;
  }
  assert(false);
}

}//namespace


// -*-C++-*-
/*
  (c) Copyright 2007, Hewlett-Packard Development Company, LP

  See the file named COPYING for license details
*/

/** @file
    SRT-specfic statistic calculation, for purpose of the DataSeries paper
    Special cased to match with what c-store can do.

    srtstat2 bytes device_number bytes logical_volume_number bytes machine_id --

    dsselect --compress-lzo Trace::BlockIO::SRT::V7 bytes,machine_id,device_number,driver_type,thread_id,queue_length,pid,logical_volume_number ~/hourly-all.lzo.ds ~/select-all.lzo.ds
*/

/* Performance notes:
   2 dual core Intel 3GhZ Xeon processors (4 cores total), 5GB memory

   (LINTEL_STATS)
   time srtstat2 bytes device_number -- select-bytes-dev.none.ds  >/tmp/f
   real    0m8.523s user    0m9.509s sys     0m2.512s
   real    0m8.568s user    0m9.573s sys     0m2.532s
   real    0m8.418s user    0m9.501s sys     0m2.744s

   (DIRECT_STATS)
   time srtstat2 bytes device_number -- select-bytes-dev.none.ds  >/tmp/f
   real    0m5.554s user    0m6.444s sys     0m2.680s
   real    0m5.609s user    0m6.268s sys     0m2.624s
   real    0m5.477s user    0m6.500s sys     0m2.764s

   time srtstat2 bytes device_number -- select-bytes-dev.lzo.ds  >/tmp/f
   real    0m5.428s user    0m7.020s sys     0m1.188s
   real    0m5.438s user    0m7.100s sys     0m1.056s
   real    0m5.407s user    0m6.980s sys     0m1.188s

*/

#include <string>
#include <malloc.h>

#include <boost/format.hpp>

#include <Lintel/Stats.hpp>
#include <Lintel/HashMap.hpp>
#include <Lintel/AssertBoost.hpp>

#include <DataSeries/RowAnalysisModule.hpp>
#include <DataSeries/TypeIndexModule.hpp>
#include <DataSeries/PrefetchBufferModule.hpp>
#include <DataSeries/SequenceModule.hpp>

using namespace std;

struct HashMap_hashintfast {
    unsigned operator()(const int _a) const {
        return _a;
    }
};

#define DIRECT_STATS 1
#define LINTEL_STATS 0

int foo;
class IntGroupByInt : public RowAnalysisModule {
  public:
    IntGroupByInt(DataSeriesModule &source,
                  const string &_value_field, const string &_groupby_field)
            : RowAnalysisModule(source),
              value_field(_value_field),
              groupby_field(_groupby_field),
              value(series, value_field),
              groupby(series, groupby_field)
    {
    }

    struct GStats {
#if DIRECT_STATS
        double sum;
        double count;
#endif
#if LINTEL_STATS
        Stats *stat;
#endif
        GStats() {
#if DIRECT_STATS
            sum = count = 0;
#endif
#if LINTEL_STATS
            stat = new Stats();
            // ++foo; INVARIANT(foo < 100000, "bad");
#endif
        }
        void add(double v) {
#if DIRECT_STATS
            sum += v;
            count += 1;
#endif
#if LINTEL_STATS
            stat->add(v);
#endif
        }
    };
    typedef HashMap<ExtentType::int32, GStats *, HashMap_hashintfast> mytableT;

    virtual ~IntGroupByInt() { }

    virtual void processRow() {
        GStats **statp = mystats.lookup(groupby.val());
        GStats *stat;
        if (statp == NULL) {
            stat = new GStats();
            mystats[groupby.val()] = stat;
        } else {
            stat = *statp;
        }
        stat->add(value.val());
    }

    virtual Extent::Ptr getSharedExtent() {
        Extent::Ptr e = source.getSharedExtent();

        if (e == NULL) {
            completeProcessing();
            return Extent::Ptr();
        }
        series.setExtent(e);

        if (!prepared) {
            prepareForProcessing();
            prepared = true;
        }
        for (;series.morerecords();++series) {
            processRow();
        }
        return e;
    }

    virtual void printResult() {
#if DIRECT_STATS
        cout << boost::format("%s, mean(%s)\n")
                % groupby_field % value_field;
        for (mytableT::iterator i = mystats.begin();
            i != mystats.end(); ++i) {
            cout << boost::format("%d, %.15g\n")
                    % static_cast<int32_t>(i->first) // % i->second->count
                    % (i->second->sum / i->second->count);
        }
#endif

#if LINTEL_STATS
        cout << boost::format("%s, count(*), mean(%s), stddev, min, max\n")
                % groupby_field % value_field;
        for (mytableT::iterator i = mystats.begin();
            i != mystats.end(); ++i) {
            cout << boost::format("%d, %d, %.6g, %.6g, %.6g, %.6g\n")
                    % static_cast<int32_t>(i->first) % i->second->stat->count()
                    % i->second->stat->mean() % i->second->stat->stddev()
                    % i->second->stat->min() % i->second->stat->max();
        }
#endif
    }

    mytableT mystats;
    string value_field, groupby_field;
    Int32Field value, groupby;
};

int
main(int argc, char *argv[])
{
    TypeIndexModule source("Trace::BlockIO::SRT");
    PrefetchBufferModule *prefetch = new PrefetchBufferModule(source,64*1024*1024);

    mallopt(M_MMAP_THRESHOLD, 1024 * 1024);
    mallopt(M_TRIM_THRESHOLD, 1024 * 1024);
    mallopt(M_MMAP_MAX, 0);
    SequenceModule seq(prefetch);
    int argpos = 1;
    for (argpos = 1; argpos < argc; ) {
        if (strcmp(argv[argpos],"--") == 0) {
            ++argpos;
            break;
        }
        INVARIANT(argpos + 2 < argc, "not enough args");
        seq.addModule(new IntGroupByInt(seq.tail(), argv[argpos], argv[argpos+1]));
        argpos += 2;
    }
    INVARIANT(argpos < argc, "missing files??");

    for (; argpos<argc; ++argpos) {
        source.addSource(argv[argpos]);
    }
    seq.getAndDelete();

    RowAnalysisModule::printAllResults(seq);

    printf("extents: %.2f MB -> %.2f MB\n",
           (double)(source.total_compressed_bytes)/(1024.0*1024),
           (double)(source.total_uncompressed_bytes)/(1024.0*1024));
    printf("                   common\n");
    printf("MB compressed:   %8.2f\n",
           (double)source.total_compressed_bytes/(1024.0*1024));
    printf("MB uncompressed: %8.2f\n",
           (double)source.total_uncompressed_bytes/(1024.0*1024));
    printf("wait fraction :  %8.2f\n",
           source.waitFraction());

    return 0;
}


//==================================================================================================
/*!
  @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_NBTRUE_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_NBTRUE_HPP_INCLUDED

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

 /*!

    @ingroup group-reduction
    Function object implementing nbtrue capabilities

    Returns the number of non @ref Zero elements of the input SIMD vector.

    @par Semantic:

    For every parameter of type T

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

    is similar to:

    @code
    T r = sum(if_one_else_zero(x));
    @endcode

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

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

#endif


//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#define NT2_UNIT_MODULE "nt2 complex.operator toolbox - arg/scalar Mode"

//////////////////////////////////////////////////////////////////////////////
// unit test behavior of boost.simd.operator components in scalar mode
//////////////////////////////////////////////////////////////////////////////
/// created  by jt the 18/02/2011
///
#include <nt2/toolbox/operator/include/functions/arg.hpp>
#include <boost/simd/sdk/simd/logical.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <nt2/toolbox/constant/constant.hpp>

NT2_TEST_CASE_TPL ( arg_real__2_0,  BOOST_SIMD_REAL_TYPES)
{

  using nt2::arg;
  using nt2::tag::arg_;
  typedef std::complex<T> cT;
  typedef typename boost::dispatch::meta::as_integer<T>::type iT;
  typedef typename boost::dispatch::meta::call<arg_(cT)>::type r_t;
  typedef typename nt2::meta::scalar_of<r_t>::type sr_t;
  typedef typename nt2::meta::scalar_of<r_t>::type ssr_t;
  typedef nt2::imaginary<T> ciT;
  typedef T wished_r_t;

  // return type conformity test
  NT2_TEST( (boost::is_same < r_t, wished_r_t >::value) );
  std::cout << std::endl;
  double ulpd;
  ulpd=0.0;

  // specific values tests
  NT2_TEST_EQUAL(arg(cT(nt2::Inf<T>())), nt2::Zero<T>());
  NT2_TEST_EQUAL(arg(cT(nt2::Minf<T>())),nt2::Pi<T>());
  NT2_TEST_EQUAL(arg(cT(nt2::Nan<T>())), nt2::Nan<T>());
  NT2_TEST_EQUAL(arg(cT(nt2::One<T>())), nt2::Zero<T>());
  NT2_TEST_EQUAL(arg(cT(nt2::Zero<T>())),nt2::Zero<T>());
  NT2_TEST_EQUAL(arg(cT(0, 1)), nt2::Pio_2<T>());
  NT2_TEST_EQUAL(arg(cT(1, 0)), nt2::Zero<T>());
  NT2_TEST_EQUAL(arg(cT(2, 2)), nt2::Pio_2<T>()/2);
  NT2_TEST_EQUAL(arg(cT(2,-2)),-nt2::Pio_2<T>()/2);
} // end of test for floating_


// ---------------------------------------------------------------------------
//
//  This file is part of PermLib.
//
// Copyright (c) 2009-2011 Thomas Rehn <thomas@carmen76.de>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------------------------------------------------------------------

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Backtrack search test - set stabilization and set images
#include <boost/test/unit_test.hpp>

#include <iostream>
#include <fstream>

#include <permlib/permutation.h>
#include <permlib/generator/product_replacement_generator.h>
#include <permlib/bsgs.h>
#include <permlib/construct/schreier_sims_construction.h>
#include <permlib/generator/bsgs_generator.h>
#include <permlib/generator/bsgs_random_generator.h>
#include <permlib/transversal/schreier_tree_transversal.h>
#include <permlib/construct/schreier_sims_construction.h>
#include <permlib/change/conjugating_base_change.h>
#include <permlib/search/classic/set_stabilizer_search.h>
#include <permlib/search/partition/set_stabilizer_search.h>
#include <permlib/search/partition/vector_stabilizer_search.h>
#include <permlib/search/classic/set_image_search.h>
#include <permlib/search/partition/set_image_search.h>

#include "test-common.h"

#include <boost/foreach.hpp>
#include <boost/iterator/counting_iterator.hpp>

using namespace permlib;
using namespace permlib::test;

template<class TRANSVERSAL>
void checkStabilizer(const GroupInformation& info, unsigned int setSize, unsigned int numberOfSets) {
	BOOST_CHECK_LE(setSize, info.n);

	typedef typename TRANSVERSAL::PERMtype PERM;
	BSGS<PERM, TRANSVERSAL> bsgs = ConstructDeterministic1<PERM, TRANSVERSAL>()(info);

	for (unsigned int i = 0; i < numberOfSets; ++i) {
		std::set<dom_int> testSet;
		while (testSet.size() < setSize) {
			testSet.insert(randomInt(info.n));
		}

		// change the base so that is prefixed by the set
		ConjugatingBaseChange<PERM,TRANSVERSAL,
			RandomBaseTranspose<PERM,TRANSVERSAL> > baseChange(bsgs);
		baseChange.change(bsgs, testSet.begin(), testSet.end());

		BSGS<PERM,TRANSVERSAL> classicStab(bsgs.n);
		// prepare search without DCM pruning
		classic::SetStabilizerSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> backtrackSearch(bsgs, 0);
		backtrackSearch.construct(testSet.begin(), testSet.end());
		backtrackSearch.search(classicStab);

		BSGS<PERM,TRANSVERSAL> partitionStab(bsgs.n);
		// prepare search without DCM pruning
		partition::SetStabilizerSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> partitionBacktrackSearch(bsgs, 0);
		partitionBacktrackSearch.construct(testSet.begin(), testSet.end());
		partitionBacktrackSearch.search(partitionStab);

		BOOST_CHECK_EQUAL( classicStab.order(), partitionStab.order() );

		// check stabilizer order by iterating over all group elements
		BSGSGenerator<TRANSVERSAL> bsgsGen(bsgs.U);
		SetwiseStabilizerPredicate<PERM> stabPred(testSet.begin(), testSet.end());
		std::list<PERM> stabilizingGroupElements;
		while (bsgsGen.hasNext()) {
			const PERM p = bsgsGen.next();
			if (stabPred(p))
				stabilizingGroupElements.push_back(p);
		}

		BOOST_CHECK_EQUAL( classicStab.order(), stabilizingGroupElements.size() );

		// check that stabilizer contains all required elements
		BOOST_FOREACH(const PERM& p, stabilizingGroupElements) {
			BOOST_CHECK(classicStab.sifts(p));
			BOOST_CHECK(partitionStab.sifts(p));
		}
	}
}

template<class TRANSVERSAL>
void checkSetImage(const GroupInformation& info, unsigned int setSize, unsigned int numberOfSets) {
	BOOST_CHECK_LE(setSize, info.n);

	typedef typename TRANSVERSAL::PERMtype PERM;
	BSGS<PERM, TRANSVERSAL> bsgs = ConstructDeterministic1<PERM, TRANSVERSAL>()(info);

	for (unsigned int i = 0; i < numberOfSets; ++i) {
		std::set<dom_int> testSet1;
		std::set<dom_int> testSet2;
		while (testSet1.size() < setSize) {
			testSet1.insert(randomInt(info.n));
		}
		if (i < numberOfSets / 2) {
			while (testSet2.size() < setSize) {
				testSet2.insert(randomInt(info.n));
			}
		} else {
			// Ensure that for at least have of the test cases a mapping element
			// exists.
			BSGSRandomGenerator<PERM,TRANSVERSAL> bsgsRandomGen(bsgs);
			const PERM p = bsgsRandomGen.next();
			BOOST_FOREACH(const dom_int& x, testSet1) {
				testSet2.insert(p / x);
			}
		}

		// change the base so that is prefixed by the set
		ConjugatingBaseChange<PERM,TRANSVERSAL,
			RandomBaseTranspose<PERM,TRANSVERSAL> > baseChange(bsgs);
		baseChange.change(bsgs, testSet1.begin(), testSet1.end());

		// prepare search without DCM pruning
		classic::SetImageSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> backtrackSearch(bsgs, 0);
		backtrackSearch.construct(testSet1.begin(), testSet1.end(), testSet2.begin(), testSet2.end());
		typename PERM::ptr classicRep = backtrackSearch.searchCosetRepresentative();

		BSGS<PERM,TRANSVERSAL> partitionStab(bsgs.n);
		// prepare search without DCM pruning
		partition::SetImageSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> partitionBacktrackSearch(bsgs, 0);
		partitionBacktrackSearch.construct(testSet1.begin(), testSet1.end(), testSet2.begin(), testSet2.end());
		typename PERM::ptr partitionRep = partitionBacktrackSearch.searchCosetRepresentative();

		bool mappingExists = false;
		// check set image result by iterating over all group elements
		BSGSGenerator<TRANSVERSAL> bsgsGen(bsgs.U);
		SetImagePredicate<PERM> stabPred(testSet1.begin(), testSet1.end(), testSet2.begin(), testSet2.end());
		while (bsgsGen.hasNext()) {
			const PERM p = bsgsGen.next();
			if (stabPred(p)) {
				mappingExists = true;
				break;
			}
		}

		BOOST_CHECK_EQUAL( mappingExists, static_cast<bool>(classicRep) );
		BOOST_CHECK_EQUAL( mappingExists, static_cast<bool>(partitionRep) );

		if (classicRep)
			BOOST_CHECK( stabPred(*classicRep) );
		if (partitionRep)
			BOOST_CHECK( stabPred(*partitionRep) );
	}
}

BOOST_AUTO_TEST_CASE( setstabilizer )
{
	// we use elementary permutations
	typedef Permutation PERM;
	// and Schreier tree transversals
	typedef SchreierTreeTransversal<PERM> TRANSVERSAL;

	checkStabilizer<TRANSVERSAL>(info_testThesis, 1, 10);
	checkStabilizer<TRANSVERSAL>(info_testThesis, 2, 10);
	checkStabilizer<TRANSVERSAL>(info_testThesis, 3, 10);
	checkStabilizer<TRANSVERSAL>(info_1997, 1, 10);
	checkStabilizer<TRANSVERSAL>(info_1997, 2, 10);
	checkStabilizer<TRANSVERSAL>(info_1997, 3, 10);
	checkStabilizer<TRANSVERSAL>(info_cyclic10, 1, 30);
	checkStabilizer<TRANSVERSAL>(info_cyclic10, 2, 30);
	checkStabilizer<TRANSVERSAL>(info_S6_3, 2, 30);
	checkStabilizer<TRANSVERSAL>(info_S6_3, 4, 30);
	checkStabilizer<TRANSVERSAL>(info_e6, 1, 15);
	checkStabilizer<TRANSVERSAL>(info_e6, 2, 15);
	checkStabilizer<TRANSVERSAL>(info_e6, 4, 15);
}

BOOST_AUTO_TEST_CASE( setimage )
{
	// we use elementary permutations
	typedef Permutation PERM;
	// and Schreier tree transversals
	typedef SchreierTreeTransversal<PERM> TRANSVERSAL;
	checkSetImage<TRANSVERSAL>(info_testThesis, 1, 20);
	checkSetImage<TRANSVERSAL>(info_testThesis, 2, 30);
	checkSetImage<TRANSVERSAL>(info_testThesis, 3, 30);
	checkSetImage<TRANSVERSAL>(info_testThesis, 5, 30);
	checkSetImage<TRANSVERSAL>(info_1997, 1, 30);
	checkSetImage<TRANSVERSAL>(info_1997, 2, 30);
	checkSetImage<TRANSVERSAL>(info_1997, 3, 30);
	checkSetImage<TRANSVERSAL>(info_1997, 5, 30);
	checkSetImage<TRANSVERSAL>(info_cyclic10, 2, 30);
	checkSetImage<TRANSVERSAL>(info_S6_3, 4, 30);
	checkSetImage<TRANSVERSAL>(info_e6, 4, 30);
	checkSetImage<TRANSVERSAL>(info_e6, 11, 10);
	checkSetImage<TRANSVERSAL>(info_cov1075, 3, 20);
	checkSetImage<TRANSVERSAL>(info_metric5, 1, 30);
	checkSetImage<TRANSVERSAL>(info_metric5, 2, 30);
	checkSetImage<TRANSVERSAL>(info_metric5, 3, 30);
	checkSetImage<TRANSVERSAL>(info_metric5, 4, 30);
}

BOOST_AUTO_TEST_CASE( vectorstabilizer_group )
{
	// we use elementary permutations
	typedef Permutation PERM;
	// and Schreier tree transversals
	typedef SchreierTreeTransversal<PERM> TRANSVERSAL;
	typedef std::list<PERM::ptr> PERMlist;
	typedef partition::VectorStabilizerSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> VecStab;

	// our group will have degree 10
	const unsigned long n = 10;

	// group generators
	PERMlist groupGenerators;
	boost::shared_ptr<PERM> gen1(new PERM(n, std::string("1 3 5 7 9 10 2 4 6 8")));
	groupGenerators.push_back(gen1);
	boost::shared_ptr<PERM> gen2(new PERM(n, std::string("1 5")));
	groupGenerators.push_back(gen2);

	// BSGS construction
	SchreierSimsConstruction<PERM, TRANSVERSAL> schreierSims(n);
	BSGS<PERM, TRANSVERSAL> group = schreierSims.construct(groupGenerators.begin(),
														  groupGenerators.end());

	std::vector<unsigned int> v(n);
	v[0] = 0;
	v[1] = 0;
	v[2] = 0;
	v[3] = 0;
	v[4] = 1;
	v[5] = 1;
	v[6] = 1;
	v[7] = 2;
	v[8] = 2;
	v[9] = 2;

	ConjugatingBaseChange<PERM,TRANSVERSAL,
			RandomBaseTranspose<PERM,TRANSVERSAL> > baseChange(group);

	baseChange.change(group, boost::counting_iterator<unsigned int>(0), boost::counting_iterator<unsigned int>(7));

	BSGS<PERM,TRANSVERSAL>* partitionStab = NULL;
	VecStab* partitionVectorSearch = NULL;

	partitionStab = new BSGS<PERM,TRANSVERSAL>(n);
	partitionVectorSearch = new VecStab(group, 0);
	BOOST_ASSERT(partitionStab);
	BOOST_ASSERT(partitionVectorSearch);
	partitionVectorSearch->construct(v.begin(), v.end(), 3);
	partitionVectorSearch->search(*partitionStab);
	VectorStabilizerPredicate<PERM> vecStabPred(v.begin(), v.end());
	BOOST_FOREACH(const PERM::ptr& g, partitionStab->S) {
		BOOST_CHECK( vecStabPred(*g) );
	}
	// correct value 16 computed with GAP
	BOOST_CHECK_EQUAL(partitionStab->order(), 16);
	delete partitionStab;
	delete partitionVectorSearch;
}

BOOST_AUTO_TEST_CASE( vectorstabilizer_cyclic )
{
	typedef Permutation PERM;
	typedef SchreierTreeTransversal<PERM> TRANS;
	typedef std::vector<unsigned int> vec;
	typedef partition::VectorStabilizerSearch<BSGS<PERM,TRANS>,TRANS> VecStab;

	const GroupInformation& info = info_cyclic500;
	BSGS<PERM,TRANS> group = construct<PERM,TRANS>(info);
	const unsigned int n = info.n;

	const unsigned int maxV = 2;
	const unsigned int maxW = 5;
	const unsigned int maxX = 25;
	vec v(n), w(n), x(n);
	vec stabV(n/2);
	for (unsigned int i = 0; i < n; ++i) {
		v[i] = i % maxV;
		w[i] = i % maxW;
		x[i] = i % maxX;
		if (i % 2)
			stabV[i/2] = i;
	}

	BSGS<PERM,TRANS>* partitionStab = NULL;
	VecStab* partitionVectorSearch = NULL;
	VectorStabilizerPredicate<PERM>* vecStabPred = NULL;

	partitionStab = new BSGS<PERM,TRANS>(n);
	BOOST_ASSERT(partitionStab);
	partition::SetStabilizerSearch<BSGS<PERM,TRANS>,TRANS> partitionSetStabSearch(group, 0);
	partitionSetStabSearch.construct(stabV.begin(), stabV.end());
	partitionSetStabSearch.search(*partitionStab);
	BOOST_CHECK_EQUAL(partitionStab->order(), n/2);
	delete partitionStab;
	delete partitionVectorSearch;

	partitionStab = new BSGS<PERM,TRANS>(n);
	partitionVectorSearch = new VecStab(group, 0);
	BOOST_ASSERT(partitionStab);
	BOOST_ASSERT(partitionVectorSearch);
	partitionVectorSearch->construct(v.begin(), v.end(), maxV);
	partitionVectorSearch->search(*partitionStab);
	BOOST_CHECK_EQUAL(partitionStab->order(), n/maxV);
	vecStabPred = new VectorStabilizerPredicate<PERM>(v.begin(), v.end());
	BOOST_FOREACH(const PERM::ptr& g, partitionStab->S) {
		BOOST_CHECK( (*vecStabPred)(*g) );
	}
	delete vecStabPred;
	delete partitionStab;
	delete partitionVectorSearch;

	partitionStab = new BSGS<PERM,TRANS>(n);
	partitionVectorSearch = new VecStab(group, 0);
	BOOST_ASSERT(partitionStab);
	BOOST_ASSERT(partitionVectorSearch);
	partitionVectorSearch->construct(w.begin(), w.end(), maxW);
	partitionVectorSearch->search(*partitionStab);
	BOOST_CHECK_EQUAL(partitionStab->order(), n/maxW);
	vecStabPred = new VectorStabilizerPredicate<PERM>(w.begin(), w.end());
	BOOST_FOREACH(const PERM::ptr& g, partitionStab->S) {
		BOOST_CHECK( (*vecStabPred)(*g) );
	}
	delete vecStabPred;
	delete partitionStab;
	delete partitionVectorSearch;

	partitionStab = new BSGS<PERM,TRANS>(n);
	partitionVectorSearch = new VecStab(group, 0);
	BOOST_ASSERT(partitionStab);
	BOOST_ASSERT(partitionVectorSearch);
	partitionVectorSearch->construct(x.begin(), x.end(), maxX);
	partitionVectorSearch->search(*partitionStab);
	BOOST_CHECK_EQUAL(partitionStab->order(), n/maxX);
	vecStabPred = new VectorStabilizerPredicate<PERM>(x.begin(), x.end());
	BOOST_FOREACH(const PERM::ptr& g, partitionStab->S) {
		BOOST_CHECK( (*vecStabPred)(*g) );
	}
	delete vecStabPred;
	delete partitionStab;
	delete partitionVectorSearch;
}

BOOST_AUTO_TEST_CASE( vectorstabilizer_group2 )
{
	// we use elementary permutations
	typedef Permutation PERM;
	// and Schreier tree transversals
	typedef SchreierTreeTransversal<PERM> TRANSVERSAL;
	typedef partition::VectorStabilizerSearch<BSGS<PERM,TRANSVERSAL>,TRANSVERSAL> VecStab;

	BSGS<PERM,TRANSVERSAL> group = construct<PERM,TRANSVERSAL>(info_myciel3);
	const unsigned long n = group.n;

	std::vector<unsigned int> v(n,1);
	v[0] = 0;

	// computed with GAP
	const unsigned int stabilizerOrder = 4;

	ConjugatingBaseChange<PERM,TRANSVERSAL,
			RandomBaseTranspose<PERM,TRANSVERSAL> > baseChange(group);

	baseChange.change(group, boost::counting_iterator<unsigned int>(0), boost::counting_iterator<unsigned int>(1));

	// point stabilizer, we can read its order from the transversal sizes
	BOOST_CHECK_EQUAL(group.order() / group.U[0].size(), stabilizerOrder);

	BSGS<PERM,TRANSVERSAL>* partitionStab = NULL;
	VecStab* partitionVectorSearch = NULL;

	partitionStab = new BSGS<PERM,TRANSVERSAL>(n);
	partitionVectorSearch = new VecStab(group, 0);
	BOOST_ASSERT(partitionStab);
	BOOST_ASSERT(partitionVectorSearch);
	partitionVectorSearch->construct(v.begin(), v.end(), 2);
	partitionVectorSearch->search(*partitionStab);
	VectorStabilizerPredicate<PERM> vecStabPred(v.begin(), v.end());
	BOOST_FOREACH(const PERM::ptr& g, partitionStab->S) {
		BOOST_CHECK( vecStabPred(*g) );
	}
	BOOST_CHECK_EQUAL(partitionStab->order(), stabilizerOrder);
	delete partitionStab;
	delete partitionVectorSearch;
}


/**
    PublishTouchDemo.cpp

    Purpose:    a ROS node for SOMA simulation demo which publishes touches. This is used to show the adaptive motions
                of different fingers

    @authors Pollayil George Jose, Pollayil Mathew Jose
*/

//BASIC INCLUDES
#include <sstream>
#include <string>
#include <exception>
#include <math.h>

// ROS INCLUDES
#include <ros/ros.h>
#include <ros/subscribe_options.h>

// MSG INCLUDES
#include <sensor_msgs/JointState.h>
#include <std_msgs/Int8.h>

// OTHER INCLUDES
#include <cmath>
#include <boost/thread.hpp>

#define DEBUG	        0
#define HAND_NAME	    "right_hand"

using namespace std;

// GLOBAL VARIABLES
sensor_msgs::JointState::ConstPtr full_joint_state;	        // a msg where the subscriber will save the joint states
ros::Publisher pub_fing_id; 							    // publisher for the id of the finger
int finger_id;
double input_synergy_threshold;
double output_synergy_threshold;

/**********************************************************************************************
 GET FINGER JOINT STATES
**********************************************************************************************/
double getFingerJointState(){
	// Creating a JointState to be filled up
	double finger_joint;

	// Saving the state of the hand synergy joint
    ROS_DEBUG_STREAM("STARTING TO FILL UP SYNERGY JOINT!");

	int index = find (full_joint_state->name.begin(),full_joint_state->name.end(),
		string(HAND_NAME) + "_synergy_joint") - full_joint_state->name.begin();
    ROS_DEBUG_STREAM("IN MID TO FILL UP SYNERGY JOINT!");
	finger_joint = full_joint_state->position[index];

    ROS_DEBUG_STREAM("FINISHED TO FILL UP SYNERGY JOINT!");

	return finger_joint;
}

/**********************************************************************************************
 SUBSCRIBER CALLBACK
**********************************************************************************************/
void getJointStates(const sensor_msgs::JointState::ConstPtr &msg){
	// Storing the message into another global message variable
	ROS_DEBUG_STREAM("GOT JOINTSTATE MSG: STARTING TO SAVE!");
	full_joint_state = msg;
	ROS_DEBUG_STREAM("SAVED JOINTSTATE MSG!");
}

/**********************************************************************************************
 PARSING PARAMS
**********************************************************************************************/
bool getParamsOfYaml(){
	bool success = true;

	if(!ros::param::get("/publish_touch_demo/input_finger_id", finger_id)){
		ROS_WARN("input_finger_id param not found in param server! Using default value 1.");
		finger_id = 1;
		success = false;
    }

	if(!ros::param::get("/publish_touch_demo/input_synergy_threshold", input_synergy_threshold)){
		ROS_WARN("input_synergy_threshold param not found in param server! Using default value 0.3.");
		input_synergy_threshold = 0.3;
		success = false;
	}

	if(!ros::param::get("/publish_touch_demo/output_synergy_threshold", output_synergy_threshold)){
		ROS_WARN("output_synergy_threshold param not found in param server! Using default value 0.8.");
		output_synergy_threshold = 0.8;
		success = false;
	}

	return success;
}

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

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

	// Initializing ROS node
	ros::init(argc, argv, "publish_touch_demo");
	ros::NodeHandle* fjs_nh = new ros::NodeHandle();

    // Getting params from yaml
    if(!getParamsOfYaml()){
        ROS_ERROR_STREAM("Params not parsed correctly!");
    }

    // Converting the finger_id passed as arg: this will determine the adaptive motion
    std_msgs::Int8 finger_id_msg;
    finger_id_msg.data = finger_id;

    // Temporary joint state for saving synergy joint
    double synergy_joint;

	// The subscriber for saving joint states
	ros::SubscribeOptions joint_state_so = ros::SubscribeOptions::create<sensor_msgs::JointState>("joint_states",
        1, getJointStates, ros::VoidPtr(), fjs_nh->getCallbackQueue());
	ros::Subscriber js_sub = fjs_nh->subscribe(joint_state_so);

    // Creating a ROS publisher for publishing all the joint states of the finger
	pub_fing_id = fjs_nh->advertise<std_msgs::Int8>("output_topic", 1);

	// Success message
	ROS_INFO("The Touch Publisher for demo ready to publish!");
	ROS_DEBUG_STREAM("DEBUG ACTIVATED!");

    // Spinning to process callback
    full_joint_state = ros::topic::waitForMessage<sensor_msgs::JointState>("/joint_states", *fjs_nh);
    ros::spinOnce();

	// Bool for couting only once
	bool first_time = true;
	bool second_time = true;

	// Spining and looking for synergy value to publish at correct time
	while(ros::ok()){
        // Getting the present synergy
        synergy_joint = getFingerJointState();

        // Publishing the finger_id if synergy is at a certain value
        if(synergy_joint >= input_synergy_threshold && synergy_joint <= output_synergy_threshold){
			if(first_time){
				ROS_INFO_STREAM("Publishing the finger_id " << finger_id << " on the touch topic!");
				first_time = false;
			}
            pub_fing_id.publish(finger_id_msg);
        }

		if(synergy_joint > output_synergy_threshold){
			if(second_time){
				ROS_INFO_STREAM("Stopping the adaptive motion!");
				second_time = false;
			}
			finger_id_msg.data = 6;
            pub_fing_id.publish(finger_id_msg);
        }

        // Spinning to process callbacks
        ros::spinOnce();
    }

    // Exit message
	ROS_INFO("Exiting Touch Publisher!");

}


#include <boost/numeric/ublas/symmetric.hpp>