///////////////////////////////////////////////////////////////////////////////
/// \file numeric.hpp
/// Defined the mathematical operator s on time series
//
//  Copyright 2006 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_TIME_SERIES_NUMERIC_NUMERIC_EAN_04_27_2006
#define BOOST_TIME_SERIES_NUMERIC_NUMERIC_EAN_04_27_2006

#include <utility>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/numeric/functional.hpp>
#include <boost/range_run_storage/algorithm/transform.hpp>
#include <boost/time_series/time_series_fwd.hpp>
#include <boost/time_series/concepts.hpp>
#include <boost/time_series/traits/generate_series.hpp>
#include <boost/time_series/traits/promotion.hpp>
#include <boost/time_series/scaled_series.hpp>
#include <boost/time_series/numeric/detail/zero.hpp>
#include <boost/detail/construct.hpp>

namespace boost { namespace time_series
{
    namespace detail
    {
        namespace rrs = range_run_storage;

        using concepts::Run;
        using concepts::TimeSeries;
        using concepts::Mutable_TimeSeries;

        template<typename Out, typename Left, typename Right, typename BinOp>
        Out &run_bin_op_union(Out &out, Left &left, Right &right, BinOp const &binop)
        {
            typename Mutable_TimeSeries<Out>::ordered_inserter_type
                o(rrs::ordered_inserter(out));

            rrs::commit(
                rrs::transform(left, right, binop, o)
            );

            return out;
        }

        // For operations that are only defined
        template<typename Out, typename Left, typename Right, typename BinOp>
        Out &run_bin_op_intersection(Out &out, Left &left, Right &right, BinOp const &binop)
        {
            typename Mutable_TimeSeries<Out>::ordered_inserter_type
                o(rrs::ordered_inserter(out));

            rrs::commit(
                rrs::transform(left, right, binop, rrs::skip, rrs::skip, o)
            );

            return out;
        }

        // operation traits
        template<typename S1, typename S2, typename Gen, typename Op, typename Disc>
        struct operation_traits_base
        {
            typedef typename TimeSeries<S1>::storage_category storage1_tag;
            typedef typename TimeSeries<S2>::storage_category storage2_tag;
            typedef typename mpl::apply<Gen, storage1_tag, storage2_tag>::type storage_category;

            typedef typename TimeSeries<S1>::value_type value1_type;
            typedef typename TimeSeries<S2>::value_type value2_type;
            typedef typename result_of<Op(value1_type, value2_type)>::type value_type;

            typedef typename TimeSeries<S1>::offset_type offset1_type;
            typedef typename TimeSeries<S2>::offset_type offset2_type;
            BOOST_MPL_ASSERT((is_same<offset1_type, offset2_type>)); // is there a better option?
            typedef offset1_type offset_type;

            typedef typename traits::generate_series<
                storage_category, value_type, Disc, offset_type
            >::type result_type;
        };

        template<typename S1, typename S2, typename Gen, typename Op
          , typename Disc1 = typename TimeSeries<S1>::discretization_type
          , typename Disc2 = typename TimeSeries<S2>::discretization_type
        >
        struct operation_traits
        {};

        template<typename S1, typename S2, typename Gen, typename Op, typename Disc>
        struct operation_traits<S1, S2, Gen, Op, time_series::any, Disc>
          : operation_traits_base<S1, S2, Gen, Op, Disc>
        {};

        template<typename S1, typename S2, typename Gen, typename Op, typename Disc>
        struct operation_traits<S1, S2, Gen, Op, Disc, time_series::any>
          : operation_traits_base<S1, S2, Gen, Op, Disc>
        {};

        template<typename S1, typename S2, typename Gen, typename Op>
        struct operation_traits<S1, S2, Gen, Op, time_series::any, time_series::any>
          : operation_traits_base<S1, S2, Gen, Op, time_series::any>
        {};

        template<typename S1, typename S2, typename Gen, typename Op, typename Disc>
        struct operation_traits<S1, S2, Gen, Op, Disc, Disc>
          : operation_traits_base<S1, S2, Gen, Op, Disc>
        {};

        template<typename Left, typename Right, typename Op>
        typename result_of<Op(
            typename TimeSeries<Left>::value_type const &
          , typename TimeSeries<Right>::value_type const &
        )>::type
        make_zero(Left &left, Right &right, Op op)
        {
            typename TimeSeries<Left>::value_type const &left_zero = rrs::zero(left);
            typename TimeSeries<Right>::value_type const &right_zero = rrs::zero(right);
            return op(left_zero, right_zero);
        }

        template<typename Discretization>
        Discretization make_discretization(Discretization left, Discretization right)
        {
            BOOST_ASSERT(left == right);
            return left;
        }

        template<typename Discretization>
        Discretization make_discretization(Discretization left, time_series::any)
        {
            return left;
        }

        template<typename Discretization>
        Discretization make_discretization(time_series::any, Discretization right)
        {
            return right;
        }

        inline time_series::any make_discretization(time_series::any, time_series::any)
        {
            return time_series::any();
        }

    } // namespace detail

    using mpl::_;

    ///////////////////////////////////////////////////////////////////////////
    // operator +
    template<typename Left, typename Right>
    typename detail::operation_traits<Left, Right, traits::plus<_, _>, numeric::op::plus>::result_type
    operator +(time_series_base<Left> const &left, time_series_base<Right> const &right)
    {
        typedef detail::operation_traits<Left, Right, traits::plus<_, _>, numeric::op::plus> op_traits;
        typedef typename op_traits::result_type result_type;

        result_type result(constructors::construct<result_type>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::plus)
        ));

