<commit_before>/*
 * File:   cql_cluster_impl.hpp
 * Author: mc
 *
 * Created on September 25, 2013, 12:16 PM
 */

#ifndef CQL_CLUSTER_IMPL_HPP_
#define	CQL_CLUSTER_IMPL_HPP_

#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>

#include "cql/cql_builder.hpp"
#include "cql/cql_connection.hpp"
#include "cql/internal/cql_connection_factory.hpp"
#include "cql/cql_metadata.hpp"
#include "cql/cql_session.hpp"
#include "cql/cql_uuid.hpp"

#include "cql/internal/cql_control_connection.hpp"
#include "cql/internal/cql_session_impl.hpp"

namespace cql {

// This is a non-SSL client factory
    struct client_functor_t
{
public:

    client_functor_t(
        boost::asio::io_service&                  service,
        cql::cql_connection_t::cql_log_callback_t log_callback) :
        _io_service(service),
        _log_callback(log_callback)
    {}

    inline boost::shared_ptr<cql::cql_connection_t>
    operator()()
    {
        // called every time the pool needs to initiate a new connection to a host
        boost::shared_ptr<cql::cql_connection_t> ret_val
            = cql::cql_connection_factory_t::create_connection(_io_service, _log_callback);
        return ret_val;
    }

private:
    boost::asio::io_service&                  _io_service;
    cql::cql_connection_t::cql_log_callback_t _log_callback;
};

// This is an SSL client factory
    struct client_ssl_functor_t
{
    public:

    client_ssl_functor_t(boost::asio::io_service&                  service,
                         boost::asio::ssl::context&                context,
                         cql::cql_connection_t::cql_log_callback_t log_callback) :
        _io_service(service),
        _ssl_ctx(context),
        _log_callback(log_callback)
    {}

    inline boost::shared_ptr<cql::cql_connection_t>
    operator()()
    {
        // called every time the pool needs to initiate a new connection to a host
        boost::shared_ptr<cql::cql_connection_t> ret_val
            = cql::cql_connection_factory_t::create_connection(_io_service, _ssl_ctx, _log_callback);
        return ret_val;
    }

private:
    boost::asio::io_service&                  _io_service;
    boost::asio::ssl::context&                _ssl_ctx;
    cql::cql_connection_t::cql_log_callback_t _log_callback;
};

class cql_cluster_impl_t :
        public cql_cluster_t
{
private:
    // Main function of thread on which we call io_service::run
    static void
    asio_thread_main(
                     boost::shared_ptr<boost::asio::io_service> io_service)
    {
        io_service->run();
    }

	bool _Iam_shotdown;

public:
    cql_cluster_impl_t(
        const std::list<cql_endpoint_t>&        endpoints,
        boost::shared_ptr<cql_configuration_t>  configuration) :
		_Iam_shotdown(false),
        _io_service(configuration->io_service()),
        _contact_points(endpoints),
        _configuration(configuration),
        _work(new boost::asio::io_service::work(*configuration->io_service()))
    {
		for(int i=0;i<configuration->client_options().thread_pool_size();i++)
			_threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&cql_cluster_impl_t::asio_thread_main, _io_service))));

		_configuration->init(this);
        const cql_policies_t& policies = _configuration->policies();

        _metadata = boost::shared_ptr<cql_metadata_t>(new cql_metadata_t(policies.reconnection_policy()));

        _metadata->add_hosts(endpoints);

        _control_connection = boost::shared_ptr<cql_control_connection_t>(
            new cql_control_connection_t(
                *this,
                *_io_service,
                configuration
                ));
        _control_connection->init();
    }

    virtual
    ~cql_cluster_impl_t()
    {
		shutdown(60*1000);
	}

    virtual boost::shared_ptr<cql::cql_session_t>
    connect()
    {
        return connect("");
    }

    virtual boost::shared_ptr<cql::cql_session_t>
    connect(
        const std::string& keyspace)
    {
        // decide which client factory we want, SSL or non-SSL.  This is a hack, if you pass any commandline arg to the
        // binary it will use the SSL factory, non-SSL by default

        cql::cql_session_t::cql_client_callback_t client_factory;
        boost::asio::ssl::context* ssl_context =
				_configuration->protocol_options()
							   .ssl_context()
							   .get();

        cql::cql_connection_t::cql_log_callback_t log_callback =
				_configuration->client_options()
							   .log_callback();

        if (ssl_context != 0) {
            client_factory = client_ssl_functor_t(
				*_io_service,
				const_cast<boost::asio::ssl::context&>(*ssl_context),
				log_callback);
        }
        else {
            client_factory = client_functor_t(*_io_service, log_callback);
        }

        // Construct the session
        cql_session_callback_info_t session_callbacks;
        session_callbacks.set_client_callback(client_factory);
        session_callbacks.set_log_callback(log_callback);

        boost::shared_ptr<cql_session_impl_t> session(
            new cql_session_impl_t(session_callbacks, _configuration));

        session->init(*_io_service);
        session->set_keyspace(keyspace);

        return session;
    }

    virtual void
    shutdown(int timeout_ms) {
		if(_Iam_shotdown)
			return;
        close_sessions();
        _control_connection->shutdown();

        if (_work.get() != NULL) {
            _work.reset();
			for(std::vector<boost::shared_ptr<boost::thread> >::iterator pos = _threads.begin() ;pos!=_threads.end();++pos)
				(*pos)->join();
        }
		_Iam_shotdown = true;
    }

    virtual boost::shared_ptr<cql_metadata_t>
    metadata() const {
        return _metadata;
    }

    friend class cql_metadata_t;

private:

    typedef std::map<cql_uuid_t, boost::shared_ptr<cql_session_t> > connected_sessions_t;

    void
    close_sessions()
    {
        boost::mutex::scoped_lock lock(_mutex);
        for (connected_sessions_t::iterator it = _connected_sessions.begin();
             it != _connected_sessions.end(); ++it)
        {
            it->second->close();
        }
		_connected_sessions.clear();
	}

    boost::shared_ptr<boost::asio::io_service> _io_service;
    const std::list<cql_endpoint_t> 	       _contact_points;
    boost::shared_ptr<cql_configuration_t>     _configuration;

    // Typically async operations are performed in the thread performing the request, because we want synchronous behavior
    // we're going to spawn a thread whose sole purpose is to perform network communication, and we'll use this thread to
    // initiate and check the status of requests.
    //
    // Also, typically the boost::asio::io_service::run will exit as soon as it's work is done, which we want to prevent
    // because it's in it's own thread.  Using boost::asio::io_service::work prevents the thread from exiting.
    boost::mutex                                     _mutex;
    boost::scoped_ptr<boost::asio::io_service::work> _work;
	std::vector<boost::shared_ptr<boost::thread>>	 _threads;
    boost::shared_ptr<cql_metadata_t>                _metadata;
    connected_sessions_t                             _connected_sessions;
    boost::shared_ptr<cql_control_connection_t>      _control_connection;
};

}

#endif	/* CQL_CLUSTER_IMPL_HPP_ */
<commit_msg>nested template definitions must include '> >' instead of '>>'<commit_after>/*
 * File:   cql_cluster_impl.hpp
 * Author: mc
 *
 * Created on September 25, 2013, 12:16 PM
 */

#ifndef CQL_CLUSTER_IMPL_HPP_
#define	CQL_CLUSTER_IMPL_HPP_

#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>

#include "cql/cql_builder.hpp"
#include "cql/cql_connection.hpp"
#include "cql/internal/cql_connection_factory.hpp"
#include "cql/cql_metadata.hpp"
#include "cql/cql_session.hpp"
#include "cql/cql_uuid.hpp"

#include "cql/internal/cql_control_connection.hpp"
#include "cql/internal/cql_session_impl.hpp"

namespace cql {

// This is a non-SSL client factory
    struct client_functor_t
{
public:

    client_functor_t(
        boost::asio::io_service&                  service,
        cql::cql_connection_t::cql_log_callback_t log_callback) :
        _io_service(service),
        _log_callback(log_callback)
    {}

    inline boost::shared_ptr<cql::cql_connection_t>
    operator()()
    {
        // called every time the pool needs to initiate a new connection to a host
        boost::shared_ptr<cql::cql_connection_t> ret_val
            = cql::cql_connection_factory_t::create_connection(_io_service, _log_callback);
        return ret_val;
    }

private:
    boost::asio::io_service&                  _io_service;
    cql::cql_connection_t::cql_log_callback_t _log_callback;
};

// This is an SSL client factory
    struct client_ssl_functor_t
{
    public:

    client_ssl_functor_t(boost::asio::io_service&                  service,
                         boost::asio::ssl::context&                context,
                         cql::cql_connection_t::cql_log_callback_t log_callback) :
        _io_service(service),
        _ssl_ctx(context),
        _log_callback(log_callback)
    {}

