//=======================================================================
// Copyright (c) 2013 Piotr Wygocki
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
/**
 * @file capacitated_voronoi.hpp
 * @brief
 * @author Piotr Wygocki
 * @version 1.0
 * @date 2013-03-20
 */
#ifndef PAAL_CAPACITATED_VORONOI_HPP
#define PAAL_CAPACITATED_VORONOI_HPP

#include "paal/data_structures/metric/metric_traits.hpp"
#include "paal/utils/irange.hpp"

#include <boost/graph/adjacency_list.hpp>
#include <boost/range/as_array.hpp>
#include <boost/range/numeric.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
#include <boost/graph/find_flow_cost.hpp>

#include <unordered_map>

namespace paal {
namespace data_structures {

/**
 * @class capacitated_voronoi
 * @brief This class is assigning vertices demands to capacitated generators in
 * such a way that the total cost is minimized.
 *        The solution is based on the min cost max flow algorithm.
 *
 * @tparam Metric
 * @tparam GeneratorsCapacieties is a functor which for each Generator returns
 * its capacity .
 * @tparam VerticesDemands is a functor which for each vertex returns its
 * demand.
 */
template <typename Metric, typename GeneratorsCapacieties,
          typename VerticesDemands>
class capacitated_voronoi {
  public:
    /**
     * @brief this class store as a distance:
     *          - sum of distances of assigned vertices to its generators
     *          - number of vertices without generator
     *       in the optimum all vertices should be assigned.
     */
    class Dist {
      public:
        typedef typename metric_traits<Metric>::DistanceType DistI;
        Dist() = default;

        /**
         * @brief constructor
         *
         * @param real
         * @param distToFullAssign
         */
        Dist(DistI real, DistI distToFullAssign)
            : m_real_dist(real), m_dist_to_full_assignment(distToFullAssign) {}

        /**
         * @brief operator-
         *
         * @param d
         */
        Dist operator-(Dist d) {
            return Dist(
                m_real_dist - d.m_real_dist,
                m_dist_to_full_assignment - d.m_dist_to_full_assignment);
        }

        /**
         * @brief how many vertices are not covered
         */
        DistI get_dist_to_full_assignment() const {
            return m_dist_to_full_assignment;
        }

        /**
         * @brief sum of distances from vertices to facilities
         */
        DistI get_real_dist() const { return m_real_dist; }

        /**
         * @brief operator==
         *
         * @param d
         */
        bool operator==(Dist d) const {
            return m_real_dist == d.m_real_dist &&
                   m_dist_to_full_assignment == d.m_dist_to_full_assignment;
        }

        /**
         * @brief operator>
         *
         * @param d
         */
        bool operator>(Dist d) const {
            if (m_dist_to_full_assignment > d.m_dist_to_full_assignment) {
                return true;
            } else if (m_dist_to_full_assignment < d.m_dist_to_full_assignment) {
                return false;
            }
            return m_real_dist > d.m_real_dist;
        }

        /**
         * @brief operator+=
         *
         * @param d
         */
        const Dist &operator+=(Dist d) {
            m_real_dist += d.m_real_dist;
            m_dist_to_full_assignment += d.m_dist_to_full_assignment;
            return *this;
        }

        /**
         * @brief operator+
         *
         * @param d
         */
        Dist operator+(Dist d) {
            Dist ret(d);
            ret += *this;
            return ret;
        }

        /**
         * @brief unary -operator
         *
         * @return
         */
        Dist operator-() {
            return Dist(-m_real_dist, -m_dist_to_full_assignment);
        }

        /**
         * @brief Dist  + scalar (interpreted as real distance)
         *
         * @param di
         * @param d
         *
         * @return
         */
        friend Dist operator+(DistI di, Dist d) {
            return Dist(d.m_real_dist + di, d.m_dist_to_full_assignment);
        }

        /**
         * @brief operator<<
         *
         * @tparam Stream
         * @param s
         * @param d
         *
         * @return
         */
        template <typename Stream>
        friend Stream &operator<<(Stream &s, Dist d) {
            return s << d.m_dist_to_full_assignment << " " << d.m_real_dist;
        }

      private:
        DistI m_real_dist;
        DistI m_dist_to_full_assignment;
    };
    typedef typename Dist::DistI DistI;
    typedef typename metric_traits<Metric>::VertexType VertexType;
    typedef std::set<VertexType> Generators;
    typedef std::vector<VertexType> Vertices;

  private:
    typedef boost::adjacency_list<
        boost::listS, boost::vecS, boost::bidirectionalS,
        boost::property<boost::vertex_name_t, VertexType>,
        boost::property<
            boost::edge_capacity_t, DistI,
            boost::property<
                boost::edge_residual_capacity_t, DistI,
                boost::property<boost::edge_reverse_t,
                                boost::adjacency_list_traits<
                                    boost::listS, boost::vecS,
                                    boost::bidirectionalS>::edge_descriptor,
                                boost::property<boost::edge_weight_t, DistI>>>>>
        Graph;
    typedef boost::graph_traits<Graph> GTraits;
    typedef typename GTraits::edge_descriptor ED;
    typedef typename GTraits::edge_iterator EI;
    typedef typename GTraits::in_edge_iterator IEI;
    typedef typename GTraits::vertex_descriptor VD;
    typedef typename boost::property_map<
        Graph, boost::edge_residual_capacity_t>::type ResidualCapacity;
    typedef typename std::unordered_map<VertexType, VD, boost::hash<VertexType>>
        VertexToGraphVertex;

    /**
     * @brief functor transforming edge descriptor into pair :
     * (reindexed source, flow on the edge)
     */
    struct Trans {
        std::pair<VertexType, DistI> operator()(const ED &e) const {
            return std::make_pair(m_v->get_vertex_for_edge(e),
                                  m_v->get_flow_on_edge(e));
        }
        const capacitated_voronoi *m_v;
    };

    typedef boost::transform_iterator<Trans, IEI, std::pair<VertexType, DistI>>
        VForGenerator;

  public:

    /**
     * @brief constructor
     *
     * @param gen
     * @param ver
     * @param m
     * @param gc
     * @param vd
     * @param costOfNoGenerator
     */
    capacitated_voronoi(const Generators &gen, Vertices ver, const Metric &m,
                        const GeneratorsCapacieties &gc,
                        const VerticesDemands &vd,
                        DistI costOfNoGenerator =
                            std::numeric_limits<DistI>::max())
        : m_s(add_vertex_to_graph()), m_t(add_vertex_to_graph()),
          m_vertices(std::move(ver)), m_metric(m), m_generators_cap(gc),
          m_first_generator_id(m_vertices.size() + 2),
          m_cost_of_no_generator(costOfNoGenerator) {
        for (VertexType v : m_vertices) {
            VD vGraph = add_vertex_to_graph(v);
            m_v_to_graph_v.insert(std::make_pair(v, vGraph));
            add_edge_to_graph(m_s, vGraph, 0, vd(v));
        }
        for (VertexType g : gen) {
            add_generator(g);
        }
    }

    /**
     * @brief copy constructor is not default  because of rev graph property
     *
     * @param other
     */
    capacitated_voronoi(const capacitated_voronoi &other)
        : m_dist(other.m_dist), m_dist_prev(other.m_dist_prev),
          m_pred(other.m_pred), m_g(other.m_g), m_s(other.m_s), m_t(other.m_t),
          m_generators(other.m_generators), m_vertices(other.m_vertices),
          m_metric(other.m_metric), m_generators_cap(other.m_generators_cap),
          m_first_generator_id(other.m_first_generator_id),
          m_cost_of_no_generator(other.m_cost_of_no_generator),
          m_v_to_graph_v(other.m_v_to_graph_v),
          m_g_to_graph_v(other.m_g_to_graph_v) {
        auto rev = get(boost::edge_reverse, m_g);
        for (auto e : boost::as_array(edges(m_g))) {
            auto eb = edge(target(e, m_g), source(e, m_g), m_g);
            assert(eb.second);
            rev[e] = eb.first;
        }
    }

    /// returns diff between new cost and old cost
    Dist add_generator(VertexType gen) {
        Dist costStart = get_cost();
        m_generators.insert(gen);
        VD genGraph = add_vertex_to_graph(gen);
        m_g_to_graph_v.insert(std::make_pair(gen, genGraph));
        for (const std::pair<VertexType, VD> &v : m_v_to_graph_v) {
            add_edge_to_graph(v.second, genGraph, m_metric(v.first, gen),
                              std::numeric_limits<DistI>::max());
        }

        add_edge_to_graph(genGraph, m_t, 0, m_generators_cap(gen));

        boost::successive_shortest_path_nonnegative_weights(
            m_g, m_s, m_t, predecessor_map(&m_pred[0]).distance_map(&m_dist[0])
                               .distance_map2(&m_dist_prev[0]));

        return get_cost() - costStart;
    }

    /// returns diff between new cost and old cost
    Dist rem_generator(VertexType gen) {
        Dist costStart = get_cost();
        m_generators.erase(gen);
        auto genGraph = m_g_to_graph_v.at(gen);
        auto rev = get(boost::edge_reverse, m_g);
        auto residual_capacity = get(boost::edge_residual_capacity, m_g);

        // removing flow from the net
        for (const ED &e :
             boost::as_array(in_edges(genGraph, m_g))) {
            bool b;
            VD v = source(e, m_g);
            if (v == m_t) {
                continue;
            }
            DistI cap = residual_capacity[rev[e]];
            ED edgeFromStart;
            std::tie(edgeFromStart, b) = edge(m_s, v, m_g);
            assert(b);
            residual_capacity[edgeFromStart] += cap;
            residual_capacity[rev[edgeFromStart]] -= cap;
        }
        clear_vertex(genGraph, m_g);
        assert(!edge(m_t, genGraph, m_g).second);
        assert(!edge(genGraph, m_t, m_g).second);
        remove_vertex(genGraph, m_g);
        restore_index();

        boost::successive_shortest_path_nonnegative_weights(
            m_g, m_s, m_t, predecessor_map(&m_pred[0]).distance_map(&m_dist[0])
                               .distance_map2(&m_dist_prev[0]));

        return get_cost() - costStart;
    }

    /**
     * @brief getter for generators
     *
     * @return
     */
    const Generators &get_generators() const { return m_generators; }

    /**
     * @brief getter for vertices
     *
     * @return
     */
    const Vertices &get_vertices() const { return m_vertices; }

    /**
     * @brief member function for getting assignment, for generator.
     *
     * @return returns range of pairs; the first element of pair is the Vertex
     * and the second element is the flow from this vertex to given generator
     *
     */
    boost::iterator_range<VForGenerator>
    get_vertices_for_generator(VertexType gen) const {
        IEI ei, end;
        VD v = m_g_to_graph_v.at(gen);
        auto r = in_edges(v, m_g);
        Trans t;
        t.m_v = this;
        return boost::make_iterator_range(VForGenerator(r.first, t),
                                          VForGenerator(r.second, t));
    }

    /**
     * @brief get total cost of the assignment
     *
     * @return
     */
    Dist get_cost() const {
        auto residual_capacity = get(boost::edge_residual_capacity, m_g);
        DistI resCap =
            boost::accumulate(out_edges(m_s, m_g), DistI(0), [&](DistI d, const ED & e) {
            return d + residual_capacity[e];
        });

        DistI cost = boost::find_flow_cost(m_g);
        return Dist(cost, resCap);
    }

    /**
     * @brief operator<<
     *
     * @tparam OStream
     * @param s
     * @param v
     *
     * @return
     */
    template <typename OStream>
    friend OStream &operator<<(OStream &s, capacitated_voronoi &v) {
        s << num_vertices(v.m_g) << ", ";
        s << v.m_s << ", " << v.m_t << "\n";
        auto verticesToDisplay = vertices(v.m_g);
        auto edgesToDisplay = edges(v.m_g);
        auto capacity = get(boost::edge_capacity, v.m_g);
        auto residual_capacity = get(boost::edge_residual_capacity, v.m_g);
        auto name = get(boost::vertex_name, v.m_g);
        for (auto v : boost::as_array(verticesToDisplay)) {
            s << v << "-> " << name[v] << ", ";
        }
        s << "\n";
        for (auto e : boost::as_array(edgesToDisplay)) {
            s << e << "-> " << residual_capacity[e] << "-> " << capacity[e]
              << ", ";
        }
        s << "\n";
        for (int g : v.m_generators) {
            s << g << "\n";
        }
        s << "\n";
        for (int g : v.m_vertices) {
            s << g << "\n";
        }
        s << "\n";
        s << v.m_first_generator_id << "\n";
        s << v.m_cost_of_no_generator << "\n";
        s << "\n";
        for (std::pair<int, int> g : v.m_v_to_graph_v) {
            s << g.first << ", " << g.second << "\n";
        }
        s << "\n";
        for (std::pair<int, int> g : v.m_g_to_graph_v) {
            s << g.first << ", " << g.second << "\n";
        }
        s << "\n";
        return s;
    }

