// Copyright (C) 2011-2012 The Trustees of Indiana University.

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

//  Authors: Jeremiah Willcock
//           Andrew Lumsdaine

#ifndef FAST_RMAT_HPP
#define FAST_RMAT_HPP

#include <boost/graph/random/nway_bernoulli_distribution.hpp>
#include <boost/graph/random/splittable_ecuyer1988.hpp>
#include <boost/graph/random/btrd_binomial_distribution.hpp>
#include <vector>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/random/variate_generator.hpp>

#include <boost/graph/random/next_level_parameters_generated.ipp>
#include <stack>

// #define KEEP_ALL

//
// Available filters
//

namespace rmat_detail {

// keep all edges
template <typename T>
struct keep_all {
  bool operator()(T base_src, T base_tgt, T log2_nverts) const { return true; }
};

// keep only edges originating from a given source range
template <typename T>
struct source_range_filter {
  T start, end;
  source_range_filter(T start, T end): start(start), end(end) {}
  source_range_filter(): start(0), end(0) {}
  bool operator()(T base_src, T base_tgt, T log2_nverts) const {
    return base_src < end &&
      (base_src + (static_cast<T>(1) << log2_nverts)) > start &&
      base_src >= base_tgt &&
      (log2_nverts != 0 || base_src > base_tgt);  // Remove self-loops
  }
};

} // end namespace rmat_detail

// TODO: Replace this with boost::spirit::tuple?
template <typename T>
struct generated_edge {
  T src;
  T tgt;
  T multiplicity;
  generated_edge(T src, T tgt, T multiplicity = 1)
    : src(src), tgt(tgt), multiplicity(multiplicity) {}
  generated_edge(): src(0), tgt(0), multiplicity(0) {}
  bool operator==(const generated_edge<T>& e) const {
    return src == e.src && tgt == e.tgt && multiplicity == e.multiplicity;
  }
};

using boost::graph::random::nway_bernoulli_distribution;
using boost::graph::random::make_nway_bernoulli_distribution;

template <typename Gen>
static inline void alter_params(double& a, double& b, double& c, double& d, Gen* gen) {
  boost::variate_generator<Gen*, boost::uniform_01<> > gen01(gen, boost::uniform_01<>());
  a *= .9 + .2 * gen01();
  b *= .9 + .2 * gen01();
  c *= .9 + .2 * gen01();
  d *= .9 + .2 * gen01();
  double divisor = a + b + c + d;
  a /= divisor;
  b /= divisor;
  c /= divisor;
  d /= divisor;
}

template <typename Gen, typename T>
static inline
generated_edge<T> make_one_edge(T base_src, T base_tgt, int log2_nverts, Gen* gen,
				double a, double b, double c, double d) {
  double params[4] = {a, b, c, d};
  while (log2_nverts != 0) {
    int quad = make_nway_bernoulli_distribution<4, double>(params, *gen)(*gen);
    --log2_nverts;
    T new_block_size = static_cast<T>(1) << log2_nverts;
    base_src += ((quad & 2) != 0 ? new_block_size : 0);
    base_tgt += ((quad & 1) != 0 ? new_block_size : 0);
    alter_params(a, b, c, d, gen);
  }
  return generated_edge<T>(base_src, base_tgt, 1);
}

template <typename Gen, typename T>
static inline
void make_quadrant_counts(T num_edges, T /* log2_nverts */, Gen* gen, double a, double b,
			  double c, double d, T* quadrant_counts) {
  if (num_edges <= 20) {
    quadrant_counts[0] = 0;
    quadrant_counts[1] = 0;
    quadrant_counts[2] = 0;
    quadrant_counts[3] = 0;
    double params[4] = {a, b, c, d};

    nway_bernoulli_distribution<4, double, typename Gen::result_type> distrib
      = make_nway_bernoulli_distribution<4, double>(params, *gen);

    for (T i = 0; i < num_edges; ++i)
      ++quadrant_counts[distrib(*gen)];

  } else {

    boost::variate_generator<Gen*, boost::uniform_01<> > gen01(gen, boost::uniform_01<>());
    quadrant_counts[0] = btrd_binomial_distribution(num_edges, a, gen01);
    quadrant_counts[1] = btrd_binomial_distribution(num_edges - quadrant_counts[0],
						    b / (1. - a),
						    gen01);
    quadrant_counts[2] = btrd_binomial_distribution(num_edges - quadrant_counts[0] - quadrant_counts[1],
						    c / (1. - a - b),
						    gen01);
    quadrant_counts[3] = num_edges - quadrant_counts[0] - quadrant_counts[1] - quadrant_counts[2];
  }
}

namespace boost {

// Note: Generator must be a splittable generator such as the splittable_ecuyer1988
template <typename Transport, typename Generator, typename Graph,
	  typename Filter =
#ifdef KEEP_ALL
	  rmat_detail::keep_all<typename graph_traits<Graph>::vertices_size_type> >
#else
	  rmat_detail::source_range_filter<typename graph_traits<Graph>::vertices_size_type> >
#endif
class recursive_rmat_generator
  : public boost::iterator_facade<recursive_rmat_generator<Transport, Generator, Graph, Filter>,
// 				  generated_edge<typename graph_traits<Graph>::vertices_size_type>,
				  std::pair<typename graph_traits<Graph>::vertices_size_type,
					    typename graph_traits<Graph>::vertices_size_type>,
				  std::forward_iterator_tag,
// 				  const generated_edge<typename graph_traits<Graph>::vertices_size_type>&>
				  const std::pair<typename graph_traits<Graph>::vertices_size_type,
						  typename graph_traits<Graph>::vertices_size_type>&>
{
  typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
  typedef typename graph_traits<Graph>::edges_size_type edges_size_type;

public:

  typedef std::pair<typename graph_traits<Graph>::vertices_size_type,
		    typename graph_traits<Graph>::vertices_size_type> value_type;

//   recursive_rmat_generator(const recursive_rmat_generator& /* x */) { assert(false); exit(-1); }
//   recursive_rmat_generator& operator=(const recursive_rmat_generator& /* x */) { assert(false); exit(-1); }

  recursive_rmat_generator(const Transport& transport, Generator& gen, vertices_size_type log2_nverts,
			   vertices_size_type nedges, double a, double b, double c, double d)
    : work(), filter(
#ifdef KEEP_ALL
		     rmat_detail::keep_all<vertices_size_type>()),
#else
                     rmat_detail::source_range_filter<vertices_size_type>
                       (transport.rank() * pow(2, log2_nverts) / transport.size(),
		       std::min((transport.rank() + 1) * pow(2, log2_nverts) / transport.size(),
		       pow(2, log2_nverts)))),
#endif
      param_data(4 * (log2_nverts + 1)), cached_edge(), at_end(false)
  {
    assert (a >= b);
    assert (a >= c);
    assert (b >= d);
    assert (c >= d);
    work_queue_entry s;
    s.gen = *gen.split_off_n(1).first;
    s.num_edges = nedges;
    s.log2_nverts = log2_nverts;
    s.base_src = s.base_tgt = 0;
    s.a = a;
    s.b = b;
    s.c = c;
    s.d = d;
    work.push(s);
    at_end = !step();
  }

  recursive_rmat_generator(const Transport& transport, Generator& gen, vertices_size_type log2_nverts,
			   vertices_size_type nedges, double a, double b, double c, double d,
			   const Filter& filter)
    : work(), filter(filter), param_data(4 * (log2_nverts + 1)),
      cached_edge(), at_end(false)
  {
    assert (a >= b);
    assert (a >= c);
    assert (b >= d);
    assert (c >= d);
    work_queue_entry s;
    s.gen = *gen.split_off_n(1).first;
    s.num_edges = nedges;
    s.log2_nverts = log2_nverts;
    s.base_src = s.base_tgt = 0;
    s.a = a;
    s.b = b;
    s.c = c;
    s.d = d;
    work.push(s);
    at_end = !step();
  }