    inline boost::shared_ptr<cql::cql_connection_t>
    operator()()
    {
        // called every time the pool needs to initiate a new connection to a host
        boost::shared_ptr<cql::cql_connection_t> ret_val
            = cql::cql_connection_factory_t::create_connection(_io_service, _ssl_ctx, _log_callback);
        return ret_val;
    }

private:
    boost::asio::io_service&                  _io_service;
    boost::asio::ssl::context&                _ssl_ctx;
    cql::cql_connection_t::cql_log_callback_t _log_callback;
};

class cql_cluster_impl_t :
        public cql_cluster_t
{
private:
    // Main function of thread on which we call io_service::run
    static void
    asio_thread_main(
                     boost::shared_ptr<boost::asio::io_service> io_service)
    {
        io_service->run();
    }

	bool _Iam_shotdown;

public:
    cql_cluster_impl_t(
        const std::list<cql_endpoint_t>&        endpoints,
        boost::shared_ptr<cql_configuration_t>  configuration) :
		_Iam_shotdown(false),
        _io_service(configuration->io_service()),
        _contact_points(endpoints),
        _configuration(configuration),
        _work(new boost::asio::io_service::work(*configuration->io_service()))
    {
		for(int i=0;i<configuration->client_options().thread_pool_size();i++)
			_threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&cql_cluster_impl_t::asio_thread_main, _io_service))));

		_configuration->init(this);
        const cql_policies_t& policies = _configuration->policies();

        _metadata = boost::shared_ptr<cql_metadata_t>(new cql_metadata_t(policies.reconnection_policy()));

        _metadata->add_hosts(endpoints);

        _control_connection = boost::shared_ptr<cql_control_connection_t>(
            new cql_control_connection_t(
                *this,
                *_io_service,
                configuration
                ));
        _control_connection->init();
    }

    virtual
    ~cql_cluster_impl_t()
    {
		shutdown(60*1000);
	}

    virtual boost::shared_ptr<cql::cql_session_t>
    connect()
    {
        return connect("");
    }

    virtual boost::shared_ptr<cql::cql_session_t>
    connect(
        const std::string& keyspace)
    {
        // decide which client factory we want, SSL or non-SSL.  This is a hack, if you pass any commandline arg to the
        // binary it will use the SSL factory, non-SSL by default

        cql::cql_session_t::cql_client_callback_t client_factory;
        boost::asio::ssl::context* ssl_context =
				_configuration->protocol_options()
							   .ssl_context()
							   .get();

        cql::cql_connection_t::cql_log_callback_t log_callback =
				_configuration->client_options()
							   .log_callback();

        if (ssl_context != 0) {
            client_factory = client_ssl_functor_t(
				*_io_service,
				const_cast<boost::asio::ssl::context&>(*ssl_context),
				log_callback);
        }
        else {
            client_factory = client_functor_t(*_io_service, log_callback);
        }

        // Construct the session
        cql_session_callback_info_t session_callbacks;
        session_callbacks.set_client_callback(client_factory);
        session_callbacks.set_log_callback(log_callback);

        boost::shared_ptr<cql_session_impl_t> session(
            new cql_session_impl_t(session_callbacks, _configuration));

        session->init(*_io_service);
        session->set_keyspace(keyspace);

        return session;
    }

    virtual void
    shutdown(int timeout_ms) {
		if(_Iam_shotdown)
			return;
        close_sessions();
        _control_connection->shutdown();

        if (_work.get() != NULL) {
            _work.reset();
			for(std::vector<boost::shared_ptr<boost::thread> >::iterator pos = _threads.begin() ;pos!=_threads.end();++pos)
				(*pos)->join();
        }
		_Iam_shotdown = true;
    }

    virtual boost::shared_ptr<cql_metadata_t>
    metadata() const {
        return _metadata;
    }

    friend class cql_metadata_t;

private:

    typedef std::map<cql_uuid_t, boost::shared_ptr<cql_session_t> > connected_sessions_t;

    void
    close_sessions()
    {
        boost::mutex::scoped_lock lock(_mutex);
        for (connected_sessions_t::iterator it = _connected_sessions.begin();
             it != _connected_sessions.end(); ++it)
        {
            it->second->close();
        }
		_connected_sessions.clear();
	}

    boost::shared_ptr<boost::asio::io_service> _io_service;
    const std::list<cql_endpoint_t> 	       _contact_points;
    boost::shared_ptr<cql_configuration_t>     _configuration;

    // Typically async operations are performed in the thread performing the request, because we want synchronous behavior
    // we're going to spawn a thread whose sole purpose is to perform network communication, and we'll use this thread to
    // initiate and check the status of requests.
    //
    // Also, typically the boost::asio::io_service::run will exit as soon as it's work is done, which we want to prevent
    // because it's in it's own thread.  Using boost::asio::io_service::work prevents the thread from exiting.
    boost::mutex                                     _mutex;
    boost::scoped_ptr<boost::asio::io_service::work> _work;
	std::vector<boost::shared_ptr<boost::thread> >	 _threads;
    boost::shared_ptr<cql_metadata_t>                _metadata;
    connected_sessions_t                             _connected_sessions;
    boost::shared_ptr<cql_control_connection_t>      _control_connection;
};

}

#endif	/* CQL_CLUSTER_IMPL_HPP_ */
<|endoftext|>


<commit_before>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "problems/tsp/tsp.h"
#include "problems/tsp/heuristics/christofides.h"
#include "problems/tsp/heuristics/local_search.h"
#include "utils/helpers.h"

namespace {

vroom::Cost compute_cost(const std::list<vroom::Index>& tour, const vroom::Matrix<vroom::Cost>& matrix) {
  vroom::Cost cost = 0;
  vroom::Index init_step = 0; // Initialization actually never used.

  auto step = tour.cbegin();
  if (tour.size() > 0) {
    init_step = *step;
  }

  vroom::Index previous_step = init_step;
  ++step;
  for (; step != tour.cend(); ++step) {
    cost += matrix[previous_step][*step];
    previous_step = *step;
  }
  if (tour.size() > 0) {
    cost += matrix[previous_step][init_step];
  }
  return cost;
}

}