        return detail::run_bin_op_union(result, left.cast(), right.cast(), numeric::plus);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator -
    template<typename Left, typename Right>
    typename detail::operation_traits<Left, Right, traits::minus<_, _>, numeric::op::minus>::result_type
    operator -(time_series_base<Left> const &left, time_series_base<Right> const &right)
    {
        typedef detail::operation_traits<Left, Right, traits::minus<_, _>, numeric::op::minus> op_traits;
        typedef typename op_traits::result_type result_type;

        result_type result(constructors::construct<result_type>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::minus)
        ));

        return detail::run_bin_op_union(result, left.cast(), right.cast(), numeric::minus);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator *
    template<typename Left, typename Right>
    typename detail::operation_traits<Left, Right, traits::multiplies<_, _>, numeric::op::multiplies>::result_type
    operator *(time_series_base<Left> const &left, time_series_base<Right> const &right)
    {
        typedef detail::operation_traits<Left, Right, traits::multiplies<_, _>, numeric::op::multiplies> op_traits;
        typedef typename op_traits::result_type result_type;

        result_type result(constructors::construct<result_type>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::multiplies)
        ));

        return detail::run_bin_op_intersection(result, left.cast(), right.cast(), numeric::multiplies);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator /
    template<typename Left, typename Right>
    typename detail::operation_traits<Left, Right, traits::divides<_, _>, numeric::op::divides>::result_type
    operator /(time_series_base<Left> const &left, time_series_base<Right> const &right)
    {
        typedef detail::operation_traits<Left, Right, traits::divides<_, _>, numeric::op::divides> op_traits;
        typedef typename op_traits::result_type result_type;

        // BUGBUG possible divide by zero, so use multiplies instead of divides here ...
        result_type result(constructors::construct<result_type>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::multiplies)
        ));

        return detail::run_bin_op_intersection(result, left.cast(), right.cast(), numeric::divides);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator +=
    template<typename Left, typename Right>
    Left &operator +=(time_series_base<Left> &left, time_series_base<Right> const &right)
    {
        BOOST_MPL_ASSERT((is_same<
            typename concepts::TimeSeries<Left>::discretization_type
          , typename concepts::TimeSeries<Right>::discretization_type
        >));

        // TODO also add the series zero
        BOOST_ASSERT(left.cast().discretization() == right.cast().discretization());
        return detail::run_bin_op_union(left.cast(), left.cast(), right.cast(), numeric::plus);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator -=
    template<typename Left, typename Right>
    Left &operator -=(time_series_base<Left> &left, time_series_base<Right> const &right)
    {
        BOOST_MPL_ASSERT((is_same<
            typename concepts::TimeSeries<Left>::discretization_type
          , typename concepts::TimeSeries<Right>::discretization_type
        >));

        // TODO also subtract the series zero
        BOOST_ASSERT(left.cast().discretization() == right.cast().discretization());
        return detail::run_bin_op_union(left.cast(), left.cast(), right.cast(), numeric::minus);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator *=
    template<typename Left, typename Right>
    Left &operator *=(time_series_base<Left> &left, time_series_base<Right> const &right)
    {
        BOOST_MPL_ASSERT((is_same<
            typename concepts::TimeSeries<Left>::discretization_type
          , typename concepts::TimeSeries<Right>::discretization_type
        >));

        BOOST_ASSERT(left.cast().discretization() == right.cast().discretization());

        // BUGBUG not optimal
        Left result(constructors::construct<Left>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::multiplies)
        ));

        left.cast().swap(detail::run_bin_op_intersection(result, left.cast(), right.cast(), numeric::multiplies));
        return left.cast();
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator /=
    template<typename Left, typename Right>
    Left &operator /=(time_series_base<Left> &left, time_series_base<Right> const &right)
    {
        BOOST_MPL_ASSERT((is_same<
            typename concepts::TimeSeries<Left>::discretization_type
          , typename concepts::TimeSeries<Right>::discretization_type
        >));

        BOOST_MPL_ASSERT((traits::is_valid_divisor<
            typename concepts::TimeSeries<Right>::storage_category
        >));

        BOOST_ASSERT(left.cast().discretization() == right.cast().discretization());

        // BUGBUG not optimal
        // BUGBUG possible divide by zero, so use multiplies instead of divides here ...
        Left result(constructors::construct<Left>(
            time_series::discretization
              = detail::make_discretization(left.cast().discretization(), right.cast().discretization())
          , time_series::zero
              = detail::make_zero(left.cast(), right.cast(), numeric::multiplies)
        ));

        left.cast().swap(detail::run_bin_op_intersection(result, left.cast(), right.cast(), numeric::divides));
        return left.cast();
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator * (with scalar)
    template<typename Series, typename Factor>
    typename disable_if<
        traits::is_time_series<Factor>
      , scaled_series<Series const, Factor> const
    >::type
    operator *(time_series_base<Series> const &left, Factor const &right)
    {
        return scaled_series<Series const, Factor>(left.cast(), right);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator * (with scalar)
    template<typename Factor, typename Series>
    typename disable_if<
        traits::is_time_series<Factor>
      , scaled_series<Series const, Factor> const
    >::type
    operator *(Factor const &left, time_series_base<Series> const &right)
    {
        return scaled_series<Series const, Factor>(right.cast(), left);
    }

    ///////////////////////////////////////////////////////////////////////////
    // operator *= (with scalar)
    template<typename Series, typename Factor>
    typename disable_if<
        traits::is_time_series<Factor>
      , Series &
    >::type
    operator *=(time_series_base<Series> &left, Factor const &right)
    {
        left.cast() = left.cast() * right;
        return left.cast();
    }

}} // namespace boost::time_series

#endif


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// 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/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <string>

using namespace std;
using namespace boost;

/*
  Interior Property Map Basics

  An interior property map is a way of associating properties
  with the vertices or edges of a graph. The "interior" part means
  that the properties are stored inside the graph object. This can be
  convenient when the need for the properties is somewhat permanent,
  and when the properties will be with a graph for the duration of its
  lifetime. A "distance from source vertex" property is often of this
  kind.

  Sample Output

  Jeremy owes Rich some money
  Jeremy owes Andrew some money
  Jeremy owes Jeff some money
  Jeremy owes Kinis some money
  Andrew owes Jeremy some money
  Andrew owes Kinis some money
  Jeff owes Jeremy some money
  Jeff owes Rich some money
  Jeff owes Kinis some money
  Kinis owes Jeremy some money
  Kinis owes Rich some money

 */

// create a tag for our new property

enum vertex_first_name_t { vertex_first_name };
namespace boost {
  BOOST_INSTALL_PROPERTY(vertex, first_name);
}

template <class EdgeIter, class Graph>
void who_owes_who(EdgeIter first, EdgeIter last, const Graph& G)
{
  // Access the propety acessor type for this graph
  typedef typename property_map<Graph, vertex_first_name_t>
    ::const_type NamePA;
  NamePA name = get(vertex_first_name, G);

  typedef typename boost::property_traits<NamePA>::value_type NameType;

  NameType src_name, targ_name;

  while (first != last) {
    src_name = boost::get(name, source(*first,G));
    targ_name = boost::get(name, target(*first,G));
    cout << src_name << " owes "
         << targ_name << " some money" << endl;
    ++first;
  }
}

int
main()
{
  {
    // Create the graph, and specify that we will use std::string to
    // store the first name's.
    typedef adjacency_list<vecS, vecS, directedS,
      property<vertex_first_name_t, std::string> > MyGraphType;

    typedef pair<int,int> Pair;
    Pair edge_array[11] = { Pair(0,1), Pair(0,2), Pair(0,3), Pair(0,4),
                            Pair(2,0), Pair(3,0), Pair(2,4), Pair(3,1),
                            Pair(3,4), Pair(4,0), Pair(4,1) };

    MyGraphType G(5);
    for (int i=0; i<11; ++i)
      add_edge(edge_array[i].first, edge_array[i].second, G);

    property_map<MyGraphType, vertex_first_name_t>::type name
      = get(vertex_first_name, G);

    boost::put(name, 0, "Jeremy");
    boost::put(name, 1, "Rich");
    boost::put(name, 2, "Andrew");
    boost::put(name, 3, "Jeff");
    name[4] = "Kinis"; // you can use operator[] too

    who_owes_who(edges(G).first, edges(G).second, G);
  }

  cout << endl;

  return 0;
}


#include <boost/config.hpp>

#include <iostream>
#include <string>

#include <boost/bimap/bimap.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/multiset_of.hpp>

#include <boost/optional.hpp>
#include <boost/none.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_inserter.hpp>

using namespace boost::bimaps;
using namespace boost;
using namespace std;
int main()
{
    typedef bimap<

    unordered_set_of<int >,
    multiset_of< double, std::greater<double> >

    > population_bimap;

    typedef population_bimap::value_type population;

    population_bimap pop;
    pop.insert( population(1,0.000001321) );
    pop.insert( population(2,0.000000023) );
    pop.insert( population(3,0.000000023));
    pop.insert( population(4,0.00001865) );
    pop.insert( population(5,0.00016363) );
    pop.insert( population(6,0.00030195) );
    pop.insert( population(7,0.00030195) );

    std::cout << "Countries by their population:    ---   " << std::endl;

    // First requirement
    /*<< The right map view works like a
     `std::multimap< long, std::string, std::greater<long> >`,
     We can iterate over it to print the results in the required order. >>*/
    for( population_bimap::right_const_iterator
        i = pop.right.begin(), iend = pop.right.end();
        i != iend ; ++i )
    {
        std::cout << i->second << " with " << i->first << std::endl;
    }

    // Second requirement
    /*<< The left map view works like a `std::unordered_map< std::string, long >`,
     given the name of the country we can use it to search for the population
     in constant time >>*/
    std::cout << "Population of China: " << pop.left.at(4) << std::endl;
    //]

    return 0;}


#pragma once
#include <omp.h>
#include <string>

#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/IterativeLinearSolvers>
#include <unsupported/Eigen/SparseExtra>
#include <unsupported/Eigen/IterativeSolvers>

#include "json11.hpp"
#include "buffalo/misc/log.hpp"

using namespace std;
using namespace json11;
using namespace Eigen;

typedef Matrix<float, Dynamic, Dynamic, RowMajor> MatrixType;
typedef RowVectorXf VectorType;

typedef Matrix<float, Dynamic, Dynamic, ColMajor> FactorType;
typedef Matrix<float, Dynamic, Dynamic, RowMajor> FactorTypeRowMajor;

class Algorithm  // Algorithm? Logic? Learner?
{
public:
    Algorithm();

    virtual ~Algorithm() {}
    virtual bool init(string opt_path) = 0;
    virtual bool parse_option(string opt_path) = 0;

    bool parse_option(string opt_path, Json& j);
    void _leastsquare(Map<MatrixType>& X, int idx, MatrixType& A, VectorType& y);

public:
    char optimizer_code_ = 0;
    int num_cg_max_iters_ = 3;
    float cg_tolerance_ = 1e-10;
    float eps_ = 1e-10;
    std::shared_ptr<spdlog::logger> logger_;
};


#include "lenslet_graph.h"

#include <Eigen/Dense>

namespace lightfields {

namespace {

struct Vec2Compare {
	bool operator()(const cv::Vec2f& v1, const cv::Vec2f& v2) const {
		if(v1[0] != v2[0])
			return v1[0] < v2[0];
		return v1[1] < v2[1];
	}
};

struct Lenslet {
	Lenslet(const cv::Vec2f& c) : center(c), neighbourCount(0), id(INT_MIN, INT_MIN) {
	}

	void addNeighbour(std::size_t index) {
		if(neighbourCount >= 6)
			throw std::runtime_error(
			    "Lenslets should be organized in a hexagonal grid, which does not seem to be the case!");

		neighbours[neighbourCount] = index;
		++neighbourCount;
	}

	cv::Vec2f center;
	std::array<std::size_t, 6> neighbours;
	unsigned char neighbourCount;
	cv::Vec2i id;
};

}  // namespace

/////////////

struct LensletGraph::Pimpl {
	Pimpl() : fitted(false) {
	}

	Imath::V2i sensorSize;
	int exclusionBorder;

	std::vector<Lenslet> lenslets;

	cv::Matx<double, 3, 3> fittedMatrix;
	bool fitted;
};

/////////////

LensletGraph::LensletGraph(Imath::V2i sensorSize, int exclusionBorder) : m_pimpl(new Pimpl()) {
	m_pimpl->sensorSize = sensorSize;
	m_pimpl->exclusionBorder = exclusionBorder;
}

LensletGraph::~LensletGraph() {
}

void LensletGraph::addLenslet(const cv::Vec2f& center) {
	m_pimpl->lenslets.push_back(Lenslet(center));
}

namespace {

/// computes relative integer offset between two lenslets (assumed to be neighbouring edges of a graph)
cv::Vec2i offset(const cv::Vec2f& l1, const cv::Vec2f& l2) {
	const float angle = atan2(l2[1] - l1[1], l2[0] - l1[0]) / M_PI * 6.0f;
	assert(angle >= -6.0f && angle <= 6.0f);

	if(angle < -5.0f || angle > 5.0f)
		return cv::Vec2i(-1, 0);

	if(angle < -3.0f)
		return cv::Vec2i(0, -1);

	if(angle > 3.0f)
		return cv::Vec2i(-1, 1);

	if(angle < -1.0f)
		return cv::Vec2i(1, -1);

	if(angle > 1.0f)
		return cv::Vec2i(0, 1);

	return cv::Vec2i(1, 0);
}

}  // namespace

void LensletGraph::fit() {
	assert(!m_pimpl->fitted);

	// build the subdiv and index
	std::map<cv::Vec2f, std::size_t, Vec2Compare> index;

	cv::Subdiv2D subdiv(cv::Rect(0, 0, m_pimpl->sensorSize[0], m_pimpl->sensorSize[1]));
	for(auto& l : m_pimpl->lenslets) {
		subdiv.insert(cv::Point2f(l.center[0], l.center[1]));
		index.insert(std::make_pair(cv::Point2f(l.center[0], l.center[1]), index.size()));
	}

	// collect and process the edges
	{
		std::vector<cv::Vec4f> srcEdgeList;
		subdiv.getEdgeList(srcEdgeList);

		for(auto eit = srcEdgeList.begin(); eit != srcEdgeList.end(); ++eit) {
			auto& e = *eit;

			if(e[0] > m_pimpl->exclusionBorder && e[0] < m_pimpl->sensorSize[0] - m_pimpl->exclusionBorder &&
			   e[1] > m_pimpl->exclusionBorder && e[1] < m_pimpl->sensorSize[1] - m_pimpl->exclusionBorder &&
			   e[2] > m_pimpl->exclusionBorder && e[2] < m_pimpl->sensorSize[0] - m_pimpl->exclusionBorder &&
			   e[3] > m_pimpl->exclusionBorder && e[3] < m_pimpl->sensorSize[1] - m_pimpl->exclusionBorder) {
				auto it1 = index.find(cv::Point2f(e[0], e[1]));
				auto it2 = index.find(cv::Point2f(e[2], e[3]));
				assert(it1 != index.end() && it2 != index.end());

				m_pimpl->lenslets[it1->second].addNeighbour(it2->second);
				m_pimpl->lenslets[it2->second].addNeighbour(it1->second);
			}
		}
	}

	// propagate IDs
	{
		// find first connected lenslet
		auto it = m_pimpl->lenslets.begin();
		while(it != m_pimpl->lenslets.end() && it->neighbourCount == 0)
			++it;

		if(it != m_pimpl->lenslets.end()) {
			// this lenslet is the "origin" now
			it->id = cv::Vec2i(0, 0);

			// initialise the edges (to-be-processed) list
			std::vector<std::pair<std::size_t, std::size_t>> edges;
			for(std::size_t n = 0; n < it->neighbourCount; ++n)
				edges.push_back(std::make_pair(it - m_pimpl->lenslets.begin(), it->neighbours[n]));

			while(!edges.empty()) {
				// get the processed edge
				auto edge = edges.back();
				edges.pop_back();

				const Lenslet& source = m_pimpl->lenslets[edge.first];
				Lenslet& target = m_pimpl->lenslets[edge.second];

				// assert the "origin" lenslet, which should have been processed already
				assert(source.id[0] > INT_MIN && source.id[1] > INT_MIN);

				// get the "offset" based on edge direction
				const cv::Vec2i off = offset(source.center, target.center);

				// either set the target, or assert its value is right
				if(target.id[0] > INT_MIN) {
					assert(target.id[0] == source.id[0] + off[0]);
					assert(target.id[1] == source.id[1] + off[1]);
				}

				else {
					target.id[0] = source.id[0] + off[0];
					target.id[1] = source.id[1] + off[1];

					// recursively continue around all edges of the target
					for(std::size_t n = 0; n < target.neighbourCount; ++n)
						edges.push_back(std::make_pair(edge.second, target.neighbours[n]));
				}
			}
		}
	}

	// least squares fit
	// Ref: Fitting a Transformation: Feature-based Alignment, Kristen Grauman, lecture notes for UT Austin
	// A = [ ...
	//       xi, yi,  0,  0, 1, 0,
	//        0,  0, xi, yi, 0, 1,
	//       ... ]
	// x = [m1, m2, m3, m4, t1, t2]^T
	// b = [ ... x'i, y'i, ... ]^T

	// count the useful lenslets
	std::size_t lensletCount = 0;
	for(auto& l : m_pimpl->lenslets)
		if(l.id[0] > INT_MIN)
			++lensletCount;

	Eigen::MatrixXd A(2 * lensletCount, 6);
	Eigen::VectorXd b(2 * lensletCount);
	lensletCount = 0;
	for(auto& l : m_pimpl->lenslets)
		if(l.id[0] > INT_MIN) {
			std::size_t rowId = lensletCount * 2;

			A(rowId, 0) = l.center[0];
			A(rowId, 1) = l.center[1];
			A(rowId, 2) = 0;
			A(rowId, 3) = 0;
			A(rowId, 4) = 1;
			A(rowId, 5) = 0;

			b(rowId) = l.id[0];

			++rowId;

			A(rowId, 0) = 0;
			A(rowId, 1) = 0;
			A(rowId, 2) = l.center[0];
			A(rowId, 3) = l.center[1];
			A(rowId, 4) = 0;
			A(rowId, 5) = 1;

			b(rowId) = l.id[1];

			++lensletCount;
		}

	Eigen::VectorXd x = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
	assert(x.size() == 6);

	m_pimpl->fitted = true;
	m_pimpl->fittedMatrix = cv::Matx<double, 3, 3>(x[0], x[2], 0, x[1], x[3], 0, x[4], x[5], 1);
}

double LensletGraph::lensPitch() const {
	std::size_t counter = 0;
	double average = 0.0;

	for(auto& l : m_pimpl->lenslets)
		if(l.id[0] > INT_MIN) {
			for(unsigned char ni = 0; ni < l.neighbourCount; ++ni) {
				const Lenslet& neighbour = m_pimpl->lenslets[l.neighbours[ni]];
				if(neighbour.id[0] > INT_MIN) {
					++counter;
					average += cv::norm(l.center - neighbour.center);
				}
			}
		}

	assert(counter > 0);

	return average / (double)counter;
}

const Imath::V2i& LensletGraph::sensorResolution() const {
	return m_pimpl->sensorSize;
}

const cv::Matx<double, 3, 3>& LensletGraph::fittedMatrix() const {
	assert(m_pimpl->fitted);
	return m_pimpl->fittedMatrix;
}

void LensletGraph::drawCenters(cv::Mat& target) const {
	assert(target.rows == m_pimpl->sensorSize[0] && target.cols == m_pimpl->sensorSize[1]);
	assert(target.type() == CV_8UC1);

	for(auto& l : m_pimpl->lenslets)
		target.at<unsigned char>(l.center[1], l.center[0]) = 255;
}

void LensletGraph::drawEdges(cv::Mat& target) const {
	assert(target.rows == m_pimpl->sensorSize[0] && target.cols == m_pimpl->sensorSize[1]);
	assert(target.type() == CV_8UC1);

	for(auto& l1 : m_pimpl->lenslets) {
		for(unsigned char n = 0; n < l1.neighbourCount; ++n) {
			auto& l2 = m_pimpl->lenslets[l1.neighbours[n]];

			const float a = atan((l2.center[1] - l1.center[1]) / (l2.center[0] - l1.center[0])) / M_PI * 2.0;

			float color = 155.0;
			if(a < -0.33)
				color = 55.0;
			if(a > 0.33)
				color = 255;

			cv::line(target, cv::Point2i(l1.center[0], l1.center[1]), cv::Point2i(l2.center[0], l2.center[1]),
			         cv::Scalar(color));
		}
	}
}

void LensletGraph::drawFit(cv::Mat& target) const {
	assert(target.rows == m_pimpl->sensorSize[0] && target.cols == m_pimpl->sensorSize[1]);
	assert(target.type() == CV_8UC1);

	for(auto& l : m_pimpl->lenslets)
		cv::circle(target, cv::Point(l.center[0], l.center[1]), 2, (l.id[0] + 2560) % 256, 2);
}

}  // namespace lightfields


#include "stdafx.h"

#include <boost/gil/gil_all.hpp>
#include <boost/test/unit_test.hpp>

using namespace boost::gil;

BOOST_AUTO_TEST_SUITE( gil_test )

struct double_zero { static double apply() { return 0.0; } };
struct double_one  { static double apply() { return 1.0; } };

BOOST_AUTO_TEST_CASE( channel_test )
{
    typedef uint64_t bits64;
    typedef int64_t bits64s;

    typedef scoped_channel_value<double, double_zero, double_one> bits64f;

    bits8   c8_min   =  channel_traits<bits8  >::min_value();
    bits8   c8_max   =  channel_traits<bits8  >::max_value();
    bits8s  c8s_min  =  channel_traits<bits8s >::min_value();
    bits8s  c8s_max  =  channel_traits<bits8s >::max_value();
    bits16  c16_min  =  channel_traits<bits16 >::min_value();
    bits16  c16_max  =  channel_traits<bits16 >::max_value();
    bits16s c16s_min =  channel_traits<bits16s>::min_value();
    bits16s c16s_max =  channel_traits<bits16s>::max_value();
    bits32  c32_min  =  channel_traits<bits32 >::min_value();
    bits32  c32_max  =  channel_traits<bits32 >::max_value();
    bits32s c32s_min =  channel_traits<bits32s>::min_value();
    bits32s c32s_max =  channel_traits<bits32s>::max_value();
    bits32f c32f_min =  channel_traits<bits32f>::min_value();
    bits32f c32f_max =  channel_traits<bits32f>::max_value();
    bits64  c64_min  =  channel_traits<bits64 >::min_value();
    bits64  c64_max  =  channel_traits<bits64 >::max_value();
    bits64s c64s_min =  channel_traits<bits64s>::min_value();
    bits64s c64s_max =  channel_traits<bits64s>::max_value();
    bits64f c64f_min =  channel_traits<bits64f>::min_value();
    bits64f c64f_max =  channel_traits<bits64f>::max_value();

    // this generates a VS compiler warning
    //boost::mpl::integral_c<bits64,-1> kk;

    //value test - channel_convert
    BOOST_CHECK_EQUAL( channel_convert<bits8>(c8_max), c8_max );
    BOOST_CHECK_EQUAL( channel_convert<bits16>(c8_max), c16_max );
    BOOST_CHECK_EQUAL( channel_convert<bits32>(c8_max), c32_max );
    //BOOST_CHECK_EQUAL( channel_convert<bits64>(c8_max), c64_max );

    //reference test

    // packed reference test
    typedef packed_channel_reference<boost::uint16_t, 0,5,true> channel16_0_5_reference_t;
    typedef packed_channel_reference<boost::uint16_t, 5,6,true> channel16_5_6_reference_t;
    typedef packed_channel_reference<boost::uint16_t, 11,5,true> channel16_11_5_reference_t;

    bits16 data = 0;
    channel16_0_5_reference_t   channel1(&data);
    channel16_5_6_reference_t   channel2(&data);
    channel16_11_5_reference_t  channel3(&data);

    channel1=channel_traits<channel16_0_5_reference_t>::max_value();
    channel2=channel_traits<channel16_5_6_reference_t>::max_value();
    channel3=channel_traits<channel16_11_5_reference_t>::max_value();
    BOOST_CHECK_EQUAL( data, 65535 );

}

BOOST_AUTO_TEST_SUITE_END()


// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

// SparseLU solve does not accept column major matrices for the destination.
// However, as expected, the generic check_sparse_square_solving routines produces row-major
// rhs and destination matrices when compiled with EIGEN_DEFAULT_TO_ROW_MAJOR

#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
#undef EIGEN_DEFAULT_TO_ROW_MAJOR
#endif

#include "sparse_solver.h"
#include <Eigen/SparseLU>
#include <unsupported/Eigen/SparseExtra>

template<typename T> void test_sparselu_T()
{
  SparseLU<SparseMatrix<T, ColMajor> /*, COLAMDOrdering<int>*/ > sparselu_colamd; // COLAMDOrdering is the default
  SparseLU<SparseMatrix<T, ColMajor>, AMDOrdering<int> > sparselu_amd;
  SparseLU<SparseMatrix<T, ColMajor, long int>, NaturalOrdering<long int> > sparselu_natural;

  check_sparse_square_solving(sparselu_colamd,  300, 100000, true);
  check_sparse_square_solving(sparselu_amd,     300,  10000, true);
  check_sparse_square_solving(sparselu_natural, 300,   2000, true);

  check_sparse_square_abs_determinant(sparselu_colamd);
  check_sparse_square_abs_determinant(sparselu_amd);

  check_sparse_square_determinant(sparselu_colamd);
  check_sparse_square_determinant(sparselu_amd);
}

EIGEN_DECLARE_TEST(sparselu)
{
  CALL_SUBTEST_1(test_sparselu_T<float>());
  CALL_SUBTEST_2(test_sparselu_T<double>());
  CALL_SUBTEST_3(test_sparselu_T<std::complex<float> >());
  CALL_SUBTEST_4(test_sparselu_T<std::complex<double> >());
}


#include <memory>
#include <Eigen/MatrixFunctions>
#include "Basis.hh"
#include "Dispatcher.hh"
#include "io/manipulators.hh"

void Basis::twoElectron(const Eigen::MatrixXd& D, Eigen::MatrixXd& G) const
{
	if (!_status.test(ELEC_REP_CURRENT))
		calcElectronRepulsion();

	int n = D.rows();
#ifdef DEBUG
	if (D.cols() != n)
		throw Li::Exception("Density matrix is not square");
#endif
	G.resize(n, n);
	G.setZero();
	int idx = 0;
	double e;
	for (int i = 0; i < n; ++i)
	{
		double Dii = D(i,i);
		for (int j = 0; j < i; ++j)
		{
			double Dij = D(i,j);
			double Djj = D(j,j);
			for (int k = 0; k < j; ++k)
			{
				double Dik = D(i,k);
				double Djk = D(j,k);
				for (int l = 0; l < k; ++l)
				{
					e = _elec_rep(idx++);
					G(i,j) += 2 * D(k,l) * e;
					G(i,k) -= 0.5 * D(j,l) * e;
					G(i,l) -= 0.5 * Djk * e;
					G(j,k) -= 0.5 * D(i,l) * e;
					G(j,l) -= 0.5 * Dik * e;
					G(k,l) += 2 * Dij * e;
				}
				e = _elec_rep(idx++);
				G(i,j) += D(k,k) * e;
				G(i,k) -= 0.5 * Djk * e;
				G(j,k) -= 0.5 * Dik * e;
				G(k,k) += 2 * Dij * e;
			}
			for (int l = 0; l < j; ++l)
			{
				e = _elec_rep(idx++);
				G(i,j) += 1.5 * D(j,l) * e;
				G(i,l) -= 0.5 * Djj * e;
				G(j,j) -= D(i,l) * e;
				G(j,l) += 1.5 * Dij * e;
			}
			e = _elec_rep(idx++);
			G(i,j) += 0.5 * Djj * e;
			G(j,j) += Dij * e;
			for (int k = j+1; k < i; ++k)
			{
				double Dik = D(i,k);
				double Dkj = D(k,j);
				for (int l = 0; l < j; ++l)
				{
					e = _elec_rep(idx++);
					G(i,j) += 2 * D(k,l) * e;
					G(i,k) -= 0.5 * D(j,l) * e;
					G(i,l) -= 0.5 * Dkj * e;
					G(j,l) -= 0.5 * Dik * e;
					G(k,j) -= 0.5 * D(i,l) * e;
					G(k,l) += 2 * Dij * e;
				}
				e = _elec_rep(idx++);
				G(i,j) += 1.5 * Dkj * e;
				G(i,k) -= 0.5 * Djj * e;
				G(j,j) -= Dik * e;
				G(k,j) += 1.5 * Dij * e;
				for (int l = j+1; l < k; ++l)
				{
					e = _elec_rep(idx++);
					G(i,j) += 2 * D(k,l) * e;
					G(i,k) -= 0.5 * D(l,j) * e;
					G(i,l) -= 0.5 * Dkj * e;
					G(k,l) += 2 * Dij * e;
					G(k,j) -= 0.5 * D(i,l) * e;
					G(l,j) -= 0.5 * Dik * e;
				}
				e = _elec_rep(idx++);
				G(i,j) += D(k,k) * e;
				G(i,k) -= 0.5 * Dkj * e;
				G(k,j) -= 0.5 * Dik * e;
				G(k,k) += 2 * Dij * e;
			}
			for (int l = 0; l < j; ++l)
			{
				e = _elec_rep(idx++);
				G(i,i) -= D(j,l) * e;
				G(i,j) += 1.5 * D(i,l) * e;
				G(i,l) += 1.5 * Dij * e;
				G(j,l) -= 0.5 * Dii * e;
			}
			e = _elec_rep(idx++);
			G(i,i) -= 0.5 * Djj * e;
			G(i,j) += 1.5 * Dij * e;
			G(j,j) -= 0.5 * Dii * e;
		}

		for (int k = 0; k < i; ++k)
		{
			double Dik = D(i, k);
			for (int l = 0; l < k; ++l)
			{
				e = _elec_rep(idx++);
				G(i,i) += 2 * D(k,l) * e;
				G(i,k) -= 0.5 * D(i,l) * e;
				G(i,l) -= 0.5 * Dik * e;
				G(k,l) += Dii * e;
			}
			e = _elec_rep(idx++);
			G(i,i) += D(k,k) * e;
			G(i,k) -= 0.5 * Dik * e;
			G(k,k) += Dii * e;
		}
		for (int l = 0; l < i; ++l)
		{
			e = _elec_rep(idx++);
			G(i,i) += D(i,l) * e;
			G(i,l) += 0.5 * Dii * e;
		}
		G(i,i) += 0.5 * Dii * _elec_rep(idx++);
	}

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j)
			G(j,i) = G(i,j);
	}
}

