<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015, Youssef Kashef
// Copyright (c) 2015, Elm Library Project
// 3-clause BSD License
//
//M*/
#include "elm/layers/saliencyitti.h"

#include <opencv2/imgproc.hpp>

#include "elm/core/defs.h"
#include "elm/core/layerconfig.h"
#include "elm/core/cv/mat_utils.h"          // Point conversions
#include "elm/core/cv/mat_utils_inl.h"      // ARange_
#include "elm/core/cv/mat_vector_utils.h"   // Reshape()
#include "elm/core/cv/mat_vector_utils_inl.h"   // Mat <-> vector
#include "elm/core/cv/neighborhood.h"
#include "elm/core/percentile.h"
#include "elm/core/signal.h"
#include "elm/encoding/orientation.h"

using namespace std;
using namespace cv;

using namespace elm;

/** Define paramter names and IO keys
  */
const std::string SaliencyItti::KEY_INPUT_SCENE         = "scene";          ///< key to visual scene stimulus
const std::string SaliencyItti::KEY_OUTPUT_SALIENCY     = "saliency";       ///< key to saliency measure
const std::string SaliencyItti::KEY_OUTPUT_SALIENT_LOC  = "salient_loc";    ///< key to most recently attended location

const float SaliencyItti::DEFAULT_SIGMA         = 3.f;
const float SaliencyItti::DEFAULT_LAMBDA        = 10.f;
const float SaliencyItti::DEFAULT_GAMMA         = 0.02f;
const float SaliencyItti::DEFAULT_PS            = 0.f;    ///< [radians]
const float SaliencyItti::DEFAULT_ORIENT_RESPONSE_PERCENTILE = 0.7f;

SaliencyItti::~SaliencyItti()
{
}

SaliencyItti::SaliencyItti()
    : base_Layer()
{
    Clear();
}

SaliencyItti::SaliencyItti(const LayerConfig &config)
    : base_Layer(config)
{
    Reset(config);
}

void SaliencyItti::Clear()
{
    saliency_ = Mat1f();
    percentile_orientation_response_ = DEFAULT_ORIENT_RESPONSE_PERCENTILE;
}

void SaliencyItti::Reset(const LayerConfig &config)
{
    // orientation conspicuity
    theta_range_ = ARange_<float>(0.f, CV_PI, 90.*CV_PI/180.);
    VecF theta = Mat_ToVec_<float>(theta_range_);

    gabors_.reset(new GaborFilterBank());
    ELM_DYN_CAST(GaborFilterBank, gabors_)->Reset(DEFAULT_RADIUS,
                                                  DEFAULT_SIGMA,
                                                  theta,
                                                  DEFAULT_LAMBDA,
                                                  DEFAULT_GAMMA,
                                                  DEFAULT_PS);

    // intensity contrast
    intensity_constrast_.Init(DEFAULT_RADIUS, 1.f);

    percentile_orientation_response_ = DEFAULT_ORIENT_RESPONSE_PERCENTILE;
}

void SaliencyItti::Reconfigure(const LayerConfig &config)
{
    Reset(config);
}

void SaliencyItti::IONames(const LayerIONames &config)
{
    name_scene_     = config.Input(KEY_INPUT_SCENE);
    name_saliency_  = config.Output(KEY_OUTPUT_SALIENCY);
    name_salient_loc_ = config.Output(KEY_OUTPUT_SALIENT_LOC);
}

void SaliencyItti::Activate(const Signal &signal)
{
    Mat1f stimulus = signal.MostRecentMat(name_scene_);
    pop_code_orient_.State(stimulus, gabors_);

    Mat orientation_spikes = pop_code_orient_.PopCode();
    Mat1i orientation_index(stimulus.size());

    Mat1f orientation_response_flat = Reshape(gabors_->Response()).reshape(1, 1);
    float low_orientation_response_percentile = Percentile()
            .CalcPercentile(orientation_response_flat,
                            percentile_orientation_response_);
    Mat1b mask_low_orientation_response(stimulus.size());

    // assing orientation to each stimulus pixel
    size_t j_step = gabors_->size();
    double min_val;
    int max_idx[2];
    for(size_t i=0, j=0; i<stimulus.total(); i++, j+=j_step) {

        minMaxIdx(orientation_spikes.colRange(j, j+j_step), &min_val, 0, 0, max_idx);
        orientation_index(i) = max_idx[1];

        mask_low_orientation_response(i) = orientation_response_flat(j+max_idx[1]) <= low_orientation_response_percentile;
    }

    // shift indices to be zero-centered.
    // subtraction should work with even as well as odd sizes.
    orientation_index -= gabors_->size()/2;

    Mat1f orientation_conspicuity, tmp;
    NeighMeanVar(orientation_index, 3, tmp, orientation_conspicuity);
    normalize(orientation_conspicuity, orientation_conspicuity, 0.f, 255.f, NORM_MINMAX, -1, noArray());

    // apply feedback on orientation measurements
    // clip away low response elements
    orientation_conspicuity.setTo(0.f, mask_low_orientation_response);

    //TODO: weigh by entropy to clip away uniform response regions, use as feedback signal

    intensity_constrast_.Compute(stimulus);
    Mat intensity_constrast_norm = intensity_constrast_.Response();
    normalize(intensity_constrast_norm, intensity_constrast_norm, 0.f, 255.f, NORM_MINMAX, -1, noArray());

    add(intensity_constrast_norm, orientation_conspicuity, saliency_);

    // generate 2d distribution from saliency map for later sampling of salient locations
    saliency_sampler_.pdf(saliency_);
}

void SaliencyItti::Response(Signal &signal)
{
    signal.Append(name_saliency_, saliency_);

    Point2i loc = saliency_sampler_.Sample();
    Mat1f loc_mat = Point2Mat(loc);

    signal.Append(name_salient_loc_, loc_mat);
}
<commit_msg>remove unnecessary include<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015, Youssef Kashef
// Copyright (c) 2015, Elm Library Project
// 3-clause BSD License
//
//M*/
#include "elm/layers/saliencyitti.h"

#include <opencv2/imgproc.hpp>

#include "elm/core/defs.h"
#include "elm/core/layerconfig.h"
#include "elm/core/cv/mat_utils.h"          // Point conversions
#include "elm/core/cv/mat_utils_inl.h"      // ARange_
#include "elm/core/cv/mat_vector_utils.h"   // Reshape()
#include "elm/core/cv/mat_vector_utils_inl.h"   // Mat <-> vector
#include "elm/core/cv/neighborhood.h"
#include "elm/core/percentile.h"
#include "elm/core/signal.h"

using namespace std;
using namespace cv;

using namespace elm;

/** Define paramter names and IO keys
  */
const std::string SaliencyItti::KEY_INPUT_SCENE         = "scene";          ///< key to visual scene stimulus
const std::string SaliencyItti::KEY_OUTPUT_SALIENCY     = "saliency";       ///< key to saliency measure
const std::string SaliencyItti::KEY_OUTPUT_SALIENT_LOC  = "salient_loc";    ///< key to most recently attended location

const float SaliencyItti::DEFAULT_SIGMA         = 3.f;
const float SaliencyItti::DEFAULT_LAMBDA        = 10.f;
const float SaliencyItti::DEFAULT_GAMMA         = 0.02f;
const float SaliencyItti::DEFAULT_PS            = 0.f;    ///< [radians]
const float SaliencyItti::DEFAULT_ORIENT_RESPONSE_PERCENTILE = 0.7f;

SaliencyItti::~SaliencyItti()
{
}

SaliencyItti::SaliencyItti()
    : base_Layer()
{
    Clear();
}

SaliencyItti::SaliencyItti(const LayerConfig &config)
    : base_Layer(config)
{
    Reset(config);
}

void SaliencyItti::Clear()
{
    saliency_ = Mat1f();
    percentile_orientation_response_ = DEFAULT_ORIENT_RESPONSE_PERCENTILE;
}

void SaliencyItti::Reset(const LayerConfig &config)
{
    // orientation conspicuity
    theta_range_ = ARange_<float>(0.f, CV_PI, 90.*CV_PI/180.);
    VecF theta = Mat_ToVec_<float>(theta_range_);

    gabors_.reset(new GaborFilterBank());
    ELM_DYN_CAST(GaborFilterBank, gabors_)->Reset(DEFAULT_RADIUS,
                                                  DEFAULT_SIGMA,
                                                  theta,
                                                  DEFAULT_LAMBDA,
                                                  DEFAULT_GAMMA,
                                                  DEFAULT_PS);

    // intensity contrast
    intensity_constrast_.Init(DEFAULT_RADIUS, 1.f);

    percentile_orientation_response_ = DEFAULT_ORIENT_RESPONSE_PERCENTILE;
}

void SaliencyItti::Reconfigure(const LayerConfig &config)
{
    Reset(config);
}

void SaliencyItti::IONames(const LayerIONames &config)
{
    name_scene_     = config.Input(KEY_INPUT_SCENE);
    name_saliency_  = config.Output(KEY_OUTPUT_SALIENCY);
    name_salient_loc_ = config.Output(KEY_OUTPUT_SALIENT_LOC);
}

void SaliencyItti::Activate(const Signal &signal)
{
    Mat1f stimulus = signal.MostRecentMat(name_scene_);
    pop_code_orient_.State(stimulus, gabors_);

    Mat orientation_spikes = pop_code_orient_.PopCode();
    Mat1i orientation_index(stimulus.size());

    Mat1f orientation_response_flat = Reshape(gabors_->Response()).reshape(1, 1);
    float low_orientation_response_percentile = Percentile()
            .CalcPercentile(orientation_response_flat,
                            percentile_orientation_response_);
    Mat1b mask_low_orientation_response(stimulus.size());

    // assing orientation to each stimulus pixel
    size_t j_step = gabors_->size();
    double min_val;
    int max_idx[2];
    for(size_t i=0, j=0; i<stimulus.total(); i++, j+=j_step) {

        minMaxIdx(orientation_spikes.colRange(j, j+j_step), &min_val, 0, 0, max_idx);
        orientation_index(i) = max_idx[1];

        mask_low_orientation_response(i) = orientation_response_flat(j+max_idx[1]) <= low_orientation_response_percentile;
    }

    // shift indices to be zero-centered.
    // subtraction should work with even as well as odd sizes.
    orientation_index -= gabors_->size()/2;

    Mat1f orientation_conspicuity, tmp;
    NeighMeanVar(orientation_index, 3, tmp, orientation_conspicuity);
    normalize(orientation_conspicuity, orientation_conspicuity, 0.f, 255.f, NORM_MINMAX, -1, noArray());

    // apply feedback on orientation measurements
    // clip away low response elements
    orientation_conspicuity.setTo(0.f, mask_low_orientation_response);

    //TODO: weigh by entropy to clip away uniform response regions, use as feedback signal

    intensity_constrast_.Compute(stimulus);
    Mat intensity_constrast_norm = intensity_constrast_.Response();
    normalize(intensity_constrast_norm, intensity_constrast_norm, 0.f, 255.f, NORM_MINMAX, -1, noArray());

    add(intensity_constrast_norm, orientation_conspicuity, saliency_);

    // generate 2d distribution from saliency map for later sampling of salient locations
    saliency_sampler_.pdf(saliency_);
}

void SaliencyItti::Response(Signal &signal)
{
    signal.Append(name_saliency_, saliency_);

    Point2i loc = saliency_sampler_.Sample();
    Mat1f loc_mat = Point2Mat(loc);

    signal.Append(name_salient_loc_, loc_mat);
}
<|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
 *
 *****************************************************************************/

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h"
#pragma GCC diagnostic pop

struct main_marker_visitor
{
    main_marker_visitor(std::string const& svg_name,
                        double scale_factor,
                        bool verbose,
                        bool auto_open)
        : svg_name_(svg_name),
          scale_factor_(scale_factor),
          verbose_(verbose),
          auto_open_(auto_open) {}

    int operator() (mapnik::marker_svg const& marker) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::rasterizer_scanline_aa<> ras_ptr;
        agg::scanline_u8 sl;

        double opacity = 1;
        double w, h;
        std::tie(w, h) = marker.dimensions();

        double svg_width = w * scale_factor_ + 0.5;
        double svg_height = h * scale_factor_ + 0.5;