namespace vroom {

TSP::TSP(const Input& input, std::vector<Index> job_ranks, Index vehicle_rank)
  : VRP(input),
    _vehicle_rank(vehicle_rank),
    _job_ranks(std::move(job_ranks)),
    _is_symmetric(true),
    _has_start(_input.vehicles[_vehicle_rank].has_start()),
    _has_end(_input.vehicles[_vehicle_rank].has_end()) {

  assert(!_job_ranks.empty());

  // Pick ranks to select from input matrix.
  std::vector<Index> matrix_ranks;
  std::transform(_job_ranks.cbegin(),
                 _job_ranks.cend(),
                 std::back_inserter(matrix_ranks),
                 [&](const auto& r) { return _input.jobs[r].index(); });

  if (_has_start) {
    // Add start and remember rank in _matrix.
    _start = matrix_ranks.size();
    matrix_ranks.push_back(
      _input.vehicles[_vehicle_rank].start.value().index());
  }
  if (_has_end) {
    // Add end and remember rank in _matrix.
    if (_has_start and (_input.vehicles[_vehicle_rank].start.value().index() ==
                        _input.vehicles[_vehicle_rank].end.value().index())) {
      // Avoiding duplicate for identical ranks.
      _end = _start;
    } else {
      _end = matrix_ranks.size();
      matrix_ranks.push_back(
        _input.vehicles[_vehicle_rank].end.value().index());
    }
  }

  // Populate TSP-solving matrix.
  _matrix = Matrix<Cost>(matrix_ranks.size());

  const auto& v = _input.vehicles[vehicle_rank];
  for (Index i = 0; i < matrix_ranks.size(); ++i) {
    for (Index j = 0; j < matrix_ranks.size(); ++j) {
      _matrix[i][j] = v.cost(matrix_ranks[i], matrix_ranks[j]);
    }
  }

  // Distances on the diagonal are never used except in the minimum
  // weight perfect matching (munkres call during the heuristic). This
  // makes sure no node will be matched with itself at that time.
  for (Index i = 0; i < _matrix.size(); ++i) {
    _matrix[i][i] = INFINITE_COST;
  }

  _round_trip = _has_start and _has_end and (_start == _end);

  if (!_round_trip) {
    // Dealing with open tour cases. Exactly one of the following
    // happens.
    if (_has_start and !_has_end) {
      // Forcing first location as start, end location decided during
      // optimization.
      for (Index i = 0; i < _matrix.size(); ++i) {
        if (i != _start) {
          _matrix[i][_start] = 0;
        }
      }
    }
    if (!_has_start and _has_end) {
      // Forcing last location as end, start location decided during
      // optimization.
      for (Index j = 0; j < _matrix.size(); ++j) {
        if (j != _end) {
          _matrix[_end][j] = 0;
        }
      }
    }
    if (_has_start and _has_end) {
      // Forcing first location as start, last location as end to
      // produce an open tour.
      assert(_start != _end);
      _matrix[_end][_start] = 0;
      for (Index j = 0; j < _matrix.size(); ++j) {
        if ((j != _start) and (j != _end)) {
          _matrix[_end][j] = INFINITE_COST;
        }
      }
    }
  }

  // Compute symmetrized matrix and update _is_symmetric flag.
  _symmetrized_matrix = Matrix<Cost>(_matrix.size());

  const Cost& (*sym_f)(const Cost&, const Cost&) = std::min<Cost>;
  if ((_has_start and !_has_end) or (!_has_start and _has_end)) {
    // Using symmetrization with max as when only start or only end is
    // forced, the matrix has a line or a column filled with zeros.
    sym_f = std::max<Cost>;
  }
  for (Index i = 0; i < _matrix.size(); ++i) {
    _symmetrized_matrix[i][i] = _matrix[i][i];
    for (Index j = i + 1; j < _matrix.size(); ++j) {
      _is_symmetric = _is_symmetric && (_matrix[i][j] == _matrix[j][i]);
      Cost val = sym_f(_matrix[i][j], _matrix[j][i]);
      _symmetrized_matrix[i][j] = val;
      _symmetrized_matrix[j][i] = val;
    }
  }
}

Cost TSP::cost(const std::list<Index>& tour) const {
  return compute_cost(tour, _matrix);
}

Cost TSP::symmetrized_cost(const std::list<Index>& tour) const {
  return compute_cost(tour, _symmetrized_matrix);
}

std::vector<Index> TSP::raw_solve(unsigned nb_threads,
                                  const Timeout& timeout) const {
  // Compute deadline including heuristic computing time.
  const Deadline deadline =
    timeout.has_value() ? utils::now() + timeout.value() : Deadline();

  // Applying heuristic.
  std::list<Index> christo_sol = tsp::christofides(_symmetrized_matrix);

  Deadline sym_deadline = deadline;
  if (deadline.has_value() and !_is_symmetric) {
    // Rule of thumb if problem is asymmetric: dedicate 70% of the
    // remaining available solving time to the symmetric local search,
    // then the rest to the asymmetric version.
    const auto after_heuristic = utils::now();
    const auto remaining_ms =
      (after_heuristic < deadline.value())
        ? std::chrono::duration_cast<std::chrono::milliseconds>(
            deadline.value() - after_heuristic)
            .count()
        : 0;
    sym_deadline =
      after_heuristic +
      std::chrono::milliseconds(static_cast<unsigned>(0.7 * remaining_ms));
  }

  // Local search on symmetric problem.
  // Applying deterministic, fast local search to improve the current
  // solution in a small amount of time. All possible moves for the
  // different neighbourhoods are performed, stopping when reaching a
  // local minima.
  tsp::LocalSearch sym_ls(_symmetrized_matrix,
                          std::make_pair(!_round_trip and _has_start and
                                           _has_end,
                                         _start),
                          christo_sol,
                          nb_threads);

  Cost sym_two_opt_gain = 0;
  Cost sym_relocate_gain = 0;
  Cost sym_or_opt_gain = 0;

  do {
    // All possible 2-opt moves.
    sym_two_opt_gain = sym_ls.perform_all_two_opt_steps(sym_deadline);

    // All relocate moves.
    sym_relocate_gain = sym_ls.perform_all_relocate_steps(sym_deadline);

    // All or-opt moves.
    sym_or_opt_gain = sym_ls.perform_all_or_opt_steps(sym_deadline);
  } while ((sym_two_opt_gain > 0) or (sym_relocate_gain > 0) or
           (sym_or_opt_gain > 0));

  Index first_loc_index;
  if (_has_start) {
    // Use start value set in constructor from vehicle input.
    first_loc_index = _start;
  } else {
    assert(_has_end);
    // Requiring the tour to be described from the "forced" end
    // location.
    first_loc_index = _end;
  }

  std::list<Index> current_sol = sym_ls.get_tour(first_loc_index);

  if (!_is_symmetric) {
    // Back to the asymmetric problem, picking the best way.
    std::list<Index> reverse_current_sol(current_sol);
    reverse_current_sol.reverse();
    Cost direct_cost = this->cost(current_sol);
    Cost reverse_cost = this->cost(reverse_current_sol);

    // Local search on asymmetric problem.
    tsp::LocalSearch
      asym_ls(_matrix,
              std::make_pair(!_round_trip and _has_start and _has_end, _start),
              (direct_cost <= reverse_cost) ? current_sol : reverse_current_sol,
              nb_threads);

    Cost asym_two_opt_gain = 0;
    Cost asym_relocate_gain = 0;
    Cost asym_or_opt_gain = 0;
    Cost asym_avoid_loops_gain = 0;

    do {
      // All avoid-loops moves.
      asym_avoid_loops_gain = asym_ls.perform_all_avoid_loop_steps(deadline);

      // All possible 2-opt moves.
      asym_two_opt_gain = asym_ls.perform_all_asym_two_opt_steps(deadline);

      // All relocate moves.
      asym_relocate_gain = asym_ls.perform_all_relocate_steps(deadline);

      // All or-opt moves.
      asym_or_opt_gain = asym_ls.perform_all_or_opt_steps(deadline);
    } while ((asym_two_opt_gain > 0) or (asym_relocate_gain > 0) or
             (asym_or_opt_gain > 0) or (asym_avoid_loops_gain > 0));

    current_sol = asym_ls.get_tour(first_loc_index);
  }

  // Deal with open tour cases requiring adaptation.
  if (!_has_start and _has_end) {
    // The tour has been listed starting with the "forced" end. This
    // index has to be popped and put back, the next element being the
    // chosen start resulting from the optimization.
    current_sol.push_back(current_sol.front());
    current_sol.pop_front();
  }

  // Handle start and end removal as output list should only contain
  // jobs.
  if (_has_start) {
    // Jobs start further away in the list.
    current_sol.pop_front();
  }
  if (!_round_trip and _has_end) {
    current_sol.pop_back();
  }

  // Back to ranks in input::_jobs.
  std::vector<Index> init_ranks_sol;
  std::transform(current_sol.cbegin(),
                 current_sol.cend(),
                 std::back_inserter(init_ranks_sol),
                 [&](const auto& i) { return _job_ranks[i]; });

  return init_ranks_sol;
}

Solution TSP::solve(unsigned,
                    unsigned nb_threads,
                    const Timeout& timeout,
                    const std::vector<HeuristicParameters>&) const {
  RawRoute r(_input, 0, 0);
  r.set_route(_input, raw_solve(nb_threads, timeout));
  return utils::format_solution(_input, {r});
}

} // namespace vroom
<commit_msg>Apply formatting<commit_after>/*

This file is part of VROOM.

Copyright (c) 2015-2022, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include "problems/tsp/tsp.h"
#include "problems/tsp/heuristics/christofides.h"
#include "problems/tsp/heuristics/local_search.h"
#include "utils/helpers.h"

namespace {

vroom::Cost compute_cost(const std::list<vroom::Index>& tour,
                         const vroom::Matrix<vroom::Cost>& matrix) {
  vroom::Cost cost = 0;
  vroom::Index init_step = 0; // Initialization actually never used.

  auto step = tour.cbegin();
  if (tour.size() > 0) {
    init_step = *step;
  }

  vroom::Index previous_step = init_step;
  ++step;
  for (; step != tour.cend(); ++step) {
    cost += matrix[previous_step][*step];
    previous_step = *step;
  }
  if (tour.size() > 0) {
    cost += matrix[previous_step][init_step];
  }
  return cost;
}

} // namespace

namespace vroom {

TSP::TSP(const Input& input, std::vector<Index> job_ranks, Index vehicle_rank)
  : VRP(input),
    _vehicle_rank(vehicle_rank),
    _job_ranks(std::move(job_ranks)),
    _is_symmetric(true),
    _has_start(_input.vehicles[_vehicle_rank].has_start()),
    _has_end(_input.vehicles[_vehicle_rank].has_end()) {

  assert(!_job_ranks.empty());

  // Pick ranks to select from input matrix.
  std::vector<Index> matrix_ranks;
  std::transform(_job_ranks.cbegin(),
                 _job_ranks.cend(),
                 std::back_inserter(matrix_ranks),
                 [&](const auto& r) { return _input.jobs[r].index(); });

  if (_has_start) {
    // Add start and remember rank in _matrix.
    _start = matrix_ranks.size();
    matrix_ranks.push_back(
      _input.vehicles[_vehicle_rank].start.value().index());
  }
  if (_has_end) {
    // Add end and remember rank in _matrix.
    if (_has_start and (_input.vehicles[_vehicle_rank].start.value().index() ==
                        _input.vehicles[_vehicle_rank].end.value().index())) {
      // Avoiding duplicate for identical ranks.
      _end = _start;
    } else {
      _end = matrix_ranks.size();
      matrix_ranks.push_back(
        _input.vehicles[_vehicle_rank].end.value().index());
    }
  }

  // Populate TSP-solving matrix.
  _matrix = Matrix<Cost>(matrix_ranks.size());

  const auto& v = _input.vehicles[vehicle_rank];
  for (Index i = 0; i < matrix_ranks.size(); ++i) {
    for (Index j = 0; j < matrix_ranks.size(); ++j) {
      _matrix[i][j] = v.cost(matrix_ranks[i], matrix_ranks[j]);
    }
  }

  // Distances on the diagonal are never used except in the minimum
  // weight perfect matching (munkres call during the heuristic). This
  // makes sure no node will be matched with itself at that time.
  for (Index i = 0; i < _matrix.size(); ++i) {
    _matrix[i][i] = INFINITE_COST;
  }

  _round_trip = _has_start and _has_end and (_start == _end);

  if (!_round_trip) {
    // Dealing with open tour cases. Exactly one of the following
    // happens.
    if (_has_start and !_has_end) {
      // Forcing first location as start, end location decided during
      // optimization.
      for (Index i = 0; i < _matrix.size(); ++i) {
        if (i != _start) {
          _matrix[i][_start] = 0;
        }
      }
    }
    if (!_has_start and _has_end) {
      // Forcing last location as end, start location decided during
      // optimization.
      for (Index j = 0; j < _matrix.size(); ++j) {
        if (j != _end) {
          _matrix[_end][j] = 0;
        }
      }
    }
    if (_has_start and _has_end) {
      // Forcing first location as start, last location as end to
      // produce an open tour.
      assert(_start != _end);
      _matrix[_end][_start] = 0;
      for (Index j = 0; j < _matrix.size(); ++j) {
        if ((j != _start) and (j != _end)) {
          _matrix[_end][j] = INFINITE_COST;
        }
      }
    }
  }

  // Compute symmetrized matrix and update _is_symmetric flag.
  _symmetrized_matrix = Matrix<Cost>(_matrix.size());

  const Cost& (*sym_f)(const Cost&, const Cost&) = std::min<Cost>;
  if ((_has_start and !_has_end) or (!_has_start and _has_end)) {
    // Using symmetrization with max as when only start or only end is
    // forced, the matrix has a line or a column filled with zeros.
    sym_f = std::max<Cost>;
  }
  for (Index i = 0; i < _matrix.size(); ++i) {
    _symmetrized_matrix[i][i] = _matrix[i][i];
    for (Index j = i + 1; j < _matrix.size(); ++j) {
      _is_symmetric = _is_symmetric && (_matrix[i][j] == _matrix[j][i]);
      Cost val = sym_f(_matrix[i][j], _matrix[j][i]);
      _symmetrized_matrix[i][j] = val;
      _symmetrized_matrix[j][i] = val;
    }
  }
}

Cost TSP::cost(const std::list<Index>& tour) const {
  return compute_cost(tour, _matrix);
}

Cost TSP::symmetrized_cost(const std::list<Index>& tour) const {
  return compute_cost(tour, _symmetrized_matrix);
}

std::vector<Index> TSP::raw_solve(unsigned nb_threads,
                                  const Timeout& timeout) const {
  // Compute deadline including heuristic computing time.
  const Deadline deadline =
    timeout.has_value() ? utils::now() + timeout.value() : Deadline();

  // Applying heuristic.
  std::list<Index> christo_sol = tsp::christofides(_symmetrized_matrix);

  Deadline sym_deadline = deadline;
  if (deadline.has_value() and !_is_symmetric) {
    // Rule of thumb if problem is asymmetric: dedicate 70% of the
    // remaining available solving time to the symmetric local search,
    // then the rest to the asymmetric version.
    const auto after_heuristic = utils::now();
    const auto remaining_ms =
      (after_heuristic < deadline.value())
        ? std::chrono::duration_cast<std::chrono::milliseconds>(
            deadline.value() - after_heuristic)
            .count()
        : 0;
    sym_deadline =
      after_heuristic +
      std::chrono::milliseconds(static_cast<unsigned>(0.7 * remaining_ms));
  }

  // Local search on symmetric problem.
  // Applying deterministic, fast local search to improve the current
  // solution in a small amount of time. All possible moves for the
  // different neighbourhoods are performed, stopping when reaching a
  // local minima.
  tsp::LocalSearch sym_ls(_symmetrized_matrix,
                          std::make_pair(!_round_trip and _has_start and
                                           _has_end,
                                         _start),
                          christo_sol,
                          nb_threads);

  Cost sym_two_opt_gain = 0;
  Cost sym_relocate_gain = 0;
  Cost sym_or_opt_gain = 0;

  do {
    // All possible 2-opt moves.
    sym_two_opt_gain = sym_ls.perform_all_two_opt_steps(sym_deadline);

    // All relocate moves.
    sym_relocate_gain = sym_ls.perform_all_relocate_steps(sym_deadline);

    // All or-opt moves.
    sym_or_opt_gain = sym_ls.perform_all_or_opt_steps(sym_deadline);
  } while ((sym_two_opt_gain > 0) or (sym_relocate_gain > 0) or
           (sym_or_opt_gain > 0));

  Index first_loc_index;
  if (_has_start) {
    // Use start value set in constructor from vehicle input.
    first_loc_index = _start;
  } else {
    assert(_has_end);
    // Requiring the tour to be described from the "forced" end
    // location.
    first_loc_index = _end;
  }

  std::list<Index> current_sol = sym_ls.get_tour(first_loc_index);

  if (!_is_symmetric) {
    // Back to the asymmetric problem, picking the best way.
    std::list<Index> reverse_current_sol(current_sol);
    reverse_current_sol.reverse();
    Cost direct_cost = this->cost(current_sol);
    Cost reverse_cost = this->cost(reverse_current_sol);

    // Local search on asymmetric problem.
    tsp::LocalSearch
      asym_ls(_matrix,
              std::make_pair(!_round_trip and _has_start and _has_end, _start),
              (direct_cost <= reverse_cost) ? current_sol : reverse_current_sol,
              nb_threads);

    Cost asym_two_opt_gain = 0;
    Cost asym_relocate_gain = 0;
    Cost asym_or_opt_gain = 0;
    Cost asym_avoid_loops_gain = 0;

    do {
      // All avoid-loops moves.
      asym_avoid_loops_gain = asym_ls.perform_all_avoid_loop_steps(deadline);

      // All possible 2-opt moves.
      asym_two_opt_gain = asym_ls.perform_all_asym_two_opt_steps(deadline);

      // All relocate moves.
      asym_relocate_gain = asym_ls.perform_all_relocate_steps(deadline);

      // All or-opt moves.
      asym_or_opt_gain = asym_ls.perform_all_or_opt_steps(deadline);
    } while ((asym_two_opt_gain > 0) or (asym_relocate_gain > 0) or
             (asym_or_opt_gain > 0) or (asym_avoid_loops_gain > 0));

    current_sol = asym_ls.get_tour(first_loc_index);
  }

  // Deal with open tour cases requiring adaptation.
  if (!_has_start and _has_end) {
    // The tour has been listed starting with the "forced" end. This
    // index has to be popped and put back, the next element being the
    // chosen start resulting from the optimization.
    current_sol.push_back(current_sol.front());
    current_sol.pop_front();
  }

  // Handle start and end removal as output list should only contain
  // jobs.
  if (_has_start) {
    // Jobs start further away in the list.
    current_sol.pop_front();
  }
  if (!_round_trip and _has_end) {
    current_sol.pop_back();
  }

  // Back to ranks in input::_jobs.
  std::vector<Index> init_ranks_sol;
  std::transform(current_sol.cbegin(),
                 current_sol.cend(),
                 std::back_inserter(init_ranks_sol),
                 [&](const auto& i) { return _job_ranks[i]; });

  return init_ranks_sol;
}

Solution TSP::solve(unsigned,
                    unsigned nb_threads,
                    const Timeout& timeout,
                    const std::vector<HeuristicParameters>&) const {
  RawRoute r(_input, 0, 0);
  r.set_route(_input, raw_solve(nb_threads, timeout));
  return utils::format_solution(_input, {r});
}

} // namespace vroom
<|endoftext|>


<commit_before>#ifndef ENGINE_API_NEAREST_PARAMETERS_HPP
#define ENGINE_API_NEAREST_PARAMETERS_HPP

#include "engine/api/base_parameters.hpp"

namespace osrm
{
namespace engine
{
namespace api
{

struct NearestParameters : public BaseParameters
{
    unsigned number_of_results;

    bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; }
};
}
}
}

#endif // ENGINE_API_NEAREST_PARAMETERS_HPP
<commit_msg>Initialize NearestParameters correctly<commit_after>#ifndef ENGINE_API_NEAREST_PARAMETERS_HPP
#define ENGINE_API_NEAREST_PARAMETERS_HPP

#include "engine/api/base_parameters.hpp"

namespace osrm
{
namespace engine
{
namespace api
{

struct NearestParameters : public BaseParameters
{
    unsigned number_of_results = 1;

    bool IsValid() const { return BaseParameters::IsValid() && number_of_results >= 1; }
};
}
}
}

#endif // ENGINE_API_NEAREST_PARAMETERS_HPP
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP
#define MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP

// mapnik
#include <mapnik/text/placements/base.hpp>

namespace mapnik {

class text_placement_info_simple;
class feature_impl;
struct attribute;

// Automatically generates placement options from a user selected list of directions and text sizes.
class MAPNIK_DECL text_placements_simple: public text_placements
{
public:
    text_placements_simple(symbolizer_base::value_type const& positions);
    text_placements_simple(symbolizer_base::value_type const& positions,
                           std::vector<directions_e> && direction,
                           std::vector<int> && text_sizes);
    text_placement_info_ptr get_placement_info(double _scale_factor, feature_impl const& feature, attributes const& vars) const;
    std::string get_positions() const;
    static text_placements_ptr from_xml(xml_node const& xml, fontset_map const& fontsets, bool is_shield);
    void init_positions(std::string const& positions) const;
    std::vector<directions_e> direction_;
    std::vector<int> text_sizes_;
private:
    symbolizer_base::value_type positions_;
    friend class text_placement_info_simple;
};

// Simple placement strategy.
// See parent class for documentation of each function.
class MAPNIK_DECL text_placement_info_simple : public text_placement_info
{
public:
    text_placement_info_simple(text_placements_simple const* parent,
                               std::string const& evaluated_positions,
                               double _scale_factor);
    bool next() const;
protected:
    bool next_position_only() const;
    mutable unsigned state;
    mutable unsigned position_state;
    mutable std::vector<directions_e> direction_;
    mutable std::vector<int> text_sizes_;
    text_placements_simple const* parent_;
};

} //namespace

#endif // MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP
<commit_msg>Remove method declaration that is not implemented<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP
#define MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP

// mapnik
#include <mapnik/text/placements/base.hpp>

namespace mapnik {

class text_placement_info_simple;
class feature_impl;
struct attribute;

// Automatically generates placement options from a user selected list of directions and text sizes.
class MAPNIK_DECL text_placements_simple: public text_placements
{
public:
    text_placements_simple(symbolizer_base::value_type const& positions);
    text_placements_simple(symbolizer_base::value_type const& positions,
                           std::vector<directions_e> && direction,
                           std::vector<int> && text_sizes);
    text_placement_info_ptr get_placement_info(double _scale_factor, feature_impl const& feature, attributes const& vars) const;
    std::string get_positions() const;
    static text_placements_ptr from_xml(xml_node const& xml, fontset_map const& fontsets, bool is_shield);
    std::vector<directions_e> direction_;
    std::vector<int> text_sizes_;
private:
    symbolizer_base::value_type positions_;
    friend class text_placement_info_simple;
};

// Simple placement strategy.
// See parent class for documentation of each function.
class MAPNIK_DECL text_placement_info_simple : public text_placement_info
{
public:
    text_placement_info_simple(text_placements_simple const* parent,
                               std::string const& evaluated_positions,
                               double _scale_factor);
    bool next() const;
protected:
    bool next_position_only() const;
    mutable unsigned state;
    mutable unsigned position_state;
    mutable std::vector<directions_e> direction_;
    mutable std::vector<int> text_sizes_;
    text_placements_simple const* parent_;
};

} //namespace

#endif // MAPNIK_TEXT_PLACEMENTS_SIMPLE_HPP
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_DATA_MANAGER_HPP
#define RJ_SHARED_DATA_MANAGER_HPP

#include <mlk/filesystem/filesystem.h>
#include <mlk/log/log.h>
#include <mlk/tools/compiletime.h>
#include <mlk/tools/stl_string_utl.h>
#include <mlk/types/types.h>

#include <map>

namespace rj
{
	using data_id = std::string;
	using data_vec = std::vector<mlk::data_packet>;

	class data_manager
	{
		mlk::fs::dir_handle m_dirh;
		mlk::fs::file_handle m_fileh;
		const std::string& m_abs_path;

		std::map<data_id, mlk::data_packet> m_data;

		bool m_valid{false};

	public:
		data_manager(const std::string& abs_datapath, bool auto_load = false) :
			m_dirh{abs_datapath},
			m_abs_path{m_dirh.get_path()},
			m_valid{m_dirh.exists()}
		{
			if(auto_load) this->load_all();
		}

		// interface
		// get:		don't loads the data to manager
		//			just 'gets' it
		auto get_all() const noexcept
		-> const decltype(m_data)&
		{return m_data;}

		mlk::data_packet get_raw(const data_id& id)
		{
			if(!this->exists_id(id))
				return {};
			return m_data[id];
		}

		data_vec get_all_containing_raw(const std::string& contain)
		{
			data_vec result;
			for(auto& a : m_data)
				if(mlk::stl_string::contains(contain, a.first))
					result.emplace_back(this->get_raw(a.first));
			return result;
		}

		template<typename T>
		T get_as(const data_id& id)
		{return this->get_as_impl<T>(id);}

		template<typename... Types, typename... Ids>
		std::tuple<Types...> get_multiple_as(Ids&&... ids)
		{
			static_assert(sizeof...(Types) == sizeof...(Ids), "Amount of types must match the amount of passed ids.");

			std::tuple<Types...> result;
			this->get_multiple_as_impl<mlk::get_upper(-1)>(result, std::forward<Ids>(ids)...);
			return result;
		}

		template<typename Type>
		std::vector<Type> get_all_containing_as(const std::string& contain)
		{
			std::vector<Type> result;
			for(auto& a : m_data)
				if(mlk::stl_string::contains(contain, a.first))
					result.emplace_back(this->get_as_impl<Type>(a.first));
			return result;
		}

		// load:	gets AND loads the data to manager
		mlk::data_packet load_raw(const data_id& id)
		{
			this->load_raw_impl(id, this->make_path(id));
			return m_data[id];
		}

		template<typename T>
		T load_as(const data_id& id)
		{return this->load_as_impl<T>(id);}

		template<typename... Types, typename... Ids>
		std::tuple<Types...> load_multiple_as(Ids&&... ids)
		{
			static_assert(sizeof...(Types) == sizeof...(Ids), "Amount of types must match the amount of passed ids.");

			std::tuple<Types...> result;
			this->load_multiple_as_impl<mlk::get_upper(-1)>(result, std::forward<Ids>(ids)...);
			return result;
		}

		bool exists_id(const data_id& id) const noexcept
		{return m_data.find(id) != std::end(m_data);}

		std::size_t num_data() const noexcept
		{return m_data.size();}

	private:
		// utils
		std::string make_path(const data_id& id)
		{return m_abs_path + id;}

		std::size_t get_datasize() const noexcept
		{
			std::size_t result{0};
			for(auto& a : m_data) result += a.second.size();
			return result;
		}

		// loads all data recursive
		// from absolute directory
		void load_all()
		{
			mlk::lout("rj::data_manager") << "loading files recursive from directory '" << m_abs_path << "'...";
			auto content(m_dirh.get_content<true>());
			auto count(0);
			for(auto& a : content)
				if(a.type == mlk::fs::item_type::file)
				{
					this->load_raw_impl(a.name, a.path);
					++count;
				}
			mlk::lout("rj::data_manager") << "loaded " << count << " files (" << this->get_datasize() << " bytes)";
		}

		// tuple impls
		template<int tup_index, typename Id_Head, typename... Types, typename... Id_Tail>
		void get_multiple_as_impl(std::tuple<Types...>& tup, const Id_Head& head, Id_Tail&&... tail)
		{
			std::get<tup_index>(tup) = this->get_as_impl<typename std::tuple_element<tup_index, std::tuple<Types...>>::type>(head);
			this->get_multiple_as_impl<mlk::get_upper(tup_index)>(tup, std::forward<Id_Tail>(tail)...);
		}

		template<int tup_index, typename... Types>
		void get_multiple_as_impl(std::tuple<Types...> &tup)
		{/* case: no args; do nothing */}

		template<int tup_index, typename Id_Head, typename... Types, typename... Id_Tail>
		void load_multiple_as_impl(std::tuple<Types...>& tup, const Id_Head& head, Id_Tail&&... tail)
		{
			std::get<tup_index>(tup) = this->load_as_impl<typename std::tuple_element<tup_index, std::tuple<Types...>>::type>(head);
			this->load_multiple_as_impl<mlk::get_upper(tup_index)>(tup, std::forward<Id_Tail>(tail)...);
		}

		template<int tup_index, typename... Types>
		void load_multiple_as_impl(std::tuple<Types...>& tup)
		{/* case: no args; do nothing */}

		// lowest level impls
		void load_raw_impl(const data_id& id, const std::string& path)
		{
			if(this->exists_id(id))
			{
				mlk::lerr()["rj::data_manager"] << "object with id '" << id << "' already loaded";
				return;
			}
			m_fileh.reopen(path, std::ios::in);
			m_data[id] = m_fileh.read_all();
			mlk::lout("rj::data_manager") << "loaded data '" << path << "'";
		}

		template<typename T>
		T load_as_impl(const data_id& id)
		{
			this->load_raw_impl(id, this->make_path(id));
			return this->get_as_impl<T>(id);
		}

		template<typename T>
		T get_as_impl(const data_id& id)
		{
			if(!this->exists_id(id))
			{
				mlk::lerr()["rj::data_manager"] << "object with id '" << id << "' not found";
				return T{};
			}
			T result;
			result.loadFromMemory(m_data[id].data(), m_data[id].size());
			return result;
		}
	};
}