  private:

    /**
     * @brief resores index (name property in the graph)
     */
    void restore_index() {
        const unsigned N = num_vertices(m_g);
        m_g_to_graph_v.clear();
        auto name = get(boost::vertex_name, m_g);
        for (unsigned i : irange(unsigned(m_first_generator_id), N)) {
            m_g_to_graph_v[name[i]] = i;
        }
    }

    /**
     * @brief add vertex to auxiliary graph
     *
     * @param v
     *
     * @return
     */
    VD add_vertex_to_graph(VertexType v = VertexType()) {
        VD vG = add_vertex(boost::property<boost::vertex_name_t, VertexType>(v),
                           m_g);
        int N = num_vertices(m_g);

        m_dist.resize(N);
        m_dist_prev.resize(N);
        m_pred.resize(N);
        return vG;
    }

    /**
     * @brief add edge to auxiliary graph
     *
     * @param v
     * @param w
     * @param weight
     * @param capacity
     */
    void add_edge_to_graph(VD v, VD w, DistI weight, DistI capacity) {
        auto rev = get(boost::edge_reverse, m_g);
        ED e, f;
        e = add_dir_edge(v, w, weight, capacity);
        f = add_dir_edge(w, v, -weight, 0);
        rev[e] = f;
        rev[f] = e;
    }

    /**
     * @brief add directed edge
     *
     * @param v
     * @param w
     * @param weight
     * @param capacity
     *
     * @return
     */
    ED add_dir_edge(VD v, VD w, DistI weight, DistI capacity) {
        bool b;
        ED e;
        auto weightMap = get(boost::edge_weight, m_g);
        auto capacityMap = get(boost::edge_capacity, m_g);
        auto residual_capacity = get(boost::edge_residual_capacity, m_g);
        std::tie(e, b) = add_edge(v, w, m_g);
        assert(b);
        capacityMap[e] = capacity;
        residual_capacity[e] = capacity;
        weightMap[e] = weight;
        return e;
    }

    /**
     * @brief gets flow on edge
     *
     * @param e
     *
     * @return
     */
    DistI get_flow_on_edge(const ED &e) const {
        auto capacityMap = get(boost::edge_capacity, m_g);
        auto residual_capacity = get(boost::edge_residual_capacity, m_g);
        return capacityMap[e] - residual_capacity[e];
    }

    /**
     * @brief get reindexed source for edge
     *
     * @param e
     *
     * @return
     */
    VertexType get_vertex_for_edge(const ED &e) const {
        auto name = get(boost::vertex_name, m_g);
        return name[source(e, m_g)];
    }

    typedef std::vector<DistI> VPropMap;
    VPropMap m_dist;
    VPropMap m_dist_prev;
    std::vector<ED> m_pred;

    Graph m_g;
    VD m_s, m_t;

    Generators m_generators;
    Vertices m_vertices;
    const Metric &m_metric;
    const GeneratorsCapacieties &m_generators_cap;
    const VD m_first_generator_id;
    DistI m_cost_of_no_generator;
    VertexToGraphVertex m_v_to_graph_v;
    VertexToGraphVertex m_g_to_graph_v;
};

} //! data_structures
} //! paal
#endif // PAAL_CAPACITATED_VORONOI_HPP


// Copyright (C) 2016 Vicente J. Botet Escriba
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// <experimental/ordinal_array.hpp>

#include <experimental/ordinal_array.hpp>
#include "../../Bool.hpp"
#include "../../Bounded.hpp"

#include <boost/detail/lightweight_test.hpp>

int main()
{

  namespace stde = std::experimental;
  using Indx = Bounded<1,3,unsigned char>;

  {
    stde::ordinal_array<int,Indx> arr;
    BOOST_TEST(arr.size() == 3);
  }
  // fixme: shouldn't {1, 2, 3.5} work?
  {
    stde::ordinal_array<int,Indx> c {{1, 2, 3}};
    BOOST_TEST(c.size() == 3);
    BOOST_TEST(c[Indx{1}] == 1);
    BOOST_TEST(c[Indx{2}] == 2);
    BOOST_TEST(c[Indx{3}] == 3);
  }
  return ::boost::report_errors();
}


//
// Created by nvidia on 6/13/18.
//

#ifndef SUPERPIXEL_SEG_PIXELCLASSIFIER_HPP
#define SUPERPIXEL_SEG_PIXELCLASSIFIER_HPP

#include "SpVec.hpp"
#include <opencv2/ximgproc.hpp>
#include <boost/functional/hash.hpp>

namespace cove {

class SsdSingleShotSuperClassifier {
public:
    explicit SsdSingleShotSuperClassifier(cv::Ptr<cv::ximgproc::SuperpixelLSC> &&x, cv::InputArray _frame,
                                          int _regionSize, double _ssdEpsilon);

    void getFloorMask(cv::OutputArray _dst);

private:
    void generateFeatureVectors();

    void buildGraph();

    void fillTrainingData(int rows = 1, int cols = 3);

    void prepareSsdClassifier();

    bool satisfiesSsd(const SpVec &v);

    std::vector<int> doBfs();

    int regionSize;
    cove::SpVec trainingMean;
    cove::SpVec populationStdDev;
    double maxTrainingSsd;
    double ssdEpsilon;
    std::vector<int> trainingLabels;
    std::vector<cove::SpVec> pixelVecs;
    cv::Mat cielab;
    cv::Mat labels;
    cv::Ptr<cv::ximgproc::SuperpixelLSC> super;
    cove::Graph g;
};

}
#endif // SUPERPIXEL_SEG_PIXELCLASSIFIER_HPP


/**
 * sudoku_sa.cpp
 *
 * By Sebastian Raaphorst, 2018.
 */

#include <iostream>
#include <memory>
#include <stdexcept>

#include <boost/program_options.hpp>

#include <GenSudokuBoard.h>
#include <GenSudokuBoardAscenderPopulator.h>
#include <SimulatedAnnealingAlgorithm.h>

#include "progopts.h"

namespace po = boost::program_options;
using namespace vorpal::gensudoku;
using namespace vorpal::stochastic;

int main(int argc, const char * const argv[]) {
    using solver = SimulatedAnnealingAlgorithm<SudokuBoard>;
    solver::options_type options;

    try {
        auto desc = init_options(options);
        desc->add_options()
                ("initial-temperature,t", po::value<double>()->default_value(10000), "initial temperature")
                ("alpha,a", po::value<double>()->default_value(0.99), "alpha (cooling rate)");
        auto done = end_options<SudokuBoardAscenderPopulator, solver::options_type>(argc, argv, desc, options,
        [](po::variables_map &vm, solver::options_type &options) {
            options.initial_temperature = vm["initial-temperature"].as<double>();
            options.alpha               = vm["alpha"].as<double>();
        });
        if (done) return 0;
    } catch (const std::exception &e) {
        std::cerr << e.what() << '\n';
        return 1;
    }

    run<solver>(options);
}


#include "mainprocessor.h"
#define ARMA_64BIT_WORD
// #define ARMA_NO_DEBUG
#include <armadillo>
//using namespace arma;

#include <QTimer>
#include <itkImageFileWriter.h>
#include <iostream>

MainProcessor::MainProcessor(QCoreApplication* a, QObject *parent) :
                QObject(parent), app(a)
{
    begin = std::chrono::high_resolution_clock::now();
    nifti2Pgm = new Nifti2Pgm();
    edisonWrapper = new EdisonWrapper();
    connect(edisonWrapper, SIGNAL(allProcessesFinished()), this, SLOT(enhanceContrast()));
}

MainProcessor::~MainProcessor()
{
    delete  nifti2Pgm;
    delete edisonWrapper;
    app->quit();
}

void MainProcessor::runProcesses(QFileInfoList imageFiles,
                                 QString edisonPath, QString outDir)
{

    this->imageFiles = imageFiles;

    if(!edisonWrapper->setProgramPath(edisonPath)) {
        std::cout << "Wrong path to Edison " << edisonPath.toStdString() << std::endl;
        return;
    }
    this->outputDir = outDir;

    for(int i = 0; i < 2; i++) {
        nifti2Pgm->setNiftiFile(imageFiles.at(i).absoluteFilePath(), i);
    }

    QList<arma::fcube> cubes = nifti2Pgm->getCubesList();
    FL_org = cubes.at(0);
    nifti2Pgm->normalizeFlair();
    nifti2Pgm->binarizeLB();
    nifti2Pgm->createOutputCubes();
    QString pgmFileName = nifti2Pgm->writePGM(outputDir);

    //edisonWrapper->setParameters(parameters);
    edisonWrapper->setImages(imageFiles);
    edisonWrapper->setOutputPaths(outputDir);
    edisonWrapper->createOutputNames();
    edisonWrapper->createEdisonFile(pgmFileName);
    edisonWrapper->launchStage();
    // enhanceContrast() is launched by signal from edisonWrapper.
}

void MainProcessor::enhanceContrast()
{
    QList<arma::fcube> cubes = nifti2Pgm->getCubesList();
    arma::fcube* FL = &(cubes[0]);
    arma::fcube* LB = &(cubes[1]);
    arma::fmat* im2edison = nifti2Pgm->getIm2edison();
    //arma::fmat* im2pgm = nifti2Pgm->getIm2pgm();
    QString gradientFileName = edisonWrapper->getGradientFile();
    QFileInfo gradientFile(gradientFileName);
    if(!gradientFile.exists()) {
        std::cout << "Gradient file " << gradientFileName.toStdString()
                  << " does not exist" << std::endl;
        return;
    }

    arma::fmat gradientMap;
    gradientMap.load(gradientFileName.toStdString(), arma::raw_ascii);

    FL_en = arma::zeros<arma::fcube>(arma::size(*FL));
//    FL_en = *FL;
    uint bins_g = 1024;
    uint bins_i = 1024;
    arma::fvec gradientMapVec = arma::vectorise(gradientMap);
    arma::fvec im2edisonVec = arma::vectorise(*im2edison);
    arma::umat N = hist3(&gradientMapVec, &im2edisonVec, bins_g, bins_i);
    N.col(0) = arma::zeros<arma::uvec>(bins_g);
    arma::umat NC = cumsum(cumsum(N, 0), 1);

    float max_iwm =im2edison->max();
    arma::fvec i_l = arma::linspace<arma::fvec>(0, max_iwm, bins_i);
    arma::fvec g_l = arma::linspace<arma::fvec>(0, 1, bins_g);
    arma::fvec p = arma::zeros<arma::fvec>(bins_g);
    for(arma::uword gi = 0; gi < bins_g; gi++) {
        unsigned long long sz = sum(NC.col(gi));
        if(sz == 0)
            p(gi) = 0;
        else {
            float sm = sum(NC.col(gi) % g_l);
            p(gi) = sm/static_cast<float>(sz);
        }
    }

    arma::fvec P = cumsum(p % i_l);

    for(arma::uword its = 0; its < FL->n_slices; its++) {
        for(arma::uword i=0; i < FL->n_rows; i++) {
            for(arma::uword j=0; j < FL->n_cols; j ++) {
//                ulong ind = static_cast<ulong>(roundf((*im2pgm)(i + its * FL->n_rows, j) * bins_g));
                ulong ind = static_cast<ulong>(roundf((*im2edison)(i + its * FL->n_rows, j) * bins_g));
                if(ind == 0)
                    FL_en(i, j, its) = 0;
                else
                    FL_en(i, j, its) = (P(ind - 1));
            }
        }
    }
    QPair<float, float> minmax = nifti2Pgm->getMinmaxFlair();
    float maxFL = minmax.second;
    float minFL = minmax.first;
    float minFL_en = FL_en.min();
    float maxFL_en = FL_en.max();
    FL_en = (FL_en - minFL_en) / (maxFL_en - minFL_en)*(maxFL-minFL) + minFL;
    arma::uvec ind = find((*LB) < 0.5);
    FL_en(ind) = FL_org(ind);

    typedef itk::Image< float, 3 > ITKImageType;
    typename ITKImageType::Pointer inputImage;

    std::memcpy(nifti2Pgm->getFlairImage().GetPointer()->GetBufferPointer(),
                FL_en.memptr(), FL_en.n_elem*sizeof(float));

    using ImageType = itk::Image<float, 3>;
    using WriterType = itk::ImageFileWriter<ImageType>;
    WriterType::Pointer writer = WriterType::New();
    QString suffix = imageFiles.at(0).completeSuffix();
    enhancedFileInfo.setFile(QDir(outputDir),
                       imageFiles.at(0).baseName() + "-enhanced." + suffix);
    writer->SetFileName(enhancedFileInfo.absoluteFilePath().toStdString());
    writer->SetInput(nifti2Pgm->getFlairImage().GetPointer());
    writer->Update();
    endMessages();
}