        int output_width = static_cast<int>(svg_width);
        int output_height = static_cast<int>(svg_height);
        if (verbose_)
        {
            std::clog << "Found width of '" << w << "' and height of '" << h << "'\n";
            auto b = marker.bounding_box();
            std::clog << "SVG BBOX:" << b << std::endl;
            std::clog << "Output image dimensions:[" << output_width << "," << output_height << "]" << std::endl;
        }
        mapnik::image_rgba8 im(output_width, output_height);
        im.set(0x00ffffff);
        agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        mapnik::box2d<double> const& bbox = {0, 0, svg_width, svg_height};
        // center the svg marker on '0,0'
        agg::trans_affine mtx = agg::trans_affine_translation(-0.5 * w, -0.5 * h);
        // Scale the image
        mtx.scale(scale_factor_);
        // render the marker at the center of the marker box
        mtx.translate(0.5 * svg_width, 0.5 * svg_height);

        mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(marker.get_data()->source());
        mapnik::svg::svg_path_adapter svg_path(stl_storage);
        mapnik::svg::renderer_agg<
            mapnik::svg_path_adapter,
            mapnik::svg_attribute_type,
            renderer_solid,
            agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path,
                                                       marker.get_data()->attributes());

        svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);

        std::string png_name(svg_name_);
        boost::algorithm::ireplace_last(png_name,".svg",".png");
        demultiply_alpha(im);
        mapnik::save_to_file<mapnik::image_rgba8>(im,png_name,"png");
        int status = 0;
        if (auto_open_)
        {
            std::ostringstream s;
#ifdef DARWIN
            s << "open " << png_name;
#else
            s << "xdg-open " << png_name;
#endif
            int ret = std::system(s.str().c_str());
            if (ret != 0)
                status = ret;
        }
        std::clog << "rendered to: " << png_name << "\n";
        return status;
    }

    // default
    template <typename T>
    int operator() (T const&) const
    {
        std::clog << "svg2png error: failed to process '" << svg_name_ << "'\n";
        return -1;
    }

  private:
    std::string svg_name_;
    double scale_factor_ = 1.0;
    bool verbose_;
    bool auto_open_;
};

int main (int argc,char** argv)
{
    namespace po = boost::program_options;

    bool verbose = false;
    bool auto_open = false;
    bool strict = false;
    int status = 0;
    std::vector<std::string> svg_files;
    mapnik::logger::instance().set_severity(mapnik::logger::error);
    double scale_factor = 1.0;
    std::string usage = "Usage: svg2png [options] <svg-file(s)>";
    try
    {
        po::options_description desc("svg2png utility");
        desc.add_options()
            ("help,h", "produce usage message")
            ("version,V","print version string")
            ("verbose,v","verbose output")
            ("open,o","automatically open the file after rendering (os x only)")
            ("strict,s","enables strict SVG parsing")
            ("scale-factor", po::value<double>(), "provide scaling factor (default: 1.0)")
            ("svg",po::value<std::vector<std::string> >(),"svg file to read")
            ;

        po::positional_options_description p;
        p.add("svg", -1);
        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("version"))
        {
            std::clog << "version " << MAPNIK_VERSION_STRING << std::endl;
            return 1;
        }

        if (vm.count("help"))
        {
            std::clog << desc << std::endl;
            std::clog << usage << std::endl;
            return 1;
        }

        if (vm.count("verbose"))
        {
            verbose = true;
        }

        if (vm.count("open"))
        {
            auto_open = true;
        }

        if (vm.count("strict"))
        {
            strict = true;
        }
        if (vm.count("scale-factor"))
        {
            scale_factor = vm["scale-factor"].as<double>();
        }
        if (vm.count("svg"))
        {
            svg_files=vm["svg"].as< std::vector<std::string> >();
        }
        else
        {
            std::clog << usage << std::endl;
            return -1;
        }

        std::vector<std::string>::const_iterator itr = svg_files.begin();
        if (itr == svg_files.end())
        {
            std::clog << usage << std::endl;
            return 0;
        }
        while (itr != svg_files.end())
        {
            std::string svg_name (*itr++);
            if (verbose)
            {
                std::clog << "found: " << svg_name << "\n";
            }
            std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false, strict);
            main_marker_visitor visitor(svg_name, scale_factor, verbose, auto_open);
            status = mapnik::util::apply_visitor(visitor, *marker);
        }
    }
    catch (std::exception const& ex)
    {
        std::clog << "Exception caught:" << ex.what() << std::endl;
        return -1;
    }
    catch (...)
    {
        std::clog << "Exception of unknown type!" << std::endl;
        return -1;
    }
    return status;
}
<commit_msg>Move 0.5 up/down rounding into rounding expression (via  @lightmare https://github.com/mapnik/mapnik/pull/4113/commits/7f54e947485df0a35e0dab9b5aacea8db2cff88c#r369294323) (ref #4116)<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
 *
 *****************************************************************************/

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h"
#pragma GCC diagnostic pop

struct main_marker_visitor
{
    main_marker_visitor(std::string const& svg_name,
                        double scale_factor,
                        bool verbose,
                        bool auto_open)
        : svg_name_(svg_name),
          scale_factor_(scale_factor),
          verbose_(verbose),
          auto_open_(auto_open) {}

    int operator() (mapnik::marker_svg const& marker) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::rasterizer_scanline_aa<> ras_ptr;
        agg::scanline_u8 sl;

        double opacity = 1;
        double w, h;
        std::tie(w, h) = marker.dimensions();

        double svg_width = w * scale_factor_;
        double svg_height = h * scale_factor_;

        int output_width = static_cast<int>(svg_width + 0.5);
        int output_height = static_cast<int>(svg_height + 0.5);
        if (verbose_)
        {
            std::clog << "Found width of '" << w << "' and height of '" << h << "'\n";
            auto b = marker.bounding_box();
            std::clog << "SVG BBOX:" << b << std::endl;
            std::clog << "Output image dimensions:[" << output_width << "," << output_height << "]" << std::endl;
        }
        mapnik::image_rgba8 im(output_width, output_height);
        im.set(0x00ffffff);
        agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        mapnik::box2d<double> const& bbox = {0, 0, svg_width, svg_height};
        // center the svg marker on '0,0'
        agg::trans_affine mtx = agg::trans_affine_translation(-0.5 * w, -0.5 * h);
        // Scale the image
        mtx.scale(scale_factor_);
        // render the marker at the center of the marker box
        mtx.translate(0.5 * svg_width, 0.5 * svg_height);

        mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage(marker.get_data()->source());
        mapnik::svg::svg_path_adapter svg_path(stl_storage);
        mapnik::svg::renderer_agg<
            mapnik::svg_path_adapter,
            mapnik::svg_attribute_type,
            renderer_solid,
            agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path,
                                                       marker.get_data()->attributes());

        svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);

        std::string png_name(svg_name_);
        boost::algorithm::ireplace_last(png_name,".svg",".png");
        demultiply_alpha(im);
        mapnik::save_to_file<mapnik::image_rgba8>(im,png_name,"png");
        int status = 0;
        if (auto_open_)
        {
            std::ostringstream s;
#ifdef DARWIN
            s << "open " << png_name;
#else
            s << "xdg-open " << png_name;
#endif
            int ret = std::system(s.str().c_str());
            if (ret != 0)
                status = ret;
        }
        std::clog << "rendered to: " << png_name << "\n";
        return status;
    }

    // default
    template <typename T>
    int operator() (T const&) const
    {
        std::clog << "svg2png error: failed to process '" << svg_name_ << "'\n";
        return -1;
    }

  private:
    std::string svg_name_;
    double scale_factor_ = 1.0;
    bool verbose_;
    bool auto_open_;
};

int main (int argc,char** argv)
{
    namespace po = boost::program_options;

    bool verbose = false;
    bool auto_open = false;
    bool strict = false;
    int status = 0;
    std::vector<std::string> svg_files;
    mapnik::logger::instance().set_severity(mapnik::logger::error);
    double scale_factor = 1.0;
    std::string usage = "Usage: svg2png [options] <svg-file(s)>";
    try
    {
        po::options_description desc("svg2png utility");
        desc.add_options()
            ("help,h", "produce usage message")
            ("version,V","print version string")
            ("verbose,v","verbose output")
            ("open,o","automatically open the file after rendering (os x only)")
            ("strict,s","enables strict SVG parsing")
            ("scale-factor", po::value<double>(), "provide scaling factor (default: 1.0)")
            ("svg",po::value<std::vector<std::string> >(),"svg file to read")
            ;

        po::positional_options_description p;
        p.add("svg", -1);
        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("version"))
        {
            std::clog << "version " << MAPNIK_VERSION_STRING << std::endl;
            return 1;
        }

        if (vm.count("help"))
        {
            std::clog << desc << std::endl;
            std::clog << usage << std::endl;
            return 1;
        }

        if (vm.count("verbose"))
        {
            verbose = true;
        }

        if (vm.count("open"))
        {
            auto_open = true;
        }

        if (vm.count("strict"))
        {
            strict = true;
        }
        if (vm.count("scale-factor"))
        {
            scale_factor = vm["scale-factor"].as<double>();
        }
        if (vm.count("svg"))
        {
            svg_files=vm["svg"].as< std::vector<std::string> >();
        }
        else
        {
            std::clog << usage << std::endl;
            return -1;
        }

        std::vector<std::string>::const_iterator itr = svg_files.begin();
        if (itr == svg_files.end())
        {
            std::clog << usage << std::endl;
            return 0;
        }
        while (itr != svg_files.end())
        {
            std::string svg_name (*itr++);
            if (verbose)
            {
                std::clog << "found: " << svg_name << "\n";
            }
            std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false, strict);
            main_marker_visitor visitor(svg_name, scale_factor, verbose, auto_open);
            status = mapnik::util::apply_visitor(visitor, *marker);
        }
    }
    catch (std::exception const& ex)
    {
        std::clog << "Exception caught:" << ex.what() << std::endl;
        return -1;
    }
    catch (...)
    {
        std::clog << "Exception of unknown type!" << std::endl;
        return -1;
    }
    return status;
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2008, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

namespace cv
{

size_t KeyPoint::hash() const
{
    size_t _Val = 2166136261U, scale = 16777619U;
    Cv32suf u;
    u.f = pt.x; _Val = (scale * _Val) ^ u.u;
    u.f = pt.y; _Val = (scale * _Val) ^ u.u;
    u.f = size; _Val = (scale * _Val) ^ u.u;
    u.f = angle; _Val = (scale * _Val) ^ u.u;
    u.f = response; _Val = (scale * _Val) ^ u.u;
    _Val = (scale * _Val) ^ ((size_t) octave);
    _Val = (scale * _Val) ^ ((size_t) class_id);
    return _Val;
}

void write(FileStorage& fs, const string& objname, const vector<KeyPoint>& keypoints)
{
    WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);

    int i, npoints = (int)keypoints.size();
    for( i = 0; i < npoints; i++ )
    {
        const KeyPoint& kpt = keypoints[i];
        write(fs, kpt.pt.x);
        write(fs, kpt.pt.y);
        write(fs, kpt.size);
        write(fs, kpt.angle);
        write(fs, kpt.response);
        write(fs, kpt.octave);
        write(fs, kpt.class_id);
    }
}

void read(const FileNode& node, vector<KeyPoint>& keypoints)
{
    keypoints.resize(0);
    FileNodeIterator it = node.begin(), it_end = node.end();
    for( ; it != it_end; )
    {
        KeyPoint kpt;
        it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
        keypoints.push_back(kpt);
    }
}

void KeyPoint::convert(const std::vector<KeyPoint>& keypoints, std::vector<Point2f>& points2f,
                       const vector<int>& keypointIndexes)
{
    if( keypointIndexes.empty() )
    {
        points2f.resize( keypoints.size() );
        for( size_t i = 0; i < keypoints.size(); i++ )
            points2f[i] = keypoints[i].pt;
    }
    else
    {
        points2f.resize( keypointIndexes.size() );
        for( size_t i = 0; i < keypointIndexes.size(); i++ )
        {
            int idx = keypointIndexes[i];
            if( idx >= 0 )
                points2f[i] = keypoints[idx].pt;
            else
            {
                CV_Error( CV_StsBadArg, "keypointIndexes has element < 0. TODO: process this case" );
                //points2f[i] = Point2f(-1, -1);
            }
        }
    }
}

void KeyPoint::convert( const std::vector<Point2f>& points2f, std::vector<KeyPoint>& keypoints,
                        float size, float response, int octave, int class_id )
{
    keypoints.resize(points2f.size());
    for( size_t i = 0; i < points2f.size(); i++ )
        keypoints[i] = KeyPoint(points2f[i], size, -1, response, octave, class_id);
}