#endif // RJ_SHARED_DATA_MANAGER_HPP
<commit_msg>data_manager: added get_all_containing_as_map_as<T>(...)<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_DATA_MANAGER_HPP
#define RJ_SHARED_DATA_MANAGER_HPP

#include <mlk/filesystem/filesystem.h>
#include <mlk/log/log.h>
#include <mlk/tools/compiletime.h>
#include <mlk/tools/stl_string_utl.h>
#include <mlk/types/types.h>

#include <map>

namespace rj
{
	using data_id = std::string;
	using data_vec = std::vector<mlk::data_packet>;

	class data_manager
	{
		mlk::fs::dir_handle m_dirh;
		mlk::fs::file_handle m_fileh;
		const std::string& m_abs_path;

		std::map<data_id, mlk::data_packet> m_data;

		bool m_valid{false};

	public:
		data_manager(const std::string& abs_datapath, bool auto_load = false) :
			m_dirh{abs_datapath},
			m_abs_path{m_dirh.get_path()},
			m_valid{m_dirh.exists()}
		{
			if(auto_load) this->load_all();
		}

		// interface
		// get:		don't loads the data to manager
		//			just 'gets' it
		auto get_all() const noexcept
		-> const decltype(m_data)&
		{return m_data;}

		mlk::data_packet get_raw(const data_id& id)
		{
			if(!this->exists_id(id))
				return {};
			return m_data[id];
		}