arma::umat MainProcessor::hist3(arma::fvec *X, arma::fvec *Y, uint n_binsX, uint n_binsY)
{
    arma::umat histogram;
    if(X->n_elem != Y->n_elem) {
        std::cout << "Vectors with different number of elements" << std::endl;
        return histogram;
    }

    histogram.zeros(n_binsX, n_binsY);
    arma::uword num_elems = X->n_elem;
    float minX = X->min();
    float maxX = X->max();
    float minY = Y->min();
    float maxY = Y->max();
    float lengthX = maxX - minX;
    float lengthY = maxY - minY;
    uint indexX, indexY;
    for(arma::uword i = 0; i < num_elems; i++) {
        indexX = static_cast<uint>(truncf((X->at(i) - minX) * n_binsX / lengthX));
        indexY = static_cast<uint>(truncf((Y->at(i) - minY) * n_binsY / lengthY));
        if(indexX == n_binsX)
            --indexX;
        if(indexY == n_binsY)
            --indexY;
        histogram(indexX, indexY) += 1;
    }

    return histogram;
}

void MainProcessor::endMessages()
{
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << std::endl << "Images generated:" << std::endl;
    std::cout << enhancedFileInfo.absoluteFilePath().toStdString() << std::endl;
    std::cout << std::endl << QString::number(std::chrono::duration_cast<std::chrono::nanoseconds>
                 (end - begin).count()/1000000.0).toStdString() << "ms." << std::endl;
    std::cout << "Contrast enhancement finished" << std::endl;
    app->quit();
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*  This file is part of the library KASKADE 7                               */
/*    see http://www.zib.de/projects/kaskade7-finite-element-toolbox         */
/*                                                                           */
/*  Copyright (C) 2002-2011 Zuse Institute Berlin                            */
/*                                                                           */
/*  KASKADE 7 is distributed under the terms of the ZIB Academic License.    */
/*    see $KASKADE/academic.txt                                              */
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**
 * \file
 * \author Bodo Erdmann , Felix Lehmann
 */

#ifndef ICCPRECOND_HH
#define ICCPRECOND_HH

#include <cstdlib>
#include <iostream>
#include <memory>
#include <vector>

#include <boost/timer/timer.hpp>

#include <dune/istl/preconditioners.hh>

#include "protospp.h" // "Malloc" from ITSOL

#include "linalg/triplet.hh"

extern "C" {
#include "taucs.h"
}

namespace Kaskade
{

//---------------------------------------------------------------------
//---------------------------------------------------------------------

/**
 * \ingroup linalg
 *
 * PrecondType::ICC Incomplete Cholesky Preconditioner from TAUCS library
 *
 * 'modified' is defined in TAUCS, if is set true, the rows of the factorization L
 * will be scaled so that LL^T has same rowsum as A
 *
 * we expect to be passed only a lower triangle of A (upper = 0).
 * If this is not the case, nnz_of_one_triangle should be passed with the number of
 * nonzeros of the lower triangle of A (including nonzeroes on diagonal)
 *
 */
template <class Op>
class ICCPreconditioner: public Dune::Preconditioner<typename Op::range_type, typename Op::range_type>
{
  typedef typename Op::range_type range_type;
  typedef range_type               domain_type;
  typedef typename Op::field_type field_type;
  typedef Dune::BCRSMatrix<Dune::FieldMatrix<field_type,1,1> > BCRS_Matrix;
  typedef typename BCRS_Matrix::ConstColIterator ColIter;

public:
  static int const category = Dune::SolverCategory::sequential;

  // nnz_of_one_triangle has to be set if lower AND upper triangle
  // are passed. We will only touch the lower triangle
  explicit ICCPreconditioner(Op& op, double droptol=1.0e-2 , int modified = false , int nnz_of_one_triangle = -1 )
  {
    boost::timer::cpu_timer iluTimer;
    std::unique_ptr<BCRS_Matrix> const A(op.template getPointer<BCRS_Matrix>());
    int n = (*A).N() , nnz;
    if(nnz_of_one_triangle > 0) nnz = nnz_of_one_triangle;
    else nnz = (*A).nonzeroes();

    taucs_logfile((char*)"stdout");

    taucs_ccs_matrix *M = taucs_ccs_create(n,n,nnz,TAUCS_DOUBLE | TAUCS_SYMMETRIC | TAUCS_LOWER);

    std::vector<std::vector<int> > entries;
    entries.resize(n);
    for(int i=0;i<n;i++)
      for (ColIter cI=(*A)[i].begin(); cI!=(*A)[i].end() && cI.index()<=i; ++cI)
        entries[cI.index()].push_back(i);

    int idx_ = 0;
    for(int k=0;k<n;k++)
    {
      (M->colptr)[k] = idx_;
      for (std::vector<int>::iterator it = entries[k].begin(); it != entries[k].end(); it++)
      {
        (M->rowind)[idx_] = *it;
        (M->values).d[idx_] = (*A)[*it][k];
        idx_ += 1;
      }
    }
    (M->colptr)[n] = nnz;

    L = taucs_ccs_factor_llt(M, droptol, modified);

    rhs     = (double *)Malloc(n*sizeof(double), "main");
    sol     = (double *)Malloc(n*sizeof(double), "main");

    std::cout << "PrecondType::ICC time = " << (double)(iluTimer.elapsed().user)/1e9 << "s\n";
  }

  ~ICCPreconditioner()
  {
    taucs_ccs_free(L);
    free(sol);
    free(rhs);
  }

  virtual void pre (domain_type&, range_type&) {}
  virtual void post (domain_type&) {}

  virtual void apply (domain_type& x, range_type const& y) {
    y.write(rhs);
    taucs_ccs_solve_llt(L,sol,rhs);
    x.read(sol);
  }

private:
  taucs_ccs_matrix *L;
  double *data;
  double *sol, *rhs;
};

/* undef stupid macro names defined in taucs.h */
#undef max
#undef min
#undef realloc
#undef malloc
#undef calloc
#undef free

}  // namespace Kaskade
#endif


/*
 * Superpixels.hpp
 *
 *  Created on: Jan 26, 2012
 *      Author: david
 */

#ifndef SUPERPIXELS_HPP_
#define SUPERPIXELS_HPP_

#include "Point.hpp"
#include "Tools.hpp"
#include "Seed.hpp"
#include <Slimage/Slimage.hpp>
#include <Slimage/Parallel.h>
#include <eigen3/Eigen/Dense>
#include <boost/graph/adjacency_list.hpp>
#include <vector>
#include <cmath>

namespace dasp
{
	extern std::map<std::string,slimage::ImagePtr> sDebugImages;

	struct ClusterGroupInfo
	{
		Histogram<float> hist_thickness;
		Histogram<float> hist_area_quotient;
		Histogram<float> hist_coverage_error;
	};

	void SetRandomNumberSeed(unsigned int seed);

	struct Partition
	{
		std::vector<std::vector<unsigned int>> segments;

		unsigned int numSegments() const {
			return segments.size();
		}

		unsigned int segmentSize(unsigned int i) const {
			return segments[i].size();
		}

		const std::vector<unsigned int>& segmentPixelIds(unsigned int i) const {
			return segments[i];
		}
	};

	class Superpixels
	{
	public:
		slimage::ThreadingOptions threadopt;

		Parameters opt;

		slimage::Image3ub color_raw;

		ImagePoints points;

		Eigen::MatrixXf density;

		Eigen::MatrixXf saliency;

		std::vector<Cluster> cluster;

		std::vector<Seed> seeds_previous;
		std::vector<Seed> seeds;

		std::size_t clusterCount() const {
			return cluster.size();
		}

		unsigned int width() const {
			return points.width();
		}

		unsigned int height() const {
			return points.height();
		}

		Superpixels();

		std::vector<Seed> getClusterCentersAsSeeds() const;

		std::vector<Eigen::Vector2f> getClusterCentersAsPoints() const;

		void CreatePoints(const slimage::Image3ub& image, const slimage::Image1ui16& depth, const slimage::Image3f& normals=slimage::Image3f());

//		/** Find super pixel clusters */
//		void ComputeSuperpixels(const slimage::Image1f& edges);

		std::vector<int> ComputePixelLabels() const;

		slimage::Image1i ComputeLabels() const;

		Partition ComputePartition() const;

		void ComputeSuperpixels(const std::vector<Seed>& seeds);

		void ConquerEnclaves();

		void ConquerMiniEnclaves();

		std::vector<Seed> FindSeeds();

		slimage::Image1f ComputeEdges();

		void ImproveSeeds(std::vector<Seed>& seeds, const slimage::Image1f& edges);

		void CreateClusters(const std::vector<Seed>& seeds);

		void PurgeInvalidClusters();

		void MoveClusters();

		/**
		 * Signature of F :
		 * void F(unsigned int cid, const dasp::Cluster& c, unsigned int pid, const dasp::Point& p)
		 */
		template<typename F>
		void ForPixelClusters(F f) const {
			for(unsigned int i=0; i<cluster.size(); i++) {
				const Cluster& c = cluster[i];
				for(unsigned int p : c.pixel_ids) {
					f(i, c, p, points[p]);
				}
			}
		}

		template<typename F>
		void ForClustersNoReturn(F f) {
			for(unsigned int i=0; i<cluster.size(); i++) {
				f(cluster[i]);
			}
		}

		template<typename F>
		auto ForClusters(F f) -> std::vector<decltype(f(cluster[0]))> {
			std::vector<decltype(f(cluster[0]))> data(cluster.size());
			for(unsigned int i=0; i<cluster.size(); i++) {
				data[i] = f(cluster[i]);
			}
			return data;
		}

		template<typename F>
		void ForClusterCentersNoReturn(F f) {
			for(unsigned int i=0; i<cluster.size(); i++) {
				f(cluster[i].center);
			}
		}

		template<typename F>
		auto ForClusterCenters(F f) -> std::vector<decltype(f(cluster[0].center))> {
			std::vector<decltype(f(cluster[0].center))> data(cluster.size());
			for(unsigned int i=0; i<cluster.size(); i++) {
				data[i] = f(cluster[i].center);
			}
			return data;
		}

		void ComputeExt() {
			return ForClustersNoReturn([this](Cluster& c) { c.ComputeExt(points, opt); });
		}

		ClusterGroupInfo ComputeClusterGroupInfo(unsigned int n, float max_thick);

		Eigen::Vector3f ColorToRGB(const Eigen::Vector3f& c) const;

		Eigen::Vector3f ColorFromRGB(const Eigen::Vector3f& c) const;

	};

	Superpixels ComputeSuperpixels(const slimage::Image3ub& color, const slimage::Image1ui16& depth, const Parameters& opt);

	void ComputeSuperpixelsIncremental(Superpixels& clustering, const slimage::Image3ub& color, const slimage::Image1ui16& depth);

}

#endif


#include <boost/test/unit_test.hpp>
#include "functions/composition.hh"
#include "functions/full_function_defs.hh"
#include "functions/std_functions.hh"
#include "functions/variables.hh"

BOOST_AUTO_TEST_CASE(composition_test) {
  using namespace manifolds;
  Composition<Sin, decltype(t)> a;
  static_assert(is_stateless<decltype(a)>::value, "");

  BOOST_CHECK_EQUAL(a(1, 2, 3, 4), std::sin(4));
  BOOST_CHECK_EQUAL(a(1, 2, 4, 8, 16), std::sin(8));

  Composition<Sin, Cos> b;
  auto c = b(t);
  BOOST_CHECK_EQUAL(c(1, 2, 3, 4), std::sin(std::cos(4)));
}


#include <numpy_eigen/boost_python_headers.hpp>
#include <aslam/backend/ErrorTermDs.hpp>
#include <boost/shared_ptr.hpp>
using namespace boost::python;
using namespace aslam::backend;

void exportErrorTermDs()
{

  class_<ErrorTermDs, boost::shared_ptr<ErrorTermDs>, bases<ErrorTerm>, boost::noncopyable>("ErrorTermDs", no_init)
    /// \brief evaluate the error term.
    ///        After this is called, the _squaredError is filled in with \f$ \mathbf e^T \mathbf R^{-1} \mathbf e \f$
;

  ;

}


#include <algorithm>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <irkit/index.hpp>
#include <irkit/index/assembler.hpp>
#include <irkit/index/score.hpp>
#include <irkit/index/source.hpp>
#include <irkit/index/types.hpp>
#include <irkit/quantize.hpp>

namespace {

namespace fs = boost::filesystem;
namespace ts = type_safe;

using posting_type = std::pair<irk::index::document_t, irk::index::frequency_t>;
using posting_map = std::map<std::string, std::vector<posting_type>>;
using irk::index::document_t;
using irk::index::frequency_t;

struct on_fly_index {
    posting_map freq_postings;
    posting_map scored_postings;
    std::vector<long> document_sizes;
    std::map<std::string, long> occurrences;
    long collection_occurrences;
    long collection_size;
};

auto scored(const posting_map& postings,
    const std::vector<long>& document_sizes,
    std::map<std::string, long> occurrences,
    long collection_occurrences,
    int collection_size,
    int bits)
{
    long max_document_size =
        *std::max_element(document_sizes.begin(), document_sizes.end());
    std::map<std::string, std::vector<posting_type>> scored;
    double max_score = 0;
    for (const auto& [term, posting_for_term] : postings)
    {
        irk::score::query_likelihood_scorer scorer(
            occurrences[term], collection_occurrences, max_document_size);
        for (const auto& [doc, freq] : posting_for_term)
        {
            max_score = std::max(max_score, scorer(freq, document_sizes[doc]));
        }
    }
    long max_int = (1 << bits) - 1;
    for (const auto& [term, posting_for_term] : postings)
    {
        std::vector<posting_type> scored_for_term;
        irk::score::query_likelihood_scorer scorer(
            occurrences[term], collection_occurrences, max_document_size);
        auto quantize = irk::LinearQuantizer{
            irk::RealRange{0, max_score}, irk::IntegralRange{1, max_int}};
        for (const auto& [doc, freq] : posting_for_term) {
            double score = scorer(freq, document_sizes[doc]);
            long quantized_score = quantize(score);
            scored_for_term.push_back({doc, quantized_score});
        }
        scored[term] = std::move(scored_for_term);
    }
    return scored;
}

on_fly_index postings_on_fly(fs::path collection_file, int bits)
{
    std::map<std::string, std::vector<posting_type>> postings;
    std::map<std::string,
        std::map<irk::index::document_t, irk::index::frequency_t>>
        postings_map;
    std::vector<long> document_sizes;
    std::map<std::string, long> occurrences;
    std::ifstream input(collection_file.c_str());
    std::string line;
    irk::index::document_t doc(0);
    long collection_occurrences = 0;
    while (std::getline(input, line)) {
        std::istringstream line_input(line);
        std::string title, term;
        line_input >> title;
        long doc_size = 0;
        while (line_input >> term) {
            postings_map[term][doc]++;
            occurrences[term]++;
            collection_occurrences++;
            doc_size++;
        }
        document_sizes.push_back(doc_size);
        doc++;
    }
    long collection_size = doc;
    for (const auto& [term, map] : postings_map)
    {
        for (const auto& [id, count] : map) {
            postings[term].push_back({id, count});
        }
        std::sort(postings[term].begin(), postings[term].end());
    }
    return {postings,
        scored(postings,
            document_sizes,
            occurrences,
            collection_occurrences,
            collection_size,
            bits),
        document_sizes,
        occurrences,
        collection_occurrences,
        collection_size};
}

class inverted_index : public ::testing::Test {
protected:
    boost::filesystem::path index_dir;
    std::string collection_file;
    on_fly_index expected_index;

    inverted_index() {
        index_dir = irk::fs::temp_directory_path()
            / "irkit-inverted_index";
        if (irk::fs::exists(index_dir)) { irk::fs::remove_all(index_dir); }
        irk::fs::create_directory(index_dir);

        // given
        collection_file = "collection.txt";
        irk::io::enforce_exist(collection_file);
        expected_index = postings_on_fly(collection_file, 8);
        irk::index::index_assembler assembler(
            fs::path(index_dir), 32, 1024, 16);

        std::ifstream input(collection_file);
        assembler.assemble(input);
        irk::index::score_index<irk::score::query_likelihood_tag,
                                irk::Inverted_Index_Mapped_Source>(index_dir, 8);
    }
};

template<class D, class F, class S>
void test(const irk::basic_inverted_index_view<D, F, S>& index_view,
    on_fly_index& expected_index)
{
    ASSERT_EQ(index_view.collection_size(), 100);
    ASSERT_EQ(index_view.occurrences_count(), expected_index.collection_occurrences);
    for (long doc = 0; doc < index_view.collection_size(); doc++) {
        ASSERT_EQ(index_view.document_size(irk::index::document_t(doc)),
            expected_index.document_sizes[doc]);
    }

    for (long term_id = 0; term_id < index_view.terms().size(); term_id++) {
        std::string term = index_view.term(term_id);
        ASSERT_EQ(index_view.term_occurrences(term_id),
            expected_index.occurrences[term]);
        auto postings = index_view.postings(term_id);
        const auto& expected =
            expected_index.freq_postings[index_view.term(term_id)];
        std::vector<posting_type> actual;
        for (const auto& posting : postings) {
            actual.emplace_back(posting.document(), posting.payload());
        }
        ASSERT_THAT(actual, ::testing::ElementsAreArray(expected));
        auto scored_postings = index_view.scored_postings(term_id);
        const auto& expected_scored =
            expected_index.scored_postings[index_view.term(term_id)];
        std::vector<posting_type> actual_scored;
        for (const auto& posting : scored_postings) {
            actual_scored.emplace_back(posting.document(), posting.payload());
        }
        ASSERT_THAT(
            actual_scored, ::testing::ElementsAreArray(expected_scored));
    }
}

TEST_F(inverted_index, mapped_file)
{
    // when
    auto data = irk::Inverted_Index_Mapped_Source::from(index_dir, {"ql-8"}).value();
    irk::inverted_index_view index_view(data);
    // then
    test(index_view, expected_index);
}

}  // namespace

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


/* =========================================================================
   Copyright (c) 2010-2014, Institute for Microelectronics,
                            Institute for Analysis and Scientific Computing,
                            TU Wien.
   Portions of this software are copyright by UChicago Argonne, LLC.

                            -----------------
                  ViennaCL - The Vienna Computing Library
                            -----------------

   Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at

   (A list of authors and contributors can be found in the PDF manual)

   License:         MIT (X11), see file LICENSE in the base directory
============================================================================= */

/** \file tests/src/scheduler_sparse.cpp  Tests the scheduler for sparse matrix operations.
*   \test Tests the scheduler for sparse matrix operations.
**/

#ifndef NDEBUG
 #define NDEBUG
#endif

//
// *** System
//
#include <iostream>

//
// *** Boost
//
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/operation_sparse.hpp>

//
// *** ViennaCL
//
//#define VIENNACL_DEBUG_ALL
#define VIENNACL_WITH_UBLAS 1
#include "viennacl/scalar.hpp"
#include "viennacl/compressed_matrix.hpp"
#include "viennacl/coordinate_matrix.hpp"
#include "viennacl/ell_matrix.hpp"
#include "viennacl/hyb_matrix.hpp"
#include "viennacl/vector.hpp"
#include "viennacl/vector_proxy.hpp"
#include "viennacl/linalg/prod.hpp"
#include "viennacl/linalg/norm_2.hpp"
#include "viennacl/linalg/ilu.hpp"
#include "viennacl/linalg/detail/ilu/common.hpp"
#include "viennacl/io/matrix_market.hpp"
#include "examples/tutorial/Random.hpp"
#include "examples/tutorial/vector-io.hpp"

#include "viennacl/scheduler/execute.hpp"
#include "viennacl/scheduler/io.hpp"

//
// -------------------------------------------------------------
//
using namespace boost::numeric;
//
// -------------------------------------------------------------
//
template<typename ScalarType>
ScalarType diff(ScalarType & s1, viennacl::scalar<ScalarType> & s2)
{
   if (s1 != s2)
      return (s1 - s2) / std::max(fabs(s1), std::fabs(s2));
   return 0;
}

template<typename ScalarType>
ScalarType diff(ublas::vector<ScalarType> & v1, viennacl::vector<ScalarType> & v2)
{
   ublas::vector<ScalarType> v2_cpu(v2.size());
   viennacl::backend::finish();
   viennacl::copy(v2.begin(), v2.end(), v2_cpu.begin());

   for (unsigned int i=0;i<v1.size(); ++i)
   {
      if ( std::max( std::fabs(v2_cpu[i]), std::fabs(v1[i]) ) > 0 )
      {
        //if (std::max( std::fabs(v2_cpu[i]), std::fabs(v1[i]) ) < 1e-10 )  //absolute tolerance (avoid round-off issues)
        //  v2_cpu[i] = 0;
        //else
          v2_cpu[i] = std::fabs(v2_cpu[i] - v1[i]) / std::max( std::fabs(v2_cpu[i]), std::fabs(v1[i]) );
      }
      else
         v2_cpu[i] = 0.0;

      if (v2_cpu[i] > 0.0001)
      {
        //std::cout << "Neighbor: "      << i-1 << ": " << v1[i-1] << " vs. " << v2_cpu[i-1] << std::endl;
        std::cout << "Error at entry " << i   << ": " << v1[i]   << " vs. " << v2_cpu[i]   << std::endl;
        //std::cout << "Neighbor: "      << i+1 << ": " << v1[i+1] << " vs. " << v2_cpu[i+1] << std::endl;
        exit(EXIT_FAILURE);
      }
   }

   return norm_inf(v2_cpu);
}

template<typename ScalarType, typename VCL_MATRIX>
ScalarType diff(ublas::compressed_matrix<ScalarType> & cpu_matrix, VCL_MATRIX & gpu_matrix)
{
  typedef ublas::compressed_matrix<ScalarType>  CPU_MATRIX;
  CPU_MATRIX from_gpu;

  viennacl::backend::finish();
  viennacl::copy(gpu_matrix, from_gpu);

  ScalarType error = 0;

  //step 1: compare all entries from cpu_matrix with gpu_matrix:
  //std::cout << "Ublas matrix: " << std::endl;
  for (typename CPU_MATRIX::const_iterator1 row_it = cpu_matrix.begin1();
        row_it != cpu_matrix.end1();
        ++row_it)
  {
    //std::cout << "Row " << row_it.index1() << ": " << std::endl;
    for (typename CPU_MATRIX::const_iterator2 col_it = row_it.begin();
          col_it != row_it.end();
          ++col_it)
    {
      //std::cout << "(" << col_it.index2() << ", " << *col_it << std::endl;
      ScalarType current_error = 0;

      if ( std::max( std::fabs(cpu_matrix(col_it.index1(), col_it.index2())),
                      std::fabs(from_gpu(col_it.index1(), col_it.index2()))   ) > 0 )
        current_error = std::fabs(cpu_matrix(col_it.index1(), col_it.index2()) - from_gpu(col_it.index1(), col_it.index2()))
                          / std::max( std::fabs(cpu_matrix(col_it.index1(), col_it.index2())),
                                      std::fabs(from_gpu(col_it.index1(), col_it.index2()))   );
      if (current_error > error)
        error = current_error;
    }
  }

  //step 2: compare all entries from gpu_matrix with cpu_matrix (sparsity pattern might differ):
  //std::cout << "ViennaCL matrix: " << std::endl;
  for (typename CPU_MATRIX::const_iterator1 row_it = from_gpu.begin1();
        row_it != from_gpu.end1();
        ++row_it)
  {
    //std::cout << "Row " << row_it.index1() << ": " << std::endl;
    for (typename CPU_MATRIX::const_iterator2 col_it = row_it.begin();
          col_it != row_it.end();
          ++col_it)
    {
      //std::cout << "(" << col_it.index2() << ", " << *col_it << std::endl;
      ScalarType current_error = 0;

      if ( std::max( std::fabs(cpu_matrix(col_it.index1(), col_it.index2())),
                      std::fabs(from_gpu(col_it.index1(), col_it.index2()))   ) > 0 )
        current_error = std::fabs(cpu_matrix(col_it.index1(), col_it.index2()) - from_gpu(col_it.index1(), col_it.index2()))
                          / std::max( std::fabs(cpu_matrix(col_it.index1(), col_it.index2())),
                                      std::fabs(from_gpu(col_it.index1(), col_it.index2()))   );
      if (current_error > error)
        error = current_error;
    }
  }

  return error;
}

//
// -------------------------------------------------------------
//
template< typename NumericT, typename Epsilon >
int test(Epsilon const& epsilon)
{
  int retval = EXIT_SUCCESS;

  // --------------------------------------------------------------------------
  NumericT alpha = static_cast<NumericT>(2.786);
  NumericT beta = static_cast<NumericT>(1.432);

  ublas::vector<NumericT> rhs;
  ublas::vector<NumericT> result;
  ublas::compressed_matrix<NumericT> ublas_matrix;

  if (viennacl::io::read_matrix_market_file(ublas_matrix, "../examples/testdata/mat65k.mtx") == EXIT_FAILURE)
  {
    std::cout << "Error reading Matrix file" << std::endl;
    return EXIT_FAILURE;
  }
  //unsigned int cg_mat_size = cg_mat.size();
  std::cout << "done reading matrix" << std::endl;

  rhs.resize(ublas_matrix.size2());
  for (std::size_t i=0; i<rhs.size(); ++i)
  {
    ublas_matrix(i,i) = NumericT(0.5);   // Get rid of round-off errors by making row-sums unequal to zero:
    rhs[i] = NumericT(1) + random<NumericT>();
  }

  result = rhs;

  viennacl::vector<NumericT> vcl_rhs(rhs.size());
  viennacl::vector<NumericT> vcl_result(result.size());
  viennacl::vector<NumericT> vcl_result2(result.size());
  viennacl::compressed_matrix<NumericT> vcl_compressed_matrix(rhs.size(), rhs.size());
  viennacl::coordinate_matrix<NumericT> vcl_coordinate_matrix(rhs.size(), rhs.size());
  viennacl::ell_matrix<NumericT> vcl_ell_matrix;
  viennacl::hyb_matrix<NumericT> vcl_hyb_matrix;

  viennacl::copy(rhs.begin(), rhs.end(), vcl_rhs.begin());
  viennacl::copy(ublas_matrix, vcl_compressed_matrix);
  viennacl::copy(ublas_matrix, vcl_coordinate_matrix);

  // --------------------------------------------------------------------------
  std::cout << "Testing products: compressed_matrix" << std::endl;
  result     = viennacl::linalg::prod(ublas_matrix, rhs);
  {
  viennacl::scheduler::statement my_statement(vcl_result, viennacl::op_assign(), viennacl::linalg::prod(vcl_compressed_matrix, vcl_rhs));
  viennacl::scheduler::execute(my_statement);
  }
  vcl_result = viennacl::linalg::prod(vcl_compressed_matrix, vcl_rhs);

  if ( std::fabs(diff(result, vcl_result)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product with compressed_matrix" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result)) << std::endl;
    retval = EXIT_FAILURE;
  }

  std::cout << "Testing products: coordinate_matrix" << std::endl;
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = viennacl::linalg::prod(ublas_matrix, rhs);
  {
  viennacl::scheduler::statement my_statement(vcl_result, viennacl::op_assign(), viennacl::linalg::prod(vcl_coordinate_matrix, vcl_rhs));
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product with coordinate_matrix" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result)) << std::endl;
    retval = EXIT_FAILURE;
  }

  result     = alpha * viennacl::linalg::prod(ublas_matrix, rhs) + beta * result;
  {
  viennacl::scheduler::statement my_statement(vcl_result2, viennacl::op_assign(), alpha * viennacl::linalg::prod(vcl_coordinate_matrix, vcl_rhs) + beta * vcl_result);
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result2)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product (coordinate_matrix) with scaled additions" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result2)) << std::endl;
    retval = EXIT_FAILURE;
  }

  //std::cout << "Copying ell_matrix" << std::endl;
  viennacl::copy(ublas_matrix, vcl_ell_matrix);
  ublas_matrix.clear();
  viennacl::copy(vcl_ell_matrix, ublas_matrix);// just to check that it's works

  std::cout << "Testing products: ell_matrix" << std::endl;
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = viennacl::linalg::prod(ublas_matrix, rhs);
  {
  //viennacl::scheduler::statement my_statement(vcl_result, viennacl::op_assign(), viennacl::linalg::prod(vcl_ell_matrix, vcl_rhs));
  //viennacl::scheduler::execute(my_statement);
  }
  vcl_result = viennacl::linalg::prod(vcl_ell_matrix, vcl_rhs);

  if ( std::fabs(diff(result, vcl_result)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product with ell_matrix" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result)) << std::endl;
    retval = EXIT_FAILURE;
  }

  //std::cout << "Copying hyb_matrix" << std::endl;
  viennacl::copy(ublas_matrix, vcl_hyb_matrix);
  ublas_matrix.clear();
  viennacl::copy(vcl_hyb_matrix, ublas_matrix);// just to check that it's works
  viennacl::copy(ublas_matrix, vcl_hyb_matrix);

  std::cout << "Testing products: hyb_matrix" << std::endl;
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = viennacl::linalg::prod(ublas_matrix, rhs);
  {
  viennacl::scheduler::statement my_statement(vcl_result, viennacl::op_assign(), viennacl::linalg::prod(vcl_hyb_matrix, vcl_rhs));
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product with hyb_matrix" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result)) << std::endl;
    retval = EXIT_FAILURE;
  }

  // --------------------------------------------------------------------------
  // --------------------------------------------------------------------------
  copy(rhs.begin(), rhs.end(), vcl_rhs.begin());
  copy(result.begin(), result.end(), vcl_result.begin());
  copy(result.begin(), result.end(), vcl_result2.begin());
  copy(ublas_matrix, vcl_compressed_matrix);
  copy(ublas_matrix, vcl_coordinate_matrix);
  copy(ublas_matrix, vcl_ell_matrix);
  copy(ublas_matrix, vcl_hyb_matrix);

  std::cout << "Testing scaled additions of products and vectors: compressed_matrix" << std::endl;
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = alpha * viennacl::linalg::prod(ublas_matrix, rhs) + beta * result;
  {
  viennacl::scheduler::statement my_statement(vcl_result2, viennacl::op_assign(), alpha * viennacl::linalg::prod(vcl_compressed_matrix, vcl_rhs) + beta * vcl_result);
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result2)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product (compressed_matrix) with scaled additions" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result2)) << std::endl;
    retval = EXIT_FAILURE;
  }

  std::cout << "Testing scaled additions of products and vectors: coordinate_matrix" << std::endl;
  copy(result.begin(), result.end(), vcl_result.begin());
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = alpha * viennacl::linalg::prod(ublas_matrix, rhs) + beta * result;
  {
  viennacl::scheduler::statement my_statement(vcl_result2, viennacl::op_assign(), alpha * viennacl::linalg::prod(vcl_coordinate_matrix, vcl_rhs) + beta * vcl_result);
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result2)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product (coordinate_matrix) with scaled additions" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result2)) << std::endl;
    retval = EXIT_FAILURE;
  }

  std::cout << "Testing scaled additions of products and vectors: ell_matrix" << std::endl;
  copy(result.begin(), result.end(), vcl_result.begin());
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = alpha * viennacl::linalg::prod(ublas_matrix, rhs) + beta * result;
  {
  viennacl::scheduler::statement my_statement(vcl_result2, viennacl::op_assign(), alpha * viennacl::linalg::prod(vcl_ell_matrix, vcl_rhs) + beta * vcl_result);
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result2)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product (ell_matrix) with scaled additions" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result2)) << std::endl;
    retval = EXIT_FAILURE;
  }

  std::cout << "Testing scaled additions of products and vectors: hyb_matrix" << std::endl;
  copy(result.begin(), result.end(), vcl_result.begin());
  rhs *= NumericT(1.1);
  vcl_rhs *= NumericT(1.1);
  result     = alpha * viennacl::linalg::prod(ublas_matrix, rhs) + beta * result;
  {
  viennacl::scheduler::statement my_statement(vcl_result2, viennacl::op_assign(), alpha * viennacl::linalg::prod(vcl_hyb_matrix, vcl_rhs) + beta * vcl_result);
  viennacl::scheduler::execute(my_statement);
  }

  if ( std::fabs(diff(result, vcl_result2)) > epsilon )
  {
    std::cout << "# Error at operation: matrix-vector product (hyb_matrix) with scaled additions" << std::endl;
    std::cout << "  diff: " << std::fabs(diff(result, vcl_result2)) << std::endl;
    retval = EXIT_FAILURE;
  }

  // --------------------------------------------------------------------------
  return retval;
}
//
// -------------------------------------------------------------
//
int main()
{
  std::cout << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << "## Test :: Sparse Matrices" << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << std::endl;

  int retval = EXIT_SUCCESS;

  std::cout << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << std::endl;
  {
    typedef float NumericT;
    NumericT epsilon = static_cast<NumericT>(1E-4);
    std::cout << "# Testing setup:" << std::endl;
    std::cout << "  eps:     " << epsilon << std::endl;
    std::cout << "  numeric: float" << std::endl;
    retval = test<NumericT>(epsilon);
    if ( retval == EXIT_SUCCESS )
        std::cout << "# Test passed" << std::endl;
    else
        return retval;
  }
  std::cout << std::endl;
  std::cout << "----------------------------------------------" << std::endl;
  std::cout << std::endl;

#ifdef VIENNACL_WITH_OPENCL
  if ( viennacl::ocl::current_device().double_support() )
#endif
  {
    {
      typedef double NumericT;
      NumericT epsilon = 1.0E-13;
      std::cout << "# Testing setup:" << std::endl;
      std::cout << "  eps:     " << epsilon << std::endl;
      std::cout << "  numeric: double" << std::endl;
      retval = test<NumericT>(epsilon);
      if ( retval == EXIT_SUCCESS )
        std::cout << "# Test passed" << std::endl;
      else
        return retval;
    }
    std::cout << std::endl;
    std::cout << "----------------------------------------------" << std::endl;
    std::cout << std::endl;
  }
#ifdef VIENNACL_WITH_OPENCL
  else
    std::cout << "No double precision support, skipping test..." << std::endl;
#endif

  std::cout << std::endl;
  std::cout << "------- Test completed --------" << std::endl;
  std::cout << std::endl;

  return retval;
}


