<commit_before>// @(#)root/thread:$Id$
// Author: Xavier Valls March 2016

/*************************************************************************
 * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TThreadExecutor
#define ROOT_TThreadExecutor

#include "RConfigure.h"

// exclude in case ROOT does not have IMT support
#ifndef R__USE_IMT
// No need to error out for dictionaries.
# if !defined(__ROOTCLING__) && !defined(G__DICTIONARY)
#  error "Cannot use ROOT::TThreadExecutor without defining R__USE_IMT."
# endif
#else

#include "ROOT/TExecutor.hxx"
#include <functional>
#include <memory>
#include <numeric>

namespace tbb { class task_scheduler_init;}

namespace ROOT {

class TThreadExecutor: public TExecutor<TThreadExecutor> {
template<class T>
friend class ParallelReductionResolver;

public:
   explicit TThreadExecutor();

   explicit TThreadExecutor(size_t nThreads);

   TThreadExecutor(TThreadExecutor &) = delete;
   TThreadExecutor & operator=(TThreadExecutor &) = delete;

   ~TThreadExecutor();

   template<class F, class Cond = noReferenceCond<F>>
   auto Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>;
   /// \cond
   template<class F, class INTEGER, class Cond = noReferenceCond<F, INTEGER>>
   auto Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>;
   template<class F, class T, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>;
   // / \endcond
   using TExecutor<TThreadExecutor>::Map;

   // // MapReduce
   // // the late return types also check at compile-time whether redfunc is compatible with func,
   // // other than checking that func is compatible with the type of arguments.
   // // a static_assert check in TThreadExecutor::Reduce is used to check that redfunc is compatible with the type returned by func
   template<class F, class R, class Cond = noReferenceCond<F>>
   auto MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> typename std::result_of<F()>::type;
   template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
   auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(INTEGER)>::type;
   // /// \cond doxygen should ignore these methods
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type;
   // /// \endcond
   using TExecutor<TThreadExecutor>::MapReduce;

  template<class T, class BINARYOP> auto Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()));
  template<class T, class R> auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
  using TExecutor<TThreadExecutor>::Reduce;

protected:

   template<class F, class R, class Cond = noReferenceCond<F>>
   auto Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F()>::type>;
   template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
   auto Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(INTEGER)>::type>;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>;

private:
    void   ParallelFor(unsigned start, unsigned end, unsigned step, const std::function<void(unsigned int i)> &f);
    double ParallelReduce(const std::vector<double> &objs, const std::function<double(double a, double b)> &redfunc);
    float  ParallelReduce(const std::vector<float> &objs, const std::function<float(float a, float b)> &redfunc);
    template<class T, class R>
    auto SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));

    std::unique_ptr<tbb::task_scheduler_init> fInitTBB;
};

/************ TEMPLATE METHODS IMPLEMENTATION ******************/

//////////////////////////////////////////////////////////////////////////
/// Execute func (with no arguments) nTimes in parallel.
/// A vector containg executions' results is returned.
/// Functions that take more than zero arguments can be executed (with
/// fixed arguments) by wrapping them in a lambda or with std::bind.
template<class F, class Cond>
auto TThreadExecutor::Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>
{
   using retType = decltype(func());
   std::vector<retType> reslist(nTimes);
   auto lambda = [&](unsigned int i){
                     reslist[i] = func();
                 };
   ParallelFor(0U, nTimes, 1, lambda);

   return reslist;
}

template<class F, class R, class Cond>
auto TThreadExecutor::Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F()>::type>
{
     if(nChunks == 0){
     return Map(func, nTimes);
   }

   using retType = decltype(func());
   std::vector<retType> reslist(nChunks);
   unsigned step = nChunks==0? 1 : (nTimes+nChunks-1)/nChunks;
   auto lambda = [&](unsigned int i){
                   std::vector<retType> partialResults(step);
                   for(unsigned j=0; j<step && (i+j)<nTimes; j++){
                     partialResults[j] = func();
                   }
                   reslist[i/step]=redfunc(partialResults);
                 };
   ParallelFor(0U, nTimes, step, lambda);

   return reslist;
}

template<class F, class INTEGER, class Cond>
auto TThreadExecutor::Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>
{
   unsigned start = *args.begin();
   unsigned end = *args.end();

   using retType = decltype(func(start));
   std::vector<retType> reslist(end-start);
   auto lambda = [&](unsigned int i){
                      reslist[i]+=func(i);
                  };
   ParallelFor(start, end, 1, lambda);

   return reslist;
}

template<class F, class INTEGER, class R, class Cond>
auto TThreadExecutor::Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(INTEGER)>::type>
{
   if(nChunks == 0){
     return Map(func, args);
   }

   unsigned start = *args.begin();
   unsigned end = *args.end();
   unsigned step = nChunks==0? 1 :(end-start+nChunks-1)/nChunks; //ceiling the division

   using retType = decltype(func(start));
   std::vector<retType> reslist(nChunks);
   auto lambda = [&](unsigned int i){
                    std::vector<retType> partialResults(step);
                    for(unsigned j=0; j<step && (i+j)<end; j++){
                      partialResults[j] = func(i+j);
                    }
                    reslist[i/step]=redfunc(partialResults);
                  };
   ParallelFor(start, end, step, lambda);

   return reslist;
}

// tell doxygen to ignore this (\endcond closes the statement)
/// \cond