		data_vec get_all_containing_raw(const std::string& contain)
		{
			data_vec result;
			for(auto& a : m_data)
				if(mlk::stl_string::contains(contain, a.first))
					result.emplace_back(this->get_raw(a.first));
			return result;
		}

		template<typename T>
		T get_as(const data_id& id)
		{return this->get_as_impl<T>(id);}

		template<typename... Types, typename... Ids>
		std::tuple<Types...> get_multiple_as(Ids&&... ids)
		{
			static_assert(sizeof...(Types) == sizeof...(Ids), "Amount of types must match the amount of passed ids.");

			std::tuple<Types...> result;
			this->get_multiple_as_impl<mlk::get_upper(-1)>(result, std::forward<Ids>(ids)...);
			return result;
		}

		template<typename Type>
		std::vector<Type> get_all_containing_as(const std::string& contain)
		{
			std::vector<Type> result;
			for(auto& a : m_data)
				if(mlk::stl_string::contains(contain, a.first))
					result.emplace_back(this->get_as_impl<Type>(a.first));
			return result;
		}

		template<typename Type>
		std::map<data_id, Type> get_all_containing_as_map_as(const std::string& contain)
		{
			std::map<data_id, Type> result;
			for(auto& a : m_data)
				if(mlk::stl_string::contains(contain, a.first))
					result.emplace(a.first, this->get_as_impl<Type>(a.first));
			return result;

		}

		// load:	gets AND loads the data to manager
		mlk::data_packet load_raw(const data_id& id)
		{
			this->load_raw_impl(id, this->make_path(id));
			return m_data[id];
		}

		template<typename T>
		T load_as(const data_id& id)
		{return this->load_as_impl<T>(id);}

		template<typename... Types, typename... Ids>
		std::tuple<Types...> load_multiple_as(Ids&&... ids)
		{
			static_assert(sizeof...(Types) == sizeof...(Ids), "Amount of types must match the amount of passed ids.");

			std::tuple<Types...> result;
			this->load_multiple_as_impl<mlk::get_upper(-1)>(result, std::forward<Ids>(ids)...);
			return result;
		}

		bool exists_id(const data_id& id) const noexcept
		{return m_data.find(id) != std::end(m_data);}

		std::size_t num_data() const noexcept
		{return m_data.size();}

	private:
		// utils
		std::string make_path(const data_id& id)
		{return m_abs_path + id;}

		std::size_t get_datasize() const noexcept
		{
			std::size_t result{0};
			for(auto& a : m_data) result += a.second.size();
			return result;
		}

		// loads all data recursive
		// from absolute directory
		void load_all()
		{
			mlk::lout("rj::data_manager") << "loading files recursive from directory '" << m_abs_path << "'...";
			auto content(m_dirh.get_content<true>());
			auto count(0);
			for(auto& a : content)
				if(a.type == mlk::fs::item_type::file)
				{
					this->load_raw_impl(a.name, a.path);
					++count;
				}
			mlk::lout("rj::data_manager") << "loaded " << count << " files (" << this->get_datasize() << " bytes)";
		}

		// tuple impls
		template<int tup_index, typename Id_Head, typename... Types, typename... Id_Tail>
		void get_multiple_as_impl(std::tuple<Types...>& tup, const Id_Head& head, Id_Tail&&... tail)
		{
			std::get<tup_index>(tup) = this->get_as_impl<typename std::tuple_element<tup_index, std::tuple<Types...>>::type>(head);
			this->get_multiple_as_impl<mlk::get_upper(tup_index)>(tup, std::forward<Id_Tail>(tail)...);
		}

		template<int tup_index, typename... Types>
		void get_multiple_as_impl(std::tuple<Types...> &tup)
		{/* case: no args; do nothing */}

		template<int tup_index, typename Id_Head, typename... Types, typename... Id_Tail>
		void load_multiple_as_impl(std::tuple<Types...>& tup, const Id_Head& head, Id_Tail&&... tail)
		{
			std::get<tup_index>(tup) = this->load_as_impl<typename std::tuple_element<tup_index, std::tuple<Types...>>::type>(head);
			this->load_multiple_as_impl<mlk::get_upper(tup_index)>(tup, std::forward<Id_Tail>(tail)...);
		}

		template<int tup_index, typename... Types>
		void load_multiple_as_impl(std::tuple<Types...>& tup)
		{/* case: no args; do nothing */}

		// lowest level impls
		void load_raw_impl(const data_id& id, const std::string& path)
		{
			if(this->exists_id(id))
			{
				mlk::lerr()["rj::data_manager"] << "object with id '" << id << "' already loaded";
				return;
			}
			m_fileh.reopen(path, std::ios::in);
			m_data[id] = m_fileh.read_all();
			mlk::lout("rj::data_manager") << "loaded data '" << path << "'";
		}

		template<typename T>
		T load_as_impl(const data_id& id)
		{
			this->load_raw_impl(id, this->make_path(id));
			return this->get_as_impl<T>(id);
		}

		template<typename T>
		T get_as_impl(const data_id& id)
		{
			if(!this->exists_id(id))
			{
				mlk::lerr()["rj::data_manager"] << "object with id '" << id << "' not found";
				return T{};
			}
			T result;
			result.loadFromMemory(m_data[id].data(), m_data[id].size());
			return result;
		}
	};
}

#endif // RJ_SHARED_DATA_MANAGER_HPP
<|endoftext|>


<commit_before>#ifndef RFR_REGRESSION_FOREST_HPP
#define RFR_REGRESSION_FOREST_HPP

#include <iostream>
#include <sstream>
#include <vector>
#include <utility>
#include <cmath>
#include <numeric>
#include <random>
#include <algorithm>
#include <functional>  // std::bind

#include "cereal/cereal.hpp"
#include <cereal/types/vector.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <iostream>
#include <sstream>

#include "rfr/trees/tree_options.hpp"
#include "rfr/forests/forest_options.hpp"
#include "rfr/util.hpp"