  recursive_rmat_generator()
    : work(), filter(Filter()), param_data(), cached_edge(), at_end(true)
  { }

  // iterator_facade operations
  friend class boost::iterator_core_access;

private:

//   const generated_edge<vertices_size_type>& dereference() const {return cached_edge;}
  const value_type& dereference() const { return current_edge; }
  vertices_size_type get_multiplicity() const { return cached_edge.multiplicity; }

  bool equal(const recursive_rmat_generator& a) const {
    return at_end == a.at_end && work == a.work;
  }

  void increment() {
    if (at_end) return;
    at_end = !step();
  }

  // Internals
  struct work_queue_entry {
    Generator gen;
    edges_size_type num_edges;
    vertices_size_type log2_nverts;
    vertices_size_type base_src, base_tgt;
    double a, b, c, d;

    friend bool operator==(const work_queue_entry& a, const work_queue_entry& b) {
      return a.num_edges == b.num_edges &&
             a.log2_nverts == b.log2_nverts &&
             a.base_src == b.base_src && a.base_tgt == b.base_tgt;
    }
  };

  std::stack<work_queue_entry, std::vector<work_queue_entry> > work;
  Filter filter;
  std::vector<double> param_data;
  generated_edge<vertices_size_type> cached_edge;
  value_type current_edge;
  bool at_end;

  bool step() { // Returns true if there is a new edge
    while (true) { // Exited by return statements in loop
      if (work.empty()) return false;
      work_queue_entry e = work.top();
      work.pop();

      if (e.log2_nverts == 0) {
        assert (e.num_edges != 0);
        cached_edge = generated_edge<vertices_size_type>(e.base_src, e.base_tgt, e.num_edges);
	current_edge = std::make_pair(cached_edge.src, cached_edge.tgt);
        return true;
      } else if (e.num_edges == 1) {
        cached_edge = make_one_edge(e.base_src, e.base_tgt, e.log2_nverts,
				    &e.gen, e.a, e.b, e.c, e.d);
	current_edge = std::make_pair(cached_edge.src, cached_edge.tgt);

        if (filter(cached_edge.src, cached_edge.tgt, 0)) {
          return true;
        }
      } else {
        edges_size_type quadrant_counts[4];
        make_quadrant_counts(e.num_edges, e.log2_nverts, &e.gen, e.a, e.b, e.c, e.d, quadrant_counts);
        typename Generator::split_iterator subparts = e.gen.split_n(4).first;
        --e.log2_nverts;
        vertices_size_type old_base_src = e.base_src;
        vertices_size_type old_base_tgt = e.base_tgt;
        vertices_size_type new_block_size = static_cast<vertices_size_type>(1) << e.log2_nverts;
        double na = e.a, nb = e.b, nc = e.c, nd = e.d;

        for (int i = 3; i >= 0; --i) { // Order reversed to push in stack correctly
          e.gen = *subparts++;
          if (quadrant_counts[i] != 0) {
            e.num_edges = quadrant_counts[i];
            e.base_src = old_base_src + ((i & 2) ? new_block_size : 0);
            e.base_tgt = old_base_tgt + ((i & 1) ? new_block_size : 0);
            if (filter(e.base_src, e.base_tgt, e.log2_nverts)) {
              e.a = na;
              e.b = nb;
              e.c = nc;
              e.d = nd;
              alter_params(e.a, e.b, e.c, e.d, &e.gen);
              work.push(e);
            }
          }
        }
        // Go to top of loop
      }
    }
  }
};

} // end namespace boost

#endif // FAST_RMAT_HPP


//==============================================================================
//         Copyright 2003 - 2013   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2013   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
//==============================================================================
#include <nt2/include/functions/pow_abs.hpp>

#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <complex>
#include <nt2/sdk/complex/complex.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/meta/as_integer.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/sdk/config.hpp>
#include <nt2/include/functions/ones.hpp>
#include <nt2/table.hpp>

#include <nt2/include/constants/i.hpp>

NT2_TEST_CASE_TPL ( pow_abs3,  NT2_REAL_TYPES)
{
  using nt2::pow_abs;
  using nt2::tag::pow_abs_;
  typedef typename std::complex<T> cT;

  nt2::table<cT> a = nt2::ones(3, 3, nt2::meta::as_<cT>());
  nt2::table<cT> b = nt2::ones(3, 3, nt2::meta::as_<cT>());

  // specific values tests
  NT2_TEST_EQUAL(a, nt2::pow_abs(a, b));
}

NT2_TEST_CASE_TPL ( pow_abs4,  NT2_REAL_TYPES)
{
  using nt2::pow_abs;
  using nt2::tag::pow_abs_;
  typedef typename std::complex<T> cT;

  nt2::table<cT> a = nt2::ones(1, 3, nt2::meta::as_<cT>());
  nt2::table<T> b = T(2)*nt2::ones(1, 3, nt2::meta::as_<T>());

  for(int i=1; i <= 3; i++) a(i) =  cT(i, i);
  // specific values tests
  NT2_TEST_ULP_EQUAL(nt2::pow_abs(a, b), T(2)*nt2::sqr(nt2::real(a)), T(2.0));
}


#include "puzzle.h"

#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <utility>
#include <vector>

#include <boost/algorithm/cxx11/any_of.hpp>

puzzle::puzzle(std::vector<int> board) {
    this->board = board;
    this->board_width = std::sqrt(board.size());

    this->fixed_squares = {};
    this->attempts = std::vector<std::vector<int>>(board.size());

    // Set fixed squares.
    for (int i = 0; i < (int)board.size(); i++) {
        if (board[i] == BLANK) this->fixed_squares.push_back(i);
    }
}

void puzzle::solve() {
    int index = 0;
    std::vector<int> moves;

    while (index >= 0 && index < (int)this->board.size()) {
        if (this->is_fixed_square(index)) {
            index++;
            continue;
        }

        moves = this->get_moves(index);

        // If there are no available moves, backtrack to try a different branch.
        if (moves.empty()) {
            do {
                if (!this->is_fixed_square(index)) {
                    this->board[index] = BLANK;
                    this->attempts[index].clear();
                }
                index--;
            } while (this->is_fixed_square(index));

            continue;
        }

        this->board[index] = moves[0];
        this->attempts[index].push_back(moves[0]);
        index++;
    }
}