void Basis::twoElectron(const Eigen::MatrixXd& D, Eigen::MatrixXd& J,
	Eigen::MatrixXd& K) const
{
	if (!_status.test(ELEC_REP_CURRENT))
		calcElectronRepulsion();

	int n = D.rows();
#ifdef DEBUG
	if (D.cols() != n)
		throw Li::Exception("Density matrix is not square");
#endif
	J.resize(n, n);
	J.setZero();
	K.resize(n, n);
	K.setZero();
	int idx = 0;
	double e;
	for (int i = 0; i < n; ++i)
	{
		double Dii = D(i,i);
		for (int j = 0; j < i; ++j)
		{
			double Dij = D(i,j);
			double Djj = D(j,j);
			for (int k = 0; k < j; ++k)
			{
				double Dik = D(i,k);
				double Djk = D(j,k);
				for (int l = 0; l < k; ++l)
				{
					e = _elec_rep(idx++);
					J(i,j) += 2 * D(k,l) * e;
					J(k,l) += 2 * Dij * e;
					K(i,k) += D(j,l) * e;
					K(i,l) += Djk * e;
					K(j,k) += D(i,l) * e;
					K(j,l) += Dik * e;
				}
				e = _elec_rep(idx++);
				J(i,j) += D(k,k) * e;
				J(k,k) += 2 * Dij * e;
				K(i,k) += Djk * e;
				K(j,k) += Dik * e;
			}
			for (int l = 0; l < j; ++l)
			{
				e = _elec_rep(idx++);
				J(i,j) += 2 * D(j,l) * e;
				J(j,l) += 2 * Dij * e;
				K(i,j) += D(j,l) * e;
				K(i,l) += Djj * e;
				K(j,j) += 2 * D(i,l) * e;
				K(j,l) += Dij * e;
			}
			e = _elec_rep(idx++);
			J(i,j) += Djj * e;
			J(j,j) += 2 * Dij * e;
			K(i,j) += Djj * e;
			K(j,j) += 2 * Dij * e;
			for (int k = j+1; k < i; ++k)
			{
				double Dik = D(i,k);
				double Dkj = D(k,j);
				for (int l = 0; l < j; ++l)
				{
					e = _elec_rep(idx++);
					J(i,j) += 2 * D(k,l) * e;
					J(k,l) += 2 * Dij * e;
					K(i,k) += D(j,l) * e;
					K(i,l) += Dkj * e;
					K(j,l) += Dik * e;
					K(k,j) += D(i,l) * e;
				}
				e = _elec_rep(idx++);
				J(i,j) += 2 * Dkj * e;
				J(k,j) += 2 * Dij * e;
				K(i,k) += Djj * e;
				K(i,j) += Dkj * e;
				K(j,j) += 2 * Dik * e;
				K(k,j) += Dij * e;
				for (int l = j+1; l < k; ++l)
				{
					e = _elec_rep(idx++);
					J(i,j) += 2 * D(k,l) * e;
					J(k,l) += 2 * Dij * e;
					K(i,k) += D(l,j) * e;
					K(i,l) += Dkj * e;
					K(k,j) += D(i,l) * e;
					K(l,j) += Dik * e;
				}
				e = _elec_rep(idx++);
				J(i,j) += D(k,k) * e;
				J(k,k) += 2 * Dij * e;
				K(i,k) += Dkj * e;
				K(k,j) += Dik * e;
			}
			for (int l = 0; l < j; ++l)
			{
				e = _elec_rep(idx++);
				J(i,j) += 2 * D(i,l) * e;
				J(i,l) += 2 * Dij * e;
				K(i,i) += 2 * D(j,l) * e;
				K(i,j) += D(i,l) * e;
				K(i,l) += Dij * e;
				K(j,l) += Dii * e;
			}
			e = _elec_rep(idx++);
			J(i,j) += 2 * Dij * e;
			K(i,i) += Djj * e;
			K(i,j) += Dij * e;
			K(j,j) += Dii * e;
		}
		for (int k = 0; k < i; ++k)
		{
			double Dik = D(i,k);
			for (int l = 0; l < k; ++l)
			{
				e = _elec_rep(idx++);
				J(i,i) += 2 * D(k,l) * e;
				J(k,l) += Dii * e;
				K(i,k) += D(i,l) * e;
				K(i,l) += Dik * e;
			}
			e = _elec_rep(idx++);
			J(i,i) += D(k,k) * e;
			J(k,k) += Dii * e;
			K(i,k) += Dik * e;
		}
		for (int l = 0; l < i; ++l)
		{
			e = _elec_rep(idx++);
			J(i,i) += 2 * D(i,l) * e;
			J(i,l) += Dii * e;
			K(i,i) += D(i,l) * e;
			K(i,l) += Dii * e;
			K(i,i) += D(i,l) * e;
		}
		e = _elec_rep(idx++);
		J(i,i) += Dii * e;
		K(i,i) += Dii * e;
	}

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j)
		{
			J(j,i) = J(i,j);
			K(j,i) = K(i,j);
		}
	}
}