float KeyPoint::overlap( const KeyPoint& kp1, const KeyPoint& kp2 )
{
    float a = kp1.size * 0.5f;
    float b = kp2.size * 0.5f;
    float a_2 = a * a;
    float b_2 = b * b;

    Point2f p1 = kp1.pt;
    Point2f p2 = kp2.pt;
    float c = (float)norm( p1 - p2 );

    float ovrl = 0.f;

    // one circle is completely encovered by the other => no intersection points!
    if( min( a, b ) + c <= max( a, b ) )
        return min( a_2, b_2 ) / max( a_2, b_2 );

    if( c < a + b ) // circles intersect
    {
        float c_2 = c * c;
        float cosAlpha = ( b_2 + c_2 - a_2 ) / ( kp2.size * c );
        float cosBeta  = ( a_2 + c_2 - b_2 ) / ( kp1.size * c );
        float alpha = acos( cosAlpha );
        float beta = acos( cosBeta );
        float sinAlpha = sin(alpha);
        float sinBeta  = sin(beta);

        float segmentAreaA = a_2 * beta;
        float segmentAreaB = b_2 * alpha;

        float triangleAreaA = a_2 * sinBeta * cosBeta;
        float triangleAreaB = b_2 * sinAlpha * cosAlpha;

        float intersectionArea = segmentAreaA + segmentAreaB - triangleAreaA - triangleAreaB;
        float unionArea = (a_2 + b_2) * (float)CV_PI - intersectionArea;

        ovrl = intersectionArea / unionArea;
    }

    return ovrl;
}

struct KeypointResponseGreaterThanThreshold
{
    KeypointResponseGreaterThanThreshold(float _value) :
    value(_value)
    {
    }
    inline bool operator()(const KeyPoint& kpt) const
    {
        return kpt.response >= value;
    }
    float value;
};

struct KeypointResponseGreater
{
    inline bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) const
    {
        return kp1.response > kp2.response;
    }
};

// takes keypoints and culls them by the response
void KeyPointsFilter::retainBest(vector<KeyPoint>& keypoints, int n_points)
{
    //this is only necessary if the keypoints size is greater than the number of desired points.
    if( n_points > 0 && keypoints.size() > (size_t)n_points )
    {
        if (n_points==0)
        {
            keypoints.clear();
            return;
        }
        //first use nth element to partition the keypoints into the best and worst.
        std::nth_element(keypoints.begin(), keypoints.begin() + n_points, keypoints.end(), KeypointResponseGreater());
        //this is the boundary response, and in the case of FAST may be ambigous
        float ambiguous_response = keypoints[n_points - 1].response;
        //use std::partition to grab all of the keypoints with the boundary response.
        vector<KeyPoint>::const_iterator new_end =
        std::partition(keypoints.begin() + n_points, keypoints.end(),
                       KeypointResponseGreaterThanThreshold(ambiguous_response));
        //resize the keypoints, given this new end point. nth_element and partition reordered the points inplace
        keypoints.resize(new_end - keypoints.begin());
    }
}

struct RoiPredicate
{
    RoiPredicate( const Rect& _r ) : r(_r)
    {}

    bool operator()( const KeyPoint& keyPt ) const
    {
        return !r.contains( keyPt.pt );
    }

    Rect r;
};

void KeyPointsFilter::runByImageBorder( vector<KeyPoint>& keypoints, Size imageSize, int borderSize )
{
    if( borderSize > 0)
    {
        if (imageSize.height <= borderSize * 2 || imageSize.width <= borderSize * 2)
            keypoints.clear();
        else
            keypoints.erase( std::remove_if(keypoints.begin(), keypoints.end(),
                                       RoiPredicate(Rect(Point(borderSize, borderSize),
                                                         Point(imageSize.width - borderSize, imageSize.height - borderSize)))),
                             keypoints.end() );
    }
}

struct SizePredicate
{
    SizePredicate( float _minSize, float _maxSize ) : minSize(_minSize), maxSize(_maxSize)
    {}

    bool operator()( const KeyPoint& keyPt ) const
    {
        float size = keyPt.size;
        return (size < minSize) || (size > maxSize);
    }

    float minSize, maxSize;
};

void KeyPointsFilter::runByKeypointSize( vector<KeyPoint>& keypoints, float minSize, float maxSize )
{
    CV_Assert( minSize >= 0 );
    CV_Assert( maxSize >= 0);
    CV_Assert( minSize <= maxSize );

    keypoints.erase( std::remove_if(keypoints.begin(), keypoints.end(), SizePredicate(minSize, maxSize)),
                     keypoints.end() );
}

class MaskPredicate
{
public:
    MaskPredicate( const Mat& _mask ) : mask(_mask) {}
    bool operator() (const KeyPoint& key_pt) const
    {
        return mask.at<uchar>( (int)(key_pt.pt.y + 0.5f), (int)(key_pt.pt.x + 0.5f) ) == 0;
    }

private:
    const Mat mask;
    MaskPredicate& operator=(const MaskPredicate&);
};

void KeyPointsFilter::runByPixelsMask( vector<KeyPoint>& keypoints, const Mat& mask )
{
    if( mask.empty() )
        return;

    keypoints.erase(std::remove_if(keypoints.begin(), keypoints.end(), MaskPredicate(mask)), keypoints.end());
}

struct KeyPoint_LessThan
{
    KeyPoint_LessThan(const vector<KeyPoint>& _kp) : kp(&_kp) {}
    bool operator()(int i, int j) const
    {
        const KeyPoint& kp1 = (*kp)[i];
        const KeyPoint& kp2 = (*kp)[j];
        if( kp1.pt.x != kp2.pt.x )
            return kp1.pt.x < kp2.pt.x;
        if( kp1.pt.y != kp2.pt.y )
            return kp1.pt.y < kp2.pt.y;
        if( kp1.size != kp2.size )
            return kp1.size > kp2.size;
        if( kp1.angle != kp2.angle )
            return kp1.angle < kp2.angle;
        if( kp1.response != kp2.response )
            return kp1.response > kp2.response;
        if( kp1.octave != kp2.octave )
            return kp1.octave > kp2.octave;
        if( kp1.class_id != kp2.class_id )
            return kp1.class_id > kp2.class_id;

        return i < j;
    }
    const vector<KeyPoint>* kp;
};

void KeyPointsFilter::removeDuplicated( vector<KeyPoint>& keypoints )
{
    int i, j, n = (int)keypoints.size();
    vector<int> kpidx(n);
    vector<uchar> mask(n, (uchar)1);

    for( i = 0; i < n; i++ )
        kpidx[i] = i;
    std::sort(kpidx.begin(), kpidx.end(), KeyPoint_LessThan(keypoints));
    for( i = 1, j = 0; i < n; i++ )
    {
        KeyPoint& kp1 = keypoints[kpidx[i]];
        KeyPoint& kp2 = keypoints[kpidx[j]];
        if( kp1.pt.x != kp2.pt.x || kp1.pt.y != kp2.pt.y ||
            kp1.size != kp2.size || kp1.angle != kp2.angle )
            j = i;
        else
            mask[kpidx[i]] = 0;
    }

    for( i = j = 0; i < n; i++ )
    {
        if( mask[i] )
        {
            if( i != j )
                keypoints[j] = keypoints[i];
            j++;
        }
    }
    keypoints.resize(j);
}

}
<commit_msg>fixed condition in KeyPointsFilter::retainBest<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2008, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"

namespace cv
{

size_t KeyPoint::hash() const
{
    size_t _Val = 2166136261U, scale = 16777619U;
    Cv32suf u;
    u.f = pt.x; _Val = (scale * _Val) ^ u.u;
    u.f = pt.y; _Val = (scale * _Val) ^ u.u;
    u.f = size; _Val = (scale * _Val) ^ u.u;
    u.f = angle; _Val = (scale * _Val) ^ u.u;
    u.f = response; _Val = (scale * _Val) ^ u.u;
    _Val = (scale * _Val) ^ ((size_t) octave);
    _Val = (scale * _Val) ^ ((size_t) class_id);
    return _Val;
}

void write(FileStorage& fs, const string& objname, const vector<KeyPoint>& keypoints)
{
    WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);

    int i, npoints = (int)keypoints.size();
    for( i = 0; i < npoints; i++ )
    {
        const KeyPoint& kpt = keypoints[i];
        write(fs, kpt.pt.x);
        write(fs, kpt.pt.y);
        write(fs, kpt.size);
        write(fs, kpt.angle);
        write(fs, kpt.response);
        write(fs, kpt.octave);
        write(fs, kpt.class_id);
    }
}

void read(const FileNode& node, vector<KeyPoint>& keypoints)
{
    keypoints.resize(0);
    FileNodeIterator it = node.begin(), it_end = node.end();
    for( ; it != it_end; )
    {
        KeyPoint kpt;
        it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
        keypoints.push_back(kpt);
    }
}

void KeyPoint::convert(const std::vector<KeyPoint>& keypoints, std::vector<Point2f>& points2f,
                       const vector<int>& keypointIndexes)
{
    if( keypointIndexes.empty() )
    {
        points2f.resize( keypoints.size() );
        for( size_t i = 0; i < keypoints.size(); i++ )
            points2f[i] = keypoints[i].pt;
    }
    else
    {
        points2f.resize( keypointIndexes.size() );
        for( size_t i = 0; i < keypointIndexes.size(); i++ )
        {
            int idx = keypointIndexes[i];
            if( idx >= 0 )
                points2f[i] = keypoints[idx].pt;
            else
            {
                CV_Error( CV_StsBadArg, "keypointIndexes has element < 0. TODO: process this case" );
                //points2f[i] = Point2f(-1, -1);
            }
        }
    }
}

void KeyPoint::convert( const std::vector<Point2f>& points2f, std::vector<KeyPoint>& keypoints,
                        float size, float response, int octave, int class_id )
{
    keypoints.resize(points2f.size());
    for( size_t i = 0; i < points2f.size(); i++ )
        keypoints[i] = KeyPoint(points2f[i], size, -1, response, octave, class_id);
}

float KeyPoint::overlap( const KeyPoint& kp1, const KeyPoint& kp2 )
{
    float a = kp1.size * 0.5f;
    float b = kp2.size * 0.5f;
    float a_2 = a * a;
    float b_2 = b * b;

    Point2f p1 = kp1.pt;
    Point2f p2 = kp2.pt;
    float c = (float)norm( p1 - p2 );

    float ovrl = 0.f;

    // one circle is completely encovered by the other => no intersection points!
    if( min( a, b ) + c <= max( a, b ) )
        return min( a_2, b_2 ) / max( a_2, b_2 );

    if( c < a + b ) // circles intersect
    {
        float c_2 = c * c;
        float cosAlpha = ( b_2 + c_2 - a_2 ) / ( kp2.size * c );
        float cosBeta  = ( a_2 + c_2 - b_2 ) / ( kp1.size * c );
        float alpha = acos( cosAlpha );
        float beta = acos( cosBeta );
        float sinAlpha = sin(alpha);
        float sinBeta  = sin(beta);

        float segmentAreaA = a_2 * beta;
        float segmentAreaB = b_2 * alpha;

        float triangleAreaA = a_2 * sinBeta * cosBeta;
        float triangleAreaB = b_2 * sinAlpha * cosAlpha;

        float intersectionArea = segmentAreaA + segmentAreaB - triangleAreaA - triangleAreaB;
        float unionArea = (a_2 + b_2) * (float)CV_PI - intersectionArea;

        ovrl = intersectionArea / unionArea;
    }

    return ovrl;
}

struct KeypointResponseGreaterThanThreshold
{
    KeypointResponseGreaterThanThreshold(float _value) :
    value(_value)
    {
    }
    inline bool operator()(const KeyPoint& kpt) const
    {
        return kpt.response >= value;
    }
    float value;
};

struct KeypointResponseGreater
{
    inline bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) const
    {
        return kp1.response > kp2.response;
    }
};