//           Copyright Matthew Pulver 2018 - 2019.
// Distributed under the Boost Software License, Version 1.0.
//      (See accompanying file LICENSE_1_0.txt or copy at
//           https://www.boost.org/LICENSE_1_0.txt)

#include <boost/math/differentiation/autodiff.hpp>
#include <iostream>

template <typename T>
T fourth_power(T const& x) {
  T x4 = x * x;  // retval in operator*() uses x4's memory via NRVO.
  x4 *= x4;      // No copies of x4 are made within operator*=() even when squaring.
  return x4;     // x4 uses y's memory in main() via NRVO.
}

int main() {
  using namespace boost::math::differentiation;

  constexpr unsigned Order = 5;                  // Highest order derivative to be calculated.
  auto const x = make_fvar<double, Order>(2.0);  // Find derivatives at x=2.
  auto const y = fourth_power(x);
  for (unsigned i = 0; i <= Order; ++i)
    std::cout << "y.derivative(" << i << ") = " << y.derivative(i) << std::endl;
  return 0;
}
/*
Output:
y.derivative(0) = 16
y.derivative(1) = 32
y.derivative(2) = 48
y.derivative(3) = 48
y.derivative(4) = 24
y.derivative(5) = 0
**/


// Copyright Abel Sinkovics (abel@sinkovics.hu) 2013.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <mpllibs/metamonad/lambda_c.hpp>
#include <mpllibs/metamonad/lazy.hpp>
#include <mpllibs/metamonad/eval_let.hpp>
#include <mpllibs/metamonad/let.hpp>
#include <mpllibs/metamonad/returns.hpp>
#include <mpllibs/metamonad/syntax.hpp>
#include <mpllibs/metamonad/eval_syntax.hpp>
#include <mpllibs/metamonad/apply.hpp>

