#include "engine/plugins/trip.hpp"

#include "extractor/tarjan_scc.hpp"

#include "engine/api/trip_api.hpp"
#include "engine/api/trip_parameters.hpp"
#include "engine/trip/trip_brute_force.hpp"
#include "engine/trip/trip_farthest_insertion.hpp"
#include "engine/trip/trip_nearest_neighbour.hpp"
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
#include "util/json_container.hpp"
#include "util/matrix_graph_wrapper.hpp" // wrapper to use tarjan scc on dist table

#include <boost/assert.hpp>

#include <algorithm>
#include <cstdlib>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace osrm
{
namespace engine
{
namespace plugins
{

// Object to hold all strongly connected components (scc) of a graph
// to access all graphs with component ID i, get the iterators by:
// auto start = std::begin(scc_component.component) + scc_component.range[i];
// auto end = std::begin(scc_component.component) + scc_component.range[i+1];
struct SCC_Component
{
    // in_component: all NodeIDs sorted by component ID
    // in_range: index where a new component starts
    //
    // example: NodeID 0, 1, 2, 4, 5 are in component 0
    //          NodeID 3, 6, 7, 8    are in component 1
    //          => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
    //          => in_range = [0, 5]
    SCC_Component(std::vector<NodeID> in_component_nodes, std::vector<size_t> in_range)
        : component(std::move(in_component_nodes)), range(std::move(in_range))
    {
        BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
        BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) == component.size(),
                         "scc component ranges are out of bound");
        BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) == 0,
                         "invalid scc component range");
        BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
                         "invalid component ranges");
    }

    std::size_t GetNumberOfComponents() const
    {
        BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
        return range.size() - 1;
    }

    const std::vector<NodeID> component;
    std::vector<std::size_t> range;
};

// takes the number of locations and its duration matrix,
// identifies and splits the graph in its strongly connected components (scc)
// and returns an SCC_Component
SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
                                         const util::DistTableWrapper<EdgeWeight> &result_table)
{

    if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
        std::end(result_table))
    {
        // whole graph is one scc
        std::vector<NodeID> location_ids(number_of_locations);
        std::iota(std::begin(location_ids), std::end(location_ids), 0);
        std::vector<size_t> range = {0, location_ids.size()};
        return SCC_Component(std::move(location_ids), std::move(range));
    }

    // Run TarjanSCC
    auto wrapper = std::make_shared<util::MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
                                                                          number_of_locations);
    auto scc = extractor::TarjanSCC<util::MatrixGraphWrapper<EdgeWeight>>(wrapper);
    scc.Run();

    const auto number_of_components = scc.GetNumberOfComponents();

    std::vector<std::size_t> range_insertion;
    std::vector<std::size_t> range;
    range_insertion.reserve(number_of_components);
    range.reserve(number_of_components);

    std::vector<NodeID> components(number_of_locations, 0);

    std::size_t prefix = 0;
    for (std::size_t j = 0; j < number_of_components; ++j)
    {
        range_insertion.push_back(prefix);
        range.push_back(prefix);
        prefix += scc.GetComponentSize(j);
    }
    // senitel
    range.push_back(components.size());

    for (std::size_t i = 0; i < number_of_locations; ++i)
    {
        components[range_insertion[scc.GetComponentID(i)]] = i;
        ++range_insertion[scc.GetComponentID(i)];
    }

    return SCC_Component(std::move(components), std::move(range));
}

InternalRouteResult TripPlugin::ComputeRoute(const datafacade::BaseDataFacade &facade,
                                             const std::vector<PhantomNode> &snapped_phantoms,
                                             const std::vector<NodeID> &trip) const
{
    InternalRouteResult min_route;
    // given he final trip, compute total duration and return the route and location permutation
    PhantomNodes viapoint;
    const auto start = std::begin(trip);
    const auto end = std::end(trip);
    // computes a roundtrip from the nodes in trip
    for (auto it = start; it != end; ++it)
    {
        const auto from_node = *it;
        // if from_node is the last node, compute the route from the last to the first location
        const auto to_node = std::next(it) != end ? *std::next(it) : *start;

        viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
        min_route.segment_end_coordinates.emplace_back(viapoint);
    }
    BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());

    shortest_path(facade, min_route.segment_end_coordinates, {false}, min_route);

    BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
    return min_route;
}

Status TripPlugin::HandleRequest(const std::shared_ptr<datafacade::BaseDataFacade> facade,
                                 const api::TripParameters &parameters,
                                 util::json::Object &json_result) const
{
    BOOST_ASSERT(parameters.IsValid());

    // enforce maximum number of locations for performance reasons
    if (max_locations_trip > 0 &&
        static_cast<int>(parameters.coordinates.size()) > max_locations_trip)
    {
        return Error("TooBig", "Too many trip coordinates", json_result);
    }

    if (!CheckAllCoordinates(parameters.coordinates))
    {
        return Error("InvalidValue", "Invalid coordinate value.", json_result);
    }

    auto phantom_node_pairs = GetPhantomNodes(*facade, parameters);
    if (phantom_node_pairs.size() != parameters.coordinates.size())
    {
        return Error("NoSegment",
                     std::string("Could not find a matching segment for coordinate ") +
                         std::to_string(phantom_node_pairs.size()),
                     json_result);
    }
    BOOST_ASSERT(phantom_node_pairs.size() == parameters.coordinates.size());

    auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);

    const auto number_of_locations = snapped_phantoms.size();

    // compute the duration table of all phantom nodes
    const auto result_table = util::DistTableWrapper<EdgeWeight>(
        duration_table(*facade, snapped_phantoms, {}, {}), number_of_locations);

    if (result_table.size() == 0)
    {
        return Status::Error;
    }

    const constexpr std::size_t BF_MAX_FEASABLE = 10;
    BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
                     "Distance Table has wrong size");

    // get scc components
    SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);

    std::vector<std::vector<NodeID>> trips;
    trips.reserve(scc.GetNumberOfComponents());
    // run Trip computation for every SCC
    for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
    {
        const auto component_size = scc.range[k + 1] - scc.range[k];

        BOOST_ASSERT_MSG(component_size > 0, "invalid component size");

        std::vector<NodeID> scc_route;
        auto route_begin = std::begin(scc.component) + scc.range[k];
        auto route_end = std::begin(scc.component) + scc.range[k + 1];

        if (component_size > 1)
        {

            if (component_size < BF_MAX_FEASABLE)
            {
                scc_route =
                    trip::BruteForceTrip(route_begin, route_end, number_of_locations, result_table);
            }
            else
            {
                scc_route = trip::FarthestInsertionTrip(
                    route_begin, route_end, number_of_locations, result_table);
            }
        }
        else
        {
            scc_route = std::vector<NodeID>(route_begin, route_end);
        }

        trips.push_back(std::move(scc_route));
    }
    if (trips.empty())
    {
        return Error("NoTrips", "Cannot find trips", json_result);
    }

    // compute all round trip routes
    std::vector<InternalRouteResult> routes;
    routes.reserve(trips.size());
    for (const auto &trip : trips)
    {
        routes.push_back(ComputeRoute(*facade, snapped_phantoms, trip));
    }

    api::TripAPI trip_api{*facade, parameters};
    trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result);

    return Status::Ok;
}
}
}
}


#include <cmath>

#include <boost/filesystem.hpp>

#include "PotreeWriter.h"
#include "LASPointReader.h"
#include "BINPointReader.hpp"
#include "LASPointWriter.hpp"
#include "BINPointWriter.hpp"

namespace fs = boost::filesystem;

PotreeWriterNode::PotreeWriterNode(PotreeWriter* potreeWriter, string name, string path, AABB aabb, float spacing, int level, int maxLevel, double scale){
	this->name = name;
	this->path = path;
	this->aabb = aabb;
	this->spacing = spacing;
	this->level = level;
	this->maxLevel = maxLevel;
	this->potreeWriter = potreeWriter;
	this->grid = new SparseGrid(aabb, spacing);
	this->scale = scale;
	numAccepted = 0;
	lastAccepted = 0;
	addCalledSinceLastFlush = false;

	for(int i = 0; i < 8; i++){
		children[i] = NULL;
	}
}

PointReader *PotreeWriterNode::createReader(string path){
	PointReader *reader = NULL;
	OutputFormat outputFormat = this->potreeWriter->outputFormat;
	if(outputFormat == OutputFormat::LAS || outputFormat == OutputFormat::LAZ){
		reader = new LASPointReader(path);
	}else if(outputFormat == OutputFormat::BINARY){
		reader = new BINPointReader(path, aabb, scale);
	}

	return reader;
}

PointWriter *PotreeWriterNode::createWriter(string path, double scale){
	PointWriter *writer = NULL;
	OutputFormat outputFormat = this->potreeWriter->outputFormat;
	if(outputFormat == OutputFormat::LAS || outputFormat == OutputFormat::LAZ){
		writer = new LASPointWriter(path, aabb, scale);
	}else if(outputFormat == OutputFormat::BINARY){
		writer = new BINPointWriter(path, aabb, scale);
	}

	return writer;

}

void PotreeWriterNode::loadFromDisk(){
	PointReader *reader = createReader(path + "/data/" + name + potreeWriter->getExtension());
	while(reader->readNextPoint()){
		Point p = reader->getPoint();
		Vector3<double> position = Vector3<double>(p.x, p.y, p.z);
		grid->addWithoutCheck(position);
	}
	grid->numAccepted = numAccepted;
	reader->close();
	delete reader;
}

PotreeWriterNode *PotreeWriterNode::add(Point &point, int minLevel){
	if(level > maxLevel){
		return NULL;
	}

	if(level < minLevel){
		// pass forth
		int childIndex = nodeIndex(aabb, point);
		if(childIndex >= 0){
			PotreeWriterNode *child = children[childIndex];

			if(child == NULL && level < maxLevel){
				child = createChild(childIndex);
			}

			return child->add(point, minLevel);
		}
	}else{
		return add(point);
	}

	return NULL;
}