// takes keypoints and culls them by the response
void KeyPointsFilter::retainBest(vector<KeyPoint>& keypoints, int n_points)
{
    //this is only necessary if the keypoints size is greater than the number of desired points.
    if( n_points >= 0 && keypoints.size() > (size_t)n_points )
    {
        if (n_points==0)
        {
            keypoints.clear();
            return;
        }
        //first use nth element to partition the keypoints into the best and worst.
        std::nth_element(keypoints.begin(), keypoints.begin() + n_points, keypoints.end(), KeypointResponseGreater());
        //this is the boundary response, and in the case of FAST may be ambigous
        float ambiguous_response = keypoints[n_points - 1].response;
        //use std::partition to grab all of the keypoints with the boundary response.
        vector<KeyPoint>::const_iterator new_end =
        std::partition(keypoints.begin() + n_points, keypoints.end(),
                       KeypointResponseGreaterThanThreshold(ambiguous_response));
        //resize the keypoints, given this new end point. nth_element and partition reordered the points inplace
        keypoints.resize(new_end - keypoints.begin());
    }
}

struct RoiPredicate
{
    RoiPredicate( const Rect& _r ) : r(_r)
    {}

    bool operator()( const KeyPoint& keyPt ) const
    {
        return !r.contains( keyPt.pt );
    }

    Rect r;
};

void KeyPointsFilter::runByImageBorder( vector<KeyPoint>& keypoints, Size imageSize, int borderSize )
{
    if( borderSize > 0)
    {
        if (imageSize.height <= borderSize * 2 || imageSize.width <= borderSize * 2)
            keypoints.clear();
        else
            keypoints.erase( std::remove_if(keypoints.begin(), keypoints.end(),
                                       RoiPredicate(Rect(Point(borderSize, borderSize),
                                                         Point(imageSize.width - borderSize, imageSize.height - borderSize)))),
                             keypoints.end() );
    }
}

struct SizePredicate
{
    SizePredicate( float _minSize, float _maxSize ) : minSize(_minSize), maxSize(_maxSize)
    {}

    bool operator()( const KeyPoint& keyPt ) const
    {
        float size = keyPt.size;
        return (size < minSize) || (size > maxSize);
    }

    float minSize, maxSize;
};

void KeyPointsFilter::runByKeypointSize( vector<KeyPoint>& keypoints, float minSize, float maxSize )
{
    CV_Assert( minSize >= 0 );
    CV_Assert( maxSize >= 0);
    CV_Assert( minSize <= maxSize );

    keypoints.erase( std::remove_if(keypoints.begin(), keypoints.end(), SizePredicate(minSize, maxSize)),
                     keypoints.end() );
}

class MaskPredicate
{
public:
    MaskPredicate( const Mat& _mask ) : mask(_mask) {}
    bool operator() (const KeyPoint& key_pt) const
    {
        return mask.at<uchar>( (int)(key_pt.pt.y + 0.5f), (int)(key_pt.pt.x + 0.5f) ) == 0;
    }

private:
    const Mat mask;
    MaskPredicate& operator=(const MaskPredicate&);
};

void KeyPointsFilter::runByPixelsMask( vector<KeyPoint>& keypoints, const Mat& mask )
{
    if( mask.empty() )
        return;

    keypoints.erase(std::remove_if(keypoints.begin(), keypoints.end(), MaskPredicate(mask)), keypoints.end());
}

struct KeyPoint_LessThan
{
    KeyPoint_LessThan(const vector<KeyPoint>& _kp) : kp(&_kp) {}
    bool operator()(int i, int j) const
    {
        const KeyPoint& kp1 = (*kp)[i];
        const KeyPoint& kp2 = (*kp)[j];
        if( kp1.pt.x != kp2.pt.x )
            return kp1.pt.x < kp2.pt.x;
        if( kp1.pt.y != kp2.pt.y )
            return kp1.pt.y < kp2.pt.y;
        if( kp1.size != kp2.size )
            return kp1.size > kp2.size;
        if( kp1.angle != kp2.angle )
            return kp1.angle < kp2.angle;
        if( kp1.response != kp2.response )
            return kp1.response > kp2.response;
        if( kp1.octave != kp2.octave )
            return kp1.octave > kp2.octave;
        if( kp1.class_id != kp2.class_id )
            return kp1.class_id > kp2.class_id;

        return i < j;
    }
    const vector<KeyPoint>* kp;
};

void KeyPointsFilter::removeDuplicated( vector<KeyPoint>& keypoints )
{
    int i, j, n = (int)keypoints.size();
    vector<int> kpidx(n);
    vector<uchar> mask(n, (uchar)1);

    for( i = 0; i < n; i++ )
        kpidx[i] = i;
    std::sort(kpidx.begin(), kpidx.end(), KeyPoint_LessThan(keypoints));
    for( i = 1, j = 0; i < n; i++ )
    {
        KeyPoint& kp1 = keypoints[kpidx[i]];
        KeyPoint& kp2 = keypoints[kpidx[j]];
        if( kp1.pt.x != kp2.pt.x || kp1.pt.y != kp2.pt.y ||
            kp1.size != kp2.size || kp1.angle != kp2.angle )
            j = i;
        else
            mask[kpidx[i]] = 0;
    }

    for( i = j = 0; i < n; i++ )
    {
        if( mask[i] )
        {
            if( i != j )
                keypoints[j] = keypoints[i];
            j++;
        }
    }
    keypoints.resize(j);
}

}
<|endoftext|>


<commit_before>#include "v_avl.h"

#ifndef VOS_OK
#define VOS_OK (0)
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cpluscplus */
#endif /* __cpluscplus */

/*lint -save -e818*/

/* OSE-684 y00165807 */
unsigned int VOS_V_AVLInit(const char *pscKey)
{
    (void)pscKey;
    return VOS_OK;
}

unsigned int VOS_V_AVLFini()
{
    return VOS_OK;
}
void AVL_Rotate_Right(AVL_NODE **ppstSubTree)
{
    /* rotate ppstSubTree of AVL tree right                                   */
    AVL_NODE *pstLeftSon;

    pstLeftSon = (*ppstSubTree)->pstLeft;

    (*ppstSubTree)->pstLeft = pstLeftSon->pstRight;
    if (NULL != (*ppstSubTree)->pstLeft)
    {
        (*ppstSubTree)->pstLeft->pstParent = (*ppstSubTree);
    }

    (*ppstSubTree)->sLHeight = pstLeftSon->sRHeight;
    pstLeftSon->pstParent    = (*ppstSubTree)->pstParent;
    pstLeftSon->pstRight     = *ppstSubTree;
    pstLeftSon->pstRight->pstParent = pstLeftSon;
    pstLeftSon->sRHeight     = (1 + VOS_V2_AVL_MAX((*ppstSubTree)->sRHeight,
                                                   (*ppstSubTree)->sLHeight));

    *ppstSubTree = pstLeftSon;

    return;
} /* AVL_Rotate_Right */
void AVL_Rotate_Left(AVL_NODE **ppstSubTree)
{
    /* rotate a ppstSubTree of the AVL tree left                              */
    AVL_NODE *pstRightSon;

    pstRightSon = (*ppstSubTree)->pstRight;

    (*ppstSubTree)->pstRight = pstRightSon->pstLeft;
    if (NULL != (*ppstSubTree)->pstRight)
    {
        (*ppstSubTree)->pstRight->pstParent = (*ppstSubTree);
    }

    (*ppstSubTree)->sRHeight = pstRightSon->sLHeight;
    pstRightSon->pstParent   = (*ppstSubTree)->pstParent;
    pstRightSon->pstLeft     = *ppstSubTree;
    pstRightSon->pstLeft->pstParent = pstRightSon;
    pstRightSon->sLHeight    = (1 + VOS_V2_AVL_MAX((*ppstSubTree)->sRHeight,
                                                   (*ppstSubTree)->sLHeight));

    *ppstSubTree = pstRightSon;

    return;
} /* AVL_Rotate_Left */
void AVL_Swap_Right_Most(AVL_TREE *pstTree,
                             AVL_NODE *pstSubTree,
                             AVL_NODE *pstNode)
{
    /* swap pstNode with right-most descendent of specified pstSubTree        */
    AVL_NODE *pstSwapNode;
    AVL_NODE *pstSwapParent;
    AVL_NODE *pstSwapLeft;

    //VOS_ASSERT(NULL != pstNode->pstRight);
    //VOS_ASSERT(NULL != pstNode->pstLeft);
    if ((NULL == pstNode->pstRight) || (NULL == pstNode->pstLeft))
    {
        return;
    }
    /* find right-most descendent of pstSubTree                               */
    pstSwapNode = pstSubTree;
    while (NULL != pstSwapNode->pstRight)
    {
        pstSwapNode = pstSwapNode->pstRight;
    }

    //VOS_ASSERT(pstSwapNode->sRHeight == 0);
    //VOS_ASSERT(pstSwapNode->sLHeight <= 1);
    if ((0 != pstSwapNode->sRHeight) || (pstSwapNode->sLHeight > 1))
    {
        return;
    }

    /* save parent and left-son of right-most descendent                      */
    pstSwapParent = pstSwapNode->pstParent;
    pstSwapLeft = pstSwapNode->pstLeft;

    /* move swap pstNode to its new position                                  */
    pstSwapNode->pstParent = pstNode->pstParent;
    pstSwapNode->pstRight  = pstNode->pstRight;
    pstSwapNode->pstLeft   = pstNode->pstLeft;
    pstSwapNode->sRHeight  = pstNode->sRHeight;
    pstSwapNode->sLHeight  = pstNode->sLHeight;
    pstSwapNode->pstRight->pstParent = pstSwapNode;
    pstSwapNode->pstLeft->pstParent  = pstSwapNode;
    if (NULL == pstNode->pstParent)
    {
        /* pstNode is at root of pstTree                                      */
        pstTree->pstRoot = pstSwapNode;
    }
    else if (pstNode->pstParent->pstRight == pstNode)
    {
        /* pstNode is right-son of parent                                     */
        pstSwapNode->pstParent->pstRight = pstSwapNode;
    }
    else
    {
        /* pstNode is left-son of parent                                      */
        pstSwapNode->pstParent->pstLeft = pstSwapNode;
    }

    /* move pstNode to its new position                                       */
    pstNode->pstParent = pstSwapParent;
    pstNode->pstRight  = NULL;
    pstNode->pstLeft   = pstSwapLeft;
    if (NULL != pstNode->pstLeft)
    {
        pstNode->pstLeft->pstParent = pstNode;
        pstNode->sLHeight = 1;
    }
    else
    {
        pstNode->sLHeight = 0;
    }

    pstNode->sRHeight = 0;
    pstNode->pstParent->pstRight = pstNode;

    return;
} /* AVL_Swap_Right_Most */
void AVL_Swap_Left_Most(AVL_TREE *pstTree,
                            AVL_NODE *pstSubTree,
                            AVL_NODE *pstNode)
{
    /* swap pstNode with left-most descendent of specified pstSubTree         */
    AVL_NODE *pstSwapNode;
    AVL_NODE *pstSwapParent;
    AVL_NODE *pstSwapRight;

    //VOS_ASSERT(NULL != pstNode->pstRight);
    //VOS_ASSERT(NULL != pstNode->pstLeft);
    if ((NULL == pstNode->pstRight) || (NULL == pstNode->pstLeft))
    {
        return;
    }

    /* find left-most descendent of pstSubTree                                */
    pstSwapNode = pstSubTree;
    while (NULL != pstSwapNode->pstLeft)
    {
        pstSwapNode = pstSwapNode->pstLeft;
    }

    //VOS_ASSERT(pstSwapNode->sLHeight == 0);
    //VOS_ASSERT(pstSwapNode->sRHeight <= 1);
    if ((pstSwapNode->sLHeight != 0) || (pstSwapNode->sRHeight > 1))
    {
        return;
    }

    /* save parent and right-son of left-most descendent                      */
    pstSwapParent = pstSwapNode->pstParent;
    pstSwapRight = pstSwapNode->pstRight;

    /* move swap pstNode to its new position                                  */
    pstSwapNode->pstParent = pstNode->pstParent;
    pstSwapNode->pstRight  = pstNode->pstRight;
    pstSwapNode->pstLeft   = pstNode->pstLeft;
    pstSwapNode->sRHeight  = pstNode->sRHeight;
    pstSwapNode->sLHeight  = pstNode->sLHeight;
    pstSwapNode->pstRight->pstParent = pstSwapNode;
    pstSwapNode->pstLeft->pstParent  = pstSwapNode;
    if (NULL == pstNode->pstParent)
    {
        /* pstNode is at root of pstTree                                      */
        pstTree->pstRoot = pstSwapNode;
    }
    else if (pstNode->pstParent->pstRight == pstNode)
    {
        /* pstNode is right-son of parent                                     */
        pstSwapNode->pstParent->pstRight = pstSwapNode;
    }
    else
    {
        /* pstNode is left-son of parent                                      */
        pstSwapNode->pstParent->pstLeft = pstSwapNode;
    }

    /* move pstNode to its new position                                       */
    pstNode->pstParent = pstSwapParent;
    pstNode->pstRight  = pstSwapRight;
    pstNode->pstLeft   = NULL;
    if (NULL != pstNode->pstRight)
    {
        pstNode->pstRight->pstParent = pstNode;
        pstNode->sRHeight = 1;
    }
    else
    {
        pstNode->sRHeight = 0;
    }

    pstNode->sLHeight = 0;
    pstNode->pstParent->pstLeft = pstNode;

    return;
} /* AVL_Swap_Left_Most */
<commit_msg>Delete v_avl.cpp<commit_after><|endoftext|>