void puzzle::display() {
    int square;

    for (int row = 0; row < this->board_width; row++) {
        for (int col = 0; col < this->board_width; col++) {
            square = this->board[this->get_index(row, col)];

            if (square == BLANK) {
                std::cout << ".";
            } else {
                std::cout << square;
            }
            std::cout << " ";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

bool puzzle::is_valid() {
    // Only support board of size 4x4, or 9x9.
    if (this->board.size() != 16 && this->board.size() != 81) return false;

    // Check board is a square.
    if (std::pow(this->board_width, 2) != this->board.size()) return false;

    // Check there is no square out of range.
    for (auto const& square : this->board) {
        if (square != BLANK && (square < 1 || square > this->board_width)) {
            return false;
        }
    }

    // We could also check that there is at most one instance of each number in
    // every row, column, and region but to keep things simple I will assume that
    // this is the case.
    return true;
}

std::vector<int> puzzle::get_board() {
    return this->board;
}

int puzzle::get_board_width() {
    return this->board_width;
}

bool puzzle::is_fixed_square(int index) {
    return !boost::algorithm::any_of_equal(this->fixed_squares, index);
}

std::vector<int> puzzle::get_moves(int index) {
    std::vector<int> seen{};

    int row = this->get_row(index);
    int col = this->get_column(index);
    int board_index;

    // Add items in rows and columns.
    for (int i = 0; i < this->board_width; i++) {
        for (int j = 0; j < this->board_width; j++) {
            board_index = this->get_index(i, j);

            if (this->board[board_index] == BLANK) continue;
            if (i == row) seen.push_back(this->board[board_index]);
            if (j == col) seen.push_back(this->board[board_index]);
        }
    }

    int region_width = (int)std::sqrt(this->board_width);
    int start_row = row - (row % region_width);
    int start_column = col - (col % region_width);

    // Range of the columns that form the region.
    std::pair<int, int> col_range =
        std::make_pair(start_column, start_column + region_width - 1);

    // Range of the rows that form the region.
    std::pair<int, int> row_range =
        std::make_pair(start_row, start_row + region_width - 1);

    // Add items in region.
    for (int i = row_range.first; i <= row_range.second; i++) {
        for (int j = col_range.first; j <= col_range.second; j++) {
            board_index = this->get_index(i, j);
            if (this->board[board_index] != BLANK) {
                seen.push_back(this->board[board_index]);
            }
        }
    }

    std::vector<int> possible_moves(this->board_width);
    std::iota(possible_moves.begin(), possible_moves.end(), 1);

    // Take the difference of the set of possible squares that can be placed and
    // the squares that were seen. Then remove the set of attempted moves, for
    // that index, from the set of available moves.
    auto available_moves = vec_difference(possible_moves, seen);
    return vec_difference(available_moves, this->attempts[index]);
}

std::vector<int> vec_difference(std::vector<int> a, std::vector<int> b) {
    std::vector<int> result;

    std::sort(a.begin(), a.end());
    std::sort(b.begin(), b.end());

    std::set_difference(
        a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(result));
    return result;
}


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

#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/traits.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_expression.hpp>
#include <boost/numeric/ublasx/operation/cumsum.hpp>
#include <boost/numeric/ublasx/tags.hpp>
#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( test_vector_container )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Vector Container" );

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

	size_type n(5);

	vector_type v(n);

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

	zero_vector_type z(n);

	vector_type expect(n, 0);
	vector_type res(n, 0);

	// cumsum(z)
	expect = vector_type(n, 0);
	res = ublasx::cumsum(z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );

	// cumsum(v)
	expect = vector_type(n);
	expect(0) = v(0);
	expect(1) = v(0)+v(1);
	expect(2) = v(0)+v(1)+v(2);
	expect(3) = v(0)+v(1)+v(2)+v(3);
	expect(4) = v(0)+v(1)+v(2)+v(3)+v(4);
	res = ublasx::cumsum(v);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << v << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );

	// cumsum<1>(v)
	expect = vector_type(n);
	expect(0) = v(0);
	expect(1) = v(0)+v(1);
	expect(2) = v(0)+v(1)+v(2);
	expect(3) = v(0)+v(1)+v(2)+v(3);
	expect(4) = v(0)+v(1)+v(2)+v(3)+v(4);
	res = ublasx::cumsum<1>(v);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << v << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );
}

BOOST_UBLASX_TEST_DEF( test_vector_expression )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Vector Expression" );

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

	size_type n(5);

	vector_type v(n);

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

	vector_type expect(n, 0);
	vector_type res(n, 0);

	// cumsum(-v)
	expect = vector_type(n);
	expect(0) = -v(0);
	expect(1) = -(v(0)+v(1));
	expect(2) = -(v(0)+v(1)+v(2));
	expect(3) = -(v(0)+v(1)+v(2)+v(3));
	expect(4) = -(v(0)+v(1)+v(2)+v(3)+v(4));
	res = ublasx::cumsum(-v);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << -v << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );

	// cumsum<1>(-v)
	expect = vector_type(n);
	expect(0) = -v(0);
	expect(1) = -(v(0)+v(1));
	expect(2) = -(v(0)+v(1)+v(2));
	expect(3) = -(v(0)+v(1)+v(2)+v(3));
	expect(4) = -(v(0)+v(1)+v(2)+v(3)+v(4));
	res = ublasx::cumsum<1>(-v);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << -v << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );
}

BOOST_UBLASX_TEST_DEF( test_vector_reference )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Vector Reference" );

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

	size_type n(5);

	vector_type v(n);

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

	vector_type expect(n, 0);
	vector_type res(n, 0);

	// cumsum(ref(v))
	expect = vector_type(n);
	expect(0) = v(0);
	expect(1) = v(0)+v(1);
	expect(2) = v(0)+v(1)+v(2);
	expect(3) = v(0)+v(1)+v(2)+v(3);
	expect(4) = v(0)+v(1)+v(2)+v(3)+v(4);
	res = ublasx::cumsum(vector_reference_type(v));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << vector_reference_type(v) << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );

	// cumsum<1>(ref(v))
	expect = vector_type(n);
	expect(0) = v(0);
	expect(1) = v(0)+v(1);
	expect(2) = v(0)+v(1)+v(2);
	expect(3) = v(0)+v(1)+v(2)+v(3);
	expect(4) = v(0)+v(1)+v(2)+v(3)+v(4);
	res = ublasx::cumsum<1>(vector_reference_type(v));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << vector_reference_type(v) << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_VECTOR_CLOSE( res, expect, n, tol );
}