std::ostream& Basis::print(std::ostream& os) const
{
	os << "Basis (\n" << indent;
	for (BasisFunList::const_iterator it = _funs.begin();
		it != _funs.end(); ++it)
	{
		os << **it << "\n";
	}
	os << dedent << ")";
	return os;
}

void Basis::setPairs() const
{
	const Dispatcher& dispatcher = Dispatcher::singleton();

	_pairs.clear();
	for (BasisFunList::const_iterator iit = _funs.begin(); iit != _funs.end(); ++iit)
	{
		for (BasisFunList::const_iterator jit = _funs.begin(); jit <= iit; ++jit)
		{
			AbstractBFPair *pair = dispatcher.pair(**iit, **jit);
			_pairs.push_back(PairPtr(pair));
		}
	}

	_status.set(PAIRS_CURRENT);
}

void Basis::setQuads() const
{
	if (!_status.test(PAIRS_CURRENT))
		setPairs();

	const Dispatcher& dispatcher = Dispatcher::singleton();

	_quads.clear();
	for (PairList::const_iterator iit = _pairs.begin(); iit != _pairs.end(); ++iit)
	{
		for (PairList::const_iterator jit = _pairs.begin(); jit <= iit; ++jit)
		{
			AbstractBFQuad *quad = dispatcher.quad(**iit, **jit, _quad_pool);
			_quads.push_back(QuadPtr(quad, _quad_pool.deleter()));
		}
	}

	_status.set(QUADS_CURRENT);
}

void Basis::calcOverlap() const
{
	if (!_status.test(PAIRS_CURRENT))
		setPairs();

	PairList::const_iterator pit = _pairs.begin();
	int n = size();
	_overlap.resize(n, n);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j, ++pit)
			_overlap(i, j) = _overlap(j, i) = (*pit)->overlap();
		_overlap(i, i) = (*pit)->overlap();
		++pit;
	}

	_status.set(OVERLAP_CURRENT);
}

void Basis::calcKinetic() const
{
	if (!_status.test(PAIRS_CURRENT))
		setPairs();

	PairList::const_iterator pit = _pairs.begin();
	int n = size();
	_kinetic.resize(n, n);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j, ++pit)
			_kinetic(i, j) = _kinetic(j, i) = (*pit)->kineticEnergy();
		_kinetic(i, i) = (*pit)->kineticEnergy();
		++pit;
	}

	_status.set(KINETIC_CURRENT);
}

void Basis::calcOneElectron() const
{
	if (!_status.test(PAIRS_CURRENT))
		setPairs();

	PairList::const_iterator pit = _pairs.begin();
	int n = size();
	_overlap.resize(n, n);
	_kinetic.resize(n, n);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j, ++pit)
		{
			(*pit)->oneElectron(_overlap(i,j), _kinetic(i,j));
			_overlap(j,i) = _overlap(i,j);
			_kinetic(j,i) = _kinetic(i,j);
		}
		(*pit)->oneElectron(_overlap(i,i), _kinetic(i,i));
		++pit;
	}

	_status.set(OVERLAP_CURRENT);
	_status.set(KINETIC_CURRENT);
}

void Basis::calcNuclearAttraction(const Eigen::MatrixXd& nuc_pos,
	const Eigen::VectorXd& nuc_charge) const
{
	if (!_status.test(PAIRS_CURRENT))
		setPairs();

	PairList::const_iterator pit = _pairs.begin();
	int n = size();
	_nuc_attr.resize(n, n);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < i; ++j, ++pit)
			_nuc_attr(i, j) = _nuc_attr(j, i)
				= (*pit)->nuclearAttraction(nuc_pos, nuc_charge);
		_nuc_attr(i, i) = (*pit)->nuclearAttraction(nuc_pos, nuc_charge);
		++pit;
	}

	_status.set(NUC_ATTR_CURRENT);
}

void Basis::calcElectronRepulsion() const
{
	if (!_status.test(QUADS_CURRENT))
		setQuads();

	_elec_rep.resize(_quads.size());
	for (unsigned int i = 0; i < _quads.size(); ++i)
		_elec_rep[i] = _quads[i]->electronRepulsion();

	_status.set(ELEC_REP_CURRENT);
}

void Basis::calcOrtho() const
{
	if (!_status.test(OVERLAP_CURRENT))
		calcOverlap();
	_ortho = _overlap.sqrt().inverse();
	_status.set(ORTHO_CURRENT);
}


#include"main.hpp"
#include"Option.hpp"
#include"Pre.hpp"
#include <boost/algorithm/string.hpp>
using boost::lexical_cast;
typedef multimap<string,Row*>::const_iterator mmit;
typedef multimap<string,const Row*>::const_iterator cmmit;

class pred_mc
{
    const double d_mc_cut;
    public:
    pred_mc(const double mc_cut) : d_mc_cut(mc_cut) { }
    bool operator() (const Row& tmprow) const { return tmprow.m_cor<d_mc_cut; }
};

class pred_g
{
    const set<string> d_set;
    public:
    pred_g(const set<string>& tmpset) : d_set(tmpset) {}
    bool operator() (const Row& tmprow) const { return d_set.end()==d_set.find(tmprow.pid); }
};

class pred_nr
{
    const int d_nr;
    public:
    pred_nr(const int nr) : d_nr(nr) {}
    bool operator() (const Row& tmpco) const { return tmpco.nrepsi<d_nr; }
};

void Pre::setMc()
{
    multimap<string,Row*> pid_mm;
    for (list<Row>::iterator it=d_pdata.begin();it!=d_pdata.end();it++) {
        pid_mm.insert(make_pair(it->pid,&(*it)));
    }
    for (mmit end1,itp=pid_mm.begin();itp!=pid_mm.end();itp=end1) {
        end1=pid_mm.upper_bound(itp->first);
        vector<vector<double> > ww;
        for (mmit it=itp;it!=end1;it++) ww.push_back(it->second->in);
        if (ww.size()==1) {
            itp->second->m_cor=1;
            continue;
        }
        mmit it=itp;
        for (unsigned f=0;f<ww.size();f++,it++) {
            vector<double> cor;
            for (unsigned g=0;g<ww.size();g++) if (f != g) {
                vector<double> center(2);
                vector<double> sd(center.size());
                int ncol0=0;
                for (int l=0;l<op().nc();l++) if (obs(ww.at(f).at(l)) and obs(ww.at(g).at(l))) {
                    center.at(0) += ww.at(f).at(l);
                    center.at(1) += ww.at(g).at(l);
                    ncol0++;
                }
                if (ncol0<2) continue;
                center.at(0) /= ncol0;
                center.at(1) /= ncol0;
                for (int l=0;l<op().nc();l++) if (obs(ww.at(f).at(l)) and obs(ww.at(g).at(l))) {
                    sd.at(0) += pow(ww.at(f).at(l)-center.at(0),2);
                    sd.at(1) += pow(ww.at(g).at(l)-center.at(1),2);
                }
                sd.at(0) = sqrt(sd.at(0));
                sd.at(1) = sqrt(sd.at(1));
                double cortmp=0;
                for (int l=0;l<op().nc();l++) if (obs(ww.at(f).at(l)) and obs(ww.at(g).at(l))) {
                    cortmp += (ww.at(f).at(l)-center.at(0))*(ww.at(g).at(l)-center.at(1));
                }
                if (sd.at(0)==0 or sd.at(1)==0) continue;
                cortmp /= sd.at(0);
                cortmp /= sd.at(1);
                cor.push_back(cortmp);
            }
            if (cor.size()==0) {
                it->second->m_cor=-1;
            } else {
                it->second->m_cor=median(cor.begin(),cor.end());
            }
        }
    }
}

void Pre::norm_data()
{
    if (op().xbool()) {
        for (int p=0;p<nprot();p++) for (int j=0;j<op().nrep();j++) {//centering by reps
            vector<double> xvec;
            for (int t=0; t<op().nt(); t++) if (obs(xx().at(p).at(j*op().nt()+t))) {
                xvec.push_back(xx().at(p).at(j*op().nt()+t));
            }
            double center_x=median(xvec.begin(),xvec.end());
            for (int t=0; t<op().nt(); t++) if (obs(xx().at(p).at(j*op().nt()+t))) {
                d_xx.at(p).at(j*op().nt()+t) -= center_x;
            }
        }
    }
    for (int p=0;p<nprot();p++) {//centering by reps
        for (unsigned q=0;q<yy().at(p).size();q++) for (int j=0;j<op().nrep();j++) {
            vector<double> yvec;
            for (int t=0; t<op().nt(); t++) if (obs(yy().at(p).at(q).at(j*op().nt()+t))) {
                yvec.push_back(yy().at(p).at(q).at(j*op().nt()+t));
            }
            double center_y=median(yvec.begin(),yvec.end());
            for (int t=0; t<op().nt(); t++) if (obs(yy().at(p).at(q).at(j*op().nt()+t))) {
                d_yy.at(p).at(q).at(j*op().nt()+t) -= center_y;
            }
        }
    }

}