<commit_before>/* Copyright (C) 2012,2013 IBM Corp.
 * This program is free software; 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* Test_Permutations.cpp - Applying plaintext permutation to encrypted vector
 */
#include <NTL/ZZ.h>
NTL_CLIENT

#include "NumbTh.h"
#include "timing.h"
#include "permutations.h"
#include "EncryptedArray.h"

void testCtxt(long m, long p, long widthBound=0, long L=0, long r=1);

void usage(char *prog)
{
  cerr << "Usage: "<<prog<<" [test=? [optional parameters...]]\n";
  cerr << "  optional parameters have the form 'attr1=val1 attr2=val2 ...'\n";
  cerr << "  e.g, 'test=1 m=108 p=2 r=1\n";
  cerr << "  test is either 0 (plaintext) or 1 (ciphertext)[default=1]\n\n";
  cerr << "test=0, permuting plaintext hypercubes (dimension upto 4):\n";
  cerr << "  ord1,ord2,ord3,ord4 size of dimensions 1..4 [default ord1=30, ord2,3,4=0]\n";
  cerr << "  good1,good2,good3,good4 native rotation flags (0/1) [default=1]\n";
  cerr << "  depth bounds the depth of permutation network [default=5]\n";
  cerr << "\ntest=1, permuting ciphertext slots:\n";
  cerr << "  m is the cyclotomic field [default=4369]\n";
  cerr << "  p,r define the plaintext space p^r [default p=2,r=1]\n";
  cerr << "  depth bounds the depth of permutation network [default=5]\n";
  cerr << "  L is number of levels in chain [default=depth]\n";
  exit(0);
}

void testCube(Vec<GenDescriptor>& vec, long widthBound)
{
  GeneratorTrees trees;
  long cost = trees.buildOptimalTrees(vec, widthBound);
  cout << "@TestCube: trees=" << trees << endl;
  cout << " cost =" << cost << endl;
  Vec<long> dims;
  trees.getCubeDims(dims);
  CubeSignature sig(dims);

  for (long cnt=0; cnt<3; cnt++) {
    Permut pi;
    randomPerm(pi, trees.getSize());
    //    if (pi.length()<100)  cout << "pi="<<pi<<endl;

    PermNetwork net;
    net.buildNetwork(pi, trees);
    //    if (pi.length()<100) {
    //      cout << "permutations network {[gIdx,e,isID,shifts]} = " << endl;
    //      cout << net << endl;
    //    }

    HyperCube<long> cube1(sig), cube2(sig);
    for (long i=0; i<cube1.getSize(); i++) cube1[i] = i;
    HyperCube<long> cube3 = cube1;
    applyPermToVec(cube2.getData(), cube1.getData(), pi); // direct application
    net.applyToCube(cube3); // applying permutation netwrok
    if (cube2==cube3) cout << "GOOD\n";
    else {
      cout << "BAD\n";
      if (cube1.getSize()<100) {
	cout << "in="<<cube1.getData() << endl;
	cout << "out1="<<cube2.getData()<<", out2="
	     << cube3.getData()<<endl<<endl;
      }
    }
  }
}

void testCtxt(long m, long p, long widthBound, long L, long r)
{
  cout << "@testCtxt(m="<<m<<",p="<<p<<",depth="<<widthBound<< ",r="<<r<<")";

  FHEcontext context(m,p,r);
  EncryptedArray ea(context); // Use G(X)=X for this ea object

  // Some arbitrary initial plaintext array
  vector<long> in(ea.size());
  for (long i=0; i<ea.size(); i++) in[i] = i % p;

  // Setup generator-descriptors for the PAlgebra generators
  Vec<GenDescriptor> vec(INIT_SIZE, ea.dimension());
  for (long i=0; i<ea.dimension(); i++)
    vec[i] = GenDescriptor(/*order=*/ea.sizeOfDimension(i),
			   /*good=*/ ea.nativeDimension(i), /*genIdx=*/i);

  // Some default for the width-bound, if not provided
  if (widthBound<=0) widthBound = 1+log2((double)ea.size());

  // Get the generator-tree structures and the corresponding hypercube
  GeneratorTrees trees;
  long cost = trees.buildOptimalTrees(vec, widthBound);
  cout << ": trees=" << trees << endl;
  cout << " cost =" << cost << endl;

  //  Vec<long> dims;
  //  trees.getCubeDims(dims);
  //  CubeSignature sig(dims);

  // 1/2 prime per level should be more or less enough, here we use 1 per layer
  if (L<=0) L = 1+trees.numLayers();
  buildModChain(context, /*nLevels=*/L, /*nDigits=*/3);
  cerr << "**Using "<<L<<" primes\n";

  cerr << context.ctxtPrimes.card() << "\n";

  // Generate a sk/pk pair
  FHESecKey secretKey(context);
  const FHEPubKey& publicKey = secretKey;
  secretKey.GenSecKey(64); // A Hamming-weight-64 secret key
  Ctxt ctxt(publicKey);

  for (long cnt=0; cnt<3; cnt++) {
    resetAllTimers();
    // Choose a random permutation
    Permut pi;
    randomPerm(pi, trees.getSize());
    //    if (pi.length()<100)  cout << "pi="<<pi<<endl;

    // Build a permutation network for pi
    PermNetwork net;
    net.buildNetwork(pi, trees);
    //    if (pi.length()<100) {
    //      cout << "permutations network {[gIdx,e,isID,shifts]} = " << endl;
    //      cout << net << endl;
    //    }

    // make sure we have the key-switching matrices needed for this network
    cout << "  ** generating matrices... " << flush;
    addMatrices4Network(secretKey, net);
    cout << "done" << endl;

    // Apply the permutation pi to the plaintext
    vector<long> out1(ea.size());
    vector<long> out2(ea.size());
    applyPermToVec(out1, in, pi); // direct application

    // Encrypt plaintext array, then apply permutation network to ciphertext
    ea.encrypt(ctxt, publicKey, in);
    cout << "  ** applying permutation network to ciphertext... " << flush;
    double t = GetTime();
    net.applyToCtxt(ctxt, ea); // applying permutation netwrok
    t = GetTime() -t;
    cout << "done in " << t << " seconds" << endl;
    ea.decrypt(ctxt, secretKey, out2);

    if (out1==out2) cout << "GOOD\n";
    else {
      cout << "************ BAD\n";
    }
    // printAllTimers();
  }
}

/* m = 31, p = 2, phi(m) = 30
  ord(p)=5
  generator 6 has order (== Z_m^*) of 6
  T = [1 6 5 30 25 26 ]

  m = 61, p = 3, phi(m) = 60
  ord(p)=10
  generator 13 has order (== Z_m^*) of 3
  generator 2 has order (!= Z_m^*) of 2
  T = [1 2 13 26 47 33 ]

  m = 683, p = 2, phi(m) = 682
  ord(p)=22
  generator 3 has order (== Z_m^*) of 31

  m = 47127, p = 2, phi(m) = 30008
  ord(p)=22
  generator 5 has order (== Z_m^*) of 682
  generator 13661 has order (== Z_m^*) of 2
*/

int main(int argc, char *argv[])
{
  argmap_t argmap;
  argmap["test"] = "1";
  argmap["m"] = "4369";
  argmap["p"] = "2";
  argmap["r"] = "1";
  argmap["depth"] = "5";
  argmap["L"] = "0";
  argmap["ord1"] = "30";
  argmap["ord2"] = "0";
  argmap["ord3"] = "0";
  argmap["ord4"] = "0";
  argmap["good1"] = "1";
  argmap["good2"] = "1";
  argmap["good3"] = "1";
  argmap["good4"] = "1";

  // get parameters from the command line

  if (!parseArgs(argc, argv, argmap)) usage(argv[0]);

  long test = atoi(argmap["test"]);
  long p = atoi(argmap["p"]);
  long r = atoi(argmap["r"]);
  long m = atoi(argmap["m"]);
  long depth = atoi(argmap["depth"]);
  long L = atoi(argmap["L"]);

  long ord1 = atoi(argmap["ord1"]);
  long ord2 = atoi(argmap["ord2"]);
  long ord3 = atoi(argmap["ord3"]);
  long ord4 = atoi(argmap["ord4"]);
  long good1 = atoi(argmap["good1"]);
  long good2 = atoi(argmap["good2"]);
  long good3 = atoi(argmap["good3"]);
  long good4 = atoi(argmap["good4"]);

  if (test==0) {
    Vec<GenDescriptor> vec;
    long nGens;
    if (ord2<=1) nGens=1;
    else if (ord3<=1) nGens=2;
    else if (ord4<=1) nGens=3;
    else nGens=4;
    vec.SetLength(nGens);

    switch (nGens) {
    case 4:  vec[3] = GenDescriptor(ord4, good4, /*genIdx=*/3);
    case 3:  vec[2] = GenDescriptor(ord3, good3, /*genIdx=*/2);
    case 2:  vec[1] = GenDescriptor(ord2, good2, /*genIdx=*/1);
    default: vec[0] = GenDescriptor(ord1, good1, /*genIdx=*/0);
    }
    cout << "***Testing ";
    for (long i=0; i<vec.length(); i++)
      cout << "("<<vec[i].order<<","<<vec[i].good<<")";
    cout << ", depth="<<depth<<"\n";
    testCube(vec, depth);
  }
  else {
    setTimersOn();
    cout << "***Testing m="<<m<<", p="<<p<<", depth="<<depth<< endl;
    testCtxt(m,p,depth,L,r);
  }
}

#if 0
  cout << "***Testing m=31, p=2, width=3\n"; // (6 good)
  testCtxt(/*m=*/31, /*p=*/2, /*width=*/3);

  cout << "\n***Testing m=61, p=3, width=3\n"; // (3 good), (2, bad)
  testCtxt(/*m=*/61, /*p=*/3, /*width=*/3);

  cout << "\n***Testing m=683, p=2, width=5\n"; // (31, good)
  testCtxt(/*m=*/683, /*p=*/2, /*width=*/5);

  //  cout << "\n***Testing m=47127, p=2, width=11\n"; // (682,good),(2,good)
  //  testCtxt(/*m=*/47127, /*p=*/2, /*width=*/11);

  // Test 1: a single good small prime-order generator (3)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/3, /*good=*/true, /*genIdx=*/0);
  cout << "***Testing (3,good), width=1\n";
  testCube(vec, /*width=*/1);
  }

  // Test 2: a single bad larger prime-order generator (31)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/31, /*good=*/false, /*genIdx=*/0);
  cout << "\n***Testing (31,bad), width=5\n";
  testCube(vec, /*width=*/5);
  }

  // Test 3: two generators with small prime orders (2,3), both bad
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/2, /*good=*/false, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/3, /*good=*/false, /*genIdx=*/1);
  cout << "\n***Testing [(2,bad),(3,bad)], width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 4: two generators with small prime orders (2,3), one good
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/3, /*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/2, /*good=*/false, /*genIdx=*/1);
  cout << "\n***Testing [(3,good),(2,bad)], width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 5: a single good composite-order generator (6)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/6, /*good=*/true, /*genIdx=*/0);
  cout << "\n***Testing (6,good), width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 6: (6,good),(2,bad)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/6,/*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/ 2, /*good=*/false,/*genIdx=*/1);
  cout << "\n**Testing [(6,good),(2,bad)], width=5\n";
  testCube(vec, /*width=*/5);
  }

  // Test 7: the "general case", (682,good),(2,bad)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/682,/*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/ 2, /*good=*/false,/*genIdx=*/1);
  cout << "\n**Testing [(682,good),(2,bad)], width=11\n";
  testCube(vec, /*width=*/11);
  }