PotreeWriterNode *PotreeWriterNode::createChild(int childIndex ){
	stringstream childName;
	childName << name << childIndex;
	AABB cAABB = childAABB(aabb, childIndex);
	PotreeWriterNode *child = new PotreeWriterNode(potreeWriter, childName.str(), path, cAABB, spacing / 2.0f, level+1, maxLevel, scale);
	children[childIndex] = child;

	return child;
}

PotreeWriterNode *PotreeWriterNode::add(Point &point){
	addCalledSinceLastFlush = true;

	// load grid from disk to memory, if necessary
	if(grid->numAccepted != numAccepted){
		loadFromDisk();
	}

	Vector3<double> position(point.x, point.y, point.z);
	bool accepted = grid->add(position);
	//float minGap = grid->add(Vector3<double>(point.x, point.y, point.z));
	//bool accepted = minGap > spacing;
	//int targetLevel = ceil(log((1/minGap) * spacing) / log(2));
	//
	//if(targetLevel > maxLevel){
	//	return NULL;
	//}

	if(accepted){
		cache.push_back(point);
		Vector3<double> position(point.x, point.y, point.z);
		acceptedAABB.update(position);
		potreeWriter->numAccepted++;
		numAccepted++;

		return this;
	}else if(level < maxLevel){
		// try adding point to higher level

		int childIndex = nodeIndex(aabb, point);
		if(childIndex >= 0){
			PotreeWriterNode *child = children[childIndex];

			// create child node if not existent
			if(child == NULL){
				child = createChild(childIndex);
			}

			return child->add(point);
			//child->add(point, targetLevel);
		} else {
			return NULL;
		}
	}
	return NULL;
}

void PotreeWriterNode::flush(){

	if(cache.size() > 0){
		 // move data file aside to temporary directory for reading
		string filepath = path + "/data/" + name + potreeWriter->getExtension();
		string temppath = path +"/temp/prepend" + potreeWriter->getExtension();
		if(fs::exists(filepath)){
			fs::rename(fs::path(filepath), fs::path(temppath));
		}

		PointWriter *writer = createWriter(path + "/data/" + name + potreeWriter->getExtension(), scale);
		if(fs::exists(temppath)){
			PointReader *reader = createReader(temppath);
			while(reader->readNextPoint()){
				writer->write(reader->getPoint());
			}
			reader->close();
			delete reader;
			fs::remove(temppath);
		}

		for(int i = 0; i < cache.size(); i++){
			writer->write(cache[i]);
		}
		writer->close();
		delete writer;

		cache = vector<Point>();
	}else if(cache.size() == 0 && grid->numAccepted > 0 && addCalledSinceLastFlush == false){
		delete grid;
		grid = new SparseGrid(aabb, spacing);
	}

	addCalledSinceLastFlush = false;

	for(int i = 0; i < 8; i++){
		if(children[i] != NULL){
			children[i]->flush();
		}
	}
}


#include <boost/test/unit_test.hpp>
#include <boost/concept_check.hpp>

#include "che/score/cm.h" // header to test

using namespace biosim;

class cm_assembly_fun : public math::cm_function<che::assembly> {
public:
  std::string get_identifier() const { return "fun"; }
  double compare(che::assembly const &, che::assembly const &) const { return -1.0; }
};

BOOST_AUTO_TEST_SUITE(suite_cm)

BOOST_AUTO_TEST_CASE(cm_instances) { BOOST_CHECK(che::score::assembly_compares::get_instances().size() == 1); }

BOOST_AUTO_TEST_CASE(cm_add) {
  size_t instance_count(che::score::assembly_compares::get_instances().size());
  che::score::assembly_compares::add(std::shared_ptr<math::cm_function<che::assembly>>(new cm_assembly_fun));
  BOOST_CHECK(che::score::assembly_compares::get_instances().size() == instance_count + 1);
}

BOOST_AUTO_TEST_SUITE_END()