#include <boost/test/unit_test.hpp>

#include "common.hpp"

#include <boost/mpl/int.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/assert.hpp>

#include <boost/type_traits.hpp>

BOOST_AUTO_TEST_CASE(test_lambda_c)
{
  using boost::mpl::plus;
  using boost::mpl::equal_to;

  using boost::is_same;

  using mpllibs::metamonad::lambda_c;
  using mpllibs::metamonad::lazy;
  using mpllibs::metamonad::eval_let;
  using mpllibs::metamonad::let;
  using mpllibs::metamonad::_;
  using mpllibs::metamonad::returns;
  using mpllibs::metamonad::syntax;
  using mpllibs::metamonad::eval_syntax;
  using mpllibs::metamonad::apply;

  // test_metaprogramming_value
  BOOST_MPL_ASSERT((
    equal_to<int13, lambda_c<plus<int2, int11> >::type::apply<>::type>
  ));

  // test_no_argument
  BOOST_MPL_ASSERT((
    equal_to<int13, lambda_c<plus<int2, int11> >::apply<>::type>
  ));

  // test_simple_lambda
  BOOST_MPL_ASSERT((
    equal_to<int13, apply<lambda_c<x, plus<x, int11> >, int2>::type>
  ));

  // test_nested_lambda
  BOOST_MPL_ASSERT((
    equal_to<
      int13,
      apply<lambda_c<x, y, plus<x, y> >, int2, int11>::type
    >
  ));

  // test_multiple_arguments
  BOOST_MPL_ASSERT((
    equal_to<
      int13,
      apply<apply<lambda_c<x, lambda_c<y, plus<x, y> > >, int2>, int11>::type
    >
  ));

  // test_currying
  BOOST_MPL_ASSERT((
    equal_to<int13, apply<apply<lambda_c<x, y, plus<x,y> >, int2>, int11>::type>
  ));

  // test_let_and_lambda_body
  BOOST_MPL_ASSERT((
    equal_to<
      int11,
      apply<
        eval_syntax<let<a, syntax<int11>, syntax<lambda_c<b, a> > > >,
        int13
      >::type
    >
  ));

  // test_let_and_lambda3_body
  BOOST_MPL_ASSERT((
    equal_to<
      int1,
      eval_syntax<
        let<
          s, syntax<int11>,
          syntax<apply<lambda_c<x, s, z, s>, int0, int1, int2> >
        >
      >::type
    >
  ));

  // test_let_and_lambda3_arg
  BOOST_MPL_ASSERT((
    equal_to<
      int11,
      eval_syntax<
        let<
          s, syntax<int11>,
          syntax<apply<lambda_c<x, s, z, int11>, int0, int1, int2> >
        >
      >::type
    >
  ));

  // test_nested_lambda
  BOOST_MPL_ASSERT((
    equal_to<
      int13,
      apply<apply<lambda_c<a, lambda_c<b, a> >, int13>, int11>::type
    >
  ));

  // test_unused_arg
  BOOST_MPL_ASSERT((is_same<_, apply<lambda_c<_, returns<_> >, int13>::type>));

  // test_parameter_hiding
  BOOST_MPL_ASSERT((
    equal_to<
      int13,
      apply<lambda_c<e, apply<lambda_c<e, e>::type, e> >, int13>::type
    >
  ));

  // test_currying_and_lambda
  BOOST_MPL_ASSERT((
    equal_to<
      int13,
      apply<
        eval_let<
          y, syntax<int1>,
          syntax<apply<lambda_c<x, y, y>, int11> >
        >,
        int13
      >::type
    >
  ));
}


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

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

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