#endif
<commit_msg>printout fix<commit_after>/* Copyright (C) 2012,2013 IBM Corp.
 * This program is free software; 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* Test_Permutations.cpp - Applying plaintext permutation to encrypted vector
 */
#include <NTL/ZZ.h>
NTL_CLIENT

#include "NumbTh.h"
#include "timing.h"
#include "permutations.h"
#include "EncryptedArray.h"

void testCtxt(long m, long p, long widthBound=0, long L=0, long r=1);

void usage(char *prog)
{
  cout << "Usage: "<<prog<<" [test=? [optional parameters...]]\n";
  cout << "  optional parameters have the form 'attr1=val1 attr2=val2 ...'\n";
  cout << "  e.g, 'test=1 m=108 p=2 r=1\n";
  cout << "  test is either 0 (plaintext) or 1 (ciphertext)[default=1]\n\n";
  cout << "test=0, permuting plaintext hypercubes (dimension upto 4):\n";
  cout << "  ord1,ord2,ord3,ord4 size of dimensions 1..4 [default ord1=30, ord2,3,4=0]\n";
  cout << "  good1,good2,good3,good4 native rotation flags (0/1) [default=1]\n";
  cout << "  depth bounds the depth of permutation network [default=5]\n";
  cout << "\ntest=1, permuting ciphertext slots:\n";
  cout << "  m is the cyclotomic field [default=4369]\n";
  cout << "  p,r define the plaintext space p^r [default p=2,r=1]\n";
  cout << "  depth bounds the depth of permutation network [default=5]\n";
  cout << "  L is number of levels in chain [default=depth]\n";
  exit(0);
}

void testCube(Vec<GenDescriptor>& vec, long widthBound)
{
  GeneratorTrees trees;
  long cost = trees.buildOptimalTrees(vec, widthBound);
  cout << "@TestCube: trees=" << trees << endl;
  cout << " cost =" << cost << endl;
  Vec<long> dims;
  trees.getCubeDims(dims);
  CubeSignature sig(dims);

  for (long cnt=0; cnt<3; cnt++) {
    Permut pi;
    randomPerm(pi, trees.getSize());
    //    if (pi.length()<100)  cout << "pi="<<pi<<endl;

    PermNetwork net;
    net.buildNetwork(pi, trees);
    //    if (pi.length()<100) {
    //      cout << "permutations network {[gIdx,e,isID,shifts]} = " << endl;
    //      cout << net << endl;
    //    }

    HyperCube<long> cube1(sig), cube2(sig);
    for (long i=0; i<cube1.getSize(); i++) cube1[i] = i;
    HyperCube<long> cube3 = cube1;
    applyPermToVec(cube2.getData(), cube1.getData(), pi); // direct application
    net.applyToCube(cube3); // applying permutation netwrok
    if (cube2==cube3) cout << "GOOD\n";
    else {
      cout << "BAD\n";
      if (cube1.getSize()<100) {
	cout << "in="<<cube1.getData() << endl;
	cout << "out1="<<cube2.getData()<<", out2="
	     << cube3.getData()<<endl<<endl;
      }
    }
  }
}

void testCtxt(long m, long p, long widthBound, long L, long r)
{
  cout << "@testCtxt(m="<<m<<",p="<<p<<",depth="<<widthBound<< ",r="<<r<<")";

  FHEcontext context(m,p,r);
  EncryptedArray ea(context); // Use G(X)=X for this ea object

  // Some arbitrary initial plaintext array
  vector<long> in(ea.size());
  for (long i=0; i<ea.size(); i++) in[i] = i % p;

  // Setup generator-descriptors for the PAlgebra generators
  Vec<GenDescriptor> vec(INIT_SIZE, ea.dimension());
  for (long i=0; i<ea.dimension(); i++)
    vec[i] = GenDescriptor(/*order=*/ea.sizeOfDimension(i),
			   /*good=*/ ea.nativeDimension(i), /*genIdx=*/i);

  // Some default for the width-bound, if not provided
  if (widthBound<=0) widthBound = 1+log2((double)ea.size());

  // Get the generator-tree structures and the corresponding hypercube
  GeneratorTrees trees;
  long cost = trees.buildOptimalTrees(vec, widthBound);
  cout << ": trees=" << trees << endl;
  cout << " cost =" << cost << endl;

  //  Vec<long> dims;
  //  trees.getCubeDims(dims);
  //  CubeSignature sig(dims);

  // 1/2 prime per level should be more or less enough, here we use 1 per layer
  if (L<=0) L = 1+trees.numLayers();
  buildModChain(context, /*nLevels=*/L, /*nDigits=*/3);
  cout << "**Using "<<L<<" primes (of which "
       << context.ctxtPrimes.card() << " are Ctxt-primes)\n";

  // Generate a sk/pk pair
  FHESecKey secretKey(context);
  const FHEPubKey& publicKey = secretKey;
  secretKey.GenSecKey(64); // A Hamming-weight-64 secret key
  Ctxt ctxt(publicKey);

  for (long cnt=0; cnt<3; cnt++) {
    resetAllTimers();
    // Choose a random permutation
    Permut pi;
    randomPerm(pi, trees.getSize());
    //    if (pi.length()<100)  cout << "pi="<<pi<<endl;

    // Build a permutation network for pi
    PermNetwork net;
    net.buildNetwork(pi, trees);
    //    if (pi.length()<100) {
    //      cout << "permutations network {[gIdx,e,isID,shifts]} = " << endl;
    //      cout << net << endl;
    //    }

    // make sure we have the key-switching matrices needed for this network
    cout << "  ** generating matrices... " << flush;
    addMatrices4Network(secretKey, net);
    cout << "done" << endl;

    // Apply the permutation pi to the plaintext
    vector<long> out1(ea.size());
    vector<long> out2(ea.size());
    applyPermToVec(out1, in, pi); // direct application

    // Encrypt plaintext array, then apply permutation network to ciphertext
    ea.encrypt(ctxt, publicKey, in);
    cout << "  ** applying permutation network to ciphertext... " << flush;
    double t = GetTime();
    net.applyToCtxt(ctxt, ea); // applying permutation netwrok
    t = GetTime() -t;
    cout << "done in " << t << " seconds" << endl;
    ea.decrypt(ctxt, secretKey, out2);

    if (out1==out2) cout << "GOOD\n";
    else {
      cout << "************ BAD\n";
    }
    // printAllTimers();
  }
}

/* m = 31, p = 2, phi(m) = 30
  ord(p)=5
  generator 6 has order (== Z_m^*) of 6
  T = [1 6 5 30 25 26 ]

  m = 61, p = 3, phi(m) = 60
  ord(p)=10
  generator 13 has order (== Z_m^*) of 3
  generator 2 has order (!= Z_m^*) of 2
  T = [1 2 13 26 47 33 ]

  m = 683, p = 2, phi(m) = 682
  ord(p)=22
  generator 3 has order (== Z_m^*) of 31

  m = 47127, p = 2, phi(m) = 30008
  ord(p)=22
  generator 5 has order (== Z_m^*) of 682
  generator 13661 has order (== Z_m^*) of 2
*/

int main(int argc, char *argv[])
{
  argmap_t argmap;
  argmap["test"] = "1";
  argmap["m"] = "4369";
  argmap["p"] = "2";
  argmap["r"] = "1";
  argmap["depth"] = "5";
  argmap["L"] = "0";
  argmap["ord1"] = "30";
  argmap["ord2"] = "0";
  argmap["ord3"] = "0";
  argmap["ord4"] = "0";
  argmap["good1"] = "1";
  argmap["good2"] = "1";
  argmap["good3"] = "1";
  argmap["good4"] = "1";

  // get parameters from the command line

  if (!parseArgs(argc, argv, argmap)) usage(argv[0]);

  long test = atoi(argmap["test"]);
  long p = atoi(argmap["p"]);
  long r = atoi(argmap["r"]);
  long m = atoi(argmap["m"]);
  long depth = atoi(argmap["depth"]);
  long L = atoi(argmap["L"]);

  long ord1 = atoi(argmap["ord1"]);
  long ord2 = atoi(argmap["ord2"]);
  long ord3 = atoi(argmap["ord3"]);
  long ord4 = atoi(argmap["ord4"]);
  long good1 = atoi(argmap["good1"]);
  long good2 = atoi(argmap["good2"]);
  long good3 = atoi(argmap["good3"]);
  long good4 = atoi(argmap["good4"]);

  if (test==0) {
    Vec<GenDescriptor> vec;
    long nGens;
    if (ord2<=1) nGens=1;
    else if (ord3<=1) nGens=2;
    else if (ord4<=1) nGens=3;
    else nGens=4;
    vec.SetLength(nGens);

    switch (nGens) {
    case 4:  vec[3] = GenDescriptor(ord4, good4, /*genIdx=*/3);
    case 3:  vec[2] = GenDescriptor(ord3, good3, /*genIdx=*/2);
    case 2:  vec[1] = GenDescriptor(ord2, good2, /*genIdx=*/1);
    default: vec[0] = GenDescriptor(ord1, good1, /*genIdx=*/0);
    }
    cout << "***Testing ";
    for (long i=0; i<vec.length(); i++)
      cout << "("<<vec[i].order<<","<<vec[i].good<<")";
    cout << ", depth="<<depth<<"\n";
    testCube(vec, depth);
  }
  else {
    setTimersOn();
    cout << "***Testing m="<<m<<", p="<<p<<", depth="<<depth<< endl;
    testCtxt(m,p,depth,L,r);
  }
}

#if 0
  cout << "***Testing m=31, p=2, width=3\n"; // (6 good)
  testCtxt(/*m=*/31, /*p=*/2, /*width=*/3);

  cout << "\n***Testing m=61, p=3, width=3\n"; // (3 good), (2, bad)
  testCtxt(/*m=*/61, /*p=*/3, /*width=*/3);

  cout << "\n***Testing m=683, p=2, width=5\n"; // (31, good)
  testCtxt(/*m=*/683, /*p=*/2, /*width=*/5);

  //  cout << "\n***Testing m=47127, p=2, width=11\n"; // (682,good),(2,good)
  //  testCtxt(/*m=*/47127, /*p=*/2, /*width=*/11);

  // Test 1: a single good small prime-order generator (3)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/3, /*good=*/true, /*genIdx=*/0);
  cout << "***Testing (3,good), width=1\n";
  testCube(vec, /*width=*/1);
  }

  // Test 2: a single bad larger prime-order generator (31)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/31, /*good=*/false, /*genIdx=*/0);
  cout << "\n***Testing (31,bad), width=5\n";
  testCube(vec, /*width=*/5);
  }

  // Test 3: two generators with small prime orders (2,3), both bad
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/2, /*good=*/false, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/3, /*good=*/false, /*genIdx=*/1);
  cout << "\n***Testing [(2,bad),(3,bad)], width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 4: two generators with small prime orders (2,3), one good
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/3, /*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/2, /*good=*/false, /*genIdx=*/1);
  cout << "\n***Testing [(3,good),(2,bad)], width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 5: a single good composite-order generator (6)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 1);
  vec[0] = GenDescriptor(/*order=*/6, /*good=*/true, /*genIdx=*/0);
  cout << "\n***Testing (6,good), width=3\n";
  testCube(vec, /*width=*/3);
  }

  // Test 6: (6,good),(2,bad)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/6,/*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/ 2, /*good=*/false,/*genIdx=*/1);
  cout << "\n**Testing [(6,good),(2,bad)], width=5\n";
  testCube(vec, /*width=*/5);
  }

  // Test 7: the "general case", (682,good),(2,bad)
  {
  Vec<GenDescriptor> vec(INIT_SIZE, 2);
  vec[0] = GenDescriptor(/*order=*/682,/*good=*/true, /*genIdx=*/0);
  vec[1] = GenDescriptor(/*order=*/ 2, /*good=*/false,/*genIdx=*/1);
  cout << "\n**Testing [(682,good),(2,bad)], width=11\n";
  testCube(vec, /*width=*/11);
  }
#endif
<|endoftext|>


<commit_before>#include "ococo.h"
#include <zlib.h>
#include <boost/utility/binary.hpp>

#include <stdint.h>
#include <stdlib.h>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <math.h>
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include "htslib/sam.h"
#include "htslib/faidx.h"
#include "htslib/kstring.h"
#include "htslib/khash.h"
#include "htslib/kseq.h"

KSEQ_INIT(gzFile, gzread);