/*
 * MIT License
 *
 * Copyright (c) 2020 Robert Grupp
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "xregRayCastSurRenderOCL.h"

#include <boost/compute/utility/source.hpp>
#include <boost/compute/types/struct.hpp>

#include "xregAssert.h"

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

BOOST_COMPUTE_ADAPT_STRUCT(xreg::RayCasterSurRenderOCL::RayCastSurRenderArgs, RayCastSurRenderArgs,
                           (thresh,
                            pad1,
                            num_backtracking_steps,
                            ambient_reflection_ratio,
                            diffuse_reflection_ratio,
                            specular_reflection_ratio,
                            alpha_shininess))

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

namespace  // un-named
{

const char* kRAY_CASTING_SUR_RENDER_OPENCL_SRC = BOOST_COMPUTE_STRINGIZE_SOURCE(

__kernel void xregSurRenderKernel1(const RayCastArgs args,
                                   const RayCastSurRenderArgs sur_render_args,
                                   __global const float4* det_pts,
                                   image3d_t vol_tex,
                                   __global const float16* cam_to_itk_phys_xforms,
                                   __global float8* dst_step_vecs_and_intersect_pts_wrt_itk_idx,
                                   __global const ulong* cam_model_for_proj,
                                   __global const float4* cam_focal_pts)
{
  const ulong idx = get_global_id(0);

  const ulong num_rays = args.num_projs * args.num_det_pts;

  if (idx < num_rays)
  {
    const ulong proj_idx   = idx / args.num_det_pts;
    const ulong det_pt_idx = idx - (proj_idx * args.num_det_pts);
    const ulong cam_idx    = cam_model_for_proj[proj_idx];

    const float4 focal_pt_wrt_cam = cam_focal_pts[cam_idx];

    const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_LINEAR;

    const float4 tex_coords_off = (float4) (0.5f, 0.5f, 0.5f, 0);

    const float16 xform_cam_to_itk_idx = xregFrm4x4Composition(args.itk_phys_pt_to_itk_idx_xform,
                                                               cam_to_itk_phys_xforms[proj_idx]);

    const float4 pinhole_wrt_itk_idx = xregFrm4x4XformFloat4Pt(xform_cam_to_itk_idx, focal_pt_wrt_cam);

    const float4 cur_det_pt_wrt_cam = det_pts[(cam_idx * args.num_det_pts) + det_pt_idx];

    const float4 pinhole_to_det_wrt_itk_idx = xregFrm4x4XformFloat4Pt(xform_cam_to_itk_idx, cur_det_pt_wrt_cam)
                                                  - pinhole_wrt_itk_idx;

    // check intersection with the image/volume boundary
    // these pointer were passed as float4's since boost::compute does not have a float3
    float2 t = xregRayRectIntersect(xregFloat4HmgToFloat3(args.img_aabb_min),
                                    xregFloat4HmgToFloat3(args.img_aabb_max),
                                    xregFloat4HmgToFloat3(pinhole_wrt_itk_idx),
                                    xregFloat4HmgToFloat3(pinhole_to_det_wrt_itk_idx));
    // t.x indicates the first intersection with the volume along the source to detector ray,
    // t.y indicates the exit of the volume along the source to detector ray
    // t.x, t.y are in [0,inf)

    const float4 start_pt_wrt_itk_idx = pinhole_wrt_itk_idx + (t.x * pinhole_to_det_wrt_itk_idx);

    const float pinhole_to_det_len_wrt_itk_idx = xregFloat4HmgNorm(pinhole_to_det_wrt_itk_idx);
    const float intersect_len_wrt_itk_idx = (t.y - t.x) * pinhole_to_det_len_wrt_itk_idx;

    const float4 focal_pt_to_det_wrt_cam = cur_det_pt_wrt_cam - focal_pt_wrt_cam;
    // NOTE: since we are transforming a vector with a scaling transform (points to indices),
    //       the output vector may not have the same norm, thus we take the norm
    const float step_len_wrt_itk_idx = xregFloat4HmgNorm(
                      xregFrm4x4XformFloat4Vec(xform_cam_to_itk_idx,
                         (focal_pt_to_det_wrt_cam / xregFloat4HmgNorm(focal_pt_to_det_wrt_cam)) * args.step_size));

    const ulong num_steps = (ulong)(intersect_len_wrt_itk_idx / step_len_wrt_itk_idx);

    float4 cur_cont_vol_idx = (float4) (start_pt_wrt_itk_idx.x, start_pt_wrt_itk_idx.y, start_pt_wrt_itk_idx.z, 0);

    // "/ pinhole_to_det_len_wrt_itk_idx" makes pinhole_to_det_wrt_itk_idx a unit vector
    const float scale_to_step = step_len_wrt_itk_idx / pinhole_to_det_len_wrt_itk_idx;

    const float4 step_vec_wrt_itk_idx = (float4) (pinhole_to_det_wrt_itk_idx.x * scale_to_step, pinhole_to_det_wrt_itk_idx.y * scale_to_step, pinhole_to_det_wrt_itk_idx.z * scale_to_step, 0);

    // The first three elements will store the step direction in ITK index space
    dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s0 = step_vec_wrt_itk_idx.x;
    dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s1 = step_vec_wrt_itk_idx.y;
    dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s2 = step_vec_wrt_itk_idx.z;

    // The fourth element will indicate whether this ray intersected the surface.
    dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s3 = 0;  //  0 -> no intersection found

    for (ulong step_idx = 0; step_idx <= num_steps; ++step_idx, cur_cont_vol_idx += step_vec_wrt_itk_idx)
    {
      if (read_imagef(vol_tex, sampler, cur_cont_vol_idx + tex_coords_off).x >= sur_render_args.thresh)
      {
        // The 5th, 6th, and 7th elements will store the initial point of intersection, before any backtracking
        dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s4 = cur_cont_vol_idx.x;
        dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s5 = cur_cont_vol_idx.y;
        dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s6 = cur_cont_vol_idx.z;
        dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s7 = 0;

        dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s3 = 1;  // 1 -> intersection found
        break;
      }
    }
  }
}

__kernel void xregSurRenderKernel2(const RayCastArgs args,
                                   const RayCastSurRenderArgs sur_render_args,
                                   image3d_t vol_tex,
                                   __global const float8* dst_step_vecs_and_intersect_pts_wrt_itk_idx,
                                   __global float* dst_intensities)
{
  const ulong idx = get_global_id(0);

  const ulong num_rays = args.num_projs * args.num_det_pts;

  if (idx < num_rays)
  {
    if (dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s3 > 1.0e-6)
    {
      const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_LINEAR;

      const float4 tex_coords_off = (float4) (0.5f, 0.5f, 0.5f, 0);

      float3 light_src_vec = (float3) (dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s0, dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s1, dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s2);
      // right now, this light source vector points from the light source, it needs to be negated, and it is when normalizing a few lines below

      // This vector will always point towards the pinhole.
      float4 step_vec_wrt_itk_idx = (float4) (light_src_vec.x, light_src_vec.y, light_src_vec.z, 0);
      step_vec_wrt_itk_idx *= 0.5f;

      // normalize the direction vector to the light source, and negate to get the right orientation
      light_src_vec /= -xregFloat3Norm(light_src_vec);

      float4 cur_cont_vol_idx = (float4) (dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s4, dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s5, dst_step_vecs_and_intersect_pts_wrt_itk_idx[idx].s6, 0);

      cur_cont_vol_idx += tex_coords_off;

      // we know that we should start out backtracking.
      cur_cont_vol_idx -= step_vec_wrt_itk_idx;

      for (ulong backtrack_idx = 0; backtrack_idx < sur_render_args.num_backtracking_steps; ++backtrack_idx)
      {
        step_vec_wrt_itk_idx *= 0.5f;

        cur_cont_vol_idx += (read_imagef(vol_tex, sampler, cur_cont_vol_idx).x >= sur_render_args.thresh) ?
                                  step_vec_wrt_itk_idx : -step_vec_wrt_itk_idx;
      }

      // compute lighting/shading according to the phong model

      // approximate the derivative at this point with finite differencing adjacent indices
      // NOTE: these are wrt image (index) axes.

      float3 tmp_vec;

      // Gradient in X Direction:
      tmp_vec.x = read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x + 1, cur_cont_vol_idx.y, cur_cont_vol_idx.z, cur_cont_vol_idx.w)).x -
                  read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x - 1, cur_cont_vol_idx.y, cur_cont_vol_idx.z, cur_cont_vol_idx.w)).x;

      // Gradient in Y Direction:
      tmp_vec.y = read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x, cur_cont_vol_idx.y + 1, cur_cont_vol_idx.z, cur_cont_vol_idx.w)).x -
                  read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x, cur_cont_vol_idx.y - 1, cur_cont_vol_idx.z, cur_cont_vol_idx.w)).x;

      // Gradient in Z Direction:
      tmp_vec.z = read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x, cur_cont_vol_idx.y, cur_cont_vol_idx.z + 1, cur_cont_vol_idx.w)).x -
                  read_imagef(vol_tex, sampler, (float4) (cur_cont_vol_idx.x, cur_cont_vol_idx.y, cur_cont_vol_idx.z - 1, cur_cont_vol_idx.w)).x;

      tmp_vec /= (-0.5f * xregFloat3Norm(tmp_vec));

      float val = sur_render_args.ambient_reflection_ratio;

      // Treating the pinhole as the light source

      float tmp_dot = xregFloat3Inner(light_src_vec, tmp_vec);
      const int diffuse_valid = tmp_dot > 1.0e-6;

      val += diffuse_valid ? (sur_render_args.diffuse_reflection_ratio * tmp_dot) : 0;

      tmp_vec *= 2 * tmp_dot;
      tmp_vec -= light_src_vec;

      tmp_dot = xregFloat3Inner(light_src_vec, tmp_vec);

      val += (tmp_dot > 1.0e-6) ?
              (sur_render_args.specular_reflection_ratio * pow(tmp_dot, sur_render_args.alpha_shininess)) : 0;

      dst_intensities[idx] += val;
    }
  }
}

);

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

}  // un-named

xreg::RayCasterSurRenderOCL::RayCasterSurRenderOCL()
  : RayCasterOCL(), step_vecs_and_intersect_pts_wrt_itk_idx_dev_(ctx_)
{ }

xreg::RayCasterSurRenderOCL::RayCasterSurRenderOCL(const boost::compute::device& dev)
  : RayCasterOCL(dev), step_vecs_and_intersect_pts_wrt_itk_idx_dev_(ctx_)
{ }

xreg::RayCasterSurRenderOCL::RayCasterSurRenderOCL(const boost::compute::context& ctx,
                                                   const boost::compute::command_queue& queue)
  : RayCasterOCL(ctx, queue), step_vecs_and_intersect_pts_wrt_itk_idx_dev_(ctx_)
{ }

void xreg::RayCasterSurRenderOCL::allocate_resources()
{
  namespace bc = boost::compute;

  RayCasterOCL::allocate_resources();

  // Build the surface rendering ray casting program
  std::stringstream ss;
  ss << RayCastBaseOCLStr()
     << boost::compute::type_definition<RayCasterSurRenderOCL::RayCastSurRenderArgs>()
     << kRAY_CASTING_SUR_RENDER_OPENCL_SRC;

  bc::program prog = bc::program::create_with_source(ss.str(), ctx_);
  prog.build();

  dev_kernel1_ = prog.create_kernel("xregSurRenderKernel1");

  dev_kernel2_ = prog.create_kernel("xregSurRenderKernel2");

  step_vecs_and_intersect_pts_wrt_itk_idx_dev_.resize(this->camera_models_[0].num_det_rows *
                                                      this->camera_models_[0].num_det_cols *
                                                      this->num_projs_,
                                                      cmd_queue_);
}

void xreg::RayCasterSurRenderOCL::compute(const size_type vol_idx)
{
  xregASSERT(this->resources_allocated_);

  compute_helper_pre_kernels(vol_idx);

  RayCastSurRenderArgs sur_args;

  sur_args.thresh = render_thresh();

  sur_args.num_backtracking_steps = num_backtracking_steps();

  sur_args.ambient_reflection_ratio =
                  surface_render_params().ambient_reflection_ratio;

  sur_args.diffuse_reflection_ratio =
                  surface_render_params().diffuse_reflection_ratio;

  sur_args.specular_reflection_ratio =
                  surface_render_params().specular_reflection_ratio;

  sur_args.alpha_shininess = surface_render_params().alpha_shininess;

  // setup kernel arguments and launch

  dev_kernel1_.set_arg(0, sizeof(ray_cast_kernel_args_), &ray_cast_kernel_args_);

  dev_kernel1_.set_arg(1, sizeof(sur_args), &sur_args);

  dev_kernel1_.set_arg(2, det_pts_dev_);

  dev_kernel1_.set_arg(3, vol_texs_dev_[vol_idx]);

  dev_kernel1_.set_arg(4, cam_to_itk_phys_xforms_dev_);

  dev_kernel1_.set_arg(5, step_vecs_and_intersect_pts_wrt_itk_idx_dev_);

  dev_kernel1_.set_arg(6, cam_model_for_proj_dev_);

  dev_kernel1_.set_arg(7, focal_pts_dev_);

  std::size_t global_work_size = ray_cast_kernel_args_.num_det_pts * this->num_projs_;
  //std::size_t local_work_size = 512;  passing null lets open CL pick a local size

  cmd_queue_.enqueue_nd_range_kernel(dev_kernel1_,
                                     1, // dim
                                     0, // null offset -> start at 0
                                     &global_work_size,
                                     0  // passing null lets open CL pick a local size
                                    ).wait();

  dev_kernel2_.set_arg(0, sizeof(ray_cast_kernel_args_), &ray_cast_kernel_args_);

  dev_kernel2_.set_arg(1, sizeof(sur_args), &sur_args);

  dev_kernel2_.set_arg(2, vol_texs_dev_[vol_idx]);

  dev_kernel2_.set_arg(3, step_vecs_and_intersect_pts_wrt_itk_idx_dev_);

  dev_kernel2_.set_arg(4, *proj_pixels_dev_to_use_);

  cmd_queue_.enqueue_nd_range_kernel(dev_kernel2_,
                                     1, // dim
                                     0, // null offset -> start at 0
                                     &global_work_size,
                                     0  // passing null lets open CL pick a local size
                                    ).wait();

  compute_helper_post_kernels(vol_idx);
}


// 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>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

// 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);
}

void 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> >());
}


/*
 *
 * Copyright (c) Karl Meerbergen & Kresimir Fresl 2003
 *
 * 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)
 *
 * KF acknowledges the support of the Faculty of Civil Engineering,
 * University of Zagreb, Croatia.
 *
 */

#ifndef BOOST_NUMERIC_BINDINGS_LAPACK_WORKSPACE_HPP
#define BOOST_NUMERIC_BINDINGS_LAPACK_WORKSPACE_HPP

#include <boost/numeric/bindings/traits/detail/array_impl.hpp>
#include <boost/numeric/bindings/traits/type.hpp>
#include <boost/numeric/bindings/traits/type_traits.hpp>
#include <boost/numeric/bindings/traits/vector_traits.hpp>
#include <memory>

namespace boost { namespace numeric { namespace bindings {

  /*
   * Organization of workspace in Lapack.
   * We allow one of the following arguments in a number of Lapack functions
   * - minimal_workspace() : the function allocates the minimum workspace required for the function
   * - optimal_workspace() : the function allocates the amount of workspace that allows optimal
   *                         execution.
   * - workspace( work )   : the function uses the workspace array in work.
   * - workspace( rwork, work ) : the function uses a real array rwork and a compolex array work as
   *                              workspace. (There are Lapack functions for complex matrices
   *                              that require two workarrays)
   * */

  namespace lapack {

     // Four classes are introduced to distinguish between the different type of memory allocations

     struct minimal_workspace {} ;

     struct optimal_workspace {} ;

     namespace detail {

        template <typename W>
        class workspace1 {
          public:
            workspace1(W& w)
            : w_( w )
            {}

          public:
            typedef typename traits::vector_traits<W>::value_type value_type ;
            W& select( value_type const& ) { return w_ ; }

          private:
            W& w_ ;
        }; // struct workspace1

        template <typename W, typename WRI>
        class workspace2 {
          public:
            workspace2(W& w, WRI& wri)
            : w_(w)
            , wri_(wri)
            {}