namespace rfr{ namespace forests{

typedef cereal::PortableBinaryInputArchive iarch_type;
typedef cereal::PortableBinaryOutputArchive oarch_type;

template <typename tree_type, typename rng_type, typename num_type = float, typename response_type = float, typename index_type = unsigned int>
class regression_forest{
  private:
	forest_options<num_type, response_type, index_type> forest_opts;
	std::vector<tree_type> the_trees;
	index_type num_features;

	std::vector<std::vector<index_type> > dirty_leafs;

  public:

  	/* serialize function for saving forests */
  	template<class Archive>
	void serialize(Archive & archive)
	{
		archive( forest_opts, the_trees);
	}

	regression_forest(){}

	regression_forest(forest_options<num_type, response_type, index_type> forest_opts): forest_opts(forest_opts), the_trees(forest_opts.num_trees){}

	/* \brief growing the random forest for a given data set
	 *
	 * \param data a filled data container
	 * \param rng the random number generator to be used
	 */
	void fit(const rfr::data_containers::data_container_base<num_type, response_type, index_type> &data, rng_type &rng){

		if ((!forest_opts.do_bootstrapping) && (data.num_data_points() < forest_opts.num_data_points_per_tree)){
			std::cout<<"You cannot use more data points per tree than actual data point present without bootstrapping!";
			return;
		}

		std::vector<index_type> data_indices( data.num_data_points());
		std::iota(data_indices.begin(), data_indices.end(), 0);
		std::vector<index_type> data_indices_to_be_used( forest_opts.num_data_points_per_tree);

		num_features = data.num_features();

		// catch some stupid things that will make the forest crash when fitting
		if (forest_opts.num_data_points_per_tree == 0)
			throw std::runtime_error("The number of data points per tree is set to zero!");

		if (forest_opts.tree_opts.max_features == 0)
			throw std::runtime_error("The number of features used for a split is set to zero!");

		for (auto &tree : the_trees){
			// prepare the data(sub)set
			if (forest_opts.do_bootstrapping){
				std::uniform_int_distribution<index_type> dist (0,data.num_data_points()-1);
				auto dice = std::bind(dist, rng);
				std::generate_n(data_indices_to_be_used.begin(), data_indices_to_be_used.size(), dice);
			}
			else{
				std::shuffle(data_indices.begin(), data_indices.end(), rng);
				data_indices_to_be_used.assign(data_indices.begin(), data_indices.begin()+ forest_opts.num_data_points_per_tree);
			}
			tree.fit(data, forest_opts.tree_opts, data_indices_to_be_used, rng);
		}
	}

	/* \brief combines the prediction of all trees in the forest
	 *
	 * Every random tree makes an individual prediction. From that, the mean and the standard
	 * deviation of those predictions is calculated. (See Frank's PhD thesis section 11.?)
	 *
	 * \param feature_vector a valid (size and values) array containing features
	 *
	 * \return std::pair<num_type, num_type> mean and total variance (= mean of variances + variance of means )
	 */
	std::pair<num_type, num_type> predict_mean_var( num_type * feature_vector){

		// collect the predictions of individual trees
		rfr::running_statistics<num_type> mean_stats, var_stats;
		for (auto &tree: the_trees){
			num_type m , v;	index_type n;

			std::tie(m, v, n) = tree.predict_mean_var_N(feature_vector);

			mean_stats(m);
			var_stats(v);
		}

		return(std::pair<num_type, num_type> (mean_stats.mean(), std::max<num_type>(0, mean_stats.variance() + var_stats.mean()) ));
	}

	/* \brief combines the prediction of all trees in the forest
	 *
	 * Every random tree makes an individual prediction. From that, the mean and the standard
	 * deviation of those predictions is calculated. (See Frank's PhD thesis section 11.?)
	 *
	 * \param feature_vector a valid (size and values) array containing features
	 *
	 * \return std::pair<num_type, num_type> mean and sqrt(total variance = mean of variances + variance of means )
	 */
	std::pair<num_type, num_type> predict_mean_std( num_type * feature_vector){
		auto p = predict_mean_var(feature_vector);
		p.second = sqrt(p.second);
		return(p);
	}

	/* \brief predict the mean and the variance deviation for a configuration marginalized over a given set of partial configurations
	 *
	 * This function will be mostly used to predict the mean over a given set of instances, but could be used to marginalize over any discrete set of partial configurations.
	 *
	 * \param features a (partial) configuration where unset values should be set to NaN
	 * \param set_features a array containing the (partial) assignments used for the averaging. Every NaN value will be replaced by the corresponding value from features.
	 * \param set_size number of feature vectors in set_features
	 *
	 * \return std::pair<num_type, num_type> mean and variance prediction of a feature vector averaged over
	 */
	std::pair<num_type, num_type> predict_mean_var_marginalized_over_set (num_type *features, num_type* set_features, index_type set_size){

		num_type fv[num_features];

		// collect the predictions of individual trees
		rfr::running_statistics<num_type> mean_stats, var_stats;
		for (auto i=0u; i < set_size; ++i){
			// construct the actual feature vector
			rfr::merge_two_vectors(features, &set_features[i*num_features], fv, num_features);

			num_type m , v; index_type n;
			std::tie(m, v, n) = predict_mean_var(fv);

			mean_stats(m);
			var_stats(v);
		}
		return(std::pair<num_type, num_type> (mean_stats.mean(), std::max<num_type>(0, mean_stats.variance() + var_stats.mean()) ));
	}

	/* \brief predict the mean and the variance of the mean prediction across a set of partial features
	 *
	 * A very special function to predict the mean response of a a partial assignment for a given set.
	 * It takes the prediction of set-mean of every individual tree and combines to estimate the mean its
	 * total variance. The predictions of two trees are considered uncorrelated
	 *
	 * \param features a (partial) configuration where unset values should be set to NaN
	 * \param set_features a 1d-array containing the (partial) assignments used for the averaging. Every NaN value will be replaced by the corresponding value from features. The array must hold set_size times the number of features entries! There is no consistency check!
	 * \param set_size number of feature vectors in set_features
	 *
	 * \return std::pair<num_type, num_type> mean and variance prediction of a feature vector averaged over
	 */
	std::pair<num_type, num_type> predict_mean_var_of_mean_response_on_set (num_type *features, num_type* set_features, index_type set_size){

		num_type fv[num_features];

		rfr::running_statistics<num_type> mean_stats, var_stats;

		for (auto &t : the_trees){

			rfr::running_statistics<num_type> tree_mean_stats, tree_var_stats;

			for (auto i=0u; i < set_size; ++i){

				rfr::merge_two_vectors(features, &set_features[i*num_features], fv, num_features);

				num_type m , v;	index_type n;
				std::tie(m, v, n) = t.predict_mean_var_N(fv);

				tree_mean_stats(m); tree_var_stats(v);
			}

			mean_stats(tree_mean_stats.mean());
			var_stats(std::max<num_type>(0,tree_mean_stats.variance() + tree_var_stats.mean()));
		}
		return(std::pair<num_type, num_type> (mean_stats.mean(), std::max<num_type>(0, mean_stats.variance() + var_stats.mean()) ));
	}

	/* \brief estimates the covariance of two feature vectors
	 *
	 * The covariance between to input vectors contains information about the
	 * feature space. For other models, like GPs, this is a natural quantity
	 * (e.g., property of the kernel). Here, we try to estimate it using the
	 * total covariance of the individual tree's prediction and the assumption
	 * that cov(X,Y) = 0, if X and Y fall into different leafs, and cov(X,Y) = var(X) = var(Y)
	 * otherwise.
	 *
	 * \param f1 a valid feature vector (no sanity checks are performed!)
	 * \param f2 a second feature vector (no sanity checks are performed!)
	 */
	num_type covariance (num_type* f1, num_type* f2){
		rfr::running_statistics<double> cov_stats;
		rfr::running_covariance<double> run_cov;
		/*
		for (auto &t: the_trees){
			auto l1 = t.find_leaf(f1);
			auto l2 = t.find_leaf(f2);

			num_type m , v;	index_type n;

			std::tie(m, v, n) = t.predict_mean_var_N(f1);
			sum_mean1 += m;
			means1.push_back(m);

			std::tie(m, v, n) = t.predict_mean_var_N(f2);
			sum_mean2 += m;
			means2.push_back(m);

			// assumption here: cov = 0 if the leafs are different, and cov = var if both feature vectors fall into the same leaf
			if (l1 == l2)
				cov_stats(v);
			else
				cov_stats(0);
		}

		num_type N = num_type (the_trees.size());
		num_type mean_covs = sum_cov/N;
		num_type m1 = sum_mean1/N, m2 = sum_mean2/N;

		num_type cov_means = 0;

		for (auto i=0u; i < the_trees.size(); ++i)
			cov_means += (means1-m1)*(means2-m2);

		cov_means /= N;

		return(mean_covs + cov_means);
		* */
	}

	std::vector< std::vector<num_type> > all_leaf_values (num_type * feature_vector){
		std::vector< std::vector<num_type> > rv;
		rv.reserve(the_trees.size());

		for (auto &t: the_trees){
			rv.push_back(t.leaf_entries(feature_vector));
		}
		return(rv);
	}

	forest_options<num_type, response_type, index_type> get_forest_options(){return(forest_opts);}

	/* \brief updates the forest by adding all provided datapoints without a complete retraining
	 *
	 * As retraining can be quite expensive, this function can be used to quickly update the forest
	 * by finding the leafs the datapoints belong into and just inserting them. This is, of course,
	 * not the right way to do it for many data points, but it should be a good approximation for a few.
	 *
	 * \param data a data container instance that will be inserted into the tree
	 */
	void pseudo_update (const rfr::data_containers::data_container_base<num_type, response_type, index_type> &data){

		for (auto i=0u; data.num_data_points(); ++i){

			auto p = data.retrieve_data_point(i);
			dirty_leafs.emplace_back(std::vector<index_type> (0, the_trees.size()));
			auto it = (dirty_leafs.back()).begin();
			//for each tree
			for (auto &t: the_trees){

				index_type index = t.find_leaf(p.data());

				// add value
				t.the_nodes[index].push_response_value(data.response(i));

				// note leaf as changed
				(*it) = index;
				it++;
			}
			rfr::print_vector(*dirty_leafs.back());
		}
	}

	bool pseudo_downdate(){
		if (dirty_leafs.empty())
			return(false);
		for (auto li: (*dirty_leafs.back()))
			the_trees.the_nodes[li].pop_back();
		return(true);
	}