const char CMD_FLUSH[]="flush";

static char bam_nt16_nt4_table[] = { 4, 0, 1, 4, 2, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4 };

typedef uint16_t counter_t ;
typedef unsigned char nt16_t ;

//enum ConsAlg { CA_MAJORITY , CA_STOCHASTIC };

/*! @typedef
 @abstract Structure for parameters for consensus calling..
 @field min_mapq    Minimum mapping quality to increase counter.
 @field min_baseq   Minimum base quality to increase counter.
 */
typedef struct {
	int min_mapq;
	int min_baseq;
}  cons_params_t;

/*
typedef struct {
	char *name;
	int length;
	counters_t *counters;
} seqstat_t;

typedef struct {
	int nseqs;
	seqstat_t *seqstats;
} stats_t;
*/

struct stats_t {
	int n_seqs;
	int *seq_len;
	char **seq_name;
	counter_t **counters;

	stats_t():
		n_seqs(0),seq_len(NULL), seq_name(NULL), counters(NULL)
	{
	}

	stats_t(bam_hdr_t &h):
		n_seqs(h.n_targets), seq_len(new int[n_seqs]), seq_name(new char*[n_seqs]), counters(new counter_t*[n_seqs])
	{
		for (int i=0;i<n_seqs;i++){
			seq_name[i]=new char[seq_len[i] + 1];
     		memcpy(seq_name[i], h.target_name[i],seq_len[i] + 1);

			counters[i]=new counter_t[seq_len[i]]();
			//printf("seq %s, len %d\n",stats->seqstats[i].name,stats->seqstats[i].length);
		}
	}

	~stats_t(){
		for (int i=0;i<n_seqs;i++){
			delete[] seq_name[i];
			delete[] counters[i];
		}
		delete[] seq_len;
		delete[] seq_name;
		delete[] counters;
	}

	//int generate_fasta(char *fasta_fn, stats_t *stats, cons_params_t cps){
	//	return 0;
	//}

	int load_fasta(string fasta_fn)
	{
		gzFile fp;
	    kseq_t *seq;
	    int l;
	    fp = gzopen(fasta_fn.c_str(), "r");
	    seq = kseq_init(fp);
	    while ((l = kseq_read(seq)) >= 0) {
	        printf("name: %s\n", seq->name.s);
	        if (seq->comment.l) printf("comment: %s\n", seq->comment.s);
	        printf("seq: %s\n", seq->seq.s);
	        if (seq->qual.l) printf("qual: %s\n", seq->qual.s);
	    }
	    kseq_destroy(seq); // STEP 5: destroy seq
	    gzclose(fp); // STEP 6: close the file handler
	    return 0;
	}
};

/*
	nt16: A=1, C=2, G=4, T=8
*/

/*
#define _NUCL_SHIFT(nt16) { \
		(4 * bam_nt16_nt4_table[nt16]) \
	}

#define _COUNTER_VAL(counters,nt16) { \
		(counters>>_NUCL_SHIFT(nt16)) & 0x0f \
	}

#define _COUNTER_SET(counters,nt16,value) { \
		( \
			value << _NUCL_SHIFT(nt16) \
		) | ( \
			counters \
			^ \
			(counters & (0x0f << _NUCL_SHIFT(nt16))) \
		) \
	}

#define _COUNTER_INC_NODIV(counters,nt16) { \
		 _COUNTER_SET (counters,nt16,_COUNTER_VAL(counters,nt16)+1) \
	}

#define _COUNTERS_NORMALIZE(counters,divide) {\
		(counters >> divide) & 0x7777 \
	}

#define _COUNTER_INC(counters,nt16) { \
		_COUNTER_INC_NODIV ( \
			_COUNTERS_NORMALIZE (counters,_COUNTER_VAL(counters,nt16)==0x0f), \
			nt16 \
		) \
	}

#define STATS_UPDATE(stats,seqid,pos,nts16) { \
		((stats->seqstats)[seqid].counters)[pos] = \
		_COUNTER_INC (((stats->seqstats)[seqid].counters)[pos],nts16), \
		(void)0 \
	}
*/

inline int _CELL_SHIFT(nt16_t nt16) {
		return 4 * bam_nt16_nt4_table[nt16];
}

inline counter_t _COUNTER_CELL_VAL(counter_t counter,nt16_t nt16) {
		return (counter>>_CELL_SHIFT(nt16)) & 0x0f;
}

inline counter_t _COUNTER_CELL_SET(counter_t counter,nt16_t nt16,int value) {
	return
		(
			value << _CELL_SHIFT(nt16) \
		) | (
			counter
			^
			(counter & (0x0f << _CELL_SHIFT(nt16)))
		);
}

inline counter_t _COUNTER_CELL_INC_NODIV(counter_t counter,nt16_t nt16) {
		 return _COUNTER_CELL_SET (counter,nt16,_COUNTER_CELL_VAL(counter,nt16)+1);
	}

inline counter_t _COUNTER_NORMALIZE(counter_t counter,bool divide) {
		return (counter >> divide) & 0x7777;
	}

inline counter_t _COUNTER_CELL_INC(counter_t counter,nt16_t nt16) { \
		return _COUNTER_CELL_INC_NODIV (
			_COUNTER_NORMALIZE (counter,_COUNTER_CELL_VAL(counter,nt16)==0x0f),
			nt16
		);
	}

inline void STATS_UPDATE(stats_t &stats,int seqid,int pos,nt16_t nt16) {
		fprintf(stderr,"Going to update stats: chrom %d, pos %d, nucl %d\n", seqid, pos, nt16);
		stats.counters[seqid][pos] = _COUNTER_CELL_INC (stats.counters[seqid][pos],nt16);
	}

/*int init_stats(bam_hdr_t *header, stats_t *stats){
	stats = new stats_t;
	stats->nseqs=header->n_targets;
	stats->seqstats=new seqstat_t[stats->nseqs];

	for (int i=0;i<stats->nseqs;i++){
		stats->seqstats[i].length=header->target_len[i];
		stats->seqstats[i].name=strdup(header->target_name[i]);
		stats->seqstats[i].counters=new counters_t[stats->seqstats[i].length];
		printf("seq %s, len %d\n",stats->seqstats[i].name,stats->seqstats[i].length);
	}
	return 0;
}*/

/*int free_seq_stat(seqstat_t *seqstat) {
	free(seqstat->name);
	free(seqstat->counters);
	free(seqstat);
	return 0;
}

int free_stats(stats_t *stats) {
	for (int i=0;i<stats->nseqs;i++){
		free_seq_stat(&stats->seqstats[i]);
	}
	free(stats);
	return 0;
}
*/

int main(int argc, const char* argv[])
{

	/*
		Default configuration.
	*/

	cons_params_t cps = {
		1, // min_mapq
		0, // min_baseq
	};

	bool debug=false;
	string fasta_fn;
	string sam_fn("-");

	/*
		Parse command-line parameters.
	*/

	try
	{
		namespace po = boost::program_options;

		po::positional_options_description pos;
		pos.add("input-file", -1);

		po::options_description vol("OPTIONS description");

		vol.add_options()
				("reference,r", po::value<string>(&fasta_fn), "FASTA reference file (with existing FAI index)")
				//("algorithm,a", po::value<string>(&alg), "Algorithm for updates: majority / randomized [majority]")
				//("counter-size,s", po::value<int>(&counterSize), "Size of counter per nucleotide in bits [3]")
				//("min-coverage,c", po::value<int>(&minCoverage), "Minimal coverage [3]")
				("min-map-qual,m", po::value<int>(&cps.min_mapq), "Minimal mapping quality [1]")
				("min-base-qual,b", po::value<int>(&cps.min_baseq), "Minimal base quality [0]")
				//("accept-level,l", po::value<float>(&acceptanceLevel), "Acceptance level [0.60]")
				("debug,d", "Debugging")
		;

		po::variables_map vm;
		try
		{
			po::store(po::command_line_parser(argc, argv).options(vol).positional(pos).run(),vm); // can throw

			if(vm.count("debug")){
				debug=true;
			}

			po::notify(vm); // throws on error, so do after help in case there are any problems

		}
		catch(po::error& e)
		{
			fprintf(stderr,"Error: %s.\n",e.what());
			return EXIT_FAILURE;
		}

	}
	catch(std::exception& e)
	{
		fprintf(stderr,"Unhandled Exception: %s.\n",e.what());
		return EXIT_FAILURE;
	}

	/*
		Read SAM headers.
	*/

	hts_itr_t *iter=NULL;

	samFile *in = NULL;
	bam1_t *b= NULL;
	bam_hdr_t *header = NULL;

	in = sam_open(sam_fn.c_str(), "r");
	if(in==NULL) {
		fprintf(stderr,"Problem with opening input ('%s').\n", sam_fn.c_str());
		return -1;
	}
	if ((header = sam_hdr_read(in)) == 0){
		fprintf(stderr,"SAM headers are missing or corrupted.\n");
		return -1;
	}

	stats_t stats(*header);

	/*
		Load FASTA.
	*/
	if (debug){
		if(fasta_fn.size()>0){
			fprintf(stderr, "Loading FASTA: %s.\n",fasta_fn.c_str());
		}
		else{
			fprintf(stderr, "No FASTA provided.\n");
		}
	}
	if (fasta_fn.size()>0){
		stats.load_fasta(fasta_fn);
	}

	/*
		Read alignments (main loop).
	*/
	if (debug){
		fprintf(stderr, "Reading alignments started.\n");
	}
	int r;
	b = bam_init1();
    while ((r = sam_read1(in, header, b)) >= 0) { // read one alignment from `in'
		const char* rname=bam_get_qname(b);
		const uint8_t *seq=bam_get_seq(b);
		const uint8_t *qual=bam_get_qual(b);
		const uint32_t *cigar = bam_get_cigar(b);
		const int n_cigar=b->core.n_cigar;
		//+b->core.l_qname
		const int chrom=b->core.tid;
		const int pos=b->core.pos;
		const int mapq=b->core.qual;
		const int flags=b->core.flag;

		printf("pos %d, chrom %d, map q %d, flag %d, name %s \n",pos,chrom,mapq, flags, rname);

		if (strcmp(rname,CMD_FLUSH)==0){
			// todo: flush fasta
			break;
		}

    	if (((b->core.flag & BAM_FUNMAP)==0) && (b->core.qual)>=cps.min_mapq){

	        for (int k=0,i=0; k < n_cigar; k++)
			{
				const int op = bam_cigar_op(cigar[k]);
				const int ol = bam_cigar_oplen(cigar[k]);
				int ni=0;
				uint8_t nt16=0;

				switch (op) {
					case BAM_CMATCH:
					case BAM_CDIFF:
					case BAM_CEQUAL:
						nt16=bam_seqi(seq, i);
						for (ni=i+ol;i<ni;i++){
							// opravdu &stats?
							fprintf(stderr,"Going to update stats: chrom %d, pos %d, nucl %d\n", chrom, pos+i, nt16);
							STATS_UPDATE(stats,chrom,pos+i,nt16);
						}
						break;

					case BAM_CDEL:
					case BAM_CSOFT_CLIP:
					case BAM_CREF_SKIP:
						i+=ol;
						break;

					case BAM_CBACK:
						fprintf(stderr,"Backward operation in CIGAR string is not supported.\n");
						exit(1);
					case BAM_CINS:
						break;

					case BAM_CPAD:
					case BAM_CHARD_CLIP:
						break;

					//update stats
						//skip ref

				}
				//printf("%d%c",ol,BAM_CIGAR_STR[op]);

			}
	        printf("\n");

    	}
    	else {
    		if (debug){
				fprintf(stderr, "Read '%s' is not used for updating counters\n", rname);
    		}
    	}
    }
	if (debug){
		fprintf(stderr, "Reading alignments finished.\n");
	}

	/*
		Free memory.
	*/

	hts_itr_destroy(iter);
	bam_destroy1(b);
	bam_hdr_destroy(header);
	sam_close(in);

	return 0;
}
<commit_msg>Few small bugs removed.<commit_after>#include "ococo.h"
#include <zlib.h>
#include <boost/utility/binary.hpp>

#include <stdint.h>
#include <stdlib.h>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <math.h>
#include <inttypes.h>
#include <stdbool.h>
#include <assert.h>
#include "htslib/sam.h"
#include "htslib/faidx.h"
#include "htslib/kstring.h"
#include "htslib/khash.h"
#include "htslib/kseq.h"