          public:
            typedef typename traits::vector_traits<W>::value_type w_value_type ;
            W& select( w_value_type const& ) { return w_ ; }

            typedef typename traits::vector_traits<WRI>::value_type wri_value_type ;
            WRI& select( wri_value_type const& ) { return wri_ ; }

          private:
            W& w_ ;
            WRI& wri_ ;
        }; // struct workspace2

        template <typename W, typename WR, typename WI>
        class workspace3 {
          public:
            workspace3(W& w, WR& wr, WI& wi)
            : w_(w)
            , wr_(wr)
            , wi_(wi)
            {}

          public:
            typedef typename traits::vector_traits<W>::value_type w_value_type ;
            W& select( w_value_type const& ) { return w_ ; }

            typedef typename traits::vector_traits<WR>::value_type wr_value_type ;
            WR& select( wr_value_type const& ) { return wr_ ; }

            typedef typename traits::vector_traits<WI>::value_type wi_value_type ;
            WI& select( wi_value_type const& ) { return wi_ ; }

          private:
            W& w_ ;
            WR& wr_ ;
            WI& wi_ ;
        }; // struct workspace3

        template <typename W, typename WR, typename WI, typename WB>
        class workspace4 {
          public:
            workspace4(W& w, WR& wr, WI& wi, WB& wb)
            : w_(w)
            , wr_(wr)
            , wi_(wi)
            , wb_(wb)
            {}

          public:
            typedef typename traits::vector_traits<W>::value_type w_value_type ;
            W& select( w_value_type const& ) { return w_ ; }

            typedef typename traits::vector_traits<WR>::value_type wr_value_type ;
            WR& select( wr_value_type const& ) { return wr_ ; }

            typedef typename traits::vector_traits<WI>::value_type wi_value_type ;
            WI& select( wi_value_type const& ) { return wi_ ; }

            typedef typename traits::vector_traits<WB>::value_type wb_value_type ;
            WB& select( wb_value_type const& ) { return wb_ ; }

          private:
            W& w_ ;
            WR& wr_ ;
            WI& wi_ ;
            WB& wb_ ;
        }; // struct workspace4

     }

     template <typename W>
     detail::workspace1<W> workspace(W& w) {
        return detail::workspace1<W>(w) ;
     } // workspace()

     //
     // Two situations:
     //   Real valued: workspace( real array, integer array )
     //   Complex valued: workspace( complex array, real array )
     //
     template <typename W, typename WRI>
     detail::workspace2<W,WRI> workspace(W& w, WRI& wri) {
        return detail::workspace2<W,WRI>(w, wri) ;
     } // workspace()

     //
     //   Complex valued: workspace( complex array, real array, integer array )
     //
     template <typename W, typename WR, typename WI>
     detail::workspace3<W,WR,WI> workspace(W& w, WR& wr, WI& wi) {
        return detail::workspace3<W,WR,WI>(w, wr, wi) ;
     } // workspace()

     //
     //   Complex valued: workspace( complex array, real array, integer array, bool array )
     //
     template <typename W, typename WR, typename WI, typename WB>
     detail::workspace4<W,WR,WI,WB> workspace(W& w, WR& wr, WI& wi, WB& wb) {
        return detail::workspace4<W,WR,WI,WB>(w, wr, wi, wb) ;
     } // workspace()

     /// Select the number of workspaces depending on the value_type
     template <typename T>
     struct n_workspace_args { };

     template <>
     struct n_workspace_args< float > {
        static const int value = 1 ;
     };

     template <>
     struct n_workspace_args< double > {
        static const int value = 1 ;
     };

     template <>
     struct n_workspace_args< traits::complex_f > {
        static const int value = 2 ;
     };

     template <>
     struct n_workspace_args< traits::complex_d > {
        static const int value = 2 ;
     };

  }

}}}

#endif


/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#include <libint2/initialize.h>
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE cubefilewriter_test

// Third party includes
#include <boost/test/unit_test.hpp>

// VOTCA includes
#include <votca/tools/getline.h>
#include <votca/tools/tokenizer.h>

// Local VOTCA includes
#include "votca/tools/eigenio_matrixmarket.h"
#include "votca/xtp/cubefile_writer.h"

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(cubefilewriter_test)

Eigen::VectorXd Readcubefile(const std::string& filename) {

  std::ifstream in1;
  in1.open(filename, std::ios::in);

  std::string result = "";
  std::string s;
  votca::tools::getline(in1, s);
  votca::tools::getline(in1, s);
  votca::tools::getline(in1, s);
  std::vector<double> cube_values;
  do {
    std::vector<double> values =
        votca::tools::Tokenizer(s, " ").ToVector<double>();
    cube_values.insert(cube_values.end(), values.begin(), values.end());
  } while (votca::tools::getline(in1, s));
  return Eigen::Map<Eigen::VectorXd>(cube_values.data(), cube_values.size());
}

BOOST_AUTO_TEST_CASE(constructors_test) {
  libint2::initialize();
  Orbitals A;
  A.setDFTbasisName(std::string(XTP_TEST_DATA_FOLDER) +
                    "/cubefile_writer/3-21G.xml");
  A.QMAtoms().LoadFromFile(std::string(XTP_TEST_DATA_FOLDER) +
                           "/cubefile_writer/molecule.xyz");
  A.setBasisSetSize(17);
  A.setNumberOfAlphaElectrons(5);
  A.setNumberOfOccupiedLevels(5);
  A.MOs().eigenvalues() = Eigen::VectorXd::Zero(17);
  A.MOs().eigenvalues() << -19.8117, -6.22408, -6.14094, -6.14094, -6.14094,
      -3.72889, -3.72889, -3.72889, -3.64731, -3.09048, -3.09048, -3.09048,
      -2.63214, -2.08206, -2.08206, -2.08206, -2.03268;

  A.MOs().eigenvectors() = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/cubefile_writer/A_MOs.mm");

  A.setBSEindices(0, 16);
  A.setTDAApprox(true);
  A.setGWindices(0, 16);
  Eigen::MatrixXd spsi_ref = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/cubefile_writer/spsi_ref.mm");

  A.BSESinglets().eigenvectors() = spsi_ref;

  Eigen::Array<votca::Index, 3, 1> steps(3, 4, 7);
  Logger log;
  double padding = 0.5;
  CubeFile_Writer writer(steps, padding, log);
  QMState state("s1");
  writer.WriteFile("test_writer.cube", A, state, false);

  auto result1 = Readcubefile("test_writer.cube");

  Eigen::VectorXd values_ref1 = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/cubefile_writer/values_ref1.mm");

  BOOST_CHECK_EQUAL(values_ref1.size(), result1.size());

  bool check_ref1 = values_ref1.isApprox(result1, 1e-4);
  BOOST_CHECK_EQUAL(check_ref1, true);
  if (!check_ref1) {
    std::cout << "ref" << std::endl;
    std::cout << values_ref1.transpose() << std::endl;
    std::cout << "result" << std::endl;
    std::cout << result1.transpose() << std::endl;
  }

  writer.WriteFile("test_writer2.cube", A, state, true);

  auto result2 = Readcubefile("test_writer2.cube");

  Eigen::VectorXd values_ref2 = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/cubefile_writer/values_ref2.mm");

  bool check_ref2 = values_ref2.isApprox(result2, 1e-4);
  BOOST_CHECK_EQUAL(values_ref2.size(), result2.size());
  BOOST_CHECK_EQUAL(check_ref2, true);
  if (!check_ref2) {
    std::cout << "ref" << std::endl;
    std::cout << values_ref2.transpose() << std::endl;
    std::cout << "result" << std::endl;
    std::cout << result2.transpose() << std::endl;
  }

  Eigen::Array<votca::Index, 3, 1> steps2(3, 4, 8);
  Logger log2;
  double padding2 = 0.75;
  CubeFile_Writer writer2(steps2, padding2, log2);

  QMState state2("ks5");
  writer2.WriteFile("test_writer3.cube", A, state2, false);

  auto result3 = Readcubefile("test_writer3.cube");

  Eigen::VectorXd values_ref3 = votca::tools::EigenIO_MatrixMarket::ReadMatrix(
      std::string(XTP_TEST_DATA_FOLDER) + "/cubefile_writer/values_ref3.mm");

  BOOST_CHECK_EQUAL(values_ref3.size(), result3.size());
  bool check_ref3 = values_ref3.isApprox(result3, 1e-4);
  BOOST_CHECK_EQUAL(check_ref3, true);
  if (!check_ref3) {
    std::cout << "ref" << std::endl;
    std::cout << values_ref3.transpose() << std::endl;
    std::cout << "result" << std::endl;
    std::cout << result3.transpose() << std::endl;
  }

  libint2::finalize();
}

BOOST_AUTO_TEST_SUITE_END()


// Author(s): Wieger Wesselink
// Copyright: see the accompanying file COPYING or copy at
// https://svn.win.tue.nl/trac/MCRL2/browser/trunk/COPYING
//
// 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)
//
/// \file abstract_test.cpp
/// \brief Test the pbes abstract algorithm.

#include <string>
#include <iostream>
#include <boost/test/minimal.hpp>
#include "mcrl2/pbes/abstract.h"
#include "mcrl2/pbes/txt2pbes.h"
#include "mcrl2/pbes/detail/pbes_parameter_map.h"

using namespace mcrl2;
using namespace mcrl2::pbes_system;

void test_pbesabstract(const std::string& pbes_spec, const std::string& variable_spec, bool value_true)
{
  pbes p = txt2pbes(pbes_spec);
  pbes_system::detail::pbes_parameter_map parameter_map = pbes_system::detail::parse_pbes_parameter_map(p, variable_spec);
  pbes_abstract_algorithm algorithm;
  algorithm.run(p, parameter_map, value_true);
  std::cout << "\n-------------------------------\n" << pbes_system::pp(p) << std::endl;
}