#include <iostream>
#include <iterator>
#include <string>

#include <geometry_test_common.hpp>

#include <boost/geometry/extensions/algorithms/midpoints.hpp>
#include <boost/geometry/algorithms/make.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

#include <boost/geometry/io/dsv/write.hpp>

#include <boost/geometry/io/wkt/wkt.hpp>

template <typename G>
void test_midpoints(G const& g, bool start_and_end)
{
    G processed;
    bg::midpoints(g, start_and_end, std::back_inserter(processed));
    std::cout << bg::dsv(processed) << std::endl;
}

template <typename G>
void test_midpoints(std::string const& wkt)
{
    G g;
    bg::read_wkt(wkt, g);
    test_midpoints(g, true);
    test_midpoints(g, false);
}

template <typename P>
void test_all()
{
    test_midpoints<bg::model::linestring<P> >("LINESTRING(1 1,2 2,3 3)");
}

int test_main(int, char* [])
{
    //test_all<bg::model::d2::point_xy<float> >();
    test_all<bg::model::d2::point_xy<double> >();

    return 0;
}


/// @file test_raster_utils.cc
/// @brief test raster utils
/// @author Jeff Perry <jeffsp@gmail.com>
/// @version 1.0
/// @date 2013-01-14

#include "horny_toad/about_equal.h"
#include "jack_rabbit/raster.h"
#include "horny_toad/raster_utils.h"
#include "jack_rabbit/subscript_function.h"
#include "horny_toad/verify.h"
#include <numeric>
#include <boost/lambda/lambda.hpp>
#include <boost/random/uniform_01.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>
#include <iostream>

using namespace boost;
using namespace boost::lambda;
using namespace horny_toad;
using namespace jack_rabbit;
using namespace std;

void test_convenience ()
{
    rotation<double> r (radians (90));
    VERIFY (about_equal (r.fx (1, 0), 0.0));
    VERIFY (about_equal (r.fy (1, 0), 1.0));
    VERIFY (about_equal (r.fx (0, 1), -1.0));
    VERIFY (about_equal (r.fy (0, 1), 0.0));
}

void test_aperture (bool verbose)
{
    raster<double> m (7, 9);
    subscript_generator<double,aperture> a (m.rows (), m.cols ());
    generate (m.begin (), m.end (), a);
    if (verbose)
        print2d (clog, m);
    VERIFY (m.front () == 0.0); // outside
    VERIFY (m (m.rows () / 2, m.cols () / 2) == 1.0); // inside
    VERIFY (m.back () == 0.0); // outside
    subscript_unary_function<double,aperture> aa (m.rows (), m.cols ());
    aa.ramp (1.0);
    transform (m.begin (), m.end (), m.begin (), aa);
    if (verbose)
        print2d (clog, m);
    VERIFY (m.front () == 0.0); // outside
    size_t on_edge = static_cast<size_t> (m.cols () / 2 - a.radius () + 1);
    VERIFY (m (m.rows () / 2, on_edge) < 1.0);
    VERIFY (m (m.rows () / 2, on_edge) > 0.0);
    VERIFY (m.back () == 0.0); // outside
    if (verbose)
    {
        clog << "aperture" << endl;
        raster<double> m (600, 800, 1.0);
        subscript_unary_function<double,aperture> a (m.rows (), m.cols ());
        a.ramp (10.0);
        transform (m.begin (), m.end (), m.begin (), a);
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 127.5));
        transform (m.begin (), m.end (), m.begin (), bind2nd (plus<double> (), 127.5));
        //Display (m);
    }
}

void test_oriented_sin (bool verbose)
{
    raster<double> m (5, 5, 1.0);
    subscript_unary_function<double,oriented_sin> g (m.rows (), m.cols ());
    transform (m.begin (), m.end (), m.begin (), g);
    if (verbose)
        print2d (clog, m);
    VERIFY (about_equal (m (0, 0), 0.0));
    VERIFY (about_equal (m (0, 1), -1.0));
    VERIFY (about_equal (m (0, 2), 0.0));
    VERIFY (about_equal (m (0, 3), 1.0));
    VERIFY (about_equal (m (0, 4), 0.0));
    g.orientation (radians (90));
    m.assign (1.0);
    transform (m.begin (), m.end (), m.begin (), g);
    if (verbose)
        print2d (clog, m);
    VERIFY (about_equal (m (0, 0), 0.0));
    VERIFY (about_equal (m (1, 0), 1.0));
    VERIFY (about_equal (m (2, 0), 0.0));
    VERIFY (about_equal (m (3, 0), -1.0));
    VERIFY (about_equal (m (4, 0), 0.0));

    if (verbose)
    {
        clog << "oriented sine" << endl;
        raster<double> m (600, 800, 1.0);
        subscript_unary_function<double,oriented_sin> s (m.rows (), m.cols ());
        s.orientation (radians (30));
        transform (m.begin (), m.end (), m.begin (), s);
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 127.5));
        transform (m.begin (), m.end (), m.begin (), bind2nd (plus<double> (), 127.5));
        //Display (m);
    }
}

void test_radial_cos (bool verbose)
{
    raster<double> m (5, 5, 1.0);
    subscript_unary_function<double,radial_cos> c (m.rows (), m.cols ());
    transform (m.begin (), m.end (), m.begin (), c);
    if (verbose)
        print2d (clog, m);
    VERIFY (about_equal (m (2, 0), -1.0));
    VERIFY (about_equal (m (2, 2), 1.0));
    VERIFY (about_equal (m (2, 4), -1.0));
    if (verbose)
    {
        clog << "radial cosine" << endl;
        raster<double> m (600, 800, 1.0);
        subscript_unary_function<double,radial_cos> c (m.rows (), m.cols ());
        transform (m.begin (), m.end (), m.begin (), c);
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 127.5));
        transform (m.begin (), m.end (), m.begin (), bind2nd (plus<double> (), 127.5));
        //Display (m);
    }
}

void test_raised_cos (bool verbose)
{
    raster<double> m (5, 5);
    subscript_generator<double,raised_cos> c (m.rows (), m.cols ());
    generate (m.begin (), m.end (), c);
    if (verbose)
        print2d (clog, m);
    //VERIFY (about_equal (m (0, 0), 0.0));
    //VERIFY (about_equal (m (0, 4), 0.0));
    //VERIFY (about_equal (m (2, 2), 1.0));
    //VERIFY (about_equal (m (4, 0), 0.0));
    //VERIFY (about_equal (m (4, 4), 0.0));
    //VERIFY (m (1, 1) != 0.0);
    //VERIFY (m (1, 1) != 1.0);
    if (verbose)
    {
        clog << "raised cosine" << endl;
        raster<double> m (600, 800);
        subscript_generator<double,raised_cos> c (m.rows (), m.cols ());
        generate (m.begin (), m.end (), c);
        //transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 127.5));
        //transform (m.begin (), m.end (), m.begin (), bind2nd (plus<double> (), 127.5));
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 255));
        //Display (m);
        clog << "raised cosine w/half_height" << endl;
        c.half_height (c.radius () * 1 / 11);
        generate (m.begin (), m.end (), c);
        //transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 127.5));
        //transform (m.begin (), m.end (), m.begin (), bind2nd (plus<double> (), 127.5));
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 255));
        //Display (m);
    }
}

void test_gaussian_window (bool verbose)
{
    raster<double> m (5, 5, 1.0);
    subscript_unary_function<double,gaussian_window> g (m.rows (), m.cols ());
    g.stddev (m.rows () / 40.0);
    transform (m.begin (), m.end (), m.begin (), g);
    if (verbose)
        print2d (clog, m);
    VERIFY (about_equal (m (2, 0), 0.0));
    VERIFY (about_equal (m (2, 2), 1.0));
    VERIFY (about_equal (m (2, 4), 0.0));

    if (verbose)
    {
        clog << "gaussian window" << endl;
        raster<double> m (600, 800);
        subscript_generator<double,gaussian_window> g (m.rows (), m.cols ());
        generate (m.begin (), m.end (), g);
        transform (m.begin (), m.end (), m.begin (), bind2nd (multiplies<double> (), 255));
        //Display (m);
    }

    {
    if (verbose)
        clog << "gaussian window" << endl;

    raster<double> m (6, 6);
    subscript_generator<double,gaussian_window> g (m.rows (), m.cols ());
    g.stddev (0.85);
    generate (m.begin (), m.end (), g);
    if (verbose)
        print2d (clog, m);
    VERIFY (about_equal (m (2, 2), 0.707));
    }
}