	// writes serialized representation into string (used for pickling in python)
	void save_to_binary_file(const std::string filename){
		std::ofstream ofs(filename, std::ios::binary);
		oarch_type oarch(ofs);
		serialize(oarch);
	}

	// deserialize from a representation provided by the string (used for unpickling in python)
	void load_from_binary_file(const std::string filename){
		std::ifstream ifs(filename, std::ios::binary);
		std::cout<<"opening file "<<filename<<std::endl;
		iarch_type iarch(ifs);
		serialize(iarch);
	}

	// serialize into a string; used for Python's pickle.dump
	std::string save_into_string(){
		std::stringstream oss;
		oarch_type oarch(oss);
		serialize(oarch);
		return(oss.str());
	}

	// deserialize from string; used for Python's pickle.load
	void load_from_string( std::string str){
		std::stringstream iss;
		iss.str(str);
		iarch_type iarch(iss);
		serialize(iarch);
	}

	/* \brief stores a latex document for every individual tree
	 *
	 * \param filename_template a string to specify the location and the naming scheme. Note the directory is not created, so make sure it exists.
	 *
	 */
	void save_latex_representation(const std::string filename_template){
		for (auto i = 0u; i<the_trees.size(); i++){
			std::stringstream filename;
			filename << filename_template<<i<<".tex";
			the_trees[i].save_latex_representation(filename.str().c_str());
		}
	}

	void print_info(){
		for (auto t: the_trees){
			t.print_info();
		}
	}
};

}}//namespace rfr::forests
#endif
<commit_msg>corrected math in predict_mean_var_of_mean_response_on_set<commit_after>#ifndef RFR_REGRESSION_FOREST_HPP
#define RFR_REGRESSION_FOREST_HPP

#include <iostream>
#include <sstream>
#include <vector>
#include <utility>
#include <cmath>
#include <numeric>
#include <tuple>
#include <random>
#include <algorithm>
#include <functional>  // std::bind

#include "cereal/cereal.hpp"
#include <cereal/types/vector.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <iostream>
#include <sstream>

#include "rfr/trees/tree_options.hpp"
#include "rfr/forests/forest_options.hpp"
#include "rfr/util.hpp"

namespace rfr{ namespace forests{

typedef cereal::PortableBinaryInputArchive iarch_type;
typedef cereal::PortableBinaryOutputArchive oarch_type;

template <typename tree_type, typename rng_type, typename num_type = float, typename response_type = float, typename index_type = unsigned int>
class regression_forest{
  private:
	forest_options<num_type, response_type, index_type> forest_opts;
	std::vector<tree_type> the_trees;
	index_type num_features;

	std::vector<std::vector<index_type> > dirty_leafs;

  public:

  	/* serialize function for saving forests */
  	template<class Archive>
	void serialize(Archive & archive)
	{
		archive( forest_opts, the_trees);
	}

	regression_forest(){}

	regression_forest(forest_options<num_type, response_type, index_type> forest_opts): forest_opts(forest_opts), the_trees(forest_opts.num_trees){}

	/* \brief growing the random forest for a given data set
	 *
	 * \param data a filled data container
	 * \param rng the random number generator to be used
	 */
	void fit(const rfr::data_containers::data_container_base<num_type, response_type, index_type> &data, rng_type &rng){

		if ((!forest_opts.do_bootstrapping) && (data.num_data_points() < forest_opts.num_data_points_per_tree)){
			std::cout<<"You cannot use more data points per tree than actual data point present without bootstrapping!";
			return;
		}

		std::vector<index_type> data_indices( data.num_data_points());
		std::iota(data_indices.begin(), data_indices.end(), 0);
		std::vector<index_type> data_indices_to_be_used( forest_opts.num_data_points_per_tree);

		num_features = data.num_features();

		// catch some stupid things that will make the forest crash when fitting
		if (forest_opts.num_data_points_per_tree == 0)
			throw std::runtime_error("The number of data points per tree is set to zero!");

		if (forest_opts.tree_opts.max_features == 0)
			throw std::runtime_error("The number of features used for a split is set to zero!");

		for (auto &tree : the_trees){
			// prepare the data(sub)set
			if (forest_opts.do_bootstrapping){
				std::uniform_int_distribution<index_type> dist (0,data.num_data_points()-1);
				auto dice = std::bind(dist, rng);
				std::generate_n(data_indices_to_be_used.begin(), data_indices_to_be_used.size(), dice);
			}
			else{
				std::shuffle(data_indices.begin(), data_indices.end(), rng);
				data_indices_to_be_used.assign(data_indices.begin(), data_indices.begin()+ forest_opts.num_data_points_per_tree);
			}
			tree.fit(data, forest_opts.tree_opts, data_indices_to_be_used, rng);
		}
	}

	/* \brief combines the prediction of all trees in the forest
	 *
	 * Every random tree makes an individual prediction. From that, the mean and the standard
	 * deviation of those predictions is calculated. (See Frank's PhD thesis section 11.?)
	 *
	 * \param feature_vector a valid (size and values) array containing features
	 *
	 * \return std::pair<num_type, num_type> mean and total variance (= mean of variances + variance of means )
	 */
	std::pair<num_type, num_type> predict_mean_var( num_type * feature_vector){

		// collect the predictions of individual trees
		rfr::running_statistics<num_type> mean_stats, var_stats;
		for (auto &tree: the_trees){
			num_type m , v;	index_type n;

			std::tie(m, v, n) = tree.predict_mean_var_N(feature_vector);

			mean_stats(m);
			var_stats(v);
		}

		return(std::pair<num_type, num_type> (mean_stats.mean(), std::max<num_type>(0, mean_stats.variance() + var_stats.mean()) ));
	}

	/* \brief combines the prediction of all trees in the forest
	 *
	 * Every random tree makes an individual prediction. From that, the mean and the standard
	 * deviation of those predictions is calculated. (See Frank's PhD thesis section 11.?)
	 *
	 * \param feature_vector a valid (size and values) array containing features
	 *
	 * \return std::pair<num_type, num_type> mean and sqrt(total variance = mean of variances + variance of means )
	 */
	std::pair<num_type, num_type> predict_mean_std( num_type * feature_vector){
		auto p = predict_mean_var(feature_vector);
		p.second = sqrt(p.second);
		return(p);
	}

	/* \brief predict the mean and the variance deviation for a configuration marginalized over a given set of partial configurations
	 *
	 * This function will be mostly used to predict the mean over a given set of instances, but could be used to marginalize over any discrete set of partial configurations.
	 *
	 * \param features a (partial) configuration where unset values should be set to NaN
	 * \param set_features a array containing the (partial) assignments used for the averaging. Every NaN value will be replaced by the corresponding value from features.
	 * \param set_size number of feature vectors in set_features
	 *
	 * \return std::pair<num_type, num_type> mean and variance prediction of a feature vector averaged over
	 */
	std::pair<num_type, num_type> predict_mean_var_marginalized_over_set (num_type *features, num_type* set_features, index_type set_size){

		num_type fv[num_features];

		// collect the predictions of individual trees
		rfr::running_statistics<num_type> mean_stats, var_stats;
		for (auto i=0u; i < set_size; ++i){
			// construct the actual feature vector
			rfr::merge_two_vectors(features, &set_features[i*num_features], fv, num_features);

			num_type m , v; index_type n;
			std::tie(m, v, n) = predict_mean_var(fv);

			mean_stats(m);
			var_stats(v);
		}
		return(std::pair<num_type, num_type> (mean_stats.mean(), std::max<num_type>(0, mean_stats.variance() + var_stats.mean()) ));
	}

	/* \brief predict the mean and the variance of the mean prediction across a set of partial features
	 *
	 * A very special function to predict the mean response of a a partial assignment for a given set.
	 * It takes the prediction of set-mean of every individual tree and combines to estimate the mean its
	 * total variance. The predictions of two trees are considered uncorrelated
	 *
	 * \param features a (partial) configuration where unset values should be set to NaN
	 * \param set_features a 1d-array containing the (partial) assignments used for the averaging. Every NaN value will be replaced by the corresponding value from features. The array must hold set_size times the number of features entries! There is no consistency check!
	 * \param set_size number of feature vectors in set_features
	 *
	 * \return std::pair<num_type, num_type> mean and variance of empirical mean prediction of a feature vector averaged over
	 */
	std::pair<num_type, num_type> predict_mean_var_of_mean_response_on_set (num_type *features, num_type* set_features, index_type set_size){

			num_type fv[num_features];

			rfr::running_statistics<num_type> mean_stats, var_stats;

			for (auto &t : the_trees){

					rfr::running_statistics<num_type> tree_mean_stats, tree_var_stats;

					for (auto i=0u; i < set_size; ++i){

							rfr::merge_two_vectors(features, &set_features[i*num_features], fv, num_features);

							num_type m , v; index_type n;
							std::tie(m, v, n) = t.predict_mean_var_N(fv);

							tree_mean_stats(m); tree_var_stats(v);
					}

					mean_stats(tree_mean_stats.mean());
					var_stats(std::max<num_type>(0, tree_var_stats.mean()/set_size));
			}

			return(std::pair<num_type, num_type>(mean_stats.mean(), std::max<num_type>(0, mean_stats.variance()) + std::max<num_type>(0, var_stats.mean())));
	}

	/* \brief estimates the covariance of two feature vectors
	 *
	 * The covariance between to input vectors contains information about the
	 * feature space. For other models, like GPs, this is a natural quantity
	 * (e.g., property of the kernel). Here, we try to estimate it using the
	 * total covariance of the individual tree's prediction and the assumption
	 * that cov(X,Y) = 0, if X and Y fall into different leafs, and cov(X,Y) = var(X) = var(Y)
	 * otherwise.
	 *
	 * \param f1 a valid feature vector (no sanity checks are performed!)
	 * \param f2 a second feature vector (no sanity checks are performed!)
	 */
	num_type covariance (num_type* f1, num_type* f2){
		rfr::running_statistics<double> cov_stats;
		rfr::running_covariance<double> run_cov;
		/*
		for (auto &t: the_trees){
			auto l1 = t.find_leaf(f1);
			auto l2 = t.find_leaf(f2);

			num_type m , v;	index_type n;

			std::tie(m, v, n) = t.predict_mean_var_N(f1);
			sum_mean1 += m;
			means1.push_back(m);

			std::tie(m, v, n) = t.predict_mean_var_N(f2);
			sum_mean2 += m;
			means2.push_back(m);

			// assumption here: cov = 0 if the leafs are different, and cov = var if both feature vectors fall into the same leaf
			if (l1 == l2)
				cov_stats(v);
			else
				cov_stats(0);
		}

		num_type N = num_type (the_trees.size());
		num_type mean_covs = sum_cov/N;
		num_type m1 = sum_mean1/N, m2 = sum_mean2/N;

		num_type cov_means = 0;

		for (auto i=0u; i < the_trees.size(); ++i)
			cov_means += (means1-m1)*(means2-m2);

		cov_means /= N;

		return(mean_covs + cov_means);
		* */
	}