void test_pbesabstract()
{
  test_pbesabstract(
    "pbes nu X(a: Bool, b: Nat) =  \n"
    "       val(a) || X(a, b + 1); \n"
    "                              \n"
    "init X(true, 0);              \n"
    ,
    "X(b:Nat)"
    ,
    true
  );

  test_pbesabstract(
    "pbes nu X1(b:Bool) = exists b:Bool.(X2 || val(b)); \n"
    "     mu X2 = X2;                                   \n"
    "                                                   \n"
    "init X1(true);                                     \n"
    ,
    "X1(b:Bool)"
    ,
    true
  );

  test_pbesabstract(
    "pbes nu X1(b:Bool) = X2 || val(b); \n"
    "     mu X2 = X2;                   \n"
    "                                   \n"
    "init X1(true);                     \n"
    ,
    "X1(b:Bool)"
    ,
    true
  );
}

int test_main(int argc, char** argv)
{
  test_pbesabstract();

  return 0;
}


/*
 * BikeInfo.hpp
 *
 *  Created on: 18.02.2019
 *      Author: tomlucas
 */

#ifndef SIXDAYS_BIKEINFO_HPP_
#define SIXDAYS_BIKEINFO_HPP_

#include <Eigen/Core>
namespace zavi::sixdays{
	struct BikeInfo{
		Eigen::Vector3d imu_to_front, imu_to_back;

		Eigen::Vector3d imuToFront(){
			return imu_to_front;
		}
		Eigen::Vector3d imuToBack(){
			return imu_to_back;
		}
	};
}

#endif /* SIXDAYS_BIKEINFO_HPP_ */


/**
@file

Copyright John Reid 2006, 2007, 2013
*/

#include "bio_test_defs.h"
#include "bio_test_data.h"

#include <bio/biobase_likelihoods.h>
#include <bio/pssm_match.h>
#include <bio/biobase_db.h>
#include <bio/biobase_filter.h>
#include <bio/biobase_data_traits.h>
#include <bio/serialisable.h>
USING_BIO_NS;

#include <boost/progress.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/assign/list_of.hpp>
using namespace boost;
using boost::unit_test::test_suite;

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

#ifdef _DEBUG
#define TEST_SEQ_LENGTH 100
#else
#define TEST_SEQ_LENGTH 10000
#endif

//#define VERBOSE_CHECKING

BOOST_TEST_DONT_PRINT_LOG_VALUE( LikelihoodsCache )

void check_likelihoods_cache()
{
	cout << "******* check_likelihoods_cache()" << endl;

	//create a random sequence
	const size_t test_seq_length = TEST_SEQ_LENGTH;
	seq_t test_seq;
	test_seq.reserve(test_seq_length);
	generate_random_nucleotide_seq(inserter(test_seq, test_seq.begin()), test_seq_length);

	LikelihoodsCache cache;
	{
#ifdef VERBOSE_CHECKING
		cout << "Updating counts" << endl;
		progress_timer timer;
#endif //VERBOSE_CHECKING

		BiobaseDb::singleton();

		cache.update_counts(BiobaseDb::singleton(), test_seq);
	}

	{
#ifdef VERBOSE_CHECKING
		cout << "Serialising cache" << endl;
		progress_timer timer;
#endif //VERBOSE_CHECKING

		serialise< false >( cache, "cache.txt" );
	}

	LikelihoodsCache copy_of_cache;
	{
#ifdef VERBOSE_CHECKING
		cout << "Deserialising cache" << endl;
		progress_timer timer;
#endif //VERBOSE_CHECKING

		deserialise< false >( copy_of_cache, "cache.txt" );
	}
	BOOST_CHECK_EQUAL(cache, copy_of_cache);

	boost::io::ios_precision_saver ips(cout);
	cout.precision(3);

	boost::io::ios_width_saver iws(cout);
	cout.width(8);

	const vector< TableLink > pssms = boost::assign::list_of
		( TableLink( SITE_DATA, 2195 ) )
		( TableLink( MATRIX_DATA, 201 ) )
		( TableLink( MATRIX_DATA, 128 ) )
		( TableLink( MATRIX_DATA, 209 ) )
		//("AG$CONS_02")
		;

	for (vector< TableLink >::const_iterator n = pssms.begin(); pssms.end() != n; ++n)
	{
		const BiobaseCounts * counts = cache.get_counts(*n);

#ifdef VERBOSE_CHECKING
		copy(counts->begin(), counts->end(), ostream_iterator<size_t>(cout, ", ")); cout << endl;
#endif //VERBOSE_CHECKING

		for (int i = 0; i < 2; ++i)
		{
			const bool background = i > 0;
			for (int j = 0; j < 2; ++j)
			{
				const bool or_better = j > 0;
				const BiobaseLikelihoods * likelihoods = cache.get_score_likelihoods(*n, background, or_better);

#ifdef VERBOSE_CHECKING
				cout
					<< *n << " "
					<< (background ? "background " : "binding ")
					<< (or_better ? "or better " : "exact ")
					<< "likelihoods"
					<< endl;
				copy(likelihoods->begin(), likelihoods->end(), ostream_iterator<BIO_NS::float_t>(cout, ", ")); cout << endl;
				cout << endl;
#endif //VERBOSE_CHECKING
			}
		}
	}
}

void check_or_better_likelihoods_bug()
{
	cout << "******* check_or_better_likelihoods_bug()" << endl;

	//const seq_t seq =
	//	"GCTCTCGCTCTTTTTTTTTTTCGCAAAAGGAGGGGAGAGGGGGTAAAAAAATGCTGCACTGTGCGGCGAAGCCGGTGAGTGAGCGGCGC"
	//	"GGGGCCAATCAGCGTGCGCCGTTCCGAAAGTTGCCTTTTATGGCTCGAGCGGCCGCGGCGGCGCCCTATAAAACCCAGCGGCGCGACGCGC"
	//	;

	const seq_t seq =
		"CCCTATAAAACCCAGCG"
		;

	Scorers scorers( seq.begin(), seq.end() );
	hit_vec_t hits;
	Matrix * pssm_M00320 = BiobaseDb::singleton().get_entry< MATRIX_DATA >( 320 );

	scorers.bayesian_or_better_calc(
		*pssm_M00320,
		std::back_inserter( hits ) );
}

struct check_likelihoods
{
	void operator()( BIO_NS::float_t likelihood ) const
	{
		BOOST_CHECK( likelihood >= BIO_NS::float_t( 0.0 ) );
		BOOST_CHECK( likelihood <= BIO_NS::float_t( 1.0 ) );

		if ( likelihood > BIO_NS::float_t( 1.0 ) )
		{
			cout << "Problem\n";
		}
	}

	void operator()( const BiobaseLikelihoods * likelihoods ) const
	{
		if ( 0 != likelihoods )
		{
			std::for_each(
				likelihoods->begin(),
				likelihoods->end(),
				*this );
		}
	}

	void operator()( const TableLink & pssm ) const
	{
		( *this )(
			LikelihoodsCache::singleton().get_score_likelihoods(
				pssm,
				false,
				false) );

		( *this )(
			LikelihoodsCache::singleton().get_score_likelihoods(
				pssm,
				false,
				true) );

		( *this )(
			LikelihoodsCache::singleton().get_score_likelihoods(
				pssm,
				true,
				false) );

		( *this )(
			LikelihoodsCache::singleton().get_score_likelihoods(
				pssm,
				true,
				true) );
	}

	template< typename MapValue >
	void operator()( const MapValue & pssm ) const
	{
		( *this )( pssm.first );
	}
};

void check_all_likelihoods()
{
	cout << "******* check_all_likelihoods()" << endl;

	//check_likelihoods()( std::string( "HOX13$CONS_02" ) ); //problem with pssm_likelihoods

	//check each site
	std::for_each(
		get_sites_begin(),
		get_sites_end(),
		check_likelihoods() );

	//check each matrix
	std::for_each(
		get_matrices_begin(),
		get_matrices_end(),
		check_likelihoods() );

}

void register_biobase_likelihoods_tests(test_suite * test)
{
	ensure_biobase_params_built();

	test->add(BOOST_TEST_CASE(&check_all_likelihoods), 0);
	test->add(BOOST_TEST_CASE(&check_likelihoods_cache), 0);
	test->add(BOOST_TEST_CASE(&check_or_better_likelihoods_bug), 0);
}

//
// Are we going to compile this test into its own executable?
//
#ifdef BIO_STANDALONE_TEST
BIO_DEFINE_STANDALONE_TEST( "biobase likeilhoods", register_biobase_likelihoods_tests )
#endif //BIO_STANDALONE_TEST


// Copyright (C) 2006-2009 Dmitry Bufistov and Andrey Parfenov

// 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_GRAPH_CYCLE_RATIO_HOWARD_HPP
#define BOOST_GRAPH_CYCLE_RATIO_HOWARD_HPP

#include <vector>
#include <list>
#include <algorithm>
#include <limits>

#include <boost/bind.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/concept_check.hpp>
#include <boost/pending/queue.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>

/** @file howard_cycle_ratio.hpp
 * @brief The implementation of the maximum/minimum cycle ratio/mean algorithm.
 * @author Dmitry Bufistov
 * @author Andrey Parfenov
 */

namespace boost {

  /**
   * The mcr_float is like numeric_limits, but only for floating point types
   * and only defines infinity() and epsilon(). This class is primarily used
   * to encapsulate a less-precise epsilon than natively supported by the
   * floating point type.
   */
  template <typename Float = double> struct mcr_float {
    typedef Float value_type;

    static Float infinity()
    { return std::numeric_limits<value_type>::infinity(); }

    static Float epsilon()
    { return Float(-0.005); }
  };

  namespace detail {

    template <typename FloatTraits> struct
    min_comparator_props {
      typedef std::greater<typename FloatTraits::value_type> comparator;
      static const int multiplier = 1;
    };

    template <typename FloatTraits> struct
    max_comparator_props {
      typedef std::less<typename FloatTraits::value_type> comparator;
      static const int multiplier = -1;
    };

    template <typename FloatTraits, typename ComparatorProps>
    struct float_wrapper {
      typedef typename FloatTraits::value_type value_type;
      typedef ComparatorProps comparator_props_t;
      typedef typename ComparatorProps::comparator comparator;