void test_mean (bool verbose)
{
    const size_t W = 4;
    const size_t H = 5;
    const size_t SW = 3;
    const size_t SH = 4;
    raster<double> m (H, W, 128.0);
    // Create a weighting function
    raster<double> w (SH, SW, 1.0);
    w (SH - 1, 0) = 2;
    // Image subregion
    subregion s = { 0, 0, SH, SW };
    // Zero out the top left corner
    for_each (m.begin (s), m.end (s), _1 = 0.0);
    double mean = local_mean (m.begin (s), m.end (s), w.begin ());
    if (verbose)
    {
        clog << "local mean" << endl;
        clog << "image" << endl;
        print2d (clog, m);
        clog << "weights" << endl;
        print2d (clog, w);
        clog << "mean = " << mean << endl;
    }
    VERIFY (about_equal (mean, 0.0));
    s.c = 1;
    mean = local_mean (m.begin (s), m.end (s), w.begin ());
    if (verbose)
        clog << "mean = " << mean << endl;
    VERIFY (about_equal (mean, 4 * 128.0));
    s.r = 1;
    mean = local_mean (m.begin (s), m.end (s), w.begin ());
    if (verbose)
        clog << "mean = " << mean << endl;
    VERIFY (about_equal (mean, 7 * 128.0));
    // violates invariant:
    //s.r = 2;
    //mean = local_mean (m, s, w);
    mean = local_mean (m.begin (s), m.end (s));
    if (verbose)
        clog << "mean = " << mean << endl;
    VERIFY (about_equal (mean, 6 * 128.0 / (SW * SH)));
}

void test_variance (bool verbose)
{
    const size_t W = 1000;
    const size_t H = 1000;
    raster<double> m (H, W);
    // Create a uniform rng
    uniform_01<boost::mt19937> uni_rng (boost::mt19937 (17));
    // Create a random patch
    generate (m.begin (), m.end (), uni_rng);
    if (verbose)
    {
        clog << "variance" << endl;
        double mean = accumulate (m.begin (), m.end (), 0.0) / (W * H);
        clog << "mean = " << mean << endl;
        double var = 0.0;
        for (size_t i = 0; i < m.size (); ++i)
            var += (m[i] - mean) * (m[i] - mean);
        var /= m.size ();
        clog << "variance = " << var << endl;
        subregion s = { 100, 100, 100, 100 };
        // Weight normalized to 1.0
        raster<double> w (s.rows, s.cols, 1.0 / (s.rows * s.cols));
        double lmean = local_mean (m.begin (s), m.end (s));
        clog << "local mean = " << lmean << endl;
        double lvar = local_variance (m.begin (s), m.end (s), w.begin ());
        clog << "local variance = " << lvar << endl;
        VERIFY (about_equal (mean, lmean, 0.01));
        VERIFY (about_equal (var, lvar, 0.01));
    }
}

void test_rms_contrast (bool verbose)
{
    const size_t W = 1000;
    const size_t H = 1000;
    raster<double> m (H, W);
    // Create a uniform rng
    uniform_01<boost::mt19937> uni_rng (boost::mt19937 (17));
    // Create a random patch
    generate (m.begin (), m.end (), uni_rng);
    double mean = accumulate (m.begin (), m.end (), 0.0) / (W * H);
    if (verbose)
        clog << "mean: " << mean << endl;
    // Create a uniform weighting function
    raster<double> w (H, W, 1.0 / (W * H));
    double w_sum = accumulate (w.begin (), w.end (), 0.0);
    double rms = local_rms_contrast_p (m.begin (), m.end (), w.begin (), w_sum, 0.0);
    // rms of uniform [0,1] = 0.5773
    if (verbose)
        clog << "rms contrast: " << rms << endl;
    VERIFY (about_equal (rms, 0.58, 0.01));
    double rms2 = local_rms_contrast (m.begin (), m.end (), w.begin ());
    if (verbose)
        clog << "rms contrast2: " << rms2 << endl;
    VERIFY (about_equal (rms, rms2));

    // Create an aperture
    subscript_generator<double,aperture> a (w.rows (), w.cols ());
    generate (w.begin (), w.end (), a);
    // Multiply by a raised cosine
    subscript_unary_function<double,radial_cos> c (w.rows (), w.cols ());
    // Raised cosine, -1 to 1
    transform (w.begin (), w.end (), w.begin (), c);
    // Raised cosine, 0 to 1
    for_each (w.begin (), w.end (), _1 = (_1 + 1.0) / 2);

    // Zero contrast
    raster<unsigned char> mc (H, W, 127);
    w_sum = accumulate (w.begin (), w.end (), 0.0);
    rms = local_rms_contrast_p (mc.begin (), mc.end (), w.begin (), w_sum, 0.0);
    if (verbose)
        clog << "rms contrast: " << rms << endl;
    VERIFY (about_equal (rms, 0.0));
    // Normalize w
    for_each (w.begin (), w.end (), _1 = (_1 / w_sum));
    w_sum = accumulate (w.begin (), w.end (), 0.0);
    if (verbose)
        clog << "w_sum: " << w_sum << endl;
    rms2 = local_rms_contrast (mc.begin (), mc.end (), w.begin ());
    if (verbose)
        clog << "rms contrast2: " << rms2 << endl;
    VERIFY (about_equal (rms, rms2));

    // Random pixels
    boost::mt19937 rng;
    uniform_int<> uni_int (0, 255);
    variate_generator<boost::mt19937&, uniform_int<> > sampler (rng, uni_int);
    generate (mc.begin (), mc.end (), sampler);
    mean = accumulate (mc.begin (), mc.end (), 0.0) / (W * H);
    w_sum = accumulate (w.begin (), w.end (), 0.0);
    rms = local_rms_contrast_p (mc.begin (), mc.end (), w.begin (), w_sum, 0.0);
    // rms of uniform [0,1] = 0.5773
    if (verbose)
        clog << "rms contrast: " << rms << endl;
    VERIFY (about_equal (rms, 0.58, 0.01));
}

void test_rms_contrast_image (bool verbose)
{
    // Test rms across an entire image
    raster<double> w (5, 5);
    subscript_generator<double,raised_cos> weighting_function (w.rows (), w.cols ());
    generate (w.begin (), w.end (), weighting_function);

    const unsigned W = 16;
    const unsigned H = 16;

    // Create a random image
    raster<uint16_t> img (H, W);
    generate (img.begin (), img.end (), rand);

    raster<double> c;

    c = rms_contrast<subregion> (img, w);

    if (verbose)
    {
        clog << "weights:" << endl;
        print2d (clog, w);
        clog << "image:" << endl;
        print2d (clog, img);
        clog << "contrast:" << endl;
        print2d (clog, c);
    }

    raster<double> m (c.rows (), c.cols ());

    rms_contrast_m<subregion> (img, w, c, m);

    if (verbose)
    {
        clog << "weights:" << endl;
        print2d (clog, w);
        clog << "image:" << endl;
        print2d (clog, img);
        clog << "contrast:" << endl;
        print2d (clog, c);
    }
}

void test_convolve (bool verbose)
{
    // Test convolution across an entire image
    raster<double> w (5, 5);
    subscript_generator<double,raised_cos> weighting_function (w.rows (), w.cols ());
    generate (w.begin (), w.end (), weighting_function);
    double w_sum = std::accumulate (w.begin (), w.end (), 0.0);
    for_each (w.begin (), w.end (),  _1 = _1 / w_sum);

    const unsigned W = 16;
    const unsigned H = 16;

    // Create a random image
    raster<uint16_t> img (H, W);
    generate (img.begin (), img.end (), rand);

    raster<double> m;

    m = convolve<subregion> (img, w);

    if (verbose)
    {
        clog << "weights:" << endl;
        print2d (clog, w);
        clog << "image:" << endl;
        print2d (clog, img);
        clog << "mean:" << endl;
        print2d (clog, m);
    }
}

void test_split3_join3 (bool verbose)
{
    raster<unsigned char> d (5, 5 * 3);
    for (raster<unsigned char>::iterator i = d.begin (); i != d.end (); )
    {
        *i++ = 'a';
        *i++ = 'b';
        *i++ = 'c';
    }
    if (verbose)
    {
        clog << "src:" << endl;
        print2d (clog, d);
    }
    raster<float> a (5, 5);
    raster<float> b (5, 5);
    raster<float> c (5, 5);
    split3 (d.begin (), d.end (), a.begin (), b.begin (), c.begin ());
    if (verbose)
    {
        clog << "a:" << endl;
        print2d (clog, a);
        clog << "b:" << endl;
        print2d (clog, b);
        clog << "c:" << endl;
        print2d (clog, c);
    }
    raster<unsigned char> e (5, 5 * 3);
    join3 (a.begin (), a.end (), b.begin (), c.begin (), e.begin ());
    if (verbose)
    {
        clog << "e:" << endl;
        print2d (clog, e);
    }
    VERIFY (d == e);
}

template<typename T>
struct add_op { T operator() (T a, T b, T c) { return a + b + c; } };

void test_transform3 (bool verbose)
{
    raster<int> a (5, 5, 1);
    raster<int> b (5, 5, 3);
    raster<int> c (5, 5, 7);
    raster<int> d (5, 5, 0);
    if (verbose)
    {
        clog << "a:" << endl;
        print2d (clog, a);
        clog << "b:" << endl;
        print2d (clog, b);
        clog << "c:" << endl;
        print2d (clog, c);
    }
    transform3 (a.begin (), a.end (), b.begin (), c.begin (), d.begin (), add_op<int> ());
    if (verbose)
    {
        clog << "d:" << endl;
        print2d (clog, d);
    }
    VERIFY (d == raster<int> (5, 5, 11));
}

void test_reflect (bool verbose)
{
    if (verbose)
        clog << "reflect(0,10)=" << reflect (0, 10) << endl;
    VERIFY (reflect (0, 10) == 0);
    if (verbose)
        clog << "reflect(-1,10)=" << reflect (-1, 10) << endl;
    VERIFY (reflect (-1, 10) == 1);
    if (verbose)
        clog << "reflect(9,10)=" << reflect (9, 10) << endl;
    VERIFY (reflect (9, 10) == 9);
    if (verbose)
        clog << "reflect(10,10)=" << reflect (10, 10) << endl;
    VERIFY (reflect (10, 10) == 10);
    if (verbose)
        clog << "reflect(11,10)=" << reflect (11, 10) << endl;
    VERIFY (reflect (11, 10) == 9);
}

void test_mirrored_dot_product (bool verbose)
{
    raster<int> p (100, 100, 1);
    // create gaussian kernel
    raster<double> g (11, 11, 1.0);
    subscript_unary_function<double,gaussian_window> f (g.rows (), g.cols ());
    f.stddev (1.0);
    std::transform (g.begin (), g.end (), g.begin (), f);
    if (verbose)
        print2d (clog, g);
    double x = mirrored_dot_product (g, p, 99, 99);
    if (verbose)
        clog << "x=" << x << endl;
    VERIFY (x > 6);
    raster<int> q (100, 200);
    for (size_t i = 0; i < q.rows (); ++i)
    for (size_t j = 0; j < q.cols (); ++j)
        q (i, j) = i;
    raster<int> h (17, 11, 1);
    // mirror at the corners
    int d1 = mirrored_dot_product (h, q, 0, 0);
    if (verbose)
        clog << "d1=" << d1 << endl;
    int d2 = mirrored_dot_product (h, q, 1-h.rows (), 1-h.cols ());
    if (verbose)
        clog << "d2=" << d2 << endl;
    VERIFY (d1 == d2);
    d1 = mirrored_dot_product (h, q, 0, q.cols()-h.cols ());
    if (verbose)
        clog << "d1=" << d1 << endl;
    d2 = mirrored_dot_product (h, q, 1-h.rows (), q.cols()-1);
    if (verbose)
        clog << "d2=" << d2 << endl;
    VERIFY (d1 == d2);
    d1 = mirrored_dot_product (h, q, q.rows()-h.rows(), 0);
    if (verbose)
        clog << "d1=" << d1 << endl;
    d2 = mirrored_dot_product (h, q, q.rows()-1, 1-h.cols());
    if (verbose)
        clog << "d2=" << d2 << endl;
    VERIFY (d1 == d2);
    d1 = mirrored_dot_product (h, q, q.rows()-h.rows(), q.cols()-h.cols());
    if (verbose)
        clog << "d1=" << d1 << endl;
    d2 = mirrored_dot_product (h, q, q.rows()-1, q.cols()-1);
    if (verbose)
        clog << "d2=" << d2 << endl;
    VERIFY (d1 == d2);
}

void test_crop (bool verbose)
{
    raster<int> p (9, 9);
    for (size_t i = 0; i < p.rows (); ++i)
        for (size_t j = 0; j < p.cols (); ++j)
            p (i, j) = (i + 1) * 10 + (j + 1);
    if (verbose)
        print2d (clog, p);
    raster<int> q = crop (p, 2, 3, 8, 7);
    if (verbose)
        print2d (clog, q);
    VERIFY (q(0,0) == 34);
    VERIFY (q(6,4) == 98);
    q = crop (p, 2);
    if (verbose)
        print2d (clog, q);
    VERIFY (q(0,0) == 33);
    VERIFY (q(4,4) == 77);
}