BOOST_UBLASX_TEST_DEF( test_row_major_matrix_container )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST 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::matrix_traits<matrix_type>::size_type size_type;

	size_type nr = 5;
	size_type 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);

	matrix_type cumsum_rows(nr,nc);
	cumsum_rows(0,0) = A(0,0); cumsum_rows(0,1) = A(0,1); cumsum_rows(0,2) = A(0,2); cumsum_rows(0,3) = A(0,3);
	cumsum_rows(1,0) = A(0,0)+A(1,0); cumsum_rows(1,1) = A(0,1)+A(1,1); cumsum_rows(1,2) = A(0,2)+A(1,2); cumsum_rows(1,3) = A(0,3)+A(1,3);
	cumsum_rows(2,0) = A(0,0)+A(1,0)+A(2,0); cumsum_rows(2,1) = A(0,1)+A(1,1)+A(2,1); cumsum_rows(2,2) = A(0,2)+A(1,2)+A(2,2); cumsum_rows(2,3) = A(0,3)+A(1,3)+A(2,3);
	cumsum_rows(3,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0); cumsum_rows(3,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1); cumsum_rows(3,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2); cumsum_rows(3,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3);
	cumsum_rows(4,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0)+A(4,0); cumsum_rows(4,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1)+A(4,1); cumsum_rows(4,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2)+A(4,2); cumsum_rows(4,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3)+A(4,3);

	matrix_type cumsum_cols(nr,nc);
	cumsum_cols(0,0) = A(0,0); cumsum_cols(0,1) = A(0,0)+A(0,1); cumsum_cols(0,2) = A(0,0)+A(0,1)+A(0,2); cumsum_cols(0,3) = A(0,0)+A(0,1)+A(0,2)+A(0,3);
	cumsum_cols(1,0) = A(1,0); cumsum_cols(1,1) = A(1,0)+A(1,1); cumsum_cols(1,2) = A(1,0)+A(1,1)+A(1,2); cumsum_cols(1,3) = A(1,0)+A(1,1)+A(1,2)+A(1,3);
	cumsum_cols(2,0) = A(2,0); cumsum_cols(2,1) = A(2,0)+A(2,1); cumsum_cols(2,2) = A(2,0)+A(2,1)+A(2,2); cumsum_cols(2,3) = A(2,0)+A(2,1)+A(2,2)+A(2,3);
	cumsum_cols(3,0) = A(3,0); cumsum_cols(3,1) = A(3,0)+A(3,1); cumsum_cols(3,2) = A(3,0)+A(3,1)+A(3,2); cumsum_cols(3,3) = A(3,0)+A(3,1)+A(3,2)+A(3,3);
	cumsum_cols(4,0) = A(4,0); cumsum_cols(4,1) = A(4,0)+A(4,1); cumsum_cols(4,2) = A(4,0)+A(4,1)+A(4,2); cumsum_cols(4,3) = A(4,0)+A(4,1)+A(4,2)+A(4,3);

	matrix_type expect(nr,nc);
	matrix_type res(nr,nc);

	// cumsum(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_rows(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_rows(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_columns(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_columns(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<1>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum<1>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<2>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum<2>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::major>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::major>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::minor>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::minor>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::leading>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::leading>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum(A)
	expect = cumsum_rows;
	res = ublasx::cumsum(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_rows(A)
	expect = cumsum_rows;
	res = ublasx::cumsum_rows(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_columns(A)
	expect = cumsum_cols;
	res = ublasx::cumsum_columns(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<1>(A)
	expect = cumsum_rows;
	res = ublasx::cumsum<1>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<2>(A)
	expect = cumsum_cols;
	res = ublasx::cumsum<2>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<2>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::major>(A)
	expect = cumsum_rows;
	res = ublasx::cumsum_by_tag<ublasx::tag::major>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::minor>(A)
	expect = cumsum_cols;
	res = ublasx::cumsum_by_tag<ublasx::tag::minor>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::leading>(A)
	expect = cumsum_cols;
	res = ublasx::cumsum_by_tag<ublasx::tag::leading>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );
}

BOOST_UBLASX_TEST_DEF( test_col_major_matrix_container )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Column-major Matrix Container" );

	typedef double value_type;
	typedef ublas::matrix<value_type, ublas::column_major> matrix_type;
	typedef ublas::zero_matrix<value_type> zero_matrix_type;
	typedef ublas::matrix_traits<matrix_type>::size_type size_type;

	size_type nr = 5;
	size_type 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);

	matrix_type cumsum_rows(nr,nc);
	cumsum_rows(0,0) = A(0,0); cumsum_rows(0,1) = A(0,1); cumsum_rows(0,2) = A(0,2); cumsum_rows(0,3) = A(0,3);
	cumsum_rows(1,0) = A(0,0)+A(1,0); cumsum_rows(1,1) = A(0,1)+A(1,1); cumsum_rows(1,2) = A(0,2)+A(1,2); cumsum_rows(1,3) = A(0,3)+A(1,3);
	cumsum_rows(2,0) = A(0,0)+A(1,0)+A(2,0); cumsum_rows(2,1) = A(0,1)+A(1,1)+A(2,1); cumsum_rows(2,2) = A(0,2)+A(1,2)+A(2,2); cumsum_rows(2,3) = A(0,3)+A(1,3)+A(2,3);
	cumsum_rows(3,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0); cumsum_rows(3,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1); cumsum_rows(3,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2); cumsum_rows(3,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3);
	cumsum_rows(4,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0)+A(4,0); cumsum_rows(4,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1)+A(4,1); cumsum_rows(4,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2)+A(4,2); cumsum_rows(4,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3)+A(4,3);

	matrix_type cumsum_cols(nr,nc);
	cumsum_cols(0,0) = A(0,0); cumsum_cols(0,1) = A(0,0)+A(0,1); cumsum_cols(0,2) = A(0,0)+A(0,1)+A(0,2); cumsum_cols(0,3) = A(0,0)+A(0,1)+A(0,2)+A(0,3);
	cumsum_cols(1,0) = A(1,0); cumsum_cols(1,1) = A(1,0)+A(1,1); cumsum_cols(1,2) = A(1,0)+A(1,1)+A(1,2); cumsum_cols(1,3) = A(1,0)+A(1,1)+A(1,2)+A(1,3);
	cumsum_cols(2,0) = A(2,0); cumsum_cols(2,1) = A(2,0)+A(2,1); cumsum_cols(2,2) = A(2,0)+A(2,1)+A(2,2); cumsum_cols(2,3) = A(2,0)+A(2,1)+A(2,2)+A(2,3);
	cumsum_cols(3,0) = A(3,0); cumsum_cols(3,1) = A(3,0)+A(3,1); cumsum_cols(3,2) = A(3,0)+A(3,1)+A(3,2); cumsum_cols(3,3) = A(3,0)+A(3,1)+A(3,2)+A(3,3);
	cumsum_cols(4,0) = A(4,0); cumsum_cols(4,1) = A(4,0)+A(4,1); cumsum_cols(4,2) = A(4,0)+A(4,1)+A(4,2); cumsum_cols(4,3) = A(4,0)+A(4,1)+A(4,2)+A(4,3);

	matrix_type expect(nr,nc);
	matrix_type res(nr,nc);

	// cumsum(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_rows(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_rows(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_columns(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_columns(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<1>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum<1>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<2>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum<2>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::major>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::major>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::minor>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::minor>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::leading>(Z)
	expect = matrix_type(nr, nc, 0);
	res = ublasx::cumsum_by_tag<ublas::tag::leading>(Z);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(" << Z << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum(A)
	expect = cumsum_rows;
	res = ublasx::cumsum(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_rows(A)
	expect = cumsum_rows;
	res = ublasx::cumsum_rows(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_columns(A)
	expect = cumsum_cols;
	res = ublasx::cumsum_columns(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<1>(A)
	expect = cumsum_rows;
	res = ublasx::cumsum<1>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<2>(A)
	expect = cumsum_cols;
	res = ublasx::cumsum<2>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<2>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::major>(A)
	expect = cumsum_cols;
	res = ublasx::cumsum_by_tag<ublasx::tag::major>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::minor>(A)
	expect = cumsum_rows;
	res = ublasx::cumsum_by_tag<ublasx::tag::minor>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::leading>(A)
	expect = cumsum_rows;
	res = ublasx::cumsum_by_tag<ublasx::tag::leading>(A);
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(" << A << ") = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );
}

BOOST_UBLASX_TEST_DEF( test_matrix_expression )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Matrix Expression" );

	typedef double value_type;
	typedef ublas::matrix<value_type> matrix_type;
	typedef ublas::matrix_traits<matrix_type>::size_type size_type;

	size_type nr = 5;
	size_type 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;

	matrix_type cumsum_rows(nr,nc);
	cumsum_rows(0,0) = A(0,0); cumsum_rows(0,1) = A(0,1); cumsum_rows(0,2) = A(0,2); cumsum_rows(0,3) = A(0,3);
	cumsum_rows(1,0) = A(0,0)+A(1,0); cumsum_rows(1,1) = A(0,1)+A(1,1); cumsum_rows(1,2) = A(0,2)+A(1,2); cumsum_rows(1,3) = A(0,3)+A(1,3);
	cumsum_rows(2,0) = A(0,0)+A(1,0)+A(2,0); cumsum_rows(2,1) = A(0,1)+A(1,1)+A(2,1); cumsum_rows(2,2) = A(0,2)+A(1,2)+A(2,2); cumsum_rows(2,3) = A(0,3)+A(1,3)+A(2,3);
	cumsum_rows(3,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0); cumsum_rows(3,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1); cumsum_rows(3,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2); cumsum_rows(3,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3);
	cumsum_rows(4,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0)+A(4,0); cumsum_rows(4,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1)+A(4,1); cumsum_rows(4,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2)+A(4,2); cumsum_rows(4,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3)+A(4,3);

	matrix_type cumsum_cols(nr,nc);
	cumsum_cols(0,0) = A(0,0); cumsum_cols(0,1) = A(0,0)+A(0,1); cumsum_cols(0,2) = A(0,0)+A(0,1)+A(0,2); cumsum_cols(0,3) = A(0,0)+A(0,1)+A(0,2)+A(0,3);
	cumsum_cols(1,0) = A(1,0); cumsum_cols(1,1) = A(1,0)+A(1,1); cumsum_cols(1,2) = A(1,0)+A(1,1)+A(1,2); cumsum_cols(1,3) = A(1,0)+A(1,1)+A(1,2)+A(1,3);
	cumsum_cols(2,0) = A(2,0); cumsum_cols(2,1) = A(2,0)+A(2,1); cumsum_cols(2,2) = A(2,0)+A(2,1)+A(2,2); cumsum_cols(2,3) = A(2,0)+A(2,1)+A(2,2)+A(2,3);
	cumsum_cols(3,0) = A(3,0); cumsum_cols(3,1) = A(3,0)+A(3,1); cumsum_cols(3,2) = A(3,0)+A(3,1)+A(3,2); cumsum_cols(3,3) = A(3,0)+A(3,1)+A(3,2)+A(3,3);
	cumsum_cols(4,0) = A(4,0); cumsum_cols(4,1) = A(4,0)+A(4,1); cumsum_cols(4,2) = A(4,0)+A(4,1)+A(4,2); cumsum_cols(4,3) = A(4,0)+A(4,1)+A(4,2)+A(4,3);

	matrix_type expect;
	matrix_type res;

	// cumsum(A')
	expect = ublas::trans(cumsum_cols);
	res = ublasx::cumsum(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum_rows(A')
	expect = ublas::trans(cumsum_cols);
	res = ublasx::cumsum_rows(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum_columns(A')
	expect = ublas::trans(cumsum_rows);
	res = ublasx::cumsum_columns(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum<1>(A')
	expect = ublas::trans(cumsum_cols);
	res = ublasx::cumsum<1>(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum<2>(A')
	expect = ublas::trans(cumsum_rows);
	res = ublasx::cumsum<2>(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<2>(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum<tag::major>(A')
	expect = ublas::trans(cumsum_rows);
	res = ublasx::cumsum_by_tag<ublasx::tag::major>(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum<tag::minor>(A')
	expect = ublas::trans(cumsum_cols);
	res = ublasx::cumsum_by_tag<ublasx::tag::minor>(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );

	// cumsum<tag::leading>(A')
	expect = ublas::trans(cumsum_cols);
	res = ublasx::cumsum_by_tag<ublasx::tag::leading>(ublas::trans(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(" << A << "') = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nc, nr, tol );
}

BOOST_UBLASX_TEST_DEF( test_matrix_reference )
{
	BOOST_UBLASX_DEBUG_TRACE( "TEST Matrix Reference" );

	typedef double value_type;
	typedef ublas::matrix<value_type> matrix_type;
	typedef ublas::matrix_reference<matrix_type> matrix_reference_type;
	typedef ublas::matrix_traits<matrix_type>::size_type size_type;

	size_type nr = 5;
	size_type 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;

	matrix_type cumsum_rows(nr,nc);
	cumsum_rows(0,0) = A(0,0); cumsum_rows(0,1) = A(0,1); cumsum_rows(0,2) = A(0,2); cumsum_rows(0,3) = A(0,3);
	cumsum_rows(1,0) = A(0,0)+A(1,0); cumsum_rows(1,1) = A(0,1)+A(1,1); cumsum_rows(1,2) = A(0,2)+A(1,2); cumsum_rows(1,3) = A(0,3)+A(1,3);
	cumsum_rows(2,0) = A(0,0)+A(1,0)+A(2,0); cumsum_rows(2,1) = A(0,1)+A(1,1)+A(2,1); cumsum_rows(2,2) = A(0,2)+A(1,2)+A(2,2); cumsum_rows(2,3) = A(0,3)+A(1,3)+A(2,3);
	cumsum_rows(3,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0); cumsum_rows(3,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1); cumsum_rows(3,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2); cumsum_rows(3,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3);
	cumsum_rows(4,0) = A(0,0)+A(1,0)+A(2,0)+A(3,0)+A(4,0); cumsum_rows(4,1) = A(0,1)+A(1,1)+A(2,1)+A(3,1)+A(4,1); cumsum_rows(4,2) = A(0,2)+A(1,2)+A(2,2)+A(3,2)+A(4,2); cumsum_rows(4,3) = A(0,3)+A(1,3)+A(2,3)+A(3,3)+A(4,3);

	matrix_type cumsum_cols(nr,nc);
	cumsum_cols(0,0) = A(0,0); cumsum_cols(0,1) = A(0,0)+A(0,1); cumsum_cols(0,2) = A(0,0)+A(0,1)+A(0,2); cumsum_cols(0,3) = A(0,0)+A(0,1)+A(0,2)+A(0,3);
	cumsum_cols(1,0) = A(1,0); cumsum_cols(1,1) = A(1,0)+A(1,1); cumsum_cols(1,2) = A(1,0)+A(1,1)+A(1,2); cumsum_cols(1,3) = A(1,0)+A(1,1)+A(1,2)+A(1,3);
	cumsum_cols(2,0) = A(2,0); cumsum_cols(2,1) = A(2,0)+A(2,1); cumsum_cols(2,2) = A(2,0)+A(2,1)+A(2,2); cumsum_cols(2,3) = A(2,0)+A(2,1)+A(2,2)+A(2,3);
	cumsum_cols(3,0) = A(3,0); cumsum_cols(3,1) = A(3,0)+A(3,1); cumsum_cols(3,2) = A(3,0)+A(3,1)+A(3,2); cumsum_cols(3,3) = A(3,0)+A(3,1)+A(3,2)+A(3,3);
	cumsum_cols(4,0) = A(4,0); cumsum_cols(4,1) = A(4,0)+A(4,1); cumsum_cols(4,2) = A(4,0)+A(4,1)+A(4,2); cumsum_cols(4,3) = A(4,0)+A(4,1)+A(4,2)+A(4,3);

	matrix_type expect;
	matrix_type res;

	// cumsum(ref(A))
	expect = cumsum_rows;
	res = ublasx::cumsum(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_rows(ref(A))
	expect = cumsum_rows;
	res = ublasx::cumsum_rows(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_rows(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum_columns(ref(A))
	expect = cumsum_cols;
	res = ublasx::cumsum_columns(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_columns(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<1>(ref(A))
	expect = cumsum_rows;
	res = ublasx::cumsum<1>(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<1>(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<2>(ref(A))
	expect = cumsum_cols;
	res = ublasx::cumsum<2>(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum<2>(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::major>(ref(A))
	expect = cumsum_rows;
	res = ublasx::cumsum_by_tag<ublasx::tag::major>(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::major>(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::minor>(ref(A))
	expect = cumsum_cols;
	res = ublasx::cumsum_by_tag<ublasx::tag::minor>(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::minor>(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );

	// cumsum<tag::leading>(ref(A))
	expect = cumsum_cols;
	res = ublasx::cumsum_by_tag<ublasx::tag::leading>(matrix_reference_type(A));
	BOOST_UBLASX_DEBUG_TRACE( "cumsum_by_tag<tag::leading>(reference(" << A << ")) = " << res << " ==> " << expect );
	BOOST_UBLASX_TEST_CHECK_MATRIX_CLOSE( res, expect, nr, nc, tol );
}

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

	BOOST_UBLASX_TEST_BEGIN();

	BOOST_UBLASX_TEST_DO( test_vector_container );
	BOOST_UBLASX_TEST_DO( test_vector_expression );
	BOOST_UBLASX_TEST_DO( test_vector_reference );
	BOOST_UBLASX_TEST_DO( test_row_major_matrix_container );
	BOOST_UBLASX_TEST_DO( test_col_major_matrix_container );
	BOOST_UBLASX_TEST_DO( test_matrix_expression );
	BOOST_UBLASX_TEST_DO( test_matrix_reference );

	BOOST_UBLASX_TEST_END();
}


/*
 * Copyright 2011-2012 Mario Mulansky
 * Copyright 2012-2013 Karsten Ahnert
 *
 * 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)
 *
 * Example for self defined vector type.
 */

#include <vector>

#include <boost/numeric/odeint.hpp>

//[my_vector
template< size_t MAX_N >
class my_vector
{
    typedef std::vector< double > vector;

public:
    typedef vector::iterator iterator;
    typedef vector::const_iterator const_iterator;

public:
    my_vector( const size_t N )
        : m_v( N )
    {
        m_v.reserve( MAX_N );
    }

    my_vector()
        : m_v()
    {
        m_v.reserve( MAX_N );
    }

// ... [ implement container interface ]
//]
    const double & operator[]( const size_t n ) const
    { return m_v[n]; }

    double & operator[]( const size_t n )
    { return m_v[n]; }

    iterator begin()
    { return m_v.begin(); }

    const_iterator begin() const
    { return m_v.begin(); }

    iterator end()
    { return m_v.end(); }

    const_iterator end() const
    { return m_v.end(); }

    size_t size() const
    { return m_v.size(); }

    void resize( const size_t n )
    { m_v.resize( n ); }

private:
    std::vector< double > m_v;

};

//[my_vector_resizeable
// define my_vector as resizeable

namespace boost { namespace numeric { namespace odeint {

template<size_t N>
struct is_resizeable< my_vector<N> >
{
    typedef boost::true_type type;
    static const bool value = type::value;
};

} } }
//]

typedef my_vector<3> state_type;

void lorenz( const state_type &x , state_type &dxdt , const double t )
{
    const double sigma( 10.0 );
    const double R( 28.0 );
    const double b( 8.0 / 3.0 );

    dxdt[0] = sigma * ( x[1] - x[0] );
    dxdt[1] = R * x[0] - x[1] - x[0] * x[2];
    dxdt[2] = -b * x[2] + x[0] * x[1];
}

using namespace boost::numeric::odeint;

int main()
{
    state_type x(3);
    x[0] = 5.0 ; x[1] = 10.0 ; x[2] = 10.0;

    // make sure resizing is ON
    BOOST_STATIC_ASSERT( is_resizeable<state_type>::value == true );

    // my_vector works with range_algebra as it implements
    // the required parts of a container interface
    // no further work is required

    integrate_const( runge_kutta4< state_type >() , lorenz , x , 0.0 , 10.0 , 0.1 );
}


/**
 * @file
 * @copyright This code is licensed under the 3-clause BSD license.\n
 *            Copyright ETH Zurich, Laboratory of Physical Chemistry, Reiher Group.\n
 *            See LICENSE.txt for details.
 */

#include <Utils/GeometricDerivatives/HessianUtilities.h>
#include <Utils/Geometry/GeometryUtilities.h>
#include <Eigen/Dense>

namespace Scine {
namespace Utils {

HessianUtilities::HessianUtilities(const Eigen::MatrixXd& hessian, const ElementTypeCollection& elements,
                                   const PositionCollection& positions, bool massWeighted)
  : _massWeighted(massWeighted), _hessian(hessian), _elements(elements) {
  _transformation = Geometry::Transformations::calculateRotTransFreeTransformMatrix(positions, elements, _massWeighted);
}

HessianUtilities::HessianUtilities(const Eigen::MatrixXd& hessian, const ElementTypeCollection& elements,
                                   const PositionCollection& positions, const GradientCollection& gradient, bool massWeighted)
  : _massWeighted(massWeighted), _hessian(hessian), _elements(elements) {
  _transformation =
      Geometry::Transformations::calculateRotTransFreeTransformMatrix(positions, elements, gradient, _massWeighted);
}

void HessianUtilities::hessianUpdate() {
  _internalEValues.reset(nullptr);
  _internalEVectors.reset(nullptr);
  _gradient.reset(nullptr);
}

void HessianUtilities::hessianUpdate(const HessianMatrix& hessian) {
  _hessian = std::ref(hessian);
  this->hessianUpdate();
}

const Eigen::MatrixXd& HessianUtilities::getTransformationMatrix() const {
  return _transformation;
}

const Eigen::VectorXd& HessianUtilities::getInternalEigenvalues() {
  if (!_internalEValues) {
    this->calculateInternal();
  }
  return *_internalEValues;
}

const Eigen::MatrixXd& HessianUtilities::getInternalEigenvectors() {
  if (!_internalEVectors) {
    this->calculateInternal();
  }
  return *_internalEVectors;
}

Eigen::MatrixXd HessianUtilities::getBackTransformedInternalEigenvectors() {
  if (!_internalEVectors) {
    this->calculateInternal();
  }
  if (_massWeighted) {
    auto masses = Geometry::Properties::getMasses(_elements);
    Eigen::MatrixXd ret = _transformation * (*_internalEVectors);
    // Back-scale the mass-weighted coordinates to cartesian coordinates.
    const int N = masses.size();
    for (int i = 0; i < N; ++i) {
      ret.middleRows(3 * i, 3) *= 1. / std::sqrt(masses[i]);
    }
    ret.colwise().normalize();
    return ret;
  }

  return _transformation * (*_internalEVectors);
}

Eigen::MatrixXd HessianUtilities::getInternalHessian() const {
  if (_massWeighted) {
    Eigen::MatrixXd m = _hessian.get();
    auto masses = Geometry::Properties::getMasses(_elements);
    for (unsigned i = 0; i < masses.size(); ++i) {
      double invSqrtM = 1. / std::sqrt(masses[i]);
      m.middleCols(3 * i, 3) *= invSqrtM;
      m.middleRows(3 * i, 3) *= invSqrtM;
    }
    return _transformation.transpose() * m * _transformation;
  }

  return _transformation.transpose() * _hessian.get() * _transformation;
}

void HessianUtilities::calculateInternal() {
  // Check whether internal Hessian would be empty
  if (_transformation.size() == 0) {
    throw EmptyInternalHessianException();
  }

  if (_massWeighted) {
    Eigen::MatrixXd m = _hessian.get();
    auto masses = Geometry::Properties::getMasses(_elements);
    // Get mass weighted Hessian
    for (unsigned i = 0; i < masses.size(); ++i) {
      double invSqrtM = 1. / std::sqrt(masses[i]);
      m.middleCols(3 * i, 3) *= invSqrtM;
      m.middleRows(3 * i, 3) *= invSqrtM;
    }
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es;
    // Project out by multiplying by  transformation matrix (has to be mass-weighted, too!)
    es.compute(_transformation.transpose() * m * _transformation);
    _internalEValues = std::make_unique<Eigen::VectorXd>(es.eigenvalues());
    _internalEVectors = std::make_unique<Eigen::MatrixXd>(es.eigenvectors());
  }
  else {
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es;
    es.compute(_transformation.transpose() * _hessian.get() * _transformation);
    _internalEValues = std::make_unique<Eigen::VectorXd>(es.eigenvalues());
    _internalEVectors = std::make_unique<Eigen::MatrixXd>(es.eigenvectors());
  }
}

} // namespace Utils
} // namespace Scine


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2014 Peter Caspers

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file zabrinterpolation.hpp
    \brief ZABR interpolation interpolation between discrete points
*/

#ifndef quantlib_zabr_interpolation_hpp
#define quantlib_zabr_interpolation_hpp

#include <ql/math/interpolations/xabrinterpolation.hpp>
#include <ql/experimental/volatility/zabrsmilesection.hpp>

#include <boost/assign/list_of.hpp>

namespace QuantLib {

namespace detail {

template <typename Evaluation> struct ZabrSpecs {
    Size dimension() { return 5; }
    Real eps() { return 0.000001; }
    void defaultValues(std::vector<Real> &params,
                       std::vector<bool> &paramIsFixed, const Real &forward,
                       const Real expiryTime, const std::vector<Real>& addParams) {
        if (params[1] == Null<Real>())
            params[1] = 0.5;
        if (params[0] == Null<Real>())
            // adapt alpha to beta level
            params[0] =
                0.2 *
                (params[1] < 0.9999 ? std::pow(forward, 1.0 - params[1]) : 1.0);
        if (params[2] == Null<Real>())
            params[2] = std::sqrt(0.4);
        if (params[3] == Null<Real>())
            params[3] = 0.0;
        if (params[4] == Null<Real>())
            params[4] = 1.0;
    }
    void guess(Array &values, const std::vector<bool> &paramIsFixed,
               const Real &forward, const Real expiryTime,
               const std::vector<Real> &r, const std::vector<Real>& addParams) {
        Size j = 0;
        if (!paramIsFixed[1])
            values[1] = (1.0 - 2E-6) * r[j++] + 1E-6;
        if (!paramIsFixed[0]) {
            values[0] = (1.0 - 2E-6) * r[j++] + 1E-6; // lognormal vol guess
            // adapt this to beta level
            if (values[1] < 0.999)
                values[0] *= std::pow(forward, 1.0 - values[1]);
        }
        if (!paramIsFixed[2])
            values[2] = 1.5 * r[j++] + 1E-6;
        if (!paramIsFixed[3])
            values[3] = (2.0 * r[j++] - 1.0) * (1.0 - 1E-6);
        if (!paramIsFixed[4])
            values[4] = r[j++] * 2.0;
    }
    Real eps1() { return .0000001; }
    Real eps2() { return .9999; }
    Real dilationFactor() { return 0.001; }
    Array inverse(const Array &y, const std::vector<bool> &,
                  const std::vector<Real> &, const Real) {
        Array x(5);
        x[0] = y[0] < 25.0 + eps1() ? std::sqrt(y[0] - eps1())
                                    : (y[0] - eps1() + 25.0) / 10.0;
        x[1] = std::sqrt(-std::log(y[1]));
        x[2] = std::tan(M_PI*(y[4]/5.0-0.5));
        x[3] = std::asin(y[3] / eps2());
        x[4] = std::tan(M_PI*(y[4]/1.9-0.5));
        return x;
    }
    Array direct(const Array &x, const std::vector<bool> &,
                 const std::vector<Real> &, const Real) {
        Array y(5);
        y[0] = std::fabs(x[0]) < 5.0 ? x[0] * x[0] + eps1()
                                     : (10.0 * std::fabs(x[0]) - 25.0) + eps1();
        y[1] = std::fabs(x[1]) < std::sqrt(-std::log(eps1()))
                   ? std::exp(-(x[1] * x[1]))
                   : eps1();
        // limit nu to 5.00
        y[2] = (std::atan(x[2])/M_PI + 0.5) * 5.0;
        y[3] = std::fabs(x[3]) < 2.5 * M_PI
                   ? eps2() * std::sin(x[3])
                   : eps2() * (x[3] > 0.0 ? 1.0 : (-1.0));
        // limit gamma to 1.9
        y[4] = (std::atan(x[4])/M_PI + 0.5) * 1.9;
        return y;
    }
    Real weight(const Real strike, const Real forward, const Real stdDev,
                const std::vector<Real> &addParams) {
        return blackFormulaStdDevDerivative(strike, forward, stdDev, 1.0);
    }
    typedef ZabrSmileSection<Evaluation> type;
    ext::shared_ptr<type> instance(const Time t, const Real &forward,
                                     const std::vector<Real> &params,
                                     const std::vector<Real> &addParams) {
        return ext::make_shared<type>(t, forward, params);
    }
};
} // end namespace detail

//! zabr smile interpolation between discrete volatility points.
template <class Evaluation> class ZabrInterpolation : public Interpolation {
  public:
    template <class I1, class I2>
    ZabrInterpolation(
        const I1 &xBegin, // x = strikes
        const I1 &xEnd,
        const I2 &yBegin, // y = volatilities
        Time t,           // option expiry
        const Real &forward, Real alpha, Real beta, Real nu, Real rho,
        Real gamma, bool alphaIsFixed, bool betaIsFixed, bool nuIsFixed,
        bool rhoIsFixed, bool gammaIsFixed, bool vegaWeighted = true,
        const ext::shared_ptr<EndCriteria> &endCriteria =
            ext::shared_ptr<EndCriteria>(),
        const ext::shared_ptr<OptimizationMethod> &optMethod =
            ext::shared_ptr<OptimizationMethod>(),
        const Real errorAccept = 0.0020, const bool useMaxError = false,
        const Size maxGuesses = 50) {
            impl_ = ext::shared_ptr<
                Interpolation::Impl>(new detail::XABRInterpolationImpl<
                I1, I2,
                detail::ZabrSpecs<Evaluation> >(
                xBegin, xEnd, yBegin, t, forward,
                boost::assign::list_of(alpha)(beta)(nu)(rho)(gamma),
                boost::assign::list_of(alphaIsFixed)(betaIsFixed)(nuIsFixed)(
                    rhoIsFixed)(gammaIsFixed),
                vegaWeighted, endCriteria, optMethod, errorAccept, useMaxError,
                maxGuesses));
            coeffs_ = ext::dynamic_pointer_cast<detail::XABRCoeffHolder<
                detail::ZabrSpecs<Evaluation> > >(impl_);
    }
    Real expiry() const { return coeffs_->t_; }
    Real forward() const { return coeffs_->forward_; }
    Real alpha() const { return coeffs_->params_[0]; }
    Real beta() const { return coeffs_->params_[1]; }
    Real nu() const { return coeffs_->params_[2]; }
    Real rho() const { return coeffs_->params_[3]; }
    Real gamma() const { return coeffs_->params_[4]; }
    Real rmsError() const { return coeffs_->error_; }
    Real maxError() const { return coeffs_->maxError_; }
    const std::vector<Real> &interpolationWeights() const {
        return coeffs_->weights_;
    }
    EndCriteria::Type endCriteria() { return coeffs_->XABREndCriteria_; }

  private:
    ext::shared_ptr<detail::XABRCoeffHolder<detail::ZabrSpecs<Evaluation> > > coeffs_;
};

//! no arbtrage sabr interpolation factory and traits
template<class Evaluation> class Zabr {
  public:
    Zabr(Time t,
         Real forward,
         Real alpha,
         Real beta,
         Real nu,
         Real rho,
         Real gamma,
         bool alphaIsFixed,
         bool betaIsFixed,
         bool nuIsFixed,
         bool rhoIsFixed,
         bool gammaIsFixed,
         bool vegaWeighted = false,
         const ext::shared_ptr<EndCriteria>& endCriteria = ext::shared_ptr<EndCriteria>(),
         const ext::shared_ptr<OptimizationMethod>& optMethod =
             ext::shared_ptr<OptimizationMethod>(),
         const Real errorAccept = 0.0020,
         const bool useMaxError = false,
         const Size maxGuesses = 50)
    : t_(t), forward_(forward), alpha_(alpha), beta_(beta), nu_(nu), rho_(rho),
      alphaIsFixed_(alphaIsFixed), betaIsFixed_(betaIsFixed), nuIsFixed_(nuIsFixed),
      rhoIsFixed_(rhoIsFixed), gammaIsFixed_(gammaIsFixed), vegaWeighted_(vegaWeighted),
      endCriteria_(endCriteria), optMethod_(optMethod), errorAccept_(errorAccept),
      useMaxError_(useMaxError), maxGuesses_(maxGuesses) {}
    template <class I1, class I2>
    Interpolation interpolate(const I1 &xBegin, const I1 &xEnd,
                              const I2 &yBegin) const {
        return ZabrInterpolation<Evaluation>(
            xBegin, xEnd, yBegin, t_, forward_, alpha_, beta_, nu_, rho_,
            gamma_, alphaIsFixed_, betaIsFixed_, nuIsFixed_, rhoIsFixed_,
            gammaIsFixed_, vegaWeighted_, endCriteria_, optMethod_,
            errorAccept_, useMaxError_, maxGuesses_);
    }
    static const bool global = true;

  private:
    Time t_;
    Real forward_;
    Real alpha_, beta_, nu_, rho_, gamma_;
    bool alphaIsFixed_, betaIsFixed_, nuIsFixed_, rhoIsFixed_, gammaIsFixed_;
    bool vegaWeighted_;
    const ext::shared_ptr<EndCriteria> endCriteria_;
    const ext::shared_ptr<OptimizationMethod> optMethod_;
    const Real errorAccept_;
    const bool useMaxError_;
    const Size maxGuesses_;
};
}

#endif


// Boost.Geometry Index
//
// n-dimensional content (hypervolume) - 2d area, 3d volume, ...
//
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
//
// This file was modified by Oracle on 2020-2022.
// Modifications copyright (c) 2020-2022 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
//
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP

#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

namespace boost { namespace geometry { namespace index { namespace detail {

template <typename Indexable>
struct default_content_result
{
    using type = typename select_most_precise
        <
            typename coordinate_type<Indexable>::type,
            double
        >::type;
};

namespace dispatch {

template <typename Box,
          std::size_t CurrentDimension = dimension<Box>::value>
struct content_box
{
    BOOST_STATIC_ASSERT(0 < CurrentDimension);

    static inline typename detail::default_content_result<Box>::type apply(Box const& b)
    {
        return content_box<Box, CurrentDimension - 1>::apply(b) *
            ( get<max_corner, CurrentDimension - 1>(b) - get<min_corner, CurrentDimension - 1>(b) );
    }
};

template <typename Box>
struct content_box<Box, 1>
{
    static inline typename detail::default_content_result<Box>::type apply(Box const& b)
    {
        return get<max_corner, 0>(b) - get<min_corner, 0>(b);
    }
};

template <typename Indexable, typename Tag>
struct content
{
    BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
        "Not implemented for this Indexable and Tag.",
        Indexable, Tag);
};

template <typename Indexable>
struct content<Indexable, point_tag>
{
    static typename detail::default_content_result<Indexable>::type apply(Indexable const&)
    {
        return 0;
    }
};

template <typename Indexable>
struct content<Indexable, box_tag>
{
    static typename default_content_result<Indexable>::type apply(Indexable const& b)
    {
        return dispatch::content_box<Indexable>::apply(b);
    }
};

} // namespace dispatch

template <typename Indexable>
typename default_content_result<Indexable>::type content(Indexable const& b)
{
    return dispatch::content
            <
                Indexable,
                typename tag<Indexable>::type
            >::apply(b);
}

}}}} // namespace boost::geometry::index::detail

#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP


#include <fstream>
#include <iostream>
using namespace std;

#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <Eigen/Geometry>
#include <boost/format.hpp>  // for formating strings
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main(int argc, char** argv) {
  vector<cv::Mat> color_images, depth_images;
  vector<Eigen::Isometry3d> poses;  // camera poses

  ifstream fin("./data/pose.txt");
  if (!fin) {
    cerr << "cannot find pose file" << endl;
    return 1;
  }

  for (int i = 0; i < 5; i++) {
    boost::format fmt("./data/%s/%d.%s");
    color_images.push_back(cv::imread((fmt % "color" % (i + 1) % "png").str()));
    depth_images.push_back(
        cv::imread((fmt % "depth" % (i + 1) % "pgm").str(), -1));

    double data[7] = {0};
    for (int i = 0; i < 7; i++) {
      fin >> data[i];
    }
    Eigen::Quaterniond q(data[6], data[3], data[4], data[5]);
    Eigen::Isometry3d T(q);
    T.pretranslate(Eigen::Vector3d(data[0], data[1], data[2]));
    poses.push_back(T);
  }

  // Camera intrinsics
  double cx = 325.5;
  double cy = 253.5;
  double fx = 518.0;
  double fy = 519.0;
  double depth_scale = 1000.0;

  cout << "Converting image to point cloud ..." << endl;

  typedef pcl::PointXYZRGB PointT;
  typedef pcl::PointCloud<PointT> PointCloud;

  // Create a new point cloud
  PointCloud::Ptr point_cloud(new PointCloud);
  for (int i = 0; i < 5; i++) {
    PointCloud::Ptr current(new PointCloud);
    cout << "转换图像中: " << i + 1 << endl;
    cv::Mat color = color_images[i];
    cv::Mat depth = depth_images[i];
    Eigen::Isometry3d T = poses[i];
    for (int v = 0; v < color.rows; v++)
      for (int u = 0; u < color.cols; u++) {
        unsigned int d = depth.ptr<unsigned short>(v)[u];  // 深度值
        if (d == 0) continue;     // 为0表示没有测量到
        if (d >= 7000) continue;  // 深度太大时不稳定，去掉
        Eigen::Vector3d point;
        point[2] = double(d) / depth_scale;
        point[0] = (u - cx) * point[2] / fx;
        point[1] = (v - cy) * point[2] / fy;
        Eigen::Vector3d point_world = T * point;

        PointT p;
        p.x = point_world[0];
        p.y = point_world[1];
        p.z = point_world[2];
        p.b = color.data[v * color.step + u * color.channels()];
        p.g = color.data[v * color.step + u * color.channels() + 1];
        p.r = color.data[v * color.step + u * color.channels() + 2];
        current->points.push_back(p);
      }
    // depth filter and statistical removal
    PointCloud::Ptr tmp(new PointCloud);
    pcl::StatisticalOutlierRemoval<PointT> stats_filter;
    stats_filter.setMeanK(50);
    stats_filter.setStddevMulThresh(1.0);
    stats_filter.setInputCloud(current);
    stats_filter.filter(*tmp);
    (*point_cloud) += *tmp;
  }

  point_cloud->is_dense = false;
  cout << "There are " << point_cloud->size() << "points." << endl;

  // voxel filter
  pcl::VoxelGrid<PointT> voxel_filter;
  voxel_filter.setLeafSize(0.01, 0.01, 0.01);  // resolution
  PointCloud::Ptr tmp(new PointCloud);
  voxel_filter.setInputCloud(point_cloud);
  voxel_filter.filter(*tmp);
  tmp->swap(*point_cloud);

  cout << "After filtering, there are " << point_cloud->size() << "points."
       << endl;

  pcl::io::savePCDFileBinary("map.pcd", *point_cloud);
  return 0;
}