	std::vector< std::vector<num_type> > all_leaf_values (num_type * feature_vector){
		std::vector< std::vector<num_type> > rv;
		rv.reserve(the_trees.size());

		for (auto &t: the_trees){
			rv.push_back(t.leaf_entries(feature_vector));
		}
		return(rv);
	}

	forest_options<num_type, response_type, index_type> get_forest_options(){return(forest_opts);}

	/* \brief updates the forest by adding all provided datapoints without a complete retraining
	 *
	 * As retraining can be quite expensive, this function can be used to quickly update the forest
	 * by finding the leafs the datapoints belong into and just inserting them. This is, of course,
	 * not the right way to do it for many data points, but it should be a good approximation for a few.
	 *
	 * \param data a data container instance that will be inserted into the tree
	 */
	void pseudo_update (const rfr::data_containers::data_container_base<num_type, response_type, index_type> &data){

		for (auto i=0u; data.num_data_points(); ++i){

			auto p = data.retrieve_data_point(i);
			dirty_leafs.emplace_back(std::vector<index_type> (0, the_trees.size()));
			auto it = (dirty_leafs.back()).begin();
			//for each tree
			for (auto &t: the_trees){

				index_type index = t.find_leaf(p.data());

				// add value
				t.the_nodes[index].push_response_value(data.response(i));

				// note leaf as changed
				(*it) = index;
				it++;
			}
			rfr::print_vector(*dirty_leafs.back());
		}
	}

	bool pseudo_downdate(){
		if (dirty_leafs.empty())
			return(false);
		for (auto li: (*dirty_leafs.back()))
			the_trees.the_nodes[li].pop_back();
		return(true);
	}

	// writes serialized representation into string (used for pickling in python)
	void save_to_binary_file(const std::string filename){
		std::ofstream ofs(filename, std::ios::binary);
		oarch_type oarch(ofs);
		serialize(oarch);
	}

	// deserialize from a representation provided by the string (used for unpickling in python)
	void load_from_binary_file(const std::string filename){
		std::ifstream ifs(filename, std::ios::binary);
		std::cout<<"opening file "<<filename<<std::endl;
		iarch_type iarch(ifs);
		serialize(iarch);
	}

	// serialize into a string; used for Python's pickle.dump
	std::string save_into_string(){
		std::stringstream oss;
		oarch_type oarch(oss);
		serialize(oarch);
		return(oss.str());
	}

	// deserialize from string; used for Python's pickle.load
	void load_from_string( std::string str){
		std::stringstream iss;
		iss.str(str);
		iarch_type iarch(iss);
		serialize(iarch);
	}

	/* \brief stores a latex document for every individual tree
	 *
	 * \param filename_template a string to specify the location and the naming scheme. Note the directory is not created, so make sure it exists.
	 *
	 */
	void save_latex_representation(const std::string filename_template){
		for (auto i = 0u; i<the_trees.size(); i++){
			std::stringstream filename;
			filename << filename_template<<i<<".tex";
			the_trees[i].save_latex_representation(filename.str().c_str());
		}
	}

	void print_info(){
		for (auto t: the_trees){
			t.print_info();
		}
	}
};

}}//namespace rfr::forests
#endif
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include "math.h"

namespace MATH_NAMESPACE
{

//-------------------------------------------------------------------------------------------------
// Sphere members
//

template <typename T, typename P>
MATH_FUNC basic_sphere<T, P>::basic_sphere(vector<3, T> const& c, T r)
    : center(c)
    , radius(r)
{
}

//-------------------------------------------------------------------------------------------------
// Geometric functions
//

template <typename T, typename P>
MATH_FUNC
basic_aabb<T> get_bounds(basic_sphere<T, P> const& s)
{
    basic_aabb<T> bounds;

    bounds.invalidate();
    bounds.insert(s.center - s.radius);
    bounds.insert(s.center + s.radius);

    return bounds;
}

template <typename T, typename P>
MATH_FUNC
T volume(basic_sphere<T, P> const& s)
{
    auto r3 = s.radius * s.radius * s.radius;
    return T(4.0) / T(3.0) * constants::pi<T>() * r3;
}

} // MATH_NAMESPACE
<commit_msg>Declare free functions inline<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include "math.h"

namespace MATH_NAMESPACE
{

//-------------------------------------------------------------------------------------------------
// Sphere members
//

template <typename T, typename P>
MATH_FUNC
inline basic_sphere<T, P>::basic_sphere(vector<3, T> const& c, T r)
    : center(c)
    , radius(r)
{
}

//-------------------------------------------------------------------------------------------------
// Geometric functions
//

template <typename T, typename P>
MATH_FUNC
inline basic_aabb<T> get_bounds(basic_sphere<T, P> const& s)
{
    basic_aabb<T> bounds;

    bounds.invalidate();
    bounds.insert(s.center - s.radius);
    bounds.insert(s.center + s.radius);

    return bounds;
}

template <typename T, typename P>
MATH_FUNC
inline T volume(basic_sphere<T, P> const& s)
{
    auto r3 = s.radius * s.radius * s.radius;
    return T(4.0) / T(3.0) * constants::pi<T>() * r3;
}

} // MATH_NAMESPACE
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#ifndef PATH_TO_REGEX_HPP
#define PATH_TO_REGEX_HPP

#include <regex>
#include <string>
#include <vector>
#include <map>

namespace route {

struct Token {
	std::string name      {};	// can be a string or an int (index)
	std::string prefix    {};
	std::string delimiter {};
	std::string pattern   {};
  bool        optional  {false};
  bool        repeat    {false};
  bool        partial   {false};
  bool        asterisk  {false};
	bool        is_string {false};	// If it is a string we only put/have a string in the name-attribute (path in parse-method)
	               	// So if this is true, we can ignore all attributes except name

  void set_string_token(const std::string& name_) {
    name = name_;
    is_string = true;
  }
}; //< struct Token

class PathToRegex {
private:
  //----------------------------------------
  // Internal class type aliases
  using Keys    = std::vector<Token>;
  using Tokens  = std::vector<Token>;
  using Options = std::map<std::string, bool>;
  //----------------------------------------
public:
  /**
   *  Creates a path-regex from string input (path)
   *  Updates keys-vector (empty input parameter)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *  Puts the tokens that are keys (not string-tokens) into keys-vector
   *
   *  std::vector<Token> keys (empty)
   *    Is created outside the class and sent in as parameter
   *    One Token-object in the keys-vector per parameter found in the path
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
	static std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options = Options{});

  /**
   *  Creates a path-regex from string input (path)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
  static std::regex path_to_regex(const std::string& path, const Options& options = Options{});

  /**
   *  Creates vector of tokens based on the given string (this vector of tokens can be sent as
   *  input to tokens_to_regex-method and includes tokens that are strings, not only tokens
   *  that are parameters in str)
   */
  static Tokens parse(const std::string& str);

  /**
   *  Creates a regex based on the tokens and options (optional) given
   */
  static std::regex tokens_to_regex(const Tokens& tokens, const Options& options = Options{});

  /**
   *  Goes through the tokens-vector and push all tokens that are not string-tokens
   *  onto keys-vector
   */
  static void tokens_to_keys(const Tokens& tokens, Keys& keys);

private:
	static const std::regex PATH_REGEXP;
}; //< class PathToRegex

}; //< namespace route

#endif //< PATH_TO_REGEX_HPP
<commit_msg>Reordered includes<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#ifndef PATH_TO_REGEX_HPP
#define PATH_TO_REGEX_HPP

#include <map>
#include <regex>
#include <string>
#include <vector>

namespace route {

struct Token {
	std::string name      {};	// can be a string or an int (index)
	std::string prefix    {};
	std::string delimiter {};
	std::string pattern   {};
  bool        optional  {false};
  bool        repeat    {false};
  bool        partial   {false};
  bool        asterisk  {false};
	bool        is_string {false};	// If it is a string we only put/have a string in the name-attribute (path in parse-method)
	               	// So if this is true, we can ignore all attributes except name

  void set_string_token(const std::string& name_) {
    name = name_;
    is_string = true;
  }
}; //< struct Token

class PathToRegex {
private:
  //----------------------------------------
  // Internal class type aliases
  using Keys    = std::vector<Token>;
  using Tokens  = std::vector<Token>;
  using Options = std::map<std::string, bool>;
  //----------------------------------------
public:
  /**
   *  Creates a path-regex from string input (path)
   *  Updates keys-vector (empty input parameter)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *  Puts the tokens that are keys (not string-tokens) into keys-vector
   *
   *  std::vector<Token> keys (empty)
   *    Is created outside the class and sent in as parameter
   *    One Token-object in the keys-vector per parameter found in the path
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
	static std::regex path_to_regex(const std::string& path, Keys& keys, const Options& options = Options{});

  /**
   *  Creates a path-regex from string input (path)
   *
   *  Calls parse-method and then tokens_to_regex-method based on the tokens returned from parse-method
   *
   *  std::map<std::string, bool> options (optional)
   *    Can contain bool-values for the keys "sensitive", "strict" and/or "end"
   *    Default:
   *      strict = false
   *      sensitive = false
   *      end = true
   */
  static std::regex path_to_regex(const std::string& path, const Options& options = Options{});

  /**
   *  Creates vector of tokens based on the given string (this vector of tokens can be sent as
   *  input to tokens_to_regex-method and includes tokens that are strings, not only tokens
   *  that are parameters in str)
   */
  static Tokens parse(const std::string& str);

  /**
   *  Creates a regex based on the tokens and options (optional) given
   */
  static std::regex tokens_to_regex(const Tokens& tokens, const Options& options = Options{});

  /**
   *  Goes through the tokens-vector and push all tokens that are not string-tokens
   *  onto keys-vector
   */
  static void tokens_to_keys(const Tokens& tokens, Keys& keys);

private:
	static const std::regex PATH_REGEXP;
}; //< class PathToRegex

}; //< namespace route

#endif //< PATH_TO_REGEX_HPP
<|endoftext|>