      static value_type infinity()
      { return FloatTraits::infinity() * ComparatorProps::multiplier; }

      static value_type epsilon()
      { return FloatTraits::epsilon() * ComparatorProps::multiplier; }

    };

    /*! @class mcr_howard
     * @brief Calculates optimum (maximum/minimum) cycle ratio of a directed graph.
     * Uses  Howard's iteration policy algorithm. </br>(It is described in the paper
     * "Experimental Analysis of the Fastest Optimum Cycle Ratio and Mean Algorithm"
     * by Ali Dasdan).
     */
    template <typename FloatTraits,
              typename Graph, typename VertexIndexMap,
              typename EdgeWeight1, typename EdgeWeight2>
    class mcr_howard
    {
    public:
      typedef typename FloatTraits::value_type float_t;
      typedef typename FloatTraits::comparator_props_t cmp_props_t;
      typedef typename FloatTraits::comparator comparator_t;
      typedef enum{ my_white = 0, my_black } my_color_type;
      typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
      typedef typename graph_traits<Graph>::edge_descriptor edge_t;
      typedef typename graph_traits<Graph>::vertices_size_type vn_t;
      typedef std::vector<float_t> vp_t;
      typedef typename boost::iterator_property_map<
        typename vp_t::iterator, VertexIndexMap
      > distance_map_t; //V -> float_t

      typedef typename std::vector<edge_t> ve_t;
      typedef std::vector<my_color_type> vcol_t;
      typedef typename ::boost::iterator_property_map<
        typename ve_t::iterator, VertexIndexMap
      > policy_t; //Vertex -> Edge
      typedef typename ::boost::iterator_property_map<
        typename vcol_t::iterator, VertexIndexMap
      > color_map_t;

      typedef typename std::list<vertex_t> pinel_t;// The in_edges list of the policy graph
      typedef typename std::vector<pinel_t> inedges1_t;
      typedef typename ::boost::iterator_property_map<
        typename inedges1_t::iterator, VertexIndexMap
      > inedges_t;
      typedef typename std::vector<edge_t> critical_cycle_t;

      //Bad  vertex flag. If true, then the vertex is "bad".
      // Vertex is "bad" if its out_degree is equal to zero.
      typedef typename boost::iterator_property_map<
        std::vector<int>::iterator, VertexIndexMap
      > badv_t;

      /*!
       * Constructor
       * \param g = (V, E) - a directed multigraph.
       * \param vim  Vertex Index Map. Read property Map: V -> [0, num_vertices(g)).
       * \param ewm  edge weight map. Read property map: E -> R
       * \param ew2m  edge weight map. Read property map: E -> R+
       * \param infty A big enough value to guaranty that there exist a cycle with
       *  better ratio.
       * \param cmp The compare operator for float_ts.
       */
      mcr_howard(const Graph &g, VertexIndexMap vim,
                  EdgeWeight1 ewm, EdgeWeight2 ew2m) :
        m_g(g), m_vim(vim), m_ew1m(ewm), m_ew2m(ew2m),
        m_bound(mcr_bound()),
        m_cr(m_bound),
        m_V(num_vertices(m_g)),
        m_dis(m_V, 0), m_dm(m_dis.begin(), m_vim),
        m_policyc(m_V), m_policy(m_policyc.begin(), m_vim),
        m_inelc(m_V), m_inel(m_inelc.begin(), m_vim),
        m_badvc(m_V, false), m_badv(m_badvc.begin(), m_vim),
        m_colcv(m_V),
        m_col_bfs(m_V)
      { }

      /*!
       * \return maximum/minimum_{for all cycles C}
       *         [sum_{e in C} w1(e)] / [sum_{e in C} w2(e)],
       * or FloatTraits::infinity() if graph has no cycles.
       */
      float_t ocr_howard()
      {
        construct_policy_graph();
        int k = 0;
        float_t mcr = 0;
        do
          {
            mcr = policy_mcr();
            ++k;
          }
        while (try_improve_policy(mcr) && k < 100); //To avoid infinite loop

        const float_t eps_ =  -0.00000001 * cmp_props_t::multiplier;
        if (m_cmp(mcr, m_bound + eps_))
          {
            return FloatTraits::infinity();
          }
        else
          {
            return  mcr;
          }
      }
      virtual ~mcr_howard() {}

    protected:
      virtual void store_critical_edge(edge_t ed, critical_cycle_t &cc) {}
      virtual void store_critical_cycle(critical_cycle_t &cc) {}

    private:
      /*!
       * \return lower/upper bound for the maximal/minimal cycle ratio
       */
      float_t mcr_bound()
      {
        typename  graph_traits<Graph>::vertex_iterator  vi, vie;
        typename  graph_traits<Graph>::out_edge_iterator  oei, oeie;
        float_t cz = (std::numeric_limits<float_t>::max)(); //Closest to zero value
        float_t s = 0;
        const float_t eps_ = std::numeric_limits<float_t>::epsilon();
        for (tie(vi, vie) = vertices(m_g); vi != vie; ++vi)
          {
            for (tie(oei, oeie) = out_edges(*vi, m_g); oei != oeie; ++oei)
              {
                s += std::abs(m_ew1m[*oei]);
                float_t a = std::abs(m_ew2m[*oei]);
                if ( a > eps_ && a < cz)
                {
                  cz = a;
                }
              }
          }
        return  cmp_props_t::multiplier * (s / cz);
      }

      /*!
       *  Constructs an arbitrary policy graph.
       */
      void construct_policy_graph()
      {
        m_sink = graph_traits<Graph>().null_vertex();
        typename  graph_traits<Graph>::vertex_iterator  vi, vie;
        typename  graph_traits<Graph>::out_edge_iterator  oei, oeie;
        for ( tie(vi, vie) = vertices(m_g); vi != vie; ++vi )
          {
            tie(oei, oeie) = out_edges(*vi, m_g);
            typename graph_traits<Graph>::out_edge_iterator mei =
              std::max_element(oei, oeie,
                               bind(m_cmp,
                                    bind(&EdgeWeight1::operator[], m_ew1m, _1),
                                    bind(&EdgeWeight1::operator[], m_ew1m, _2)
                                    )
                               );
            if (mei == oeie)
              {
                if (m_sink == graph_traits<Graph>().null_vertex())
                  {
                    m_sink = *vi;
                  }
                m_badv[*vi] = true;
                m_inel[m_sink].push_back(*vi);
              }
            else
              {
                m_inel[target(*mei, m_g)].push_back(*vi);
                m_policy[*vi] = *mei;
              }
          }
      }
      /*! Sets the distance value for all vertices "v" such that there is
       * a path from "v" to "sv". It does "inverse" breadth first visit of the policy
       * graph, starting from the vertex "sv".
       */
      void mcr_bfv(vertex_t sv, float_t cr, color_map_t c)
      {
        boost::queue<vertex_t> Q;
        c[sv] = my_black;
        Q.push(sv);
        while (!Q.empty())
          {
            vertex_t v = Q.top(); Q.pop();
            for (typename pinel_t::const_iterator itr = m_inel[v].begin();
                 itr != m_inel[v].end(); ++itr)
              //For all in_edges of the policy graph
              {
                if (*itr != sv)
                  {
                    if (m_badv[*itr])
                      {
                        m_dm[*itr] = m_dm[v] + m_bound - cr;
                      }
                    else
                      {
                        m_dm[*itr] = m_dm[v] + m_ew1m[m_policy[*itr]] -
                          m_ew2m[m_policy[*itr]] * cr;
                      }
                    c[*itr] = my_black;
                    Q.push(*itr);
                  }
              }
          }
      }

      /*!
       * \param sv an arbitrary (undiscovered) vertex of the policy graph.
       * \return a vertex in the policy graph that belongs to a cycle.
       * Performs a depth first visit until a cycle edge is found.
       */
      vertex_t find_cycle_vertex(vertex_t sv)
      {
        vertex_t gv = sv;
        std::fill(m_colcv.begin(), m_colcv.end(), my_white);
        color_map_t cm(m_colcv.begin(), m_vim);
        do
          {
            cm[gv] = my_black;
            if (! m_badv[gv])
              {
                gv = target(m_policy[gv], m_g);
              }
            else
              {
                gv = m_sink;
              }
          }
        while (cm[gv] != my_black);
        return gv;
      }

      /*!
       * \param sv - vertex that belongs to a cycle in the policy graph.
       */
      float_t cycle_ratio(vertex_t sv)
      {
        if (sv == m_sink) return m_bound;
        std::pair<float_t, float_t> sums_(float_t(0), float_t(0));
        vertex_t v = sv;
        critical_cycle_t cc;
        do
          {
            store_critical_edge(m_policy[v], cc);
            sums_.first += m_ew1m[m_policy[v]];
            sums_.second += m_ew2m[m_policy[v]];
            v = target(m_policy[v], m_g);
          }
        while (v != sv);
        float_t cr = sums_.first / sums_.second;
        if ( m_cmp(m_cr, cr) )
          {
            m_cr = cr;
            store_critical_cycle(cc);
          }
        return cr;
      }

      /*!
       *  Finds the optimal cycle ratio of the policy graph
       */
      float_t policy_mcr()
      {
        std::fill(m_col_bfs.begin(), m_col_bfs.end(), my_white);
        color_map_t vcm_ = color_map_t(m_col_bfs.begin(), m_vim);
        typename graph_traits<Graph>::vertex_iterator uv_itr, vie;
        tie(uv_itr, vie) = vertices(m_g);
        float_t mcr = m_bound;
        while ( (uv_itr = std::find_if(uv_itr, vie,
                                       bind(std::equal_to<my_color_type>(),
                                            my_white,
                                            bind(&color_map_t::operator[], vcm_, _1)
                                            )
                                       )
                 ) != vie )
          ///While there are undiscovered vertices
          {
            vertex_t gv = find_cycle_vertex(*uv_itr);
            float_t cr = cycle_ratio(gv) ;
            mcr_bfv(gv, cr, vcm_);
            if ( m_cmp(mcr, cr) )  mcr = cr;
            ++uv_itr;
          }
        return mcr;
      }