Pre::Pre(const Option& op) : d_op(op)
{
    read();
    setAll();
}

void Pre::read()
{
    ifstream y_ifs(op().filey().c_str());
    ifstream x_ifs(op().filex().c_str());

    string str0;
    istringstream iss;
    getline(y_ifs,str0);
    split(d_yh, str0, boost::is_any_of("\t"));
    if (int(yh().size())<op().nc()) throw runtime_error("file_y");

    getline(x_ifs,str0);
    split(d_xh, str0, boost::is_any_of("\t"));

    for (int i=2;getline(x_ifs,str0) and (not str0.empty());i++) {
        Row tmp_f(op().nc());
        iss.clear(); iss.str(str0+"\t");
        getline(iss,tmp_f.pid,'\t'); //tmp_f.pid+="_"+lexical_cast<string>(i);
        for (int l=0;l<op().nc();l++) {
            if (not getline(iss,str0,'\t')) throw runtime_error("FILE_X unequal columns: row "+lexical_cast<string>(i));
            if (str0=="NA" or str0.empty() or lexical_cast<double>(str0)==0) {
                tmp_f.in.at(l)=NAN;
            } else {
                try {
                    if (op().log_x()) tmp_f.in.at(l)=log(lexical_cast<double>(str0));
                    else tmp_f.in.at(l)=(lexical_cast<double>(str0));
                } catch (boost::bad_lexical_cast& e) {
                    cerr<<e.what()<<"FILE_X : row "<<i<<", column "<<l+1+op().level();
                    exit(1);
                }
            }
        }
        d_gdata0.push_back(tmp_f);
    }

    for (int i=2;getline(y_ifs,str0) and (not str0.empty());i++) {
        Row tmp_f(op().nc());
        iss.clear(); iss.str(str0+"\t");
        getline(iss,tmp_f.pid,'\t'); //tmp_f.pid+="_"+lexical_cast<string>(i);
        if (op().level()==1) tmp_f.qid=tmp_f.pid;
        else if (op().level()==2) getline(iss,tmp_f.qid,'\t');
        for (int l=0;l<op().nc();l++) {
            if (not getline(iss,str0,'\t')) throw runtime_error("FILE_Y unequal columns: row "+lexical_cast<string>(i));
            if (str0=="NA" or lexical_cast<double>(str0)==0 or str0.empty()) {
                tmp_f.in.at(l)=NAN;
            } else {
                try {
                    if (op().log_y()) tmp_f.in.at(l)=log(lexical_cast<double>(str0));
                    else tmp_f.in.at(l)=(lexical_cast<double>(str0));
                } catch (boost::bad_lexical_cast& e) {
                    cerr<<e.what()<<"FILE_Y : row "<<i<<", column "<<l+1+op().level();
                    exit(1);
                }
            }
        }
        d_pdata0.push_back(tmp_f);
    }
}

void Pre::setAll()
{
    multimap<string,const Row*> gid_mm;
    for (list<Row>::const_iterator it=gdata0().begin();it!=gdata0().end();it++) {
        gid_mm.insert(make_pair(it->pid,&(*it)));
    }
    for (cmmit end1,itp=gid_mm.begin();itp!=gid_mm.end();itp=end1) {
        end1=gid_mm.upper_bound(itp->first);
        Row tmp_f(op().nc());
        tmp_f.pid=itp->first;
        vector<int> cobs(op().nc());
        for (cmmit it=itp;it!=end1;it++) {
            for (int i=0;i<op().nc();i++) {
                if (obs(it->second->in.at(i))) {
                    tmp_f.in.at(i)+=it->second->in.at(i);
                    cobs.at(i)++;
                }
            }
        }
        for (int i=0;i<op().nc();i++) {
            if (cobs.at(i)>0) tmp_f.in.at(i) /= cobs.at(i); else tmp_f.in.at(i)=NAN;
        }
        d_gdata.push_back(tmp_f);
    }

    multimap<string,const Row*> pqid_mm;
    for (list<Row>::const_iterator it=pdata0().begin();it!=pdata0().end();it++) {
        pqid_mm.insert(make_pair(it->pid+it->qid,&(*it)));
    }
    for (cmmit end1,itp=pqid_mm.begin();itp!=pqid_mm.end();itp=end1) {
        end1=pqid_mm.upper_bound(itp->first);
        Row tmp_f(op().nc());
        tmp_f.pid=itp->second->pid;
        tmp_f.qid=itp->second->qid;
        vector<int> cobs(op().nc());
        for (cmmit it=itp;it!=end1;it++) {
            for (int i=0;i<op().nc();i++) {
                if (obs(it->second->in.at(i))) {
                    tmp_f.in.at(i)+=it->second->in.at(i);
                    cobs.at(i)++;
                }
            }
        }
        for (int i=0;i<op().nc();i++) {
            if (cobs.at(i)>0) tmp_f.in.at(i) /= cobs.at(i); else tmp_f.in.at(i)=NAN;
        }
        d_pdata.push_back(tmp_f);
    }

    for (list<Row>::iterator it=d_gdata.begin();it!=d_gdata.end();it++) {
        for (int l=0;l<op().nc();l++) {
            if (not obs(it->in.at(l))) {it->nrepsi--; /*break;*/ }
        }
    }
    for (list<Row>::iterator it=d_pdata.begin();it!=d_pdata.end();it++) {
        for (int l=0;l<op().nc();l++) {
            if (not obs(it->in.at(l))) {it->nrepsi--; /*break;*/ }
        }
    }

    //d_gdata.remove_if(pred_nr(op().nc()-2));
    //d_pdata.remove_if(pred_nr(op().nc()-2));

    setMc();
    d_pdata.remove_if(pred_mc(op().min_correl()));

    set<string> gset;
    for (list<Row>::const_iterator it=gdata().begin();it!=gdata().end();it++) {
        gset.insert(it->pid);
    }
    d_pdata.remove_if(pred_g(gset));

    gset.clear();
    for (list<Row>::const_iterator it=pdata().begin();it!=pdata().end();it++) {
        gset.insert(it->pid);
    }
    d_gdata.remove_if(pred_g(gset));

    map<string,const Row*> gid_m;
    for (list<Row>::const_iterator it=gdata().begin();it!=gdata().end();it++) {
        gid_m[it->pid]=&(*it);
    }

    multimap<string,const Row*> pid_mm;
    for (list<Row>::const_iterator it=pdata().begin();it!=pdata().end();it++) {
        pid_mm.insert(make_pair(it->pid,&(*it)));
    }

    cout<<"nprot = "<<nprot()<<'\n';
    d_xid.resize(nprot());
    d_pid.resize(nprot());
    d_qid.resize(nprot());
    d_xx.resize(nprot(),vector<double>(op().nc()));
    d_yy.resize(nprot());
    int p=0;
    multimap<string,const Row*>::const_iterator end1,itp=pid_mm.begin();
    for (map<string,const Row*>::const_iterator itg=gid_m.begin();itg!=gid_m.end();itg++,itp=end1,p++) {
        d_xid.at(p)=itg->second->pid;
        d_pid.at(p)=itp->second->pid;
        for (int l=0;l<op().nc();l++) d_xx.at(p).at(l)=itg->second->in.at(l);
        end1=pid_mm.upper_bound(itp->first);
        for (cmmit it=itp;it!=end1;it++) {
            d_qid.at(p).push_back(it->second->qid);
            d_yy.at(p).push_back(it->second->in);
        }
    }
    if (not op().xbool()) {
        for (int g=0;g<nprot();g++) for (int l=0;l<op().nc();l++) d_xx.at(g).at(l)=0;
    }

}

#include"Eigen/Dense"

double Pre::Kfn(const vector<double>&theta,const double xp,const double xq,const int e=1)
{
    if (not op().smooth()) return exp(-pow((xp-xq),2)/2);
    const static double ll = op().smoothing().at(1);
    return pow(op().smoothing().at(0),2)*exp(-pow((xp-xq)/ll,2)/2)+e*(xp==xq);
}

double Pre::Mfn(const vector<double>& m,const double xs,const vector<double>& adjdiff)
{
    if (op().timei().front()>xs or xs>op().timei().back()) throw runtime_error("xs range");
    int fxs=-1;
    if (xs==op().timei().back()) return m.back();
    for (int i=op().nt()-2;i>=0;i--) if (op().timei().at(i)<=xs) {fxs=i; break;}
    return m.at(fxs)+(m.at(fxs+1)-m.at(fxs))/adjdiff.at(fxs+1)*(xs-op().timei().at(fxs));
}

typedef multimap<int,int>::const_iterator cmmii;

void Pre::impute_x()
{
    double** data = new double*[nprot()];
    int** mask = new int*[nprot()];
    for (int i = 0; i < nprot(); i++) {
        data[i] = new double[op().nc()];
        mask[i] = new int[op().nc()];
    }

    vector<vector<double> > mvec(nprot(),vector<double>(op().nrep()));
    vector<vector<double> > vvec(nprot(),vector<double>(op().nrep()));
    for (int p=0;p<nprot();p++) for (int j=0;j<op().nrep();j++) {
        int nj=0;
        const vector<double>& xxp=xx().at(p);
        for (int t=0;t<op().nt();t++) if (obs(xxp.at(j*op().nt()+t))) {
            mvec.at(p).at(j)+=xxp.at(j*op().nt()+t);
            nj++;
        }
        mvec.at(p).at(j) /= nj;
        for (int t=0;t<op().nt();t++) if (obs(xxp.at(j*op().nt()+t))) {
            vvec.at(p).at(j) += pow(xxp.at(j*op().nt()+t)-mvec.at(p).at(j),2);
        }
        vvec.at(p).at(j) /= nj-1;
        if (vvec.at(p).at(j)==0) vvec.at(p).at(j)=1;
        for (int t=0;t<op().nt();t++) if (obs(xxp.at(j*op().nt()+t))) {
            d_xx.at(p).at(j*op().nt()+t) -= mvec.at(p).at(j);
            d_xx.at(p).at(j*op().nt()+t) /= sqrt(vvec.at(p).at(j));
        }
    }

    for (int p=0;p<nprot();p++) for (int l=0; l<op().nc(); l++) {
        data[p][l]=0;
        int nq=0;
        if (obs(xx().at(p).at(l))) {
            data[p][l] += xx().at(p).at(l);
            nq++;
        }
        if (nq>0) {
            data[p][l] /= nq;
            mask[p][l] = 1;
        } else {
            data[p][l] = NAN;
            mask[p][l] = 0;
        }
    }

    vector<int> clusterid(nprot());

    multimap<int,int> c_mm;
    for (int p=0;p<nprot();p++) c_mm.insert(make_pair(clusterid[p],p));

    vector<vector<Eigen::VectorXd> > xax,yy_;
    xax.resize(xx().size());
    yy_.resize(xx().size());
    for (int p=0;p<nprot();p++) {
        xax.at(p).resize(op().nrep());
        yy_.at(p).resize(op().nrep());
        for (int j=0;j<op().nrep();j++) {
            vector<double> x,y;
            for (int t=0;t<op().nt();t++) {
                if (obs(xx().at(p).at(j*op().nt()+t))) {
                    x.push_back(op().timei().at(t));
                    y.push_back(xx().at(p).at(j*op().nt()+t));
                }
            }
            xax.at(p).at(j).resize(x.size());
            yy_.at(p).at(j).resize(y.size());
            for (unsigned i=0;i<x.size();i++) {
                xax.at(p).at(j)(i)=x.at(i);
                yy_.at(p).at(j)(i)=y.at(i);
            }
        }
    }

    const int Ns=100;
    const double step=double(op().timei().back()-op().timei().front())/Ns;
    Eigen::VectorXd xs(Ns);
    for (int i=0;i<Ns;i++) xs(i)=op().timei().at(0)+step/2+i*step;

    ofstream ofs1("EfsX.txt");
    ofs1<<"p\tq\tj";
    for (unsigned i=0;i<xs.size();i++) ofs1<<'\t'<<xs(i);
    ofs1<<'\n';

    int ijk=0;
    vector<double> adjdiff(op().timei().size());
    adjacent_difference(op().timei().begin(),op().timei().end(),adjdiff.begin());

    for (cmmii end1,itc=c_mm.begin();itc!=c_mm.end()/*,ijk<8*/;itc=end1,ijk++) {
        end1=c_mm.upper_bound(itc->first);

        vector<vector<double> > m(op().nrep(),vector<double>(op().nt()));

        vector<double> theta(3,1);

        for (cmmii it=itc;it!=end1;it++) {
            const int p=it->second;
            for (int j=0;j<op().nrep();j++) {
                Eigen::VectorXd& y = yy_.at(p).at(j);
                Eigen::VectorXd& x = xax.at(p).at(j);
                const int N = y.size();
                Eigen::MatrixXd Ky(N,N);
                for (int i=0;i<N;i++) for (int k=0;k<N;k++) Ky(i,k)=Kfn(theta,x(i),x(k));
                Eigen::VectorXd ym(y);
                for (int i=0;i<N;i++) ym(i)-=Mfn(m.at(j),x(i),adjdiff);
                Eigen::MatrixXd invKy=Ky.inverse();
                ofs1<<p<<"\t0\t"<<j;
                for (unsigned i=0;i<xs.size();i++) {
                    Eigen::VectorXd ks(N);
                    for (int k=0;k<N;k++) ks(k)=Kfn(theta,xs(i),x(k),0);
                    const double Efs=ks.transpose()*invKy*ym+Mfn(m.at(j),xs(i),adjdiff);
                    ofs1<<'\t'<<Efs*sqrt(vvec.at(p).at(j))+mvec.at(p).at(j);
                }
                ofs1<<'\n';

                for (int t=0;t<op().nt();t++) {
                    Eigen::VectorXd ks(N);
                    for (int k=0;k<N;k++) ks(k)=Kfn(theta,op().timei().at(t),x(k),0);
                    d_xx.at(p).at(j*op().nt()+t)=
                        ks.transpose()*invKy*ym+Mfn(m.at(j),op().timei().at(t),adjdiff);
                    d_xx.at(p).at(j*op().nt()+t)*=sqrt(vvec.at(p).at(j));
                    d_xx.at(p).at(j*op().nt()+t)+=mvec.at(p).at(j);
                }
            }
        }
    }
}