// actual implementation of the Map method. all other calls with arguments eventually
// call this one
template<class F, class T, class Cond>
auto TThreadExecutor::Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>
{
   // //check whether func is callable
   using retType = decltype(func(args.front()));

   unsigned int fNToProcess = args.size();
   std::vector<retType> reslist(fNToProcess);

   auto lambda = [&](unsigned int i){
                     reslist[i] = func(args[i]);
                 };

   ParallelFor(0U, fNToProcess, 1, lambda);

   return reslist;
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>
{
   if(nChunks == 0){
     return Map(func, args);
   }
   // //check whether func is callable
   using retType = decltype(func(args.front()));

   unsigned int fNToProcess = args.size();
   std::vector<retType> reslist(nChunks);
   unsigned step = (fNToProcess+nChunks-1)/nChunks; //ceiling the division

   auto lambda = [&](unsigned int i){
                   std::vector<T> partialResults(step);
                   for(unsigned j=0; j<step && (i+j)<fNToProcess; j++){
                     partialResults[j] = func(args[i+j]);
                   }
                   reslist[i/step]=redfunc(partialResults);
                 };

   ParallelFor(0U, fNToProcess, step, lambda);

   return reslist;
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>
{
   std::vector<T> vargs(std::move(args));
   const auto &reslist = Map(func, vargs, redfunc, nChunks);
   return reslist;
}

// // tell doxygen to stop ignoring code
// /// \endcond

// //////////////////////////////////////////////////////////////////////////
// /// This method behaves just like Map, but an additional redfunc function
// /// must be provided. redfunc is applied to the vector Map would return and
// /// must return the same type as func. In practice, redfunc can be used to
// /// "squash" the vector returned by Map into a single object by merging,
// /// adding, mixing the elements of the vector.
template<class F, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> typename std::result_of<F()>::type
{
   return Reduce(Map(func, nTimes, redfunc, nChunks), redfunc);
}

/// \cond doxygen should ignore these methods
template<class F, class INTEGER, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(INTEGER)>::type
{
  return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type
{
   return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type
{
   return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

/// Check that redfunc has the right signature and call it on objs
template<class T, class BINARYOP>
auto TThreadExecutor::Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()))
{
   // check we can apply reduce to objs
   static_assert(std::is_same<decltype(redfunc(objs.front(), objs.front())), T>::value, "redfunc does not have the correct signature");
   return ParallelReduce(objs, redfunc);
}

template<class T, class R>
auto TThreadExecutor::Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
{
   // check we can apply reduce to objs
   static_assert(std::is_same<decltype(redfunc(objs)), T>::value, "redfunc does not have the correct signature");
   return SeqReduce(objs, redfunc);
}

template<class T, class R>
auto TThreadExecutor::SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
{
   return redfunc(objs);
}

} // namespace ROOT

#endif   // R__USE_IMT
#endif
<commit_msg>Fix storing mapped elements in TThreadExecutor<commit_after>// @(#)root/thread:$Id$
// Author: Xavier Valls March 2016

/*************************************************************************
 * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TThreadExecutor
#define ROOT_TThreadExecutor

#include "RConfigure.h"

// exclude in case ROOT does not have IMT support
#ifndef R__USE_IMT
// No need to error out for dictionaries.
# if !defined(__ROOTCLING__) && !defined(G__DICTIONARY)
#  error "Cannot use ROOT::TThreadExecutor without defining R__USE_IMT."
# endif
#else

#include "ROOT/TExecutor.hxx"
#include <functional>
#include <memory>
#include <numeric>

namespace tbb { class task_scheduler_init;}

namespace ROOT {

class TThreadExecutor: public TExecutor<TThreadExecutor> {
template<class T>
friend class ParallelReductionResolver;

public:
   explicit TThreadExecutor();

   explicit TThreadExecutor(size_t nThreads);

   TThreadExecutor(TThreadExecutor &) = delete;
   TThreadExecutor & operator=(TThreadExecutor &) = delete;

   ~TThreadExecutor();

   template<class F, class Cond = noReferenceCond<F>>
   auto Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>;
   /// \cond
   template<class F, class INTEGER, class Cond = noReferenceCond<F, INTEGER>>
   auto Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>;
   template<class F, class T, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>;
   // / \endcond
   using TExecutor<TThreadExecutor>::Map;

   // // MapReduce
   // // the late return types also check at compile-time whether redfunc is compatible with func,
   // // other than checking that func is compatible with the type of arguments.
   // // a static_assert check in TThreadExecutor::Reduce is used to check that redfunc is compatible with the type returned by func
   template<class F, class R, class Cond = noReferenceCond<F>>
   auto MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> typename std::result_of<F()>::type;
   template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
   auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(INTEGER)>::type;
   // /// \cond doxygen should ignore these methods
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type;
   // /// \endcond
   using TExecutor<TThreadExecutor>::MapReduce;

  template<class T, class BINARYOP> auto Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()));
  template<class T, class R> auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
  using TExecutor<TThreadExecutor>::Reduce;

protected:

   template<class F, class R, class Cond = noReferenceCond<F>>
   auto Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F()>::type>;
   template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
   auto Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(INTEGER)>::type>;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>;
   template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
   auto Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>;

private:
    void   ParallelFor(unsigned start, unsigned end, unsigned step, const std::function<void(unsigned int i)> &f);
    double ParallelReduce(const std::vector<double> &objs, const std::function<double(double a, double b)> &redfunc);
    float  ParallelReduce(const std::vector<float> &objs, const std::function<float(float a, float b)> &redfunc);
    template<class T, class R>
    auto SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));

    std::unique_ptr<tbb::task_scheduler_init> fInitTBB;
};

/************ TEMPLATE METHODS IMPLEMENTATION ******************/

//////////////////////////////////////////////////////////////////////////
/// Execute func (with no arguments) nTimes in parallel.
/// A vector containg executions' results is returned.
/// Functions that take more than zero arguments can be executed (with
/// fixed arguments) by wrapping them in a lambda or with std::bind.
template<class F, class Cond>
auto TThreadExecutor::Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>
{
   using retType = decltype(func());
   std::vector<retType> reslist(nTimes);
   auto lambda = [&](unsigned int i){
                     reslist[i] = func();
                 };
   ParallelFor(0U, nTimes, 1, lambda);

   return reslist;
}

template<class F, class R, class Cond>
auto TThreadExecutor::Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F()>::type>
{
     if(nChunks == 0){
     return Map(func, nTimes);
   }

   using retType = decltype(func());
   std::vector<retType> reslist(nChunks);
   unsigned step = nChunks==0? 1 : (nTimes+nChunks-1)/nChunks;
   auto lambda = [&](unsigned int i){
                   std::vector<retType> partialResults(step);
                   for(unsigned j=0; j<step && (i+j)<nTimes; j++){
                     partialResults[j] = func();
                   }
                   reslist[i/step]=redfunc(partialResults);
                 };
   ParallelFor(0U, nTimes, step, lambda);

   return reslist;
}

template<class F, class INTEGER, class Cond>
auto TThreadExecutor::Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>
{
   unsigned start = *args.begin();
   unsigned end = *args.end();

   using retType = decltype(func(start));
   std::vector<retType> reslist(end-start);
   auto lambda = [&](unsigned int i){
                      reslist[i] = func(i);
                  };
   ParallelFor(start, end, 1, lambda);

   return reslist;
}

template<class F, class INTEGER, class R, class Cond>
auto TThreadExecutor::Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(INTEGER)>::type>
{
   if(nChunks == 0){
     return Map(func, args);
   }

   unsigned start = *args.begin();
   unsigned end = *args.end();
   unsigned step = nChunks==0? 1 :(end-start+nChunks-1)/nChunks; //ceiling the division

   using retType = decltype(func(start));
   std::vector<retType> reslist(nChunks);
   auto lambda = [&](unsigned int i){
                    std::vector<retType> partialResults(step);
                    for(unsigned j=0; j<step && (i+j)<end; j++){
                      partialResults[j] = func(i+j);
                    }
                    reslist[i/step]=redfunc(partialResults);
                  };
   ParallelFor(start, end, step, lambda);

   return reslist;
}

// tell doxygen to ignore this (\endcond closes the statement)
/// \cond

// actual implementation of the Map method. all other calls with arguments eventually
// call this one
template<class F, class T, class Cond>
auto TThreadExecutor::Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>
{
   // //check whether func is callable
   using retType = decltype(func(args.front()));

   unsigned int fNToProcess = args.size();
   std::vector<retType> reslist(fNToProcess);

   auto lambda = [&](unsigned int i){
                     reslist[i] = func(args[i]);
                 };

   ParallelFor(0U, fNToProcess, 1, lambda);

   return reslist;
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>
{
   if(nChunks == 0){
     return Map(func, args);
   }
   // //check whether func is callable
   using retType = decltype(func(args.front()));

   unsigned int fNToProcess = args.size();
   std::vector<retType> reslist(nChunks);
   unsigned step = (fNToProcess+nChunks-1)/nChunks; //ceiling the division

   auto lambda = [&](unsigned int i){
                   std::vector<T> partialResults(step);
                   for(unsigned j=0; j<step && (i+j)<fNToProcess; j++){
                     partialResults[j] = func(args[i+j]);
                   }
                   reslist[i/step]=redfunc(partialResults);
                 };

   ParallelFor(0U, fNToProcess, step, lambda);

   return reslist;
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> std::vector<typename std::result_of<F(T)>::type>
{
   std::vector<T> vargs(std::move(args));
   const auto &reslist = Map(func, vargs, redfunc, nChunks);
   return reslist;
}

// // tell doxygen to stop ignoring code
// /// \endcond

// //////////////////////////////////////////////////////////////////////////
// /// This method behaves just like Map, but an additional redfunc function
// /// must be provided. redfunc is applied to the vector Map would return and
// /// must return the same type as func. In practice, redfunc can be used to
// /// "squash" the vector returned by Map into a single object by merging,
// /// adding, mixing the elements of the vector.
template<class F, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> typename std::result_of<F()>::type
{
   return Reduce(Map(func, nTimes, redfunc, nChunks), redfunc);
}

/// \cond doxygen should ignore these methods
template<class F, class INTEGER, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(INTEGER)>::type
{
  return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type
{
   return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

template<class F, class T, class R, class Cond>
auto TThreadExecutor::MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> typename std::result_of<F(T)>::type
{
   return Reduce(Map(func, args, redfunc, nChunks), redfunc);
}

/// Check that redfunc has the right signature and call it on objs
template<class T, class BINARYOP>
auto TThreadExecutor::Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()))
{
   // check we can apply reduce to objs
   static_assert(std::is_same<decltype(redfunc(objs.front(), objs.front())), T>::value, "redfunc does not have the correct signature");
   return ParallelReduce(objs, redfunc);
}

template<class T, class R>
auto TThreadExecutor::Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
{
   // check we can apply reduce to objs
   static_assert(std::is_same<decltype(redfunc(objs)), T>::value, "redfunc does not have the correct signature");
   return SeqReduce(objs, redfunc);
}

template<class T, class R>
auto TThreadExecutor::SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
{
   return redfunc(objs);
}

} // namespace ROOT

#endif   // R__USE_IMT
#endif
<|endoftext|>


<commit_before>#include "line.hpp"

// Include standard headers
#include <cmath>     // NAN, std::isnan, std::pow
#include <string>    // std::string
#include <vector>    // std::vector

namespace geometry
{
    // constructor.
    // can be used for creating n-dimensional lines.
    Line::Line(const std::vector<float> point1, const std::vector<float> point2)
    {
        if (point1 == point2 || point1.size() != point2.size())
        {
            this->is_valid = false; // two identical points do not define a line.
            this->general_form_coefficients.push_back(NAN);
            this->general_form_constant = NAN;
        }
        else
        {
            this->is_valid = true; // two distinct points define a line.
            this->are_points_defined = true;
            this->point1 = point1;
            this->point2 = point2;
        }
    }

    // constructor.
    // can be used for creating n-dimensional lines.
    Line::Line(const std::vector<float> general_form_coefficients, const float general_form_constant)
    {
        this->general_form_coefficients = general_form_coefficients;
        this->general_form_constant = general_form_constant;
    }

    std::string Line::get_general_form_equation()
    {
        // TODO: implement this function!
        std::string line_equation;
        return line_equation;
    }
}
<commit_msg>Bugfix `Line::Line`: always initialize `general_form_constant`.<commit_after>#include "line.hpp"

// Include standard headers
#include <cmath>     // NAN, std::isnan, std::pow
#include <string>    // std::string
#include <vector>    // std::vector

namespace geometry
{
    // constructor.
    // can be used for creating n-dimensional lines.
    Line::Line(const std::vector<float> point1, const std::vector<float> point2)
    {
        this->general_form_constant = NAN;

        if (point1 == point2 || point1.size() != point2.size())
        {
            this->is_valid = false; // two identical points do not define a line.
            this->general_form_coefficients.push_back(NAN);
        }
        else
        {
            this->is_valid = true; // two distinct points define a line.
            this->are_points_defined = true;
            this->point1 = point1;
            this->point2 = point2;
        }
    }

    // constructor.
    // can be used for creating n-dimensional lines.
    Line::Line(const std::vector<float> general_form_coefficients, const float general_form_constant)
    {
        this->general_form_coefficients = general_form_coefficients;
        this->general_form_constant = general_form_constant;
    }

    std::string Line::get_general_form_equation()
    {
        // TODO: implement this function!
        std::string line_equation;
        return line_equation;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <Chaos/Memory/MemoryPool.h>
#include "object.h"
#include "ref_memory.h"

namespace gc {

void* RefMemory::alloc(std::size_t n) {
  return Chaos::MemoryPool::get_instance().alloc(n);
}

void RefMemory::dealloc(BaseObject* obj) {
  if (obj->is_int())
    Chaos::MemoryPool::get_instance().dealloc(obj, sizeof(Int));
  else if (obj->is_pair())
    Chaos::MemoryPool::get_instance().dealloc(obj, sizeof(Pair));
}

void RefMemory::inc(BaseObject* ref) {
  if (ref != nullptr)
    inc_objects_.push(ref);
}

void RefMemory::dec(BaseObject* ref) {
  if (ref != nullptr)
    dec_objects_.push(ref);
}

void RefMemory::write(BaseObject* target, BaseObject* obj, bool is_first) {
  // only for pair object
  auto* pair = as_pair(target);
  inc(obj);
  if (is_first) {
    dec(pair->first());
    pair->set_first(obj);
  }
  else {
    dec(pair->second());
    pair->set_second(obj);
  }
}

void RefMemory::apply_increments(void) {
  while (!inc_objects_.empty()) {
    auto* obj = inc_objects_.top();
    inc_objects_.pop();
    obj->inc_ref();
  }
}

void RefMemory::scan_counting(void) {
  while (!dec_objects_.empty()) {
    auto* obj = dec_objects_.top();
    dec_objects_.pop();
    if (obj->dec_def() == 0 && obj->is_pair()) {
      auto append_fn = [this](BaseObject* ob) {
        if (ob != nullptr)
          dec_objects_.push(ob);
      };

      append_fn(as_pair(obj)->first());
      append_fn(as_pair(obj)->second());
    }
  }
}

void RefMemory::sweep_counting(void) {
  for (auto it = objects_.begin(); it != objects_.end();) {
    if ((*it)->ref() == 0) {
      dealloc(*it);
      objects_.erase(it++);
    }
    else {
      ++it;
    }
  }
}

RefMemory& RefMemory::get_instance(void) {
  static RefMemory ins;
  return ins;
}

void RefMemory::collect_counting(void) {
  auto old_count = objects_.size();

  apply_increments();
  scan_counting();
  sweep_counting();

  std::cout
    << "[" << old_count - objects_.size() << "] objects collected, "
    << "[" << objects_.size() << "] objects remaining." << std::endl;
}

BaseObject* RefMemory::create_int(int value) {
  if (objects_.size() >= kMaxObjects)
    collect_counting();

  auto* obj = new (alloc(sizeof(Int))) Int();
  obj->set_value(value);

  roots_.push_back(obj);
  objects_.push_back(obj);
  inc(obj);

  return obj;
}

BaseObject* RefMemory::create_pair(BaseObject* first, BaseObject* second) {
  if (objects_.size() >= kMaxObjects)
    collect_counting();

  auto* obj = new (alloc(sizeof(Pair))) Pair();
  if (first != nullptr)
    write(obj->first(), first, true);
  if (second != nullptr)
    write(obj->second(), second, false);

  roots_.push_back(obj);
  objects_.push_back(obj);
  inc(obj);

  return obj;
}

BaseObject* RefMemory::release_object(void) {
  auto* obj = roots_.back();
  roots_.pop_back();
  dec(obj);
  return obj;
}

}
<commit_msg>:bug: fix(RefMemory): fixed update attribute method for reference counting gc with memory pool<commit_after>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <Chaos/Memory/MemoryPool.h>
#include "object.h"
#include "ref_memory.h"

namespace gc {

void* RefMemory::alloc(std::size_t n) {
  return Chaos::MemoryPool::get_instance().alloc(n);
}

void RefMemory::dealloc(BaseObject* obj) {
  if (obj->is_int())
    Chaos::MemoryPool::get_instance().dealloc(obj, sizeof(Int));
  else if (obj->is_pair())
    Chaos::MemoryPool::get_instance().dealloc(obj, sizeof(Pair));
}

void RefMemory::inc(BaseObject* ref) {
  if (ref != nullptr)
    inc_objects_.push(ref);
}

void RefMemory::dec(BaseObject* ref) {
  if (ref != nullptr)
    dec_objects_.push(ref);
}

void RefMemory::write(BaseObject* target, BaseObject* obj, bool is_first) {
  // only for pair object
  auto* pair = as_pair(target);
  inc(obj);
  if (is_first) {
    dec(pair->first());
    pair->set_first(obj);
  }
  else {
    dec(pair->second());
    pair->set_second(obj);
  }
}

void RefMemory::apply_increments(void) {
  while (!inc_objects_.empty()) {
    auto* obj = inc_objects_.top();
    inc_objects_.pop();
    obj->inc_ref();
  }
}

void RefMemory::scan_counting(void) {
  while (!dec_objects_.empty()) {
    auto* obj = dec_objects_.top();
    dec_objects_.pop();
    if (obj->dec_def() == 0 && obj->is_pair()) {
      auto append_fn = [this](BaseObject* ob) {
        if (ob != nullptr)
          dec_objects_.push(ob);
      };

      append_fn(as_pair(obj)->first());
      append_fn(as_pair(obj)->second());
    }
  }
}

void RefMemory::sweep_counting(void) {
  for (auto it = objects_.begin(); it != objects_.end();) {
    if ((*it)->ref() == 0) {
      dealloc(*it);
      objects_.erase(it++);
    }
    else {
      ++it;
    }
  }
}

RefMemory& RefMemory::get_instance(void) {
  static RefMemory ins;
  return ins;
}

void RefMemory::collect_counting(void) {
  auto old_count = objects_.size();

  apply_increments();
  scan_counting();
  sweep_counting();

  std::cout
    << "[" << old_count - objects_.size() << "] objects collected, "
    << "[" << objects_.size() << "] objects remaining." << std::endl;
}

BaseObject* RefMemory::create_int(int value) {
  if (objects_.size() >= kMaxObjects)
    collect_counting();

  auto* obj = new (alloc(sizeof(Int))) Int();
  obj->set_value(value);

  roots_.push_back(obj);
  objects_.push_back(obj);
  inc(obj);

  return obj;
}

BaseObject* RefMemory::create_pair(BaseObject* first, BaseObject* second) {
  if (objects_.size() >= kMaxObjects)
    collect_counting();

  auto* obj = new (alloc(sizeof(Pair))) Pair();
  if (first != nullptr)
    write(obj, first, true);
  if (second != nullptr)
    write(obj, second, false);

  roots_.push_back(obj);
  objects_.push_back(obj);
  inc(obj);

  return obj;
}

BaseObject* RefMemory::release_object(void) {
  auto* obj = roots_.back();
  roots_.pop_back();
  dec(obj);
  return obj;
}

}
<|endoftext|>


<commit_before>#include <memory>

#include <SmurffCpp/Types.h>
#include <SmurffCpp/Types.h>

#include <SmurffCpp/Utils/counters.h>
#include <SmurffCpp/Utils/StateFile.h>
#include <SmurffCpp/Utils/MatrixUtils.h>
#include <SmurffCpp/result.h>
#include <SmurffCpp/ResultItem.h>

#include <SmurffCpp/Model.h>

#include <SmurffCpp/Predict/PredictSession.h>

namespace smurff
{

PredictSession::PredictSession(const std::string &model_file)
    : ISession(Config()) //FIXME
    , m_model_file(StateFile(model_file))
    , m_pred_savefile()
    , m_has_config(false)
    , m_num_latent(-1)
    , m_dims(PVec<>(0))
{
    m_stepfiles = m_model_file.openSampleSteps();
}

PredictSession::PredictSession(const Config &config)
    : ISession(config)
    , m_model_file(StateFile(config.getRestoreName()))
    , m_pred_savefile(std::make_unique<StateFile>(config.getSaveName()))
    , m_has_config(true)
    , m_num_latent(-1)
    , m_dims(PVec<>(0))
{
    m_stepfiles = m_model_file.openSampleSteps();
}

void PredictSession::run()
{
    THROWERROR_ASSERT(m_has_config);

    if (getConfig().getTest().hasData())
    {
        init();
        while (step())
            ;

        return;
    }
    else
    {
        std::pair<int, const DataConfig &> side_info =
            (getConfig().getRowFeatures().hasData()) ?
            std::make_pair(0, getConfig().getRowFeatures()) :
            std::make_pair(1, getConfig().getColFeatures()) ;

        THROWERROR_ASSERT_MSG(!side_info.second.hasData(), "Need either test, row features or col features");

        if (side_info.second.isDense())
        {
            const auto &dense_matrix = side_info.second.getDenseMatrixData();
            predict(side_info.first, dense_matrix, getConfig().getSaveFreq());
        }
        else
        {
            const auto &sparse_matrix = side_info.second.getSparseMatrixData();
            predict(side_info.first, sparse_matrix, getConfig().getSaveFreq());
        }
    }
}

void PredictSession::init()
{
    THROWERROR_ASSERT(m_has_config);
    THROWERROR_ASSERT(getConfig().getTest().hasData());
    m_result = Result(getConfig().getTest(), getConfig().getNSamples());

    m_pos = m_stepfiles.rbegin();
    m_iter = 0;
    m_is_init = true;

    THROWERROR_ASSERT_MSG(getConfig().getSaveName() != m_model_file.getPath(),
                          "Cannot have same output file for model and predictions - both have " + getConfig().getSaveName());

    if (getConfig().getSaveFreq())
    {
        // create save file
        m_pred_savefile = std::make_unique<StateFile>(getConfig().getSaveName(), true);
    }

    if (getConfig().getVerbose())
        info(std::cout, "");
}

bool PredictSession::step()
{
    THROWERROR_ASSERT(m_has_config);
    THROWERROR_ASSERT(m_is_init);
    THROWERROR_ASSERT(m_pos != m_stepfiles.rend());

    double start = tick();
    Model model;
    restoreModel(model, *m_pos);
    m_result.update(model, false);
    double stop = tick();
    m_iter++;
    m_secs_per_iter = stop - start;
    m_secs_total += m_secs_per_iter;

    if (getConfig().getVerbose())
        std::cout << getStatus().asString() << std::endl;

    if (getConfig().getSaveFreq() > 0 && (m_iter % getConfig().getSaveFreq()) == 0)
        save();

    auto next_pos = m_pos;
    next_pos++;
    bool last_iter = next_pos == m_stepfiles.rend();

    //save last iter
    if (last_iter && getConfig().getSaveFreq() == -1)
        save();

    m_pos++;
    return !last_iter;
}

void PredictSession::save()
{
    //save this iteration
    SaveState saveState = m_pred_savefile->createSampleStep(m_iter, false);

    if (getConfig().getVerbose())
    {
        std::cout << "-- Saving predictions into '" << m_pred_savefile->getPath() << "'." << std::endl;
    }

    m_result.save(saveState);
}

StatusItem PredictSession::getStatus() const
{
    StatusItem ret;
    ret.phase = "Predict";
    ret.iter = m_pos->getIsample();
    ret.phase_iter = m_stepfiles.size();

    ret.train_rmse = NAN;

    ret.rmse_avg = m_result.rmse_avg;
    ret.rmse_1sample = m_result.rmse_1sample;

    ret.auc_avg = m_result.auc_avg;
    ret.auc_1sample = m_result.auc_1sample;

    ret.elapsed_iter = m_secs_per_iter;
    ret.elapsed_total = m_secs_total;

    return ret;
}

const Result &PredictSession::getResult() const
{
    return m_result;
}

std::ostream &PredictSession::info(std::ostream &os, std::string indent) const
{
    os << indent << "PredictSession {\n";
    os << indent << "  Model {\n";
    os << indent << "    model-file: " << m_model_file.getPath() << "\n";
    os << indent << "    num-samples: " << getNumSteps() << "\n";
    os << indent << "    num-latent: " << getNumLatent() << "\n";
    os << indent << "    dimensions: " << getModelDims() << "\n";
    os << indent << "  }\n";
    os << indent << "  Predictions {\n";
    m_result.info(os, indent + "    ");
    if (getConfig().getSaveFreq() > 0)
    {
        os << indent << "    Save predictions: every " << getConfig().getSaveFreq() << " iteration\n";
        os << indent << "    Output file: " << getConfig().getSaveName() << "\n";
    }
    else if (getConfig().getSaveFreq() < 0)
    {
        os << indent << "    Save predictions after last iteration\n";
        os << indent << "    Output file: " << getConfig().getSaveName() << "\n";
    }
    else
    {
        os << indent << "    Don't save predictions\n";
    }
    os << indent << "  }" << std::endl;
    os << indent << "}\n";
    return os;
}

void PredictSession::restoreModel(Model &model, const SaveState &sf, int skip_mode)
{
    model.restore(sf, skip_mode);

    if (m_num_latent <= 0)
    {
        m_num_latent = model.nlatent();
        m_dims = model.getDims();
    }
    else
    {
        THROWERROR_ASSERT(m_num_latent == model.nlatent());
        THROWERROR_ASSERT(m_dims == model.getDims());
    }

    THROWERROR_ASSERT(m_num_latent > 0);
}

void PredictSession::restoreModel(Model &model, int i, int skip_mode)
{
    restoreModel(model, m_stepfiles.at(i), skip_mode);
}

// predict one element
ResultItem PredictSession::predict(PVec<> pos, const SaveState &sf)
{
    ResultItem ret{pos};
    predict(ret, sf);
    return ret;
}

// predict one element
void PredictSession::predict(ResultItem &res, const SaveState &sf)
{
    Model model;
    model.restore(sf);
    auto pred = model.predict(res.coords);
    res.update(pred);
}

// predict one element
void PredictSession::predict(ResultItem &res)
{
    auto stepfiles = m_model_file.openSampleSteps();

    for (const auto &sf : stepfiles)
        predict(res, sf);
}

ResultItem PredictSession::predict(PVec<> pos)
{
    ResultItem ret{pos};
    predict(ret);
    return ret;
}

// predict all elements in Ytest
std::shared_ptr<Result> PredictSession::predict(const DataConfig &Y)
{
    auto res = std::make_shared<Result>(Y, getNumSteps());

    for (const auto &s : m_stepfiles)
    {
        Model model;
        restoreModel(model, s);
        res->update(model, false);
    }

    return res;
}

SparseMatrix predict_matrix(const SparseMatrix &coords, const std::vector<Matrix> &latents)
{
    THROWERROR_ASSERT(latents.size() == 2);

    const Matrix &U = latents.at(0);
    const Matrix &V = latents.at(1);

    SparseMatrix result = coords;
    #pragma omp parallel for collapse(2)
    for (int k = 0; k < result.outerSize(); ++k)
        for (SparseMatrix::InnerIterator it(result, k); it; ++it)
            it.valueRef() = U.row(it.row()).dot(V.row(it.col()));

    return result;
}

SparseTensor predict_tensor(const SparseTensor &coords, const std::vector<Matrix> &latents)
{
    THROWERROR_ASSERT(latents.size() == coords.getNModes());

    unsigned num_latent = latents.at(0).cols();

    SparseTensor result = coords;
    #pragma omp parallel for
    for (std::size_t k = 0; k < result.getNNZ(); ++k)
    {
        Array1D P = Array1D::Ones(num_latent);
        auto pos = result.get(k).first; // pos

        for(uint32_t d = 0; d < coords.getNModes(); ++d)
            P *= latents.at(d).row(pos.at(d)).array();

        result.getValues().at(k) =  P.sum();
    }

    return result;
}

} // end namespace smurff
<commit_msg>FIX: simpler OpenMP for older compilers<commit_after>#include <memory>

#include <SmurffCpp/Types.h>
#include <SmurffCpp/Types.h>

#include <SmurffCpp/Utils/counters.h>
#include <SmurffCpp/Utils/StateFile.h>
#include <SmurffCpp/Utils/MatrixUtils.h>
#include <SmurffCpp/result.h>
#include <SmurffCpp/ResultItem.h>

#include <SmurffCpp/Model.h>

#include <SmurffCpp/Predict/PredictSession.h>

namespace smurff
{

PredictSession::PredictSession(const std::string &model_file)
    : ISession(Config()) //FIXME
    , m_model_file(StateFile(model_file))
    , m_pred_savefile()
    , m_has_config(false)
    , m_num_latent(-1)
    , m_dims(PVec<>(0))
{
    m_stepfiles = m_model_file.openSampleSteps();
}

PredictSession::PredictSession(const Config &config)
    : ISession(config)
    , m_model_file(StateFile(config.getRestoreName()))
    , m_pred_savefile(std::make_unique<StateFile>(config.getSaveName()))
    , m_has_config(true)
    , m_num_latent(-1)
    , m_dims(PVec<>(0))
{
    m_stepfiles = m_model_file.openSampleSteps();
}

void PredictSession::run()
{
    THROWERROR_ASSERT(m_has_config);

    if (getConfig().getTest().hasData())
    {
        init();
        while (step())
            ;

        return;
    }
    else
    {
        std::pair<int, const DataConfig &> side_info =
            (getConfig().getRowFeatures().hasData()) ?
            std::make_pair(0, getConfig().getRowFeatures()) :
            std::make_pair(1, getConfig().getColFeatures()) ;

        THROWERROR_ASSERT_MSG(!side_info.second.hasData(), "Need either test, row features or col features");

        if (side_info.second.isDense())
        {
            const auto &dense_matrix = side_info.second.getDenseMatrixData();
            predict(side_info.first, dense_matrix, getConfig().getSaveFreq());
        }
        else
        {
            const auto &sparse_matrix = side_info.second.getSparseMatrixData();
            predict(side_info.first, sparse_matrix, getConfig().getSaveFreq());
        }
    }
}

void PredictSession::init()
{
    THROWERROR_ASSERT(m_has_config);
    THROWERROR_ASSERT(getConfig().getTest().hasData());
    m_result = Result(getConfig().getTest(), getConfig().getNSamples());

    m_pos = m_stepfiles.rbegin();
    m_iter = 0;
    m_is_init = true;

    THROWERROR_ASSERT_MSG(getConfig().getSaveName() != m_model_file.getPath(),
                          "Cannot have same output file for model and predictions - both have " + getConfig().getSaveName());

    if (getConfig().getSaveFreq())
    {
        // create save file
        m_pred_savefile = std::make_unique<StateFile>(getConfig().getSaveName(), true);
    }

    if (getConfig().getVerbose())
        info(std::cout, "");
}

bool PredictSession::step()
{
    THROWERROR_ASSERT(m_has_config);
    THROWERROR_ASSERT(m_is_init);
    THROWERROR_ASSERT(m_pos != m_stepfiles.rend());

    double start = tick();
    Model model;
    restoreModel(model, *m_pos);
    m_result.update(model, false);
    double stop = tick();
    m_iter++;
    m_secs_per_iter = stop - start;
    m_secs_total += m_secs_per_iter;

    if (getConfig().getVerbose())
        std::cout << getStatus().asString() << std::endl;

    if (getConfig().getSaveFreq() > 0 && (m_iter % getConfig().getSaveFreq()) == 0)
        save();

    auto next_pos = m_pos;
    next_pos++;
    bool last_iter = next_pos == m_stepfiles.rend();

    //save last iter
    if (last_iter && getConfig().getSaveFreq() == -1)
        save();

    m_pos++;
    return !last_iter;
}

void PredictSession::save()
{
    //save this iteration
    SaveState saveState = m_pred_savefile->createSampleStep(m_iter, false);

    if (getConfig().getVerbose())
    {
        std::cout << "-- Saving predictions into '" << m_pred_savefile->getPath() << "'." << std::endl;
    }

    m_result.save(saveState);
}

StatusItem PredictSession::getStatus() const
{
    StatusItem ret;
    ret.phase = "Predict";
    ret.iter = m_pos->getIsample();
    ret.phase_iter = m_stepfiles.size();

    ret.train_rmse = NAN;

    ret.rmse_avg = m_result.rmse_avg;
    ret.rmse_1sample = m_result.rmse_1sample;

    ret.auc_avg = m_result.auc_avg;
    ret.auc_1sample = m_result.auc_1sample;

    ret.elapsed_iter = m_secs_per_iter;
    ret.elapsed_total = m_secs_total;

    return ret;
}

const Result &PredictSession::getResult() const
{
    return m_result;
}

std::ostream &PredictSession::info(std::ostream &os, std::string indent) const
{
    os << indent << "PredictSession {\n";
    os << indent << "  Model {\n";
    os << indent << "    model-file: " << m_model_file.getPath() << "\n";
    os << indent << "    num-samples: " << getNumSteps() << "\n";
    os << indent << "    num-latent: " << getNumLatent() << "\n";
    os << indent << "    dimensions: " << getModelDims() << "\n";
    os << indent << "  }\n";
    os << indent << "  Predictions {\n";
    m_result.info(os, indent + "    ");
    if (getConfig().getSaveFreq() > 0)
    {
        os << indent << "    Save predictions: every " << getConfig().getSaveFreq() << " iteration\n";
        os << indent << "    Output file: " << getConfig().getSaveName() << "\n";
    }
    else if (getConfig().getSaveFreq() < 0)
    {
        os << indent << "    Save predictions after last iteration\n";
        os << indent << "    Output file: " << getConfig().getSaveName() << "\n";
    }
    else
    {
        os << indent << "    Don't save predictions\n";
    }
    os << indent << "  }" << std::endl;
    os << indent << "}\n";
    return os;
}

void PredictSession::restoreModel(Model &model, const SaveState &sf, int skip_mode)
{
    model.restore(sf, skip_mode);

    if (m_num_latent <= 0)
    {
        m_num_latent = model.nlatent();
        m_dims = model.getDims();
    }
    else
    {
        THROWERROR_ASSERT(m_num_latent == model.nlatent());
        THROWERROR_ASSERT(m_dims == model.getDims());
    }

    THROWERROR_ASSERT(m_num_latent > 0);
}

void PredictSession::restoreModel(Model &model, int i, int skip_mode)
{
    restoreModel(model, m_stepfiles.at(i), skip_mode);
}

// predict one element
ResultItem PredictSession::predict(PVec<> pos, const SaveState &sf)
{
    ResultItem ret{pos};
    predict(ret, sf);
    return ret;
}

// predict one element
void PredictSession::predict(ResultItem &res, const SaveState &sf)
{
    Model model;
    model.restore(sf);
    auto pred = model.predict(res.coords);
    res.update(pred);
}

// predict one element
void PredictSession::predict(ResultItem &res)
{
    auto stepfiles = m_model_file.openSampleSteps();

    for (const auto &sf : stepfiles)
        predict(res, sf);
}

ResultItem PredictSession::predict(PVec<> pos)
{
    ResultItem ret{pos};
    predict(ret);
    return ret;
}

// predict all elements in Ytest
std::shared_ptr<Result> PredictSession::predict(const DataConfig &Y)
{
    auto res = std::make_shared<Result>(Y, getNumSteps());

    for (const auto &s : m_stepfiles)
    {
        Model model;
        restoreModel(model, s);
        res->update(model, false);
    }

    return res;
}

SparseMatrix predict_matrix(const SparseMatrix &coords, const std::vector<Matrix> &latents)
{
    THROWERROR_ASSERT(latents.size() == 2);

    const Matrix &U = latents.at(0);
    const Matrix &V = latents.at(1);

    SparseMatrix result = coords;
    #pragma omp parallel for
    for (int k = 0; k < result.outerSize(); ++k)
        for (SparseMatrix::InnerIterator it(result, k); it; ++it)
            it.valueRef() = U.row(it.row()).dot(V.row(it.col()));

    return result;
}

SparseTensor predict_tensor(const SparseTensor &coords, const std::vector<Matrix> &latents)
{
    THROWERROR_ASSERT(latents.size() == coords.getNModes());

    unsigned num_latent = latents.at(0).cols();

    SparseTensor result = coords;
    #pragma omp parallel for
    for (std::size_t k = 0; k < result.getNNZ(); ++k)
    {
        Array1D P = Array1D::Ones(num_latent);
        auto pos = result.get(k).first; // pos

        for(uint32_t d = 0; d < coords.getNModes(); ++d)
            P *= latents.at(d).row(pos.at(d)).array();

        result.getValues().at(k) =  P.sum();
    }

    return result;
}

} // end namespace smurff
<|endoftext|>


<commit_before>#ifndef PACKET_HPP
#define PACKET_HPP

#include <SFML/Network/Packet.hpp>
#include <vector>
#include <array>
#include <crc32.hpp>
#include <variadic.hpp>
#include <sorted_vector.hpp>
#include "serialized_packet.hpp"

struct color32;

namespace sf {
    // Extend sf::Packet to handle 64bit types
    #ifdef HAS_UINT64_T
    packet_t::base& operator << (packet_t::base& p, std::uint64_t data);
    packet_t::base& operator >> (packet_t::base& p, std::uint64_t& data);
    #else
    struct impl_u64 {
        std::uint32_t lo, hi;
        bool operator < (const impl_u64& i) const;
    };
    packet_t::base& operator << (packet_t::base& p, impl_u64 data);
    packet_t::base& operator >> (packet_t::base& p, impl_u64& data);
    #endif

    template<typename T, typename enable = typename std::enable_if<std::is_enum<T>::value>::type>
    packet_t::base& operator >> (packet_t::base& p, T& t) {
        return p >> reinterpret_cast<typename std::underlying_type<T>::type&>(t);
    }

    template<typename T, typename enable = typename std::enable_if<std::is_enum<T>::value>::type>
    packet_t::base& operator << (packet_t::base& p, T t) {
        return p << static_cast<typename std::underlying_type<T>::type>(t);
    }

    packet_t::base& operator << (packet_t::base& o, ctl::empty_t);
    packet_t::base& operator >> (packet_t::base& i, ctl::empty_t);

    template<typename T>
    packet_t::base& operator >> (packet_t::base& p, std::vector<T>& t) {
        std::uint32_t s;
        p >> s;
        std::uint32_t i0 = t.size();
        t.resize(i0 + s);
        for (std::uint32_t i = 0; i < s; ++i) {
            p >> t[i0+i];
        }
        return p;
    }

    template<typename T>
    packet_t::base& operator << (packet_t::base& p, const std::vector<T>& t) {
        p << (std::uint32_t)t.size();
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    template<typename T, typename C>
    packet_t::base& operator >> (packet_t::base& p, ctl::sorted_vector<T,C>& t) {
        std::uint32_t s; p >> s;
        for (std::uint32_t i = 0; i < s; ++i) {
            T tmp;
            p >> tmp;
            t.insert(std::move(tmp));
        }
        return p;
    }

    template<typename T, typename C>
    packet_t::base& operator << (packet_t::base& p, const ctl::sorted_vector<T,C>& t) {
        p << (std::uint32_t)t.size();
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    template<typename T, std::size_t N>
    packet_t::base& operator >> (packet_t::base& p, std::array<T,N>& t) {
        for (std::size_t i = 0; i < N; ++i) {
            p >> t[i];
        }
        return p;
    }

    template<typename T, std::size_t N>
    packet_t::base& operator << (packet_t::base& p, const std::array<T,N>& t) {
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    packet_t::base& operator << (packet_t::base& s, const color32& c);
    packet_t::base& operator >> (packet_t::base& s, color32& c);
}

/// Physical type of a packet identifier.
using packet_id_t = std::uint32_t;

/// Return a user readable name for a given packet.
std::string get_packet_name(packet_id_t id);

/// Check if the provided ID matches that of a real packet.
bool is_packet_id(packet_id_t id);

namespace packet_impl {
    template<typename T>
    struct packet_builder;
}

/// Create a packet and set its elements.
template<typename T, typename ... Args>
T make_packet(Args&& ... args) {
    return packet_impl::packet_builder<T>()(std::forward<Args>(args)...);
}

/// Write a list of objects into a packet.
template<typename P>
void packet_write(P& p) {}

template<typename P, typename T, typename ... Args>
void packet_write(P& p, T&& t, Args&& ... args) {
    p << std::forward<T>(t);
    packet_write(p, std::forward<Args>(args)...);
}

/// Read a list of objects from a packet.
template<typename P>
void packet_read(P& p) {}

template<typename P, typename T, typename ... Args>
void packet_read(P& p, T& t, Args& ... args) {
    p >> t;
    packet_read(p, args...);
}

namespace packet_impl {
    struct base_ {};

    template<packet_id_t ID>
    struct base : base_ {
        static const packet_id_t packet_id__ = ID;
        static const char* packet_name__;
    };

    template<packet_id_t ID>
    const packet_id_t base<ID>::packet_id__;

    template<typename T>
    using is_packet = std::is_base_of<base_, T>;
}

#define NETCOM_PACKET(name) \
    struct name : packet_impl::base<#name ## _crc32>

#endif
<commit_msg>Added serialization for std::atomic types.<commit_after>#ifndef PACKET_HPP
#define PACKET_HPP

#include <SFML/Network/Packet.hpp>
#include <vector>
#include <atomic>
#include <array>
#include <crc32.hpp>
#include <variadic.hpp>
#include <sorted_vector.hpp>
#include "serialized_packet.hpp"

struct color32;

namespace sf {
    // Extend sf::Packet to handle 64bit types
    #ifdef HAS_UINT64_T
    packet_t::base& operator << (packet_t::base& p, std::uint64_t data);
    packet_t::base& operator >> (packet_t::base& p, std::uint64_t& data);
    #else
    struct impl_u64 {
        std::uint32_t lo, hi;
        bool operator < (const impl_u64& i) const;
    };
    packet_t::base& operator << (packet_t::base& p, impl_u64 data);
    packet_t::base& operator >> (packet_t::base& p, impl_u64& data);
    #endif

    template<typename T, typename enable = typename std::enable_if<std::is_enum<T>::value>::type>
    packet_t::base& operator >> (packet_t::base& p, T& t) {
        return p >> reinterpret_cast<typename std::underlying_type<T>::type&>(t);
    }

    template<typename T, typename enable = typename std::enable_if<std::is_enum<T>::value>::type>
    packet_t::base& operator << (packet_t::base& p, T t) {
        return p << static_cast<typename std::underlying_type<T>::type>(t);
    }

    packet_t::base& operator << (packet_t::base& o, ctl::empty_t);
    packet_t::base& operator >> (packet_t::base& i, ctl::empty_t);

    template<typename T>
    packet_t::base& operator >> (packet_t::base& p, std::vector<T>& t) {
        std::uint32_t s;
        p >> s;
        std::uint32_t i0 = t.size();
        t.resize(i0 + s);
        for (std::uint32_t i = 0; i < s; ++i) {
            p >> t[i0+i];
        }
        return p;
    }

    template<typename T>
    packet_t::base& operator << (packet_t::base& p, const std::vector<T>& t) {
        p << (std::uint32_t)t.size();
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    template<typename T, typename C>
    packet_t::base& operator >> (packet_t::base& p, ctl::sorted_vector<T,C>& t) {
        std::uint32_t s; p >> s;
        for (std::uint32_t i = 0; i < s; ++i) {
            T tmp;
            p >> tmp;
            t.insert(std::move(tmp));
        }
        return p;
    }

    template<typename T, typename C>
    packet_t::base& operator << (packet_t::base& p, const ctl::sorted_vector<T,C>& t) {
        p << (std::uint32_t)t.size();
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    template<typename T, std::size_t N>
    packet_t::base& operator >> (packet_t::base& p, std::array<T,N>& t) {
        for (std::size_t i = 0; i < N; ++i) {
            p >> t[i];
        }
        return p;
    }

    template<typename T, std::size_t N>
    packet_t::base& operator << (packet_t::base& p, const std::array<T,N>& t) {
        for (auto& i : t) {
            p << i;
        }
        return p;
    }

    template<typename T>
    packet_t::base& operator >> (packet_t::base& p, std::atomic<T>& t) {
        T tmp; p >> tmp;
        t = tmp;
        return p;
    }

    template<typename T, typename C>
    packet_t::base& operator << (packet_t::base& p, const std::atomic<T>& t) {
        p << t.load();
        return p;
    }

    packet_t::base& operator << (packet_t::base& s, const color32& c);
    packet_t::base& operator >> (packet_t::base& s, color32& c);
}

/// Physical type of a packet identifier.
using packet_id_t = std::uint32_t;

/// Return a user readable name for a given packet.
std::string get_packet_name(packet_id_t id);

/// Check if the provided ID matches that of a real packet.
bool is_packet_id(packet_id_t id);

namespace packet_impl {
    template<typename T>
    struct packet_builder;
}

/// Create a packet and set its elements.
template<typename T, typename ... Args>
T make_packet(Args&& ... args) {
    return packet_impl::packet_builder<T>()(std::forward<Args>(args)...);
}

/// Write a list of objects into a packet.
template<typename P>
void packet_write(P& p) {}

template<typename P, typename T, typename ... Args>
void packet_write(P& p, T&& t, Args&& ... args) {
    p << std::forward<T>(t);
    packet_write(p, std::forward<Args>(args)...);
}

/// Read a list of objects from a packet.
template<typename P>
void packet_read(P& p) {}

template<typename P, typename T, typename ... Args>
void packet_read(P& p, T& t, Args& ... args) {
    p >> t;
    packet_read(p, args...);
}

namespace packet_impl {
    struct base_ {};

    template<packet_id_t ID>
    struct base : base_ {
        static const packet_id_t packet_id__ = ID;
        static const char* packet_name__;
    };

    template<packet_id_t ID>
    const packet_id_t base<ID>::packet_id__;

    template<typename T>
    using is_packet = std::is_base_of<base_, T>;
}

#define NETCOM_PACKET(name) \
    struct name : packet_impl::base<#name ## _crc32>

#endif
<|endoftext|>


<commit_before>#include "helper.h"

#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif

uint32_t _ntohl(uint8_t *val) {
  return (uint32_t(val[0]) << 24) + (uint32_t(val[1]) << 16) +
         (uint32_t(val[2]) << 8) + (uint32_t(val[3]));
}

uint8_t clamp(int32_t val) {
  if (val < 0) {
    return 0;
  }
  if (val > 255) {
    return 255;
  }
  return (uint8_t)val;
}

bool isNumeric(const char *str) {
  if (str[0] == '-' && str[1] != '\0') {
    ++str;
  }
  while (*str != '\0') {
    if (*str < '0' || *str > '9') {
      return false;
    }
    ++str;
  }
  return true;
}

void splitCoords(const Coordinates<int32_t> &original,
                 Coordinates<int32_t> *subCoords, const uint16_t count) {
  // Split the coordinates of the entire terrain in `count` terrain fragments

  for (uint16_t index = 0; index < count; index++) {
    // Initialization with the original's values
    subCoords[index] = Coordinates(original);

    // The first fragment begins at the terrain's beginning, the other fragments
    // begin one block behind the last fragment
    subCoords[index].minX =
        (index ? subCoords[index - 1].maxX + 1 : original.minX);

    // Each fragment has a fixed size
    subCoords[index].maxX =
        subCoords[index].minX + (original.maxX - original.minX + 1) / count - 1;

    // Adjust the last terrain fragment to make sure the terrain is fully
    // covered
    if (index == count - 1)
      subCoords[index].maxX = original.maxX;
  }
}
<commit_msg>Image size warning<commit_after>#include "helper.h"

#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif

uint32_t _ntohl(uint8_t *val) {
  return (uint32_t(val[0]) << 24) + (uint32_t(val[1]) << 16) +
         (uint32_t(val[2]) << 8) + (uint32_t(val[3]));
}

uint8_t clamp(int32_t val) {
  if (val < 0) {
    return 0;
  }
  if (val > 255) {
    return 255;
  }
  return (uint8_t)val;
}

bool isNumeric(const char *str) {
  if (str[0] == '-' && str[1] != '\0') {
    ++str;
  }
  while (*str != '\0') {
    if (*str < '0' || *str > '9') {
      return false;
    }
    ++str;
  }
  return true;
}

void splitCoords(const Coordinates<int32_t> &original,
                 Coordinates<int32_t> *subCoords, const uint16_t count) {
  // Split the coordinates of the entire terrain in `count` terrain fragments
  uint32_t width = (original.sizeX() + original.sizeZ()) * 2;
  uint32_t height = original.sizeX() + original.sizeZ() +
                    (original.maxY - original.minY + 1) * 3 - 1;
  logger::debug("Rendering map {} requires a {}x{} image of {}MB\n",
                original.to_string(), width, height,
                width * height * 4 / (1024 * 1024));

  for (uint16_t index = 0; index < count; index++) {
    // Initialization with the original's values
    subCoords[index] = Coordinates(original);

    // The first fragment begins at the terrain's beginning, the other fragments
    // begin one block behind the last fragment
    subCoords[index].minX =
        (index ? subCoords[index - 1].maxX + 1 : original.minX);

    // Each fragment has a fixed size
    subCoords[index].maxX =
        subCoords[index].minX + (original.maxX - original.minX + 1) / count - 1;

    // Adjust the last terrain fragment to make sure the terrain is fully
    // covered
    if (index == count - 1)
      subCoords[index].maxX = original.maxX;
  }

  if (count > 1) {
    width = (subCoords[0].sizeX() + subCoords[0].sizeZ()) * 2;
    height = subCoords[0].sizeX() + subCoords[0].sizeZ() +
             (subCoords[0].maxY - subCoords[0].minY + 1) * 3 - 1;
    logger::debug("Splitting into {} maps requiring {} {}x{} images of {}MB\n",
                  count, count, width, height,
                  width * height * 4 / (1024 * 1024));
  }
}
<|endoftext|>


<commit_before>#include "stack.hpp"
#include <catch.hpp>
#include <iostream>
using namespace std;

SCENARIO("count", "[count]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.count()==1);
}

SCENARIO("push", "[push]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.count()==1);
  REQUIRE(s.top()==1);
}

SCENARIO("pop", "[pop]"){
  stack<int> s;
  s.push(1); s.pop();
  REQUIRE(s.count()==0);
}

SCENARIO("cop", "[cop]"){
  stack<int> s;
  s.push(1);
  stack<int> s2=s;
  REQUIRE(s2.count()==1);
  REQUIRE(s2.top()==1);
}

SCENARIO("top", "[top]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.top()==1);
}

SCENARIO("empty", "[empty]"){
  stack<int> s1, s2;
  s1.push(1);
  REQUIRE(!s1.empty());
  REQUIRE(s2.empty());
}

<commit_msg>Update init.cpp<commit_after>#include "stack.hpp"
#include <catch.hpp>
#include <iostream>
using namespace std;

SCENARIO("count", "[count]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.count()==1);
}

SCENARIO("push", "[push]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.count()==1);
  REQUIRE(s.top()==1);
}

SCENARIO("pop", "[pop]"){
  stack<int> s;
  s.push(1); s.pop();
  REQUIRE(s.count()==0);
}

SCENARIO("cop", "[cop]"){
  stack<int> s;
  s.push(1);
  stack<int> s2=s;
  REQUIRE(s.count()==1);
  REQUIRE(s.top()==1);
}

SCENARIO("top", "[top]"){
  stack<int> s;
  s.push(1);
  REQUIRE(s.top()==1);
}

SCENARIO("empty", "[empty]"){
  stack<int> s1, s2;
  s1.push(1);
  REQUIRE(!s1.empty());
  REQUIRE(s2.empty());
}

<|endoftext|>


<commit_before>#include <matrix.hpp>
#include <catch.hpp>
#include <iostream>

using namespace std;

SCENARIO("matrix init", "[init]") {
	Matrix matrix;
	REQUIRE(matrix.rows() == 0);
	REQUIRE(matrix.columns() == 0);
}

SCENARIO("params init", "[init with params]") {
	int init = 5;
	Matrix matrix(init, init);
	REQUIRE(matrix.rows() == 5);
	REQUIRE(matrix.columns() == 5);
}

SCENARIO("copy", "[copy]")
{
	int init = 2;
	Matrix m1(init, init);
	Matrix copy(m1);
	REQUIRE(copy.rows() == 2);
	REQUIRE(copy.columns() == 2);
}

SCENARIO("m+", "[m+]")
{
	Matrix A(2, 2);
	Matrix B(2, 2);
	Matrix C(2, 2);
	std::ifstream ("f1.txt") >> A;
	std::ifstream ("f2.txt") >> B;
	std::ifstream ("f3.txt") >> C;
	REQUIRE((A + B) == C);
}

SCENARIO("m*", "[m*]")
{
	Matrix A (2, 2);
	Matrix B (2, 2);
	Matrix C (2, 2);
	std::ifstream("f1.txt") >> A;
	std::ifstream("f2.txt") >> B;
	std::ifstream("f4.txt") >> C;
	REQUIRE((A*B) == C);
}

SCENARIO("m=", "[m=]")
{
	Matrix A(2, 2);
	Matrix B = A;
	REQUIRE(B == A);
}

SCENARIO("read", "[read]")
{
	Matrix A(2, 2);
	Matrix B (2, 2);
	std::ifstream("f1.txt") >> A;
	std::ofstream("f5.txt") << A;
	std::ifstream("f5.txt") >> B;
	REQUIRE(B == A);
}
<commit_msg>Update init.cpp<commit_after>#include <matrix.hpp>
#include <catch.hpp>
#include <iostream>

using namespace std;

SCENARIO("matrix init", "[init]") {
	Matrix matrix;
	REQUIRE(matrix.rows() == 0);
	REQUIRE(matrix.columns() == 0);
}

SCENARIO("params init", "[init with params]") {
	int init = 5;
	Matrix matrix(init, init);
	REQUIRE(matrix.rows() == 5);
	REQUIRE(matrix.columns() == 5);
}

SCENARIO("copy", "[copy]")
{
	int init = 2;
	Matrix m1(init, init);
	Matrix copy(m1);
	REQUIRE(copy.rows() == 2);
	REQUIRE(copy.columns() == 2);
}

SCENARIO("m+", "[m+]")
{
	Matrix A(2, 2);
	Matrix B(2, 2);
	Matrix C(2, 2);
	std::ifstream ("f1.txt") >> A;
	std::ifstream ("f2.txt") >> B;
	std::ifstream ("f3.txt") >> C;
	REQUIRE((A + B) == C);
}

SCENARIO("m*", "[m*]")
{
	Matrix A (2, 2);
	Matrix B (2, 2);
	Matrix C (2, 2);
	std::ifstream("f1.txt") >> A;
	std::ifstream("f2.txt") >> B;
	std::ifstream("f4.txt") >> C;
	REQUIRE((A*B) == C);
}

SCENARIO("m=", "[m=]")
{
	Matrix A(2, 2);
	Matrix B = A;
	REQUIRE(B == A);
}

<|endoftext|>


<commit_before>/*  This file is part of the Vc library.

    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "unittest.h"
#include <iostream>

using namespace Vc;

template<typename T> static constexpr T min(T a, T b) { return a < b ? a : b; }

template<typename Vec> constexpr unsigned long alignmentMask()
{
    return Vec::Size == 1 ? (
            // on 32bit the maximal alignment is 4 Bytes, even for 8-Byte doubles.
            min(sizeof(void*), sizeof(typename Vec::EntryType)) - 1
        ) : (
            // AVX::VectorAlignment is too large
            min<size_t>(sizeof(Vec), VectorAlignment) - 1
        );
}

template<typename Vec> void checkAlignment()
{
    unsigned char i = 1;
    Vec a[10];
    unsigned long mask = alignmentMask<Vec>();
    for (i = 0; i < 10; ++i) {
        VERIFY((reinterpret_cast<size_t>(&a[i]) & mask) == 0) << "a = " << a << ", mask = " << mask;
    }
    const char *data = reinterpret_cast<const char *>(&a[0]);
    for (i = 0; i < 10; ++i) {
        VERIFY(&data[i * sizeof(Vec)] == reinterpret_cast<const char *>(&a[i]));
    }
}

void *hack_to_put_b_on_the_stack = 0;

template<typename Vec> void checkMemoryAlignment()
{
    typedef typename Vec::EntryType T;
    const T *b = 0;
    Vc::Memory<Vec, 10> a;
    b = a;
    hack_to_put_b_on_the_stack = &b;
    size_t mask = memory_alignment<Vec>::value - 1;
    for (int i = 0; i < 10; ++i) {
        VERIFY((reinterpret_cast<size_t>(&b[i * Vec::Size]) & mask) == 0) << "b = " << b << ", mask = " << mask;
    }
}

template<typename Vec> void loadArray()
{
    typedef typename Vec::EntryType T;
    typedef typename Vec::IndexType I;

    enum loadArrayEnum { count = 256 * 1024 / sizeof(T) };
    Vc::Memory<Vec, count> array;
    for (int i = 0; i < count; ++i) {
        array[i] = i;
    }

    const I indexesFromZero(IndexesFromZero);

    const Vec offsets(indexesFromZero);
    for (int i = 0; i < count; i += Vec::Size) {
        const T *const addr = &array[i];
        Vec ii(i);
        ii += offsets;

        Vec a(addr, Vc::Aligned);
        COMPARE(a, ii);

        Vec b = Vec::Zero();
        b.load(addr, Vc::Aligned);
        COMPARE(b, ii);
    }

    // check that Vc allows construction from objects that auto-convert to T*
    Vec tmp0(array, Vc::Aligned);
    tmp0.load(array, Vc::Aligned);
}

enum Enum {
    loadArrayShortCount = 32 * 1024,
    streamingLoadCount = 1024
};
template<typename Vec> void loadArrayShort()
{
    typedef typename Vec::EntryType T;

    Vc::Memory<Vec, loadArrayShortCount> array;
    for (int i = 0; i < loadArrayShortCount; ++i) {
        array[i] = i;
    }

    const Vec &offsets = static_cast<Vec>(ushort_v::IndexesFromZero());
    for (int i = 0; i < loadArrayShortCount; i += Vec::Size) {
        const T *const addr = &array[i];
        Vec ii(i);
        ii += offsets;

        Vec a(addr, Vc::Aligned);
        COMPARE(a, ii);

        Vec b = Vec::Zero();
        b.load(addr, Vc::Aligned);
        COMPARE(b, ii);
    }
}

template<typename Vec> void streamingLoad()
{
    typedef typename Vec::EntryType T;

    Vc::Memory<Vec, streamingLoadCount> data;
    data[0] = static_cast<T>(-streamingLoadCount/2);
    for (int i = 1; i < streamingLoadCount; ++i) {
        data[i] = data[i - 1];
        ++data[i];
    }

    Vec ref = data.firstVector();
    for (size_t i = 0; i < streamingLoadCount - Vec::Size; ++i, ++ref) {
        Vec v1, v2;
        if (0 == i % Vec::Size) {
            v1 = Vec(&data[i], Vc::Aligned | Vc::Streaming);
            v2.load (&data[i], Vc::Aligned | Vc::Streaming);
        } else {
            v1 = Vec(&data[i], Vc::Streaming | Vc::Unaligned);
            v2.load (&data[i], Vc::Unaligned | Vc::Streaming);
        }
        COMPARE(v1, ref) << ", i = " << i;
        COMPARE(v2, ref) << ", i = " << i;
    }
}

template<typename T> struct TypeInfo;
template<> struct TypeInfo<double        > { static const char *string() { return "double"; } };
template<> struct TypeInfo<float         > { static const char *string() { return "float"; } };
template<> struct TypeInfo<int           > { static const char *string() { return "int"; } };
template<> struct TypeInfo<unsigned int  > { static const char *string() { return "uint"; } };
template<> struct TypeInfo<short         > { static const char *string() { return "short"; } };
template<> struct TypeInfo<unsigned short> { static const char *string() { return "ushort"; } };
template<> struct TypeInfo<signed char   > { static const char *string() { return "schar"; } };
template<> struct TypeInfo<unsigned char > { static const char *string() { return "uchar"; } };
template<> struct TypeInfo<double_v      > { static const char *string() { return "double_v"; } };
template<> struct TypeInfo<float_v       > { static const char *string() { return "float_v"; } };
template<> struct TypeInfo<int_v         > { static const char *string() { return "int_v"; } };
template<> struct TypeInfo<uint_v        > { static const char *string() { return "uint_v"; } };
template<> struct TypeInfo<short_v       > { static const char *string() { return "short_v"; } };
template<> struct TypeInfo<ushort_v      > { static const char *string() { return "ushort_v"; } };

template<typename T, typename Current = void> struct SupportedConversions { typedef void Next; };
template<> struct SupportedConversions<float, void>           { typedef double         Next; };
template<> struct SupportedConversions<float, double>         { typedef int            Next; };
template<> struct SupportedConversions<float, int>            { typedef unsigned int   Next; };
template<> struct SupportedConversions<float, unsigned int>   { typedef short          Next; };
template<> struct SupportedConversions<float, short>          { typedef unsigned short Next; };
template<> struct SupportedConversions<float, unsigned short> { typedef signed char    Next; };
template<> struct SupportedConversions<float, signed char>    { typedef unsigned char  Next; };
template<> struct SupportedConversions<float, unsigned char>  { typedef void           Next; };
template<> struct SupportedConversions<int  , void          > { typedef unsigned int   Next; };
template<> struct SupportedConversions<int  , unsigned int  > { typedef short          Next; };
template<> struct SupportedConversions<int  , short         > { typedef unsigned short Next; };
template<> struct SupportedConversions<int  , unsigned short> { typedef signed char    Next; };
template<> struct SupportedConversions<int  , signed char   > { typedef unsigned char  Next; };
template<> struct SupportedConversions<int  , unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<unsigned int, void          > { typedef unsigned short Next; };
template<> struct SupportedConversions<unsigned int, unsigned short> { typedef unsigned char  Next; };
template<> struct SupportedConversions<unsigned int, unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<unsigned short, void          > { typedef unsigned char  Next; };
template<> struct SupportedConversions<unsigned short, unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<         short, void          > { typedef unsigned char  Next; };
template<> struct SupportedConversions<         short, unsigned char > { typedef signed char    Next; };
template<> struct SupportedConversions<         short,   signed char > { typedef void           Next; };

template<typename Vec, typename MemT> struct LoadCvt {
    static void test() {
        typedef typename Vec::EntryType VecT;
        MemT *data = Vc::malloc<MemT, Vc::AlignOnCacheline>(128);
        for (size_t i = 0; i < 128; ++i) {
            data[i] = static_cast<MemT>(i - 64);
        }

        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v = Vec(&data[i]);
            } else if (i % Vec::Size == 0) {
                v = Vec(&data[i], Vc::Aligned);
            } else {
                v = Vec(&data[i], Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }
        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v.load(&data[i]);
            } else if (i % Vec::Size == 0) {
                v.load(&data[i], Vc::Aligned);
            } else {
                v.load(&data[i], Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }
        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v = Vec(&data[i], Vc::Streaming);
            } else if (i % Vec::Size == 0) {
                v = Vec(&data[i], Vc::Streaming | Vc::Aligned);
            } else {
                v = Vec(&data[i], Vc::Streaming | Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }

        ADD_PASS() << "loadCvt: load " << TypeInfo<MemT>::string() << "* as " << TypeInfo<Vec>::string();
        LoadCvt<Vec, typename SupportedConversions<VecT, MemT>::Next>::test();
    }
};
template<typename Vec> struct LoadCvt<Vec, void> { static void test() {} };

template<typename Vec> void loadCvt()
{
    typedef typename Vec::EntryType T;
    LoadCvt<Vec, typename SupportedConversions<T>::Next>::test();
}

void testmain()
{
    runTest(checkAlignment<int_v>);
    runTest(checkAlignment<uint_v>);
    runTest(checkAlignment<float_v>);
    runTest(checkAlignment<double_v>);
    runTest(checkAlignment<short_v>);
    runTest(checkAlignment<ushort_v>);
    testAllTypes(checkMemoryAlignment);
    runTest(loadArray<int_v>);
    runTest(loadArray<uint_v>);
    runTest(loadArray<float_v>);
    runTest(loadArray<double_v>);
    runTest(loadArrayShort<short_v>);
    runTest(loadArrayShort<ushort_v>);

    testAllTypes(streamingLoad);

    testAllTypes(loadCvt);
}
<commit_msg>convert to new unittest macros<commit_after>/*  This file is part of the Vc library.

    Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#define VC_NEWTEST
#include "unittest.h"
#include <iostream>

using namespace Vc;

template<typename T> static constexpr T min(T a, T b) { return a < b ? a : b; }

template<typename Vec> constexpr unsigned long alignmentMask()
{
    return Vec::Size == 1 ? (
            // on 32bit the maximal alignment is 4 Bytes, even for 8-Byte doubles.
            min(sizeof(void*), sizeof(typename Vec::EntryType)) - 1
        ) : (
            // AVX::VectorAlignment is too large
            min<size_t>(sizeof(Vec), VectorAlignment) - 1
        );
}

TEST_ALL_V(Vec, checkAlignment)
{
    unsigned char i = 1;
    Vec a[10];
    unsigned long mask = alignmentMask<Vec>();
    for (i = 0; i < 10; ++i) {
        VERIFY((reinterpret_cast<size_t>(&a[i]) & mask) == 0) << "a = " << a << ", mask = " << mask;
    }
    const char *data = reinterpret_cast<const char *>(&a[0]);
    for (i = 0; i < 10; ++i) {
        VERIFY(&data[i * sizeof(Vec)] == reinterpret_cast<const char *>(&a[i]));
    }
}

void *hack_to_put_b_on_the_stack = 0;

TEST_ALL_V(Vec, checkMemoryAlignment)
{
    typedef typename Vec::EntryType T;
    const T *b = 0;
    Vc::Memory<Vec, 10> a;
    b = a;
    hack_to_put_b_on_the_stack = &b;
    size_t mask = memory_alignment<Vec>::value - 1;
    for (int i = 0; i < 10; ++i) {
        VERIFY((reinterpret_cast<size_t>(&b[i * Vec::Size]) & mask) == 0) << "b = " << b << ", mask = " << mask;
    }
}

enum Enum {
    loadArrayShortCount = 32 * 1024,
    streamingLoadCount = 1024
};
template<typename Vec> void loadArrayShort()
{
    typedef typename Vec::EntryType T;

    Vc::Memory<Vec, loadArrayShortCount> array;
    for (int i = 0; i < loadArrayShortCount; ++i) {
        array[i] = i;
    }

    const Vec offsets(IndexesFromZero);
    for (int i = 0; i < loadArrayShortCount; i += Vec::Size) {
        const T *const addr = &array[i];
        Vec ii(i);
        ii += offsets;

        Vec a(addr, Vc::Aligned);
        COMPARE(a, ii);

        Vec b = Vec::Zero();
        b.load(addr, Vc::Aligned);
        COMPARE(b, ii);
    }
}

TEST_ALL_V(Vec, loadArray)
{
    typedef typename Vec::EntryType T;
    typedef typename Vec::IndexType I;
    if (sizeof(T) < 32) {
        loadArrayShort<Vec>();
        return;
    }

    enum loadArrayEnum { count = 256 * 1024 / sizeof(T) };
    Vc::Memory<Vec, count> array;
    for (int i = 0; i < count; ++i) {
        array[i] = i;
    }

    const Vec offsets(IndexesFromZero);
    for (int i = 0; i < count; i += Vec::Size) {
        const T *const addr = &array[i];
        Vec ii(i);
        ii += offsets;

        Vec a(addr, Vc::Aligned);
        COMPARE(a, ii);

        Vec b = Vec::Zero();
        b.load(addr, Vc::Aligned);
        COMPARE(b, ii);
    }

    // check that Vc allows construction from objects that auto-convert to T*
    Vec tmp0(array, Vc::Aligned);
    tmp0.load(array, Vc::Aligned);
}

TEST_ALL_V(Vec, streamingLoad)
{
    typedef typename Vec::EntryType T;

    Vc::Memory<Vec, streamingLoadCount> data;
    data[0] = static_cast<T>(-streamingLoadCount/2);
    for (int i = 1; i < streamingLoadCount; ++i) {
        data[i] = data[i - 1];
        ++data[i];
    }

    Vec ref = data.firstVector();
    for (size_t i = 0; i < streamingLoadCount - Vec::Size; ++i, ++ref) {
        Vec v1, v2;
        if (0 == i % Vec::Size) {
            v1 = Vec(&data[i], Vc::Aligned | Vc::Streaming);
            v2.load (&data[i], Vc::Aligned | Vc::Streaming);
        } else {
            v1 = Vec(&data[i], Vc::Streaming | Vc::Unaligned);
            v2.load (&data[i], Vc::Unaligned | Vc::Streaming);
        }
        COMPARE(v1, ref) << ", i = " << i;
        COMPARE(v2, ref) << ", i = " << i;
    }
}

template<typename T> struct TypeInfo;
template<> struct TypeInfo<double        > { static const char *string() { return "double"; } };
template<> struct TypeInfo<float         > { static const char *string() { return "float"; } };
template<> struct TypeInfo<int           > { static const char *string() { return "int"; } };
template<> struct TypeInfo<unsigned int  > { static const char *string() { return "uint"; } };
template<> struct TypeInfo<short         > { static const char *string() { return "short"; } };
template<> struct TypeInfo<unsigned short> { static const char *string() { return "ushort"; } };
template<> struct TypeInfo<signed char   > { static const char *string() { return "schar"; } };
template<> struct TypeInfo<unsigned char > { static const char *string() { return "uchar"; } };
template<> struct TypeInfo<double_v      > { static const char *string() { return "double_v"; } };
template<> struct TypeInfo<float_v       > { static const char *string() { return "float_v"; } };
template<> struct TypeInfo<int_v         > { static const char *string() { return "int_v"; } };
template<> struct TypeInfo<uint_v        > { static const char *string() { return "uint_v"; } };
template<> struct TypeInfo<short_v       > { static const char *string() { return "short_v"; } };
template<> struct TypeInfo<ushort_v      > { static const char *string() { return "ushort_v"; } };

template<typename T, typename Current = void> struct SupportedConversions { typedef void Next; };
template<> struct SupportedConversions<float, void>           { typedef double         Next; };
template<> struct SupportedConversions<float, double>         { typedef int            Next; };
template<> struct SupportedConversions<float, int>            { typedef unsigned int   Next; };
template<> struct SupportedConversions<float, unsigned int>   { typedef short          Next; };
template<> struct SupportedConversions<float, short>          { typedef unsigned short Next; };
template<> struct SupportedConversions<float, unsigned short> { typedef signed char    Next; };
template<> struct SupportedConversions<float, signed char>    { typedef unsigned char  Next; };
template<> struct SupportedConversions<float, unsigned char>  { typedef void           Next; };
template<> struct SupportedConversions<int  , void          > { typedef unsigned int   Next; };
template<> struct SupportedConversions<int  , unsigned int  > { typedef short          Next; };
template<> struct SupportedConversions<int  , short         > { typedef unsigned short Next; };
template<> struct SupportedConversions<int  , unsigned short> { typedef signed char    Next; };
template<> struct SupportedConversions<int  , signed char   > { typedef unsigned char  Next; };
template<> struct SupportedConversions<int  , unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<unsigned int, void          > { typedef unsigned short Next; };
template<> struct SupportedConversions<unsigned int, unsigned short> { typedef unsigned char  Next; };
template<> struct SupportedConversions<unsigned int, unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<unsigned short, void          > { typedef unsigned char  Next; };
template<> struct SupportedConversions<unsigned short, unsigned char > { typedef void           Next; };
template<> struct SupportedConversions<         short, void          > { typedef unsigned char  Next; };
template<> struct SupportedConversions<         short, unsigned char > { typedef signed char    Next; };
template<> struct SupportedConversions<         short,   signed char > { typedef void           Next; };

template<typename Vec, typename MemT> struct LoadCvt {
    static void test() {
        typedef typename Vec::EntryType VecT;
        MemT *data = Vc::malloc<MemT, Vc::AlignOnCacheline>(128);
        for (size_t i = 0; i < 128; ++i) {
            data[i] = static_cast<MemT>(i - 64);
        }

        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v = Vec(&data[i]);
            } else if (i % Vec::Size == 0) {
                v = Vec(&data[i], Vc::Aligned);
            } else {
                v = Vec(&data[i], Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }
        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v.load(&data[i]);
            } else if (i % Vec::Size == 0) {
                v.load(&data[i], Vc::Aligned);
            } else {
                v.load(&data[i], Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }
        for (size_t i = 0; i < 128 - Vec::Size + 1; ++i) {
            Vec v;
            if (i % (2 * Vec::Size) == 0) {
                v = Vec(&data[i], Vc::Streaming);
            } else if (i % Vec::Size == 0) {
                v = Vec(&data[i], Vc::Streaming | Vc::Aligned);
            } else {
                v = Vec(&data[i], Vc::Streaming | Vc::Unaligned);
            }
            for (size_t j = 0; j < Vec::Size; ++j) {
                COMPARE(v[j], static_cast<VecT>(data[i + j])) << " " << TypeInfo<MemT>::string();
            }
        }

        ADD_PASS() << "loadCvt: load " << TypeInfo<MemT>::string() << "* as " << TypeInfo<Vec>::string();
        LoadCvt<Vec, typename SupportedConversions<VecT, MemT>::Next>::test();
    }
};
template<typename Vec> struct LoadCvt<Vec, void> { static void test() {} };

TEST_ALL_V(Vec, loadCvt)
{
    typedef typename Vec::EntryType T;
    LoadCvt<Vec, typename SupportedConversions<T>::Next>::test();
}

<|endoftext|>