      /*!
       * Changes the edge m_policy[s] to the new_edge.
       */
      void improve_policy(vertex_t s, edge_t new_edge)
      {
        vertex_t t = target(m_policy[s], m_g);
        typename property_traits<VertexIndexMap>::value_type ti = m_vim[t];
        m_inelc[ti].erase( std::find(m_inelc[ti].begin(), m_inelc[ti].end(), s));
        m_policy[s] = new_edge;
        t = target(new_edge, m_g);
        m_inel[t].push_back(s); ///Maintain in_edge list
      }

      /*!
       * A negative cycle detector.
       */
      bool try_improve_policy(float_t cr)
      {
        bool improved = false;
        typename  graph_traits<Graph>::vertex_iterator  vi, vie;
        typename  graph_traits<Graph>::out_edge_iterator  oei, oeie;
        const float_t eps_ =  FloatTraits::epsilon();
        for (tie(vi, vie) = vertices(m_g); vi != vie; ++vi)
          {
            if (!m_badv[*vi])
              {
                for (tie(oei, oeie) = out_edges(*vi, m_g); oei != oeie; ++oei)
                  {
                    vertex_t t = target(*oei, m_g);
                    //Current distance from *vi to some vertex
                    float_t dis_ = m_ew1m[*oei] - m_ew2m[*oei] * cr + m_dm[t];
                    if ( m_cmp(m_dm[*vi] + eps_, dis_) )
                      {
                        improve_policy(*vi, *oei);
                        m_dm[*vi] = dis_;
                        improved = true;
                      }
                  }
              }
            else
              {
                float_t dis_ = m_bound - cr + m_dm[m_sink];
                if ( m_cmp(m_dm[*vi] + eps_, dis_) )
                  {
                    m_dm[*vi] = dis_;
                  }
              }
          }
        return improved;
      }
    private:
      const Graph &m_g;
      VertexIndexMap m_vim;
      EdgeWeight1 m_ew1m;
      EdgeWeight2 m_ew2m;
      comparator_t m_cmp;
      float_t m_bound; //> The lower/upper bound to the maximal/minimal cycle ratio
      float_t m_cr; //>The best cycle ratio that has been found so far

      vn_t m_V; //>The number of the vertices in the graph
      vp_t m_dis; //>Container for the distance map
      distance_map_t m_dm; //>Distance map

      ve_t m_policyc; //>Container for the policy graph
      policy_t m_policy; //>The interface for the policy graph

      inedges1_t m_inelc; //>Container fot in edges list
      inedges_t m_inel; //>Policy graph, input edges list

      std::vector<int> m_badvc;
      badv_t m_badv; //Marks "bad" vertices

      vcol_t m_colcv, m_col_bfs; //Color maps
      vertex_t m_sink; //To convert any graph to "good"
    };

    /*! \class mcr_howard1
  * \brief Finds optimum cycle raio and a critical cycle
     */
    template <typename FloatTraits,
              typename Graph, typename VertexIndexMap,
              typename EdgeWeight1, typename EdgeWeight2>
    class mcr_howard1  : public
    mcr_howard<FloatTraits, Graph, VertexIndexMap,
               EdgeWeight1, EdgeWeight2>
    {
    public:
      typedef mcr_howard<FloatTraits, Graph, VertexIndexMap,
        EdgeWeight1, EdgeWeight2> inhr_t;
      mcr_howard1(const Graph &g, VertexIndexMap vim,
        EdgeWeight1 ewm, EdgeWeight2 ew2m) :
        inhr_t(g, vim, ewm, ew2m)
      { }

      void get_critical_cycle(typename inhr_t::critical_cycle_t &cc)
      { return cc.swap(m_cc); }

    protected:
      void store_critical_edge(typename inhr_t::edge_t ed,
        typename inhr_t::critical_cycle_t &cc)
      { cc.push_back(ed); }

      void store_critical_cycle(typename inhr_t::critical_cycle_t &cc)
      { m_cc.swap(cc); }

    private:
      typename inhr_t::critical_cycle_t m_cc; //Critical cycle
    };

    /*!
     * \param g a directed multigraph.
     * \param vim Vertex Index Map. A map V->[0, num_vertices(g))
     * \param ewm Edge weight1 map.
     * \param ew2m Edge weight2 map.
     * \param pcc  pointer to the critical edges list.
     * \return Optimum cycle ratio of g or FloatTraits::infinity() if g has no cycles.
     */
    template <typename FT,
              typename TG, typename TVIM,
              typename TEW1, typename TEW2,
              typename EV>
    typename FT::value_type
 optimum_cycle_ratio(const TG &g, TVIM vim, TEW1 ewm, TEW2 ew2m, EV* pcc)
    {
      typedef typename graph_traits<TG>::directed_category DirCat;
      BOOST_STATIC_ASSERT((is_convertible<DirCat*, directed_tag*>::value == true));
      function_requires< IncidenceGraphConcept<TG> >();
      function_requires< VertexListGraphConcept<TG> >();
      typedef typename graph_traits<TG>::vertex_descriptor Vertex;
      function_requires< ReadablePropertyMapConcept<TVIM, Vertex> >();
      typedef typename graph_traits<TG>::edge_descriptor Edge;
      function_requires< ReadablePropertyMapConcept<TEW1, Edge> >();
      function_requires< ReadablePropertyMapConcept<TEW2, Edge> >();

      if(pcc == 0) {
          return detail::mcr_howard<FT,TG, TVIM, TEW1, TEW2>(
            g, vim, ewm, ew2m
          ).ocr_howard();
      }

      detail::mcr_howard1<FT, TG, TVIM, TEW1, TEW2> obj(g, vim, ewm, ew2m);
      double ocr = obj.ocr_howard();
      obj.get_critical_cycle(*pcc);
      return ocr;
    }
  } // namespace detail

// Algorithms
// Maximum Cycle Ratio

template <
    typename FloatTraits,
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeight1Map,
    typename EdgeWeight2Map>
inline typename FloatTraits::value_type
maximum_cycle_ratio(const Graph &g, VertexIndexMap vim, EdgeWeight1Map ew1m,
                    EdgeWeight2Map ew2m,
                    std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0,
                    FloatTraits = FloatTraits())
{
    typedef detail::float_wrapper<
        FloatTraits, detail::max_comparator_props<FloatTraits>
    > Traits;
    return detail::optimum_cycle_ratio<Traits>(g, vim, ew1m, ew2m, pcc);
}

template <
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeight1Map,
    typename EdgeWeight2Map>
inline double
maximum_cycle_ratio(const Graph &g, VertexIndexMap vim,
                    EdgeWeight1Map ew1m, EdgeWeight2Map ew2m,
                    std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0)
{ return maximum_cycle_ratio(g, vim, ew1m, ew2m, pcc, mcr_float<>()); }

// Minimum Cycle Ratio

template <
    typename FloatTraits,
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeight1Map,
    typename EdgeWeight2Map>
typename FloatTraits::value_type
minimum_cycle_ratio(const Graph &g, VertexIndexMap vim,
                    EdgeWeight1Map ew1m, EdgeWeight2Map ew2m,
                    std::vector<typename graph_traits<Graph>::edge_descriptor> *pcc = 0,
                    FloatTraits = FloatTraits())
{
    typedef detail::float_wrapper<
        FloatTraits, detail::min_comparator_props<FloatTraits>
    > Traits;
    return detail::optimum_cycle_ratio<Traits>(g, vim, ew1m, ew2m, pcc);
}

template <
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeight1Map,
    typename EdgeWeight2Map>
inline double
minimum_cycle_ratio(const Graph &g, VertexIndexMap vim,
                    EdgeWeight1Map ew1m, EdgeWeight2Map ew2m,
                    std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0)
{ return minimum_cycle_ratio(g, vim, ew1m, ew2m, pcc, mcr_float<>()); }

// Maximum Cycle Mean

template <
    typename FloatTraits,
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeightMap,
    typename EdgeIndexMap>
inline typename FloatTraits::value_type
maximum_cycle_mean(const Graph &g, VertexIndexMap vim,
                   EdgeWeightMap ewm, EdgeIndexMap eim,
                   std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0,
                   FloatTraits ft = FloatTraits())
{
    typedef typename remove_const<
        typename property_traits<EdgeWeightMap>::value_type
    >::type Weight;
    typename std::vector<Weight> ed_w2(boost::num_edges(g), 1);
    return maximum_cycle_ratio(g, vim, ewm,
                               make_iterator_property_map(ed_w2.begin(), eim),
                               pcc, ft);
}

template <
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeightMap,
    typename EdgeIndexMap>
inline double
maximum_cycle_mean(const Graph& g, VertexIndexMap vim,
                   EdgeWeightMap ewm, EdgeIndexMap eim,
                   std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0)
{ return maximum_cycle_mean(g, vim, ewm, eim, pcc, mcr_float<>()); }

// Minimum Cycle Mean

template <
    typename FloatTraits,
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeightMap,
    typename EdgeIndexMap>
inline typename FloatTraits::value_type
minimum_cycle_mean(const Graph &g, VertexIndexMap vim,
                   EdgeWeightMap ewm, EdgeIndexMap eim,
                   std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0,
                   FloatTraits ft = FloatTraits())
{
    typedef typename remove_const<
        typename property_traits<EdgeWeightMap>::value_type
    >::type Weight;
    typename std::vector<Weight> ed_w2(boost::num_edges(g), 1);
    return minimum_cycle_ratio(g, vim, ewm,
                               make_iterator_property_map(ed_w2.begin(), eim),
                               pcc, ft);
}

template <
    typename Graph,
    typename VertexIndexMap,
    typename EdgeWeightMap,
    typename EdgeIndexMap>
inline double
minimum_cycle_mean(const Graph &g, VertexIndexMap vim,
                   EdgeWeightMap ewm, EdgeIndexMap eim,
                   std::vector<typename graph_traits<Graph>::edge_descriptor>* pcc = 0)
{ return minimum_cycle_mean(g, vim, ewm, eim, pcc, mcr_float<>()); }

} //namespace boost

#endif