void Pre::impute_y()
{
    double** data = new double*[nprot()];
    int** mask = new int*[nprot()];
    for (int i = 0; i < nprot(); i++) {
        data[i] = new double[op().nc()];
        mask[i] = new int[op().nc()];
    }

    vector<vector<vector<double> > > mvec(nprot());
    vector<vector<vector<double> > > vvec(nprot());
    for (int p=0;p<nprot();p++) {
        mvec.at(p).resize(yy().at(p).size(),vector<double>(op().nrep()));
        vvec.at(p).resize(yy().at(p).size(),vector<double>(op().nrep()));
        for (unsigned q=0;q<yy().at(p).size();q++) for (int j=0;j<op().nrep();j++) {
            int nj=0;
            const vector<double>& yypq=yy().at(p).at(q);
            for (int t=0;t<op().nt();t++) if (obs(yypq.at(j*op().nt()+t))) {
                mvec.at(p).at(q).at(j)+=yypq.at(j*op().nt()+t);
                nj++;
            }
            mvec.at(p).at(q).at(j) /= nj;
            for (int t=0;t<op().nt();t++) if (obs(yypq.at(j*op().nt()+t))) {
                vvec.at(p).at(q).at(j) += pow(yypq.at(j*op().nt()+t)-mvec.at(p).at(q).at(j),2);
            }
            vvec.at(p).at(q).at(j) /= nj-1;
            if (vvec.at(p).at(q).at(j)==0) vvec.at(p).at(q).at(j)=1;
            for (int t=0;t<op().nt();t++) if (obs(yypq.at(j*op().nt()+t))) {
                d_yy.at(p).at(q).at(j*op().nt()+t) -= mvec.at(p).at(q).at(j);
                d_yy.at(p).at(q).at(j*op().nt()+t) /= sqrt(vvec.at(p).at(q).at(j));
            }
        }
    }

    for (int p=0;p<nprot();p++) for (int l=0; l<op().nc(); l++) {
        data[p][l]=0;
        int nq=0;
        for (unsigned q=0;q<yy().at(p).size();q++) if (obs(yy().at(p).at(q).at(l))) {
            data[p][l] += yy().at(p).at(q).at(l);
            nq++;
        }
        if (nq>0) {
            data[p][l] /= nq;
            mask[p][l] = 1;
        } else {
            data[p][l] = NAN;
            mask[p][l] = 0;
        }
    }

    //double* weight = new double[op().nc()];
    //for (int i = 0; i < op().nc(); i++) weight[i] = 1.0;
    //Node* tree = treecluster(nprot(), op().nc(), data, mask, weight, 0, 'c', 'a', 0);
    //delete[] weight;
    //if (!tree) { /* Indication that the treecluster routine failed */
    //    cout<< "treecluster routine failed due to insufficient memory\n";
    //    return;
    //}
    //int* clusterid = new int[nprot()];
    //cuttree(nprot(), tree, nprot()/100, clusterid);
    //delete[] tree;

    vector<int> clusterid(nprot());

    multimap<int,int> c_mm;
    for (int p=0;p<nprot();p++) c_mm.insert(make_pair(clusterid[p],p));

    vector<vector<vector<Eigen::VectorXd> > > xax,yy_;
    xax.resize(yy().size());
    yy_.resize(yy().size());
    for (int p=0;p<nprot();p++) {
        xax.at(p).resize(yy().at(p).size());
        yy_.at(p).resize(yy().at(p).size());
        for (unsigned q=0;q<yy().at(p).size();q++) {
            xax.at(p).at(q).resize(op().nrep());
            yy_.at(p).at(q).resize(op().nrep());
            for (int j=0;j<op().nrep();j++) {
                vector<double> x,y;
                for (int t=0;t<op().nt();t++) {
                    if (obs(yy().at(p).at(q).at(j*op().nt()+t))) {
                        x.push_back(op().timei().at(t));
                        y.push_back(yy().at(p).at(q).at(j*op().nt()+t));
                    }
                }
                xax.at(p).at(q).at(j).resize(x.size());
                yy_.at(p).at(q).at(j).resize(y.size());
                for (unsigned i=0;i<x.size();i++) {
                    xax.at(p).at(q).at(j)(i)=x.at(i);
                    yy_.at(p).at(q).at(j)(i)=y.at(i);
                }
            }
        }
    }

    const int Ns=100;
    const double step=double(op().timei().back()-op().timei().front())/Ns;
    Eigen::VectorXd xs(Ns);
    for (int i=0;i<Ns;i++) xs(i)=op().timei().at(0)+step/2+i*step;

    ofstream ofs1("EfsY.txt");
    ofs1<<"p\tq\tj";
    for (unsigned i=0;i<xs.size();i++) ofs1<<'\t'<<xs(i);
    ofs1<<'\n';

    int ijk=0;
    vector<double> adjdiff(op().timei().size());
    adjacent_difference(op().timei().begin(),op().timei().end(),adjdiff.begin());

    for (cmmii end1,itc=c_mm.begin();itc!=c_mm.end()/*,ijk<8*/;itc=end1,ijk++) {
        end1=c_mm.upper_bound(itc->first);

        vector<vector<double> > m(op().nrep(),vector<double>(op().nt()));

        vector<double> theta(3,1);

        for (cmmii it=itc;it!=end1;it++) {
            const int p=it->second;
            for (unsigned q=0;q<yy_.at(p).size();q++) for (int j=0;j<op().nrep();j++) {
                Eigen::VectorXd& y = yy_.at(p).at(q).at(j);
                Eigen::VectorXd& x = xax.at(p).at(q).at(j);
                const int N = y.size();

                Eigen::MatrixXd Ky(N,N);
                for (int i=0;i<N;i++) for (int k=0;k<N;k++) Ky(i,k)=Kfn(theta,x(i),x(k));
                Eigen::VectorXd ym(y);
                for (int i=0;i<N;i++) ym(i)-=Mfn(m.at(j),x(i),adjdiff);
                Eigen::MatrixXd invKy=Ky.inverse();
                ofs1<<p<<'\t'<<q<<'\t'<<j;
                for (unsigned i=0;i<xs.size();i++) {
                    Eigen::VectorXd ks(N);
                    for (int k=0;k<N;k++) ks(k)=Kfn(theta,xs(i),x(k),0);
                    const double Efs=ks.transpose()*invKy*ym+Mfn(m.at(j),xs(i),adjdiff);
                    ofs1<<'\t'<<Efs*sqrt(vvec.at(p).at(q).at(j))+mvec.at(p).at(q).at(j);
                }
                ofs1<<'\n';

                for (int t=0;t<op().nt();t++) {
                    Eigen::VectorXd ks(N);
                    for (int k=0;k<N;k++) ks(k)=Kfn(theta,op().timei().at(t),x(k),0);
                    d_yy.at(p).at(q).at(j*op().nt()+t)=
                        ks.transpose()*invKy*ym+Mfn(m.at(j),op().timei().at(t),adjdiff);
                    d_yy.at(p).at(q).at(j*op().nt()+t)*=sqrt(vvec.at(p).at(q).at(j));
                    d_yy.at(p).at(q).at(j*op().nt()+t)+=mvec.at(p).at(q).at(j);
                }
            }
        }
    }
}


#include "engine.hpp"

#include "functional.hpp"

#include <cassert>
#include <vector>

#include <ranges>

#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/algebra/fusion_algebra.hpp>
#include <boost/numeric/odeint/algebra/fusion_algebra_dispatcher.hpp>

namespace EvolutionaryWalker::Physics
{

namespace Impl
{

    class Engine
    {
    public:
        constexpr static const std::size_t number_of_dimensions = 2;
        using VelocityVector = LibUtils::Point<VelocityQuantity, number_of_dimensions>;
        using AccelerationVector = LibUtils::Point<AccelerationQuantity, number_of_dimensions>;
        using state_type = /*std::vector<*/ boost::fusion::vector<LengthQuantity, VelocityQuantity> /*>*/;
        using deriv_type = /*std::vector<*/ boost::fusion::vector<VelocityQuantity, AccelerationQuantity> /*>*/;
        using StepperType = boost::numeric::odeint::runge_kutta_dopri5<state_type, double, deriv_type, TimeQuantity>;

        struct Node
        {
            bool is_fixed;
            MassQuantity mass;
            Point2d position;
            VelocityVector speed;
        };

        struct Spring
        {
            std::array<NodeIndex, 2> nodes;
            SpringCharacteristics characteristics;
        };

        Engine(AccelerationQuantity gravity)
            : m_gravity(std::move(gravity))
        {
        }

        ~Engine() = default;

        void init()
        {
            m_stepper = std::make_unique<StepperType>();
        }

        void step(TimeQuantity time_step)
        {
            assert(numberOfFreeNodes() == 1); // for now
            assert(m_stepper);
            auto x = currentState();
            m_stepper->do_step(std::cref(*this), x, TimeQuantity{}, time_step);
            applyNewState(x);
        }

        void operator()(const state_type& x, deriv_type& dxdt, const TimeQuantity& /* t */) const
        {
            // assert(x.size() == dxdt.size());
            // for(std::size_t i = 0; i < x.size(); i++)
            // {
            //     // dxdt[i].first = x[i].second;
            //     // dxdt[i].second = -x[0] - gam * x[1];
            //
            //     // fusion::at_c<0>(dxdt) = fusion::at_c<1>(x);
            //     // fusion::at_c<1>(dxdt) = -m_omega * m_omega * fusion::at_c<0>(x);
            // }

            // using boost::fusion::at_c;
            at_c<0>(dxdt) = at_c<1>(x);
            at_c<1>(dxdt) = -m_gravity; //-m_omega * m_omega * at_c<0>(x);
        }

        static VelocityVector nullVelocity()
        {
            return {{0 * boost::units::si::meters_per_second, 0 * boost::units::si::meters_per_second}};
        }

        NodeIndex addFixedNode(Point2d position)
        {
            m_nodes.emplace_back(true, 0 * boost::units::si::kilograms, std::move(position), nullVelocity());
            return NodeIndex{m_nodes.size() - 1};
        }

        NodeIndex addNode(Point2d position, MassQuantity mass)
        {
            m_nodes.emplace_back(false, std::move(mass), std::move(position), nullVelocity());
            return NodeIndex{m_nodes.size() - 1};
        }

        SpringIndex addSpring(const NodeIndex node1, const NodeIndex node2, SpringCharacteristics characteristics)
        {
            m_springs.push_back({{node1, node2}, std::move(characteristics)});
            return SpringIndex{m_nodes.size() - 1};
        }

        Point2d node(const NodeIndex i) const
        {
            return m_nodes[i].position;
        }

        std::size_t numberOfFreeNodes() const
        {
            return freeNodes().size();
        }

    private:
        const AccelerationQuantity m_gravity;
        std::vector<Node> m_nodes;
        std::vector<Spring> m_springs;
        std::unique_ptr<StepperType> m_stepper = nullptr;