KSEQ_INIT(gzFile, gzread);

const char CMD_FLUSH[]="flush";

static char bam_nt16_nt4_table[] = { 4, 0, 1, 4, 2, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4 };

typedef uint16_t counter_t ;
typedef unsigned char nt16_t ;

//enum ConsAlg { CA_MAJORITY , CA_STOCHASTIC };

/*! @typedef
 @abstract Structure for parameters for consensus calling..
 @field min_mapq    Minimum mapping quality to increase counter.
 @field min_baseq   Minimum base quality to increase counter.
 */
typedef struct {
	int min_mapq;
	int min_baseq;
}  cons_params_t;

/*
typedef struct {
	char *name;
	int length;
	counters_t *counters;
} seqstat_t;

typedef struct {
	int nseqs;
	seqstat_t *seqstats;
} stats_t;
*/

struct stats_t {
	int n_seqs;
	int *seq_len;
	char **seq_name;
	counter_t **counters;

	stats_t():
		n_seqs(0),seq_len(NULL), seq_name(NULL), counters(NULL)
	{
	}

	stats_t(bam_hdr_t &h):
		n_seqs(h.n_targets), seq_len(new int[n_seqs]()), seq_name(new char*[n_seqs]()), counters(new counter_t*[n_seqs]())
	{
		for (int i=0;i<n_seqs;i++){
			seq_len[i]=h.target_len[i];
			fprintf(stderr,"allocating %d chars\n",seq_len[i]);
			const int seq_len_name=strlen(h.target_name[i]);
			seq_name[i]=new char[seq_len_name+1];
			//printf("name: %s\n",h.target_name[i]);
     		memcpy(seq_name[i], h.target_name[i],seq_len_name+1);

			counters[i]=new counter_t[seq_len[i]]();
			//printf("seq %s, len %d\n",stats->seqstats[i].name,stats->seqstats[i].length);
			fprintf(stderr,"ok\n");
		}
	}

	~stats_t(){
		for (int i=0;i<n_seqs;i++){
			delete[] seq_name[i];
			delete[] counters[i];
		}
		delete[] seq_len;
		delete[] seq_name;
		delete[] counters;
	}

	//int generate_fasta(char *fasta_fn, stats_t *stats, cons_params_t cps){
	//	return 0;
	//}

	int load_fasta(string fasta_fn)
	{
		gzFile fp;
	    kseq_t *seq;
	    int l;
	    fp = gzopen(fasta_fn.c_str(), "r");
	    seq = kseq_init(fp);
	    while ((l = kseq_read(seq)) >= 0) {
	        fprintf(stderr,"name: %s\n", seq->name.s);
	        if (seq->comment.l) printf("comment: %s\n", seq->comment.s);
	        fprintf(stderr,"seq: %s\n", seq->seq.s);
	        if (seq->qual.l) printf("qual: %s\n", seq->qual.s);
	    }
	    kseq_destroy(seq); // STEP 5: destroy seq
	    gzclose(fp); // STEP 6: close the file handler
	    return 0;
	}
};

/*
	nt16: A=1, C=2, G=4, T=8
*/

/*
#define _NUCL_SHIFT(nt16) { \
		(4 * bam_nt16_nt4_table[nt16]) \
	}

#define _COUNTER_VAL(counters,nt16) { \
		(counters>>_NUCL_SHIFT(nt16)) & 0x0f \
	}

#define _COUNTER_SET(counters,nt16,value) { \
		( \
			value << _NUCL_SHIFT(nt16) \
		) | ( \
			counters \
			^ \
			(counters & (0x0f << _NUCL_SHIFT(nt16))) \
		) \
	}

#define _COUNTER_INC_NODIV(counters,nt16) { \
		 _COUNTER_SET (counters,nt16,_COUNTER_VAL(counters,nt16)+1) \
	}

#define _COUNTERS_NORMALIZE(counters,divide) {\
		(counters >> divide) & 0x7777 \
	}

#define _COUNTER_INC(counters,nt16) { \
		_COUNTER_INC_NODIV ( \
			_COUNTERS_NORMALIZE (counters,_COUNTER_VAL(counters,nt16)==0x0f), \
			nt16 \
		) \
	}

#define STATS_UPDATE(stats,seqid,pos,nts16) { \
		((stats->seqstats)[seqid].counters)[pos] = \
		_COUNTER_INC (((stats->seqstats)[seqid].counters)[pos],nts16), \
		(void)0 \
	}
*/

inline int _CELL_SHIFT(nt16_t nt16) {
		return 4 * bam_nt16_nt4_table[nt16];
}

inline counter_t _COUNTER_CELL_VAL(counter_t counter,nt16_t nt16) {
		return (counter>>_CELL_SHIFT(nt16)) & 0x0f;
}

inline counter_t _COUNTER_CELL_SET(counter_t counter,nt16_t nt16,int value) {
	return
		(
			value << _CELL_SHIFT(nt16) \
		) | (
			counter
			^
			(counter & (0x0f << _CELL_SHIFT(nt16)))
		);
}

inline counter_t _COUNTER_CELL_INC_NODIV(counter_t counter,nt16_t nt16) {
		 return _COUNTER_CELL_SET (counter,nt16,_COUNTER_CELL_VAL(counter,nt16)+1);
	}

inline counter_t _COUNTER_NORMALIZE(counter_t counter,bool divide) {
		return (counter >> divide) & 0x7777;
	}

inline counter_t _COUNTER_CELL_INC(counter_t counter,nt16_t nt16) { \
		return _COUNTER_CELL_INC_NODIV (
			_COUNTER_NORMALIZE (counter,_COUNTER_CELL_VAL(counter,nt16)==0x0f),
			nt16
		);
	}

inline void STATS_UPDATE(stats_t &stats,int seqid,int pos,nt16_t nt16) {
		fprintf(stderr,"Going to update stats: chrom %d, pos %d, nucl %d\n", seqid, pos, nt16);
		stats.counters[seqid][pos] = _COUNTER_CELL_INC (stats.counters[seqid][pos],nt16);
	}

/*int init_stats(bam_hdr_t *header, stats_t *stats){
	stats = new stats_t;
	stats->nseqs=header->n_targets;
	stats->seqstats=new seqstat_t[stats->nseqs];

	for (int i=0;i<stats->nseqs;i++){
		stats->seqstats[i].length=header->target_len[i];
		stats->seqstats[i].name=strdup(header->target_name[i]);
		stats->seqstats[i].counters=new counters_t[stats->seqstats[i].length];
		printf("seq %s, len %d\n",stats->seqstats[i].name,stats->seqstats[i].length);
	}
	return 0;
}*/

/*int free_seq_stat(seqstat_t *seqstat) {
	free(seqstat->name);
	free(seqstat->counters);
	free(seqstat);
	return 0;
}

int free_stats(stats_t *stats) {
	for (int i=0;i<stats->nseqs;i++){
		free_seq_stat(&stats->seqstats[i]);
	}
	free(stats);
	return 0;
}
*/

int main(int argc, const char* argv[])
{

	/*
		Default configuration.
	*/

	cons_params_t cps = {
		1, // min_mapq
		0, // min_baseq
	};

	bool debug=false;
	string fasta_fn;
	//string sam_fn("-");
	string sam_fn("BWA-MEM.bam"); //debuging

	/*
		Parse command-line parameters.
	*/

	try
	{
		namespace po = boost::program_options;

		po::positional_options_description pos;
		pos.add("input-file", -1);

		po::options_description vol("OPTIONS description");

		vol.add_options()
				("reference,r", po::value<string>(&fasta_fn), "FASTA reference file (with existing FAI index)")
				//("algorithm,a", po::value<string>(&alg), "Algorithm for updates: majority / randomized [majority]")
				//("counter-size,s", po::value<int>(&counterSize), "Size of counter per nucleotide in bits [3]")
				//("min-coverage,c", po::value<int>(&minCoverage), "Minimal coverage [3]")
				("min-map-qual,m", po::value<int>(&cps.min_mapq), "Minimal mapping quality [1]")
				("min-base-qual,b", po::value<int>(&cps.min_baseq), "Minimal base quality [0]")
				//("accept-level,l", po::value<float>(&acceptanceLevel), "Acceptance level [0.60]")
				("debug,d", "Debugging")
		;

		po::variables_map vm;
		try
		{
			po::store(po::command_line_parser(argc, argv).options(vol).positional(pos).run(),vm); // can throw

			if(vm.count("debug")){
				debug=true;
			}

			po::notify(vm); // throws on error, so do after help in case there are any problems

		}
		catch(po::error& e)
		{
			fprintf(stderr,"Error: %s.\n",e.what());
			return EXIT_FAILURE;
		}

	}
	catch(std::exception& e)
	{
		fprintf(stderr,"Unhandled Exception: %s.\n",e.what());
		return EXIT_FAILURE;
	}

	/*
		Read SAM headers.
	*/

	hts_itr_t *iter=NULL;

	samFile *in = NULL;
	bam1_t *b= NULL;
	bam_hdr_t *header = NULL;

	in = sam_open(sam_fn.c_str(), "r");
	if(in==NULL) {
		fprintf(stderr,"Problem with opening input ('%s').\n", sam_fn.c_str());
		return -1;
	}
	if ((header = sam_hdr_read(in)) == 0){
		fprintf(stderr,"SAM headers are missing or corrupted.\n");
		return -1;
	}

	stats_t stats(*header);

	/*
		Load FASTA.
	*/
	if (debug){
		if(fasta_fn.size()>0){
			fprintf(stderr, "Loading FASTA: %s.\n",fasta_fn.c_str());
		}
		else{
			fprintf(stderr, "No FASTA provided.\n");
		}
	}
	if (fasta_fn.size()>0){
		stats.load_fasta(fasta_fn);
	}

	/*
		Read alignments (main loop).
	*/
	if (debug){
		fprintf(stderr, "Reading alignments started.\n");
	}
	int r;
	b = bam_init1();
    while ((r = sam_read1(in, header, b)) >= 0) { // read one alignment from `in'
		const char* rname=bam_get_qname(b);
		const uint8_t *seq=bam_get_seq(b);
		const uint8_t *qual=bam_get_qual(b);
		const uint32_t *cigar = bam_get_cigar(b);
		const int n_cigar=b->core.n_cigar;
		//+b->core.l_qname
		const int chrom=b->core.tid;
		const int pos=b->core.pos;
		const int mapq=b->core.qual;
		const int flags=b->core.flag;

		fprintf(stderr,"pos %d, chrom %d, map q %d, flag %d, name %s \n",pos,chrom,mapq, flags, rname);

		if (strcmp(rname,CMD_FLUSH)==0){
			// todo: flush fasta
			break;
		}

    	if (((b->core.flag & BAM_FUNMAP)==0) && (b->core.qual)>=cps.min_mapq){

	        for (int k=0,i=0; k < n_cigar; k++)
			{
				const int op = bam_cigar_op(cigar[k]);
				const int ol = bam_cigar_oplen(cigar[k]);
				int ni=0;
				uint8_t nt16=0;

				switch (op) {
					case BAM_CMATCH:
					case BAM_CDIFF:
					case BAM_CEQUAL:
						nt16=bam_seqi(seq, i);
						for (ni=i+ol;i<ni;i++){
							// opravdu &stats?
							fprintf(stderr,"Going to update stats: chrom %d, pos %d, nucl %d\n", chrom, pos+i, nt16);
							STATS_UPDATE(stats,chrom,pos+i,nt16);
						}
						break;

					case BAM_CDEL:
					case BAM_CSOFT_CLIP:
					case BAM_CREF_SKIP:
						i+=ol;
						break;

					case BAM_CBACK:
						fprintf(stderr,"Backward operation in CIGAR string is not supported.\n");
						exit(1);
					case BAM_CINS:
						break;

					case BAM_CPAD:
					case BAM_CHARD_CLIP:
						break;

					//update stats
						//skip ref

				}
				//printf("%d%c",ol,BAM_CIGAR_STR[op]);

			}
	        printf("\n");

    	}
    	else {
    		if (debug){
				fprintf(stderr, "Read '%s' is not used for updating counters\n", rname);
    		}
    	}
    }
	if (debug){
		fprintf(stderr, "Reading alignments finished.\n");
	}

	/*
		Free memory.
	*/

	hts_itr_destroy(iter);
	bam_destroy1(b);
	bam_hdr_destroy(header);
	sam_close(in);

	return 0;
}
<|endoftext|>