void test_border (bool verbose)
{
    raster<int> p (3, 3);
    for (size_t i = 0; i < p.rows (); ++i)
        for (size_t j = 0; j < p.cols (); ++j)
            p (i, j) = (i + 1) * 10 + (j + 1);
    if (verbose)
        print2d (clog, p);
    raster<int> q = border<subregion> (p, 2);
    if (verbose)
        print2d (clog, q);
    VERIFY (q(0,0) == 0);
    VERIFY (q(2,2) == 11);
    VERIFY (q(4,4) == 33);
    q = mborder<subregion> (p, 2);
    if (verbose)
        print2d (clog, q);
    VERIFY (q(0,0) == 33);
    VERIFY (q(0,3) == 32);
    VERIFY (q(3,0) == 23);
    VERIFY (q(2,2) == 11);
    VERIFY (q(4,4) == 33);
    VERIFY (q(6,6) == 11);
    VERIFY (q(3,6) == 21);
    VERIFY (q(6,3) == 12);
}

unsigned rand (unsigned n) { return rand () % n; }

void test_flip (bool verbose)
{
    const size_t N = 10;
    for (size_t n = 0; n < rand (N); ++n)
    {
        const size_t R = rand (N) + N;
        const size_t C = rand (N) + N;
        raster<int> p (R, C);
        raster<int> q (R, C);
        for (size_t i = 0; i < p.rows (); ++i)
            for (size_t j = 0; j < p.cols (); ++j)
                p (i, j) = i * p.cols () + j;
        for (size_t i = 0; i < q.rows (); ++i)
            for (size_t j = 0; j < q.cols (); ++j)
                q (i, j) = i * q.cols () + q.cols () - j - 1;
        if (verbose)
            print2d (clog, p);
        if (verbose)
            print2d (clog, q);
        q = fliplr (q);
        if (verbose)
            print2d (clog, q);
        VERIFY (p == q);
        for (size_t i = 0; i < q.rows (); ++i)
            for (size_t j = 0; j < q.cols (); ++j)
                q (i, j) = (q.rows () - i - 1) * q.cols () + j;
        if (verbose)
            print2d (clog, p);
        if (verbose)
            print2d (clog, q);
        q = flipud (q);
        if (verbose)
            print2d (clog, q);
        VERIFY (p == q);
        for (size_t i = 0; i < q.rows (); ++i)
            for (size_t j = 0; j < q.cols (); ++j)
                q (i, j) = (q.rows () - i - 1) * q.cols () + (q.cols () - j - 1);
        if (verbose)
            print2d (clog, p);
        if (verbose)
            print2d (clog, q);
        q = fliplrud (q);
        if (verbose)
            print2d (clog, q);
        VERIFY (p == q);
    }
}

void test_transpose (bool verbose)
{
    const size_t N = 10;
    for (size_t n = 0; n < rand (N); ++n)
    {
        const size_t R = rand (N) + N;
        const size_t C = rand (N) + N;
        raster<int> p (R, C);
        raster<int> q (C, R);
        for (size_t i = 0; i < p.rows (); ++i)
            for (size_t j = 0; j < p.cols (); ++j)
                p (i, j) = q (j, i) = i * p.cols () + j;
        if (verbose)
            print2d (clog, p);
        if (verbose)
            print2d (clog, q);
        q = transpose (q);
        if (verbose)
            print2d (clog, q);
        VERIFY (p == q);
    }
}

int main (int argc, char **)
{
    try
    {
        const bool verbose = (argc != 1);
        test_convenience ();
        test_aperture (verbose);
        test_oriented_sin (verbose);
        test_radial_cos (verbose);
        test_raised_cos (verbose);
        test_gaussian_window (verbose);
        test_mean (verbose);
        test_variance (verbose);
        test_rms_contrast (verbose);
        test_rms_contrast_image (verbose);
        test_convolve (verbose);
        test_split3_join3 (verbose);
        test_transform3 (verbose);
        test_reflect (verbose);
        test_mirrored_dot_product (verbose);
        test_crop (verbose);
        test_border (verbose);
        test_flip (verbose);
        test_transpose (verbose);

        return 0;
    }
    catch (const exception &e)
    {
        cerr << e.what () << endl;
        return -1;
    }
}


#include <omp.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <sstream>
#include <functional>
#include <cstring>
#include <sys/time.h>
#include <boost/random.hpp>
#include <boost/random/random_device.hpp>

#define N_NODES 1024000

using namespace std;
using namespace boost::random;

int random_gen(int low_lim, int high_lim);

typedef struct Edge{
	int src, dest;
}Edge;

class Graph{
	public:
	vector<vector<int>>* adjList;
	Graph(){
		this->adjList = new vector<vector<int>>(N_NODES, vector<int>(10));
	};
	Graph(const Graph &g){
		this->adjList = new vector<vector<int>>(N_NODES);
		*adjList = *(g.adjList);
	};
	Graph(vector<vector<int>> *adjList){
		this->adjList =  new vector<vector<int>>();
		this->adjList->resize(adjList->size());
		for(int i=0; i< adjList->size(); i++){
			for(auto v:adjList->at(i)){
				(this->adjList)->at(i).push_back(v);
			}
		}
		*(this->adjList) = *adjList;
	};
	Graph(vector<Edge> const &edges, int n_nodes){
		this->adjList =  new vector<vector<int>>();
		adjList->resize(n_nodes);
		for(auto &edge:edges){
			(*adjList)[edge.src].push_back(edge.dest);
		}
	};
};

class PageRank{
	public:
	vector<float>* PR;
	Graph* g;
	PageRank(Graph *g){
		this->PR = new vector<float>(N_NODES, 1);
		this->g = new Graph(*g);
	};
	void Update(int num_iter){
		vector<float>* PR_new = new vector<float>(N_NODES, 0.0);
		while(num_iter--){
			PR_new->resize(N_NODES, 0.0);
			for(int i = 0; i < this->g->adjList->size(); i++){
				int adjLen = this->g->adjList->at(i).size();
				for(int j = 0; j < adjLen; j++){
					int dest = this->g->adjList->at(i).at(j);
					PR_new->at(dest) += this->PR->at(i) / adjLen;
				}
			}
			this->PR = PR_new;
		}
	};
	void UpdatePar(int num_iter){
		vector<float>* PR_new = new vector<float>(N_NODES, 0.0);
		omp_lock_t lock[N_NODES];
		for (int i=0; i<N_NODES; i++){
			omp_init_lock(&(lock[i]));
		}
		while(num_iter--){
			PR_new->resize(N_NODES, 0.0);
			int i,j;
			#pragma omp parallel for shared(PR_new) private(i,j)
			for(i = 0; i < this->g->adjList->size(); i++){
				int adjLen = this->g->adjList->at(i).size();
				for(j = 0; j < adjLen; j++){
					int dest = this->g->adjList->at(i).at(j);
					//#pragma omp critical
					omp_set_lock(&(lock[dest]));
					PR_new->at(dest) += this->PR->at(i) / adjLen;

					omp_unset_lock(&(lock[dest]));
				}
			}
			this->PR = PR_new;
		}
		for (int i=0; i<N_NODES; i++){
			omp_destroy_lock(&(lock[i]));
		}
	};
	void Print(){
		for(auto pr:*PR){
			std::cout << pr << " ";
		}
		std::cout <<  std::endl;
	};
	bool operator ==(const PageRank& rt){
		if(this->PR->size() != rt.PR->size()){
			return false;
		}
		for(int i=0; i < this->PR->size(); i++){
			//std::cout <<"i: "<< i << " " << this->PR->at(i) << " " << rt.PR->at(i) << std::endl;
			if( fabs(this->PR->at(i) - rt.PR->at(i)) > 0.001 ){
				return false;
			}
		};
		return true;
	}
};

int random_gen(int low_lim, int high_lim){
	boost::random::random_device seeder;
	boost::random::mt19937 gen(seeder());
	boost::random::uniform_int_distribution<> dist(low_lim,high_lim);

	int rand_num = dist(gen);
	return rand_num;
}

Graph *g;

void init(){
	vector<vector<int>>* adjList = new vector<vector<int>>(N_NODES);
	#pragma omp parallel for shared(adjList)
	for(int i = 0; i< N_NODES; i++){
		int n_edge_this_node = random_gen(1,10);
		vector<int> edges;
		while(n_edge_this_node > 0){
			bool edge_exists = false;
			int dest = random_gen(0, N_NODES - 1);
			if(dest == i){
				continue;
			}
			for(auto it = edges.begin(); it != edges.end(); ++it){
				if(*it == dest){
					edge_exists = true;
					break;
				}
			}
			if(edge_exists){
				continue;
			}
			n_edge_this_node--;
			edges.push_back(dest);
		}
		//adjList->at(i) = *(new vector<int>(edges));
		adjList->at(i) = edges;
	}
	std::cout << "Finished Init Graph" << std::endl;
	g = new Graph(adjList);
}

std::string time_cal(std::function<void()> func){

	struct timespec start,end;

	clock_gettime(CLOCK_REALTIME, &start);
	func();
	clock_gettime(CLOCK_REALTIME, &end);
	std::stringstream ss;
	ss <<  end.tv_sec - start.tv_sec;
	ss <<  " ";
	ss <<  end.tv_nsec - start.tv_nsec;

	return ss.str();
}

void print_graph(Graph* g){
	for(int i=0; i < g->adjList->size(); i++){
		std:cout << "Edges: src at " << i << "Len dests:" << g->adjList->at(i).size() << std::endl;
		for(auto v:g->adjList->at(i)){
			std::cout << v <<" ";
		}
		std::cout << std::endl;
	}
}

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

	init();
	PageRank* pr = new PageRank(g);
	PageRank* pr_par = new PageRank(g);
	bool is_same;
	int num_iter = 100;

	auto up_seq = std::bind(&PageRank::Update, pr, num_iter);
	auto up_par = std::bind(&PageRank::UpdatePar, pr_par, num_iter);
	auto seq_time = time_cal(up_seq);
	auto par_time = time_cal(up_par);

	is_same = (*pr) == (*pr_par);
	std::cout << is_same << std::endl;
	std::cout << seq_time << std::endl;
	std::cout << par_time << std::endl;
}


// ysoftman
// boost datetimestring 파싱
#include <iostream>
#include <sstream>
#include <string>
#include <boost/date_time/format_date_parser.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/special_values_parser.hpp>

using namespace std;

bool parseDateString(string datestring)
{
	string dateformat("%Y%m%d%H%M%s");
	std::locale loc("");
	// 그레고리안 달력 타입으로 파싱
	// format_date_parser 는 년,월,일,달력등의 date_type 만 받을 수 있음
	boost::date_time::format_date_parser<boost::gregorian::date, char> parser("", loc);
	boost::date_time::special_values_parser<boost::gregorian::date, char> svp;

	boost::gregorian::date d;
	try
	{
		d = parser.parse_date(datestring, dateformat, svp);
		cout << d << endl;
	}
	catch (...)
	{
		cout << "parse_date() exception!" << endl;
		return false;
	}

	return true;
}

int main()
{
	cout << "boost date_time_string test" << endl;
	// 정상적인 경우
	cout << "return :" << parseDateString("20060102150405") << endl;
	// 비정상적인 날짜
	cout << "return :" << parseDateString("20062102150405") << endl;
	// 시,분,초는 영향을 주지 않는다.
	cout << "return :" << parseDateString("20060102150495") << endl;

	return 0;
}


#include <boost/graph/adjacency_list.hpp>
#include <boost/test/unit_test.hpp>

#include "algos.h"
#include "random_graph.h"

#define REPEAT(n) for (unsigned i__ = 0; i__ < (n); i__++)

typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph;

BOOST_AUTO_TEST_SUITE(LexP)

/**
 * Ensure that the elimination order computed by lex_p() on a chordal graph is
 * perfect (i.e. it has empty fill-in).
 */
BOOST_AUTO_TEST_CASE(order_is_perfect_for_chordal_graphs) {
	REPEAT(10) {
		Graph g = gen_random_chordal_graph<Graph>(500, 75000);
		auto o = lex_p(g);
		auto f = fill_in(g, o);

		BOOST_CHECK_EQUAL(f.size(), 0);
		BOOST_CHECK(is_perfect_elimination_order(g, o));
	}
}

BOOST_AUTO_TEST_SUITE_END()