        state_type currentState() const
        {
            // state_type res;
            // for(const auto& node : m_nodes)
            // {
            //     if(node.is_fixed) continue;
            //     res.emplace_back(node.position, node.speed);
            // }
            // return res;

            const auto nodes = freeNodes();
            state_type res;
            at_c<0>(res) = nodes.front().position[1];
            at_c<1>(res) = nodes.front().speed[1];
            return res;
        }

        void applyNewState(const state_type& state)
        {
            // TODO do better
            m_nodes.back().position[1] = at_c<0>(state);
            m_nodes.back().speed[1] = at_c<1>(state);
        }

        std::vector<Node> freeNodes() const
        {
            using LibUtils::Functional::Not;
            // TODO try with ranges?
            // return m_nodes | std::views::filter(LibUtils::Functional::Not(&Node::is_fixed));
            decltype(m_nodes) res;
            std::copy_if(begin(m_nodes), end(m_nodes), std::back_inserter(res), Not(std::mem_fn(&Node::is_fixed)));
            return res;
        }
    };

} // namespace Impl

Engine::Engine(AccelerationQuantity gravity)
    : m_pimpl(std::make_unique<Impl::Engine>(std::move(gravity)))
{
}

Engine::~Engine() = default;

void Engine::init()
{
    m_pimpl->init();
}

void Engine::step(TimeQuantity time_step)
{
    m_pimpl->step(time_step);
}

NodeIndex Engine::addFixedNode(Point2d position)
{
    return m_pimpl->addFixedNode(std::move(position));
}

NodeIndex Engine::addNode(Point2d position, MassQuantity mass)
{
    return m_pimpl->addNode(std::move(position), std::move(mass));
}

SpringIndex Engine::addSpring(const NodeIndex node1, const NodeIndex node2, SpringCharacteristics characteristics)
{
    return m_pimpl->addSpring(node1, node2, std::move(characteristics));
}

Point2d Engine::node(const NodeIndex i) const
{
    return m_pimpl->node(i);
}

} // namespace EvolutionaryWalker::Physics


//==================================================================================================
/*!

  Copyright 2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/function/scalar/all.hpp>
#include <simd_test.hpp>
#include <boost/dispatch/meta/as_integer.hpp>

STF_CASE_TPL ( "all", STF_ALL_TYPES)
{
  namespace bs = boost::simd;
  using bs::all;

  STF_EQUAL( all(T(1)) , true  );
  STF_EQUAL( all(T(0)), false );
}


//==============================================================================
//         Copyright 2003 & onward LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 & onward 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
//==============================================================================
#ifndef BOOST_SIMD_SDK_META_REAL_C_HPP_INCLUDED
#define BOOST_SIMD_SDK_META_REAL_C_HPP_INCLUDED

#include <boost/config.hpp>
#include <boost/dispatch/meta/as_floating.hpp>
#include <boost/simd/include/functions/scalar/bitwise_cast.hpp>

namespace boost { namespace simd { namespace meta
{
 template<typename Type, Type Value> struct real_c
 {
   BOOST_STATIC_CONSTANT(Type, value = Value);
   typedef real_c                                       type;
   typedef typename dispatch::meta::as_floating<Type>::type value_type;

   operator value_type() const
   {
     return bitwise_cast<value_type>(Value);
   }
 };

} } }

#endif


///////////////////////////////////////////////////////////////////////////////
// cells.hpp                                                                 //
//                                                                           //
//  Copyright 2010 Erwann Rogard. Distributed under the Boost                //
//  Software License, Version 1.0. (See accompanying file                    //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)         //
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_DETAIL_NON_PARAMETRIC_CONTINGENCY_TABLE_CELLS_CELLS_HPP_ER_2010
#define BOOST_STATISTICS_DETAIL_NON_PARAMETRIC_CONTINGENCY_TABLE_CELLS_CELLS_HPP_ER_2010
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_const.hpp>

#include <boost/math/policies/policy.hpp>

#include <boost/fusion/include/at_key.hpp>
#include <boost/fusion/container/map/detail/extract_keys.hpp> // needed?
#include <boost/fusion/container/map/detail/subset_traits.hpp>
#include <boost/fusion/container/map/detail/hashable_map.hpp>

#include <boost/unordered_map.hpp>

#include <boost/accumulators/framework/extractor.hpp>
#include <boost/accumulators/framework/accumulator_base.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/depends_on.hpp>
#include <boost/accumulators/statistics_fwd.hpp>
#include <boost/accumulators/framework/parameters/weight.hpp>
#include <boost/accumulators/framework/detail/unpack_depends_on.hpp>
#include <boost/accumulators/framework/detail/parameters/policy.hpp>

#include <boost/statistics/detail/non_parametric/contingency_table/detail/raise_domain_error.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/factor/levels.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/factor/vec_levels.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/factor/domain_error_logger.hpp>
#include <boost/statistics/detail/non_parametric/contingency_table/factor/check_against_domain.hpp>

// Usage:
//  typedef cells<mpl::vector<X,Y,Z> > cells_
// This is a Boost.Accumulator feature specifying a contingency table asso-
// ciated with variables X, Y, and Z.

namespace boost {
namespace statistics{
namespace detail{
namespace contingency_table{
namespace cells_aux{

   template<typename Keys>
   struct depends_on{
        typedef typename contingency_table::vec_levels<Keys>::type vec_levels_;
        typedef typename boost::accumulators::detail::unpack_depends_on<
            vec_levels_
        >::type type;
   };

    template<typename T,typename Keys>
    struct traits{
        typedef boost::fusion::detail::map_subset_traits<T,Keys> inner_traits;
        typedef typename inner_traits::map subsample_;
        typedef boost::fusion::detail::hashable_map<
            subsample_> hashable_subsample_;
        typedef typename boost::unordered_map<
            hashable_subsample_,std::size_t> map_;

    };
}// cells_aux
namespace impl{

    template<typename T,typename Keys>
    class cells : public boost::accumulators::accumulator_base{
        typedef boost::accumulators::dont_care dont_care_;
        typedef std::size_t size_;

        typedef contingency_table::cells_aux::traits<T,Keys> traits_;
        typedef typename traits_::hashable_subsample_ hashable_subsample_;
        typedef typename traits_::map_ map_;

        public:

        typedef T 		sample_type;
        typedef size_ 	size_type;

        typedef map_& result_type; // not const bec map[] is non-const

        cells(dont_care_){}

        //template<typename A1,typename A2>
        //void operator()(const A1& a1,const A2& a2){
        //
        //}

        template<typename Args>
        void operator()(const Args& args){
            typedef boost::math::policies::policy<> pol_;
            this->update_if(
                hashable_subsample_( args[ boost::accumulators::sample ] ),
                args[ boost::accumulators::accumulator ],
                args[ boost::accumulators::detail::_policy |  pol_() ],
                args[ boost::accumulators::weight ]
            );
        }

        result_type result(dont_care_)const{
            return this->map;
        }

		private:
        template<typename V,typename N>
        void update(
            const V& s,
            const N& size
        ){
            ( this->map )[ s ] += size;
        }

        typedef ::boost::math::policies::domain_error<
             boost::math::policies::ignore_error
        > ignore_policy_;
        template<typename V,typename A,typename N>
        void update_if(
            const V& s,
            const A& acc,
            const ignore_policy_& policy,
            const N& size
        ){
            this->update(s,acc,size);
        }

        template<typename V,typename A,typename P,typename N>
        void update_if(
            const V& s,
            const A& acc,
            const P& policy,
            const N& size
        ){
            namespace ct = contingency_table;
            this->error_logger.reset();
            boost::fusion::for_each(
                s,
                ct::make_check_against_domain( acc, this->error_logger)
            );
            if(!this->error_logger.is_error())
            {
                this->update( s, size );
            }else{
                static const char* fun = "impl::cells::update_if %1%";
                ct::raise_domain_error<V>(
                  fun,
                  this->error_logger().c_str(),
                  policy
                );
            }
        }

        mutable map_ map;
        typedef contingency_table::domain_error_logger error_logger_;
        error_logger_ error_logger;
	};

}// impl
namespace tag
{

    template<typename Keys>
    struct cells
        : contingency_table::cells_aux::depends_on<Keys>::type
    {
        typedef typename contingency_table::par_spec< Keys >::type par_spec_;

        struct impl{
            template<typename T,typename W>
            struct apply{
        		typedef contingency_table::impl::cells<T,Keys> type;
            };
        };
    };

}// tag
namespace result_of{
namespace extract{

    template<typename Keys,typename AccSet>
    struct cells
    : boost::accumulators::detail::extractor_result<
        AccSet,
        contingency_table::tag::cells<Keys>
    >{};

}// extract
}// result_of
namespace extract
{
  	template<typename Keys,typename AccSet>
    typename contingency_table::result_of::extract::template
        cells<Keys,AccSet>::type
  	cells(AccSet const& acc)
    {
    	typedef contingency_table::tag::cells<Keys> the_tag;
        return boost::accumulators::extract_result<the_tag>(acc);
  	}

}// extract

using extract::cells;

}// contingency_table
}// detail
}// statistics
}// boost

#endif


#include "sm_extension.h"
#include <blitz/tinyvec.h>
#include "io.h"

sm_extension::sm_extension() : PHMM(NUM_STATES), dirty(true), stop_at_repeat(false) {
	set_default_parameters( blitz::TinyVector<double,4>(0.25,0.25,0.25,0.25) );
}

// Legacy to create a uniform api with mm_alignment.
void sm_extension::disable_random_model() {}

int sm_extension::num_models() const { return 1; }

void sm_extension::reset() { store.clear(); dstore.clear(); }

void sm_extension::set_default_parameters( blitz::TinyVector<double,4> nq ) {
	using namespace std;
	using namespace boost;

	nw_model_parameters newp;
	newp.q = nq;
	newp.set_p_hky( 0.4, 1.0 );
	newp.pr_open = 0.0625;
	newp.mean_gap_length = 2.0;
	set_parameters( 0, newp, 200 );

	// set start and end states
	PHMM.set_start_state(state_M);
	PHMM.set_end_state(state_E);

	// set silent states for end state
	PHMM.set_emmission(state_E,APHMM::NOTHING,APHMM::NOTHING,1.0);

	set_random_distribution(nq);
	PHMM.optimize();
	dirty = false;
}

void sm_extension::set_stop_at_repeat( bool t ) { stop_at_repeat = t; }

void sm_extension::set_random_distribution( blitz::TinyVector<double,4> nq ) {
	dirty = true;
	for( int i = 0; i < 4; ++i) q(i) = nq(i);
}

double sm_extension::get_region_length( int k ) const {
	assert( k == 0 );
	// since we didn't tie the "t" parts, we'll just average all three values
	double sum = (double)PHMM.get_transition(state_M,state_E);
	sum += (double)PHMM.get_transition(state_Ia,state_E);
	sum += (double)PHMM.get_transition(state_Ib,state_E);
	double p_1mt = sum/3.0;
	return 1.0/p_1mt;
}

void sm_extension::set_parameters( int k, nw_model_parameters const &nwp, int len ) {
	assert( k == 0 );
	dirty = true;
	double pt = 1.0-1.0/(double)len;

	// set open
	double p_at = nwp.pr_open*pt;
	double p_1m2at = (1.0-2.0*nwp.pr_open)*pt;
	PHMM.set_transition(state_M,state_Ia,p_at);
	PHMM.set_transition(state_M,state_Ib,p_at);
	PHMM.set_transition(state_M,state_M,p_1m2at);

	// Since a gap is length 1 by the virtue of opening it, we adjust n down by 1.
	// The remaining gap extension probability corresponds to the mean of a
	// geometric distribution allowing zero extensions.
	double p_b = 1.0-1.0/nwp.mean_gap_length;
	double p_bt = p_b*pt;
	double p_1mbt = (1.0 - p_b)*pt;
	PHMM.set_transition(state_Ia,state_Ia,p_bt);
	PHMM.set_transition(state_Ia,state_M,p_1mbt);
	PHMM.set_transition(state_Ib,state_Ib,p_bt);
	PHMM.set_transition(state_Ib,state_M,p_1mbt);

	// set end transitions
	double p_1mt = 1.0 - pt;
	PHMM.set_transition(state_M,state_E,p_1mt);
	PHMM.set_transition(state_Ia,state_E,p_1mt);
	PHMM.set_transition(state_Ib,state_E,p_1mt);

	// set background
	for( int i = 0; i < 4; i++ ) {
      PHMM.set_emmission(state_Ia,i,APHMM::NOTHING,nwp.q(i));
      PHMM.set_emmission(state_Ib,APHMM::NOTHING,i,nwp.q(i));
   }

	// set p
	for( int i = 0; i < 4; i++ ) {
		for( int j = 0; j < 4; j++ ) {
			PHMM.set_emmission(state_M,i,j,nwp.p(i,j));
		}
   }
}

nw_model_parameters_ptr sm_extension::get_parameters( int k ) const {
	assert( k == 0 );
	nw_model_parameters_ptr nwp( new nw_model_parameters() );
	double t = 1.0 - 1.0/get_region_length(0);
	nwp->pr_open = (double) PHMM.get_transition(state_M,state_Ia)/t;

	nwp->mean_gap_length = 1.0/(1.0- (double)PHMM.get_transition(state_Ia,state_Ia)/t );

	for( int x = 0; x < APHMM::NOTHING; ++x ) {
		double qx = 0.0;
		for( int y = 0; y < APHMM::NOTHING; ++y ) {
			nwp->p(x,y) = (double)PHMM.get_emmission(state_M,x,y);
			qx += nwp->p(x,y);
		}
		nwp->q(x) = qx;
	}

	return nwp;
}

blitz::TinyVector<double,4> sm_extension::get_random_distribution() const {
	return q;
}

void sm_extension::pretty_print_parameters( std::ostream &out ) const {
	using namespace std;

	out  << "Background: " << get_random_distribution() << endl;
	nw_model_parameters_ptr nwp = get_parameters(0);
	nwp->pretty_print(out);
	double pr_match = 0;
	for( int i = 0; i < 4; ++i ) pr_match += nwp->p(i,i);
	out << "Pr(match): " << pr_match << endl;
}

void sm_extension::write_parameters( std::ostream &out ) const {
	using namespace std;

	out  << "# Background: " << get_random_distribution() << endl << endl;

	nw_model_parameters_ptr nwp = get_parameters(0);
	nwp->pretty_print( out, "# " );
	out << endl;
	out << endl << "# Machine readable parameters follow. " << "---------------------------------------------" << endl;

	blitz::TinyVector<double,4> q = get_random_distribution();
	for( int i = 0; i < 4; ++i )  out << q(i) << " ";
	out << endl;
	out << *get_parameters(0) << endl;

}

void sm_extension::read_parameters( std::istream &in ) {
	using namespace std;
	vector<double> mdist;
	mdist.push_back( read<double>(in) );
	// Skip unused random model parameters.
	read<double>(in);	read<double>(in);
	for( int i = 0; i < 4; ++i ) q(i) = read<double>(in);

	int nmodels = read<int>(in);
	assert(nmodels == 1);

	mdist.push_back( read<double>(in) );
	int length =  read<double>(in);
	nw_model_parameters param;
	in >> param;
	set_parameters( 0, param, length );
	PHMM.optimize();
	dirty = false;
}


//
// Created by realngnx on 11/06/2021.
//
#ifndef SHARDER_H
#define SHARDER_H

#include <boost/optional.hpp>
#include <map>
#include <iostream>
#include "./hasher.hpp"
#include "./node.hpp"

class Sharder {
public:
    virtual boost::optional<std::shared_ptr<ServiceNode>> route(std::string key) = 0;

};

class ConsistentHash: public Sharder {
public:
    ConsistentHash();
    ~ConsistentHash();

    boost::optional<std::shared_ptr<ServiceNode>> route(std::string key) override;
    void add(ServiceNode& node, long virtual_node_count);
    void remove(ServiceNode& node);
    void clear();
    long get_existing_replicas(ServiceNode& node);

private:
    Digest digest;
    std::map<long, VirtualNode*> ring;

    std::vector<long> extract_keys() {
        std::vector<long> keys;
        for (auto const& element : ring) {
            keys.push_back(element.first);
        }
        return keys;
    }
};

#endif //SHARDER_H


#pragma once

#include <boost/intrusive_ptr.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "formula_callable.hpp"
#include "formula_callable_definition.hpp"
#include "frustum.hpp"
#include "variant.hpp"

class camera_callable : public game_logic::formula_callable
{
public:
	enum CAMERA_TYPE { PERSPECTIVE_CAMERA, ORTHOGONAL_CAMERA };
	camera_callable();
	explicit camera_callable(CAMERA_TYPE type, int left, int right, int top, int bottom);
	explicit camera_callable(CAMERA_TYPE type, float fov, float aspect, float near_clip, float far_clip);
	explicit camera_callable(const variant& node);
	virtual ~camera_callable();
	//virtual variant get_value(const std::string&) const;
	//virtual void set_value(const std::string& key, const variant& value);

	void compute_view();
	void compute_projection();

	void set_mousespeed(float ms) { mouse_speed_ = ms; }
	void set_speed(float spd) { speed_ = spd; }
	void set_hangle(float ha) { horizontal_angle_ = ha; }
	void set_vangle(float va) { vertical_angle_ = va; }
	void set_fov(float fov);
	void set_aspect(float aspect);
	void set_clip_planes(float z_near, float z_far);
	void set_type(CAMERA_TYPE type);
	void set_ortho_window(int left, int right, int top, int bottom);
	float mousespeed() const { return mouse_speed_; }
	float speed() const { return speed_; }
	float hangle() const { return horizontal_angle_; }
	float vangle() const { return vertical_angle_; }
	float fov() const { return fov_; }
	float aspect() const { return aspect_; }
	float near_clip() const { return near_clip_; }
	float far_clip() const { return far_clip_; }
	CAMERA_TYPE type() const { return type_; }
	int ortho_left() const { return ortho_left_; }
	int ortho_right() const { return ortho_right_; }
	int ortho_top() const { return ortho_top_; }
	int ortho_bottom() const { return ortho_bottom_; }
	const glm::vec3& position() const { return position_; }
	const glm::vec3& right() const { return right_; }
	const glm::vec3& direction() const { return direction_; }
	const glm::vec3& target() const { return target_; }
	const glm::vec3& up() const { return up_; }
	void set_position(const glm::vec3& position) { position_ = position; }

	void look_at(glm::vec3 position, glm::vec3 target, glm::vec3 up);

	const float* projection() const { return glm::value_ptr(projection_); }
	const float* view() const { return glm::value_ptr(view_); }
	const glm::mat4& view_mat() const { return view_; }
	const glm::mat4& projection_mat() const { return projection_; }

	const graphics::frustum& frustum() { return frustum_; }

	glm::vec3 screen_to_world(int x, int y, int wx, int wy) const;
	glm::ivec3 get_facing(const glm::vec3& coords) const;

	variant write();
protected:
private:
	DECLARE_CALLABLE(camera_callable);

	enum {MODE_AUTO, MODE_MANUAL} mode_;

	float fov_;
	float horizontal_angle_;
	float vertical_angle_;
	glm::vec3 position_;
	glm::vec3 target_;
	glm::vec3 up_;
	glm::vec3 right_;
	glm::vec3 direction_;
	float speed_;
	float mouse_speed_;

	float near_clip_;
	float far_clip_;
	bool clip_planes_set_;

	float aspect_;

	graphics::frustum frustum_;

	CAMERA_TYPE type_;
	int ortho_left_;
	int ortho_right_;
	int ortho_top_;
	int ortho_bottom_;

	glm::mat4 projection_;
	glm::mat4 view_;

	camera_callable(const camera_callable&);
};

typedef boost::intrusive_ptr<camera_callable> camera_callable_ptr;
typedef boost::intrusive_ptr<const camera_callable> const_camera_callable_ptr;


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2020 Digvijay Janartha, Hamirpur, India.

// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020, 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_GEOMETRIES_POINT_XYZ_HPP
#define BOOST_GEOMETRY_GEOMETRIES_POINT_XYZ_HPP

#include <cstddef>
#include <type_traits>

#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/geometries/point.hpp>

namespace boost { namespace geometry
{

namespace model { namespace d3
{

/*!
\brief 3D point in Cartesian coordinate system
\tparam CoordinateType numeric type, for example, double, float, int
\tparam CoordinateSystem coordinate system, defaults to cs::cartesian

\qbk{[include reference/geometries/point_xyz.qbk]}
\qbk{before.synopsis,
[heading Model of]
[link geometry.reference.concepts.concept_point Point Concept]
}

\qbk{[include reference/geometries/point_assign_warning.qbk]}

*/
template<typename CoordinateType, typename CoordinateSystem = cs::cartesian>
class point_xyz : public model::point<CoordinateType, 3, CoordinateSystem>
{
public:
    /// \constructor_default_no_init
    constexpr point_xyz() = default;