//
// Copyright (c) 2009 Rutger ter Borg
//
// 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_NUMERIC_BINDINGS_UBLAS_SYMMETRIC_HPP
#define BOOST_NUMERIC_BINDINGS_UBLAS_SYMMETRIC_HPP

#include <boost/numeric/bindings/begin.hpp>
#include <boost/numeric/bindings/detail/adaptor.hpp>
#include <boost/numeric/bindings/end.hpp>
#include <boost/numeric/bindings/ublas/detail/convert_to.hpp>
#include <boost/numeric/bindings/ublas/detail/basic_ublas_adaptor.hpp>
#include <boost/numeric/bindings/ublas/matrix.hpp>
#include <boost/numeric/bindings/ublas/triangular.hpp>
#include <boost/numeric/bindings/value_type.hpp>
#include <boost/numeric/ublas/symmetric.hpp>

namespace boost {
namespace numeric {
namespace bindings {
namespace detail {

template< typename T, typename F1, typename F2, typename A, typename Id, typename Enable >
struct adaptor< ublas::symmetric_matrix< T, F1, F2, A >, Id, Enable > {

    typedef typename copy_const< Id, T >::type value_type;
    typedef mpl::map<
        mpl::pair< tag::value_type, value_type >,
        mpl::pair< tag::entity, tag::matrix >,
        mpl::pair< tag::size_type<1>, std::ptrdiff_t >,
        mpl::pair< tag::size_type<2>, std::ptrdiff_t >,
        mpl::pair< tag::matrix_type, tag::symmetric >,
        mpl::pair< tag::data_structure, tag::triangular_array >,
        mpl::pair< tag::data_side, typename convert_to< tag::data_side, F1 >::type >,
        mpl::pair< tag::data_order, typename convert_to< tag::data_order, F2 >::type >
    > property_map;

    static std::ptrdiff_t size1( const Id& t ) {
        return t.size1();
    }

    static std::ptrdiff_t size2( const Id& t ) {
        return t.size2();
    }

    static value_type* begin_value( Id& t ) {
        return bindings::begin_value( t.data() );
    }

    static value_type* end_value( Id& t ) {
        return bindings::end_value( t.data() );
    }

};

template< typename T, typename F, typename Id, typename Enable >
struct adaptor< ublas::symmetric_adaptor< T, F >, Id, Enable >:
    basic_ublas_adaptor<
        T,
        Id,
        mpl::pair< tag::matrix_type, tag::symmetric >,
        mpl::pair< tag::data_side, typename convert_to< tag::data_side, F >::type >
    > {

    typedef typename convert_to< tag::data_side, F >::type data_side;

    static std::ptrdiff_t bandwidth1( const Id& id ) {
        return bindings::bandwidth( id.data(), data_side() );
    }

    static std::ptrdiff_t bandwidth2( const Id& id ) {
        return bindings::bandwidth( id.data(), data_side() );
    }

};

} // namespace detail
} // namespace bindings
} // namespace numeric
} // namespace boost

#endif


//
// Created by joshua on 8/30/17.
//

#include <mps/planner/ompl/state/SimEnvWorldStateDistanceMeasure.h>
#include <boost/format.hpp>
#include <mps/planner/util/Logging.h>

using namespace mps::planner::ompl::state;
namespace mps_logging = mps::planner::util::logging;

SimEnvWorldStateDistanceMeasure::SimEnvWorldStateDistanceMeasure(ompl::state::SimEnvWorldStateSpacePtr state_space,
                                                       const std::vector<float> &weights):
    _weak_state_space(state_space),
    _weights(weights)
{
    _active_flags = std::vector<bool>(state_space->getNumObjects(), true);
    if (_weights.size() == 0) {
        _weights.resize(_active_flags.size(), 1.0f);
    }
}

SimEnvWorldStateDistanceMeasure::~SimEnvWorldStateDistanceMeasure() = default;

void SimEnvWorldStateDistanceMeasure::setWeights(const std::vector<float> &weights) {
    if (weights.size() == _weights.size()) {
        _weights = weights;
    } else {
        mps::planner::util::logging::logErr("Insufficient number of weights provided. Not resetting weights.",
                                            "[mps::planner::pushing::SimEnvWorldStateDistanceMeasure::setWeights]");
    }
}

double SimEnvWorldStateDistanceMeasure::distance(const ::ompl::base::State *state1,
                                            const ::ompl::base::State *state2) const {
    auto state_space = getStateSpace();
    auto* sim_env_state_1 = state1->as<ompl::state::SimEnvWorldState>();
    auto* sim_env_state_2 = state2->as<ompl::state::SimEnvWorldState>();

    double dist = 0.0;
    for (unsigned int i = 0; i < state_space->getNumObjects(); ++i) {
        if (_active_flags.at(i)) {
            dist += _weights.at(i) * state_space->getSubspace(i)->distance(sim_env_state_1->getObjectState(i),
                                                                            sim_env_state_2->getObjectState(i));
        }
    }
//    mps_logging::logDebug("Computed distance between state " + sim_env_state_1->toString() +
//                                  " and state " + sim_env_state_2->toString() + " distance is: " + std::to_string(dist),
//                          "[SimEnvWorldStateDistanceMeasure]");
    return dist;
}

void SimEnvWorldStateDistanceMeasure::setActive(unsigned int i, bool active) {
    _active_flags.at(i) = active;
}

void SimEnvWorldStateDistanceMeasure::setActive(const std::string &object_name, bool active) {
    auto state_space = getStateSpace();
    int idx = state_space->getObjectIndex(object_name);
    if (idx < 0) {
        throw std::runtime_error(boost::str(
                boost::format("[mps::planner::pushing::setActive] Unknown object %s ") % object_name));
    }
    _active_flags.at(idx) = active;
}

void SimEnvWorldStateDistanceMeasure::setAll(bool active) {
    for (unsigned int i = 0; i < _active_flags.size(); ++i) {
        _active_flags.at(i) = active;
    }
}

bool SimEnvWorldStateDistanceMeasure::isActive(unsigned int i) const {
    return _active_flags.at(i);
}

bool SimEnvWorldStateDistanceMeasure::isActive(const std::string& object_name) const {
    auto state_space = getStateSpace();
    int idx = state_space->getObjectIndex(object_name);
    if (idx < 0) {
        throw std::runtime_error(boost::str(
                boost::format("[mps::planner::pushing::setActive] Unknown object %s ") % object_name));
    }
    return _active_flags.at(idx);
}

mps::planner::ompl::state::SimEnvWorldStateSpacePtr SimEnvWorldStateDistanceMeasure::getStateSpace() const {
    auto pointer = _weak_state_space.lock();
    if (!pointer) {
        throw std::logic_error("[mps::planner::pushing::SimEnvWorldStateDistanceMeasure::getStateSpace] Can not access state space");
    }
    return pointer;
}


// Copyright (c) 2015-2018 Daniel Cooke
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

#include "alt_allele_count.hpp"

#include <iterator>
#include <algorithm>

#include <boost/variant.hpp>

#include "io/variant/vcf_record.hpp"
#include "io/variant/vcf_spec.hpp"
#include "../facets/samples.hpp"

namespace octopus { namespace csr {

const std::string AltAlleleCount::name_ = "AC";

std::unique_ptr<Measure> AltAlleleCount::do_clone() const
{
    return std::make_unique<AltAlleleCount>(*this);
}

namespace {

int count_non_ref_alleles(const VcfRecord& call, const VcfRecord::SampleName& sample)
{
    const auto genotype = get_genotype(call, sample);
    return genotype.size() - std::count(std::cbegin(genotype), std::cend(genotype), call.ref());
}

} // namespace

Measure::ResultType AltAlleleCount::do_evaluate(const VcfRecord& call, const FacetMap& facets) const
{
    const auto& samples = get_value<Samples>(facets.at("Samples"));
    std::vector<int> result {};
    result.reserve(samples.size());
    for (const auto& sample : samples) {
        result.push_back(count_non_ref_alleles(call, sample));
    }
    return result;
}

Measure::ResultCardinality AltAlleleCount::do_cardinality() const noexcept
{
    return ResultCardinality::num_samples;
}

const std::string& AltAlleleCount::do_name() const
{
    return name_;
}

std::string AltAlleleCount::do_describe() const
{
    return "Number of non-reference alleles called for each sample";
}

std::vector<std::string> AltAlleleCount::do_requirements() const
{
    return {"Samples"};
}

} // namespace csr
} // namespace octopus


#include <boost/units/systems/si/surface_density.hpp>


#ifndef PARSER_BED_HPP
#define PARSER_BED_HPP

#include <iostream>
#include "data/locus.hpp"
#include "data/reader.hpp"
#include "data/biology.hpp"
#include "parsers/parser.hpp"
#include <boost/algorithm/string.hpp>

namespace Anaquin
{
    struct ParserBed
    {
        struct Data
        {
            operator const std::string &() const { return name; }

            ChrID cID;

            // Forward or reverse strand?
            Strand strand;

            Locus l;

            // Eg: chr1_10482481_10483779
            std::string name;
        };

        template <typename F> static void parse(const Reader &r, F f)
        {
            Data d;
            ParserProgress p;

            std::vector<std::string> sizes, starts, tokens;

            while (r.nextTokens(tokens, "\t"))
            {
                // Empty line?
                if (tokens.size() == 1)
                {
                    return;
                }

                // Name of the chromosome
                d.cID = tokens[0];

                /*
                 * https://genome.ucsc.edu/FAQ/FAQformat.html#format1
                 *
                 * The starting position requires to increment because BED position is a 0-based.
                 * The end position requies no increment because it is "not included in the display".
                 */

                d.l = Locus(stod(tokens[1])+1, stod(tokens[2]));

                if (tokens.size() >= 6)
                {
                    // Defines the strand, either '+' or '-'
                    d.strand = tokens[5] == "+" ? Strand::Forward : Strand::Backward;
                }

                if (tokens.size() >= 4)
                {
                    // Name of the BED line (eg: gene)
                    d.name = tokens[3];
                }

                f(d, p);
                p.i++;
            }
        }
    };
}

#endif