    /// Constructor with x/y/z values
    constexpr point_xyz(CoordinateType const& x, CoordinateType const& y, CoordinateType const& z)
        : model::point<CoordinateType, 3, CoordinateSystem>(x, y, z)
    {}

    /// Get x-value
    constexpr CoordinateType const& x() const
    { return this->template get<0>(); }

    /// Get y-value
    constexpr CoordinateType const& y() const
    { return this->template get<1>(); }

    /// Get z-value
    constexpr CoordinateType const& z() const
    { return this->template get<2>(); }

    /// Set x-value
    void x(CoordinateType const& v)
    { this->template set<0>(v); }

    /// Set y-value
    void y(CoordinateType const& v)
    { this->template set<1>(v); }

    /// Set z-value
    void z(CoordinateType const& v)
    { this->template set<2>(v); }
};

}} // namespace model::d3

// Adapt the point_xyz to the concept
#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
namespace traits
{

template <typename CoordinateType, typename CoordinateSystem>
struct tag<model::d3::point_xyz<CoordinateType, CoordinateSystem> >
{
    typedef point_tag type;
};

template<typename CoordinateType, typename CoordinateSystem>
struct coordinate_type<model::d3::point_xyz<CoordinateType, CoordinateSystem> >
{
    typedef CoordinateType type;
};

template<typename CoordinateType, typename CoordinateSystem>
struct coordinate_system<model::d3::point_xyz<CoordinateType, CoordinateSystem> >
{
    typedef CoordinateSystem type;
};

template<typename CoordinateType, typename CoordinateSystem>
struct dimension<model::d3::point_xyz<CoordinateType, CoordinateSystem> >
    : std::integral_constant<std::size_t, 3>
{};

template<typename CoordinateType, typename CoordinateSystem, std::size_t Dimension>
struct access<model::d3::point_xyz<CoordinateType, CoordinateSystem>, Dimension>
{
    static constexpr CoordinateType get(
        model::d3::point_xyz<CoordinateType, CoordinateSystem> const& p)
    {
        return p.template get<Dimension>();
    }

    static void set(model::d3::point_xyz<CoordinateType, CoordinateSystem>& p,
        CoordinateType const& value)
    {
        p.template set<Dimension>(value);
    }
};

template<typename CoordinateType, typename CoordinateSystem>
struct make<model::d3::point_xyz<CoordinateType, CoordinateSystem> >
{
    typedef model::d3::point_xyz<CoordinateType, CoordinateSystem> point_type;

    static const bool is_specialized = true;

    static constexpr point_type apply(CoordinateType const& x,
                                      CoordinateType const& y,
                                      CoordinateType const& z)
    {
        return point_type(x, y, z);
    }
};

} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_GEOMETRIES_POINT_XYZ_HPP


#include "testsuite.h"
#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

int main()
{
  {
    Array<int, 2> A(7,11, contiguousArray);
    BZTEST(A.isStorageContiguous());

    BZTEST(!(A(Range(fromStart, toEnd, 2),
        Range::all())).isStorageContiguous());
    BZTEST(A.reverse(firstDim).isStorageContiguous());
    BZTEST(A.reverse(secondDim).isStorageContiguous());
    BZTEST(!A(Range::all(), 4).isStorageContiguous());
    BZTEST(A(4, Range::all()).isStorageContiguous());
  }

  {
    Array<int, 2> A(7,11, ColumnMajorArray<2>(contiguousData));
    BZTEST(A.isStorageContiguous());

    BZTEST(!(A(Range(fromStart, toEnd, 2),
        Range::all())).isStorageContiguous());
    BZTEST(A.reverse(firstDim).isStorageContiguous());
    BZTEST(A.reverse(secondDim).isStorageContiguous());
    BZTEST(A(Range::all(), 4).isStorageContiguous());
    BZTEST(!A(4, Range::all()).isStorageContiguous());
  }

  {
    Array<int, 2> A(Range(-4,8),Range(4,27), contiguousArray);
    BZTEST(A.isStorageContiguous());

    BZTEST(!(A(Range(fromStart, toEnd, 2),
        Range::all())).isStorageContiguous());
    BZTEST(A.reverse(firstDim).isStorageContiguous());
    BZTEST(A.reverse(secondDim).isStorageContiguous());
    BZTEST(!A(Range::all(), 4).isStorageContiguous());
    BZTEST(A(4, Range::all()).isStorageContiguous());
  }
}