<commit_before>/*
 * Copyright (C) 2009-2012, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file urbi/object/object.hxx
 ** \brief Definition of object::Object.
 */

#ifndef OBJECT_OBJECT_HXX
# define OBJECT_OBJECT_HXX

# include <ostream>
# include <typeinfo>

# include <boost/bind.hpp>
# include <boost/tr1/type_traits.hpp>

# include <libport/containers.hh>
# include <libport/debug.hh>
# include <libport/foreach.hh>
# include <libport/indent.hh>
# include <libport/intrusive-ptr.hh>
# include <libport/typelist.hh>

# include <urbi/object/object.hh>

# include <urbi/kernel/userver.hh>

# include <urbi/runner/raise.hh>

namespace urbi
{
  namespace object
  {
    /*---------.
    | Protos.  |
    `---------*/

    inline
    bool
    Object::protos_has() const
    {
      return proto_ || (protos_ && !protos_->empty());
    }

    inline
    rObject
    Object::protos_get_first() const
    {
      if (proto_)
        return proto_;
      else if (protos_ && !protos_->empty())
        return protos_->front();
      else
        return rObject();
    }

    inline
    Object&
    Object::unsafe_proto_add(const rObject& v)
    {
      if (protos_)
        protos_->push_front(v);
      else
        if (!proto_)
          proto_ = v;
        else
        {
          protos_ = new protos_type;
          protos_->push_back(v);
          protos_->push_back(proto_);
          proto_ = 0;
        }
      return *this;
    }

    inline
    Object&
    Object::proto_remove(const rObject& p)
    {
      aver(p);
      if (!protos_)
      {
        if (proto_ == p)
          proto_ = 0;
      }
      else
        for (protos_type::iterator i = protos_->begin();
           i != protos_->end();
           /* nothing */)
          if (*i == p)
            i = protos_->erase(i);
          else
            ++i;
      return *this;
    }

    /*--------.
    | Slots.  |
    `--------*/

    inline
    bool
    Object::slot_remove(key_type k)
    {
      return slots_.erase(this, k);
    }

    inline
    const Object::slots_implem&
    Object::slots_get() const
    {
      return slots_;
    }

    /*--------.
    | Clone.  |
    `--------*/

    inline rObject
    Object::clone() const
    {
      rObject res = new Object;
      // FIXME: clone should not be const!  This was already noted,
      // did the const come back at some point?
      res->proto_add(const_cast<Object*>(this));
      return res;
    }

    /*--------------------------.
    | Free standing functions.  |
    `--------------------------*/

    template<class F> bool
    for_all_protos(const rObject& r, F& f, Object::objects_set_type& objects)
    {
      if (libport::has(objects, r))
        return false;
      if (f(r))
        return true;
      objects.insert(r);
      if (r->protos_)
      {
        foreach(const rObject& p, *r->protos_)
          if (for_all_protos(p, f, objects))
            return true;
      }
      else if (r->proto_)
        if (for_all_protos(r->proto_, f, objects))
          return true;
      return false;
    }
    template<class F> bool
    for_all_protos(const rObject& r, F f)
    {
      Object::objects_set_type objects;
      return for_all_protos(r, f, objects);
    }

    inline const rObject&
    to_boolean(bool b)
    {
      return b ? true_class : false_class;
    }

    /*---------------.
    | Binding system |
    `---------------*/

    template <bool mem, typename T>
    struct DispatchBind_
    {
      static void
      res(Object* o, const std::string& name, T p)
      {
        o->bindfun_(name, p);
      }
    };

    template <typename T>
    struct DispatchBind_<true, T>
    {
      static void
      res(Object* o, const std::string& name, T p)
      {
        o->bindvar_(name, p);
      }
    };

    template <typename T>
    inline void
    Object::bind(const std::string& name, T p)
    {
      DispatchBind_<std::tr1::is_member_object_pointer<T>::value, T>
        ::res(this, name, p);
    }

    template <typename T>
    inline void
    Object::bindfun_(const std::string& name, T p)
    {
      GD_CATEGORY(Urbi.Object);

      libport::Symbol sym(name);
      rObject v = local_slot_get_value(sym);
      if (!v)
      {
        GD_FINFO_DEBUG("create primitive %s with C++ routine (type: %s)",
                       name, typeid(T).name());
        slot_set_value(sym, primitive(p), true);
      }
      else
      {
        GD_FINFO_DEBUG("extend primitive %s with C++ routine (type: %s)",
                       name, typeid(T).name());
        rPrimitive prim = v->as<Primitive>();
        assert(prim);
        primitive(prim, p);

      }
    }

    template <typename Self, typename T>
    T bindvar_getter_(Self& self, T (Self::*Attr))
    {
      return self.*Attr;
    }

    template <typename T>
    struct Ref
    {
      typedef T& res;
    };

    template <typename T>
    struct Ref<T*>
    {
      typedef T* res;
    };

    template <typename Self, typename T>
    T bindvar_setter_(typename Ref<Self>::res  self, T val, T (Self::*Attr))
    {
      return self.*Attr = val;
    }

    template <typename Self, typename T>
    inline void
    Object::bindvar_(const std::string& name, T (Self::*attr))
    {
      boost::function2<T, Self&, rObject>
        getter(boost::bind(&bindvar_getter_<Self, T>, _1, attr));
      boost::function3<void, Self&, T, rObject>
        setter(boost::bind(&bindvar_setter_<Self, T>, _1, _2, attr));
      slot_set(libport::Symbol(name), primitive(getter)->template as<Object>(),
               primitive(setter)->template as<Object>());
    }
    namespace detail
    {

    template <typename G> rObject make_getter(G g, libport::meta::False)
    {
      return primitive(g);
    }

    template <typename G> rObject make_getter(G g, libport::meta::True)
    {
      typedef typename
        libport::meta::member_function_0_trait<G>::class_type Self;
      typedef typename
        libport::meta::member_function_0_trait<G>::base_return_type T;
      boost::function2<T, Self&, rObject> getter(boost::bind(g, _1));
      return primitive(getter);
    }

    template<typename S> rObject make_setter(S s, libport::meta::True)
    {
      typedef typename
        libport::meta::member_function_1_trait<S>::class_type Self;
      typedef typename
        libport::meta::member_function_1_trait<S>::base_argument_1_type T;
      boost::function3<void, Self&, T, rObject> setter(boost::bind(s, _1, _2));
      return primitive(setter);
    }

    template<typename S> rObject make_setter(S, libport::meta::False)
    {
      return 0;
    }
    }
    template <typename G, typename S>
    inline void
    Object::bind(const std::string& name,
                G g,
                S s)
    {
      GD_CATEGORY(Urbi.Object);
      rObject getter = detail::make_getter(g,
        typename libport::meta::member_function_0_trait<G>::is_valid());
      rObject setter = detail::make_setter(s,
        typename libport::meta::member_function_1_trait<S>::is_valid());
      GD_FINFO_TRACE("Binding %s, g=%s (%s), s=%s (%s)", name, !!g, !!getter,
        !!s, !!setter);
      slot_set(libport::Symbol(name),
               getter, setter);
    }

    bool
    Object::as_check_(const std::type_info* req)
    {
      return req == &typeid(Object);
    }

    // Function heavily inlined, keep as short as possible (no GD_ !).
    template <typename T>
    libport::intrusive_ptr<T>
    Object::as() const
    {
      return const_cast<Object*>(this)->as<T>();
    }

    template <typename T>
    libport::intrusive_ptr<T>
    Object::as()
    {
      return reinterpret_cast<T*>(as_dispatch_(&typeid(T)));
    }

    // Function heavily inlined, keep as short as possible (no GD_ !).
    template <typename T>
    libport::intrusive_ptr<T>
    Object::as_checked() const
    {
      return const_cast<Object*>(this)->as_checked<T>();
    }

    template <typename T>
    libport::intrusive_ptr<T>
    Object::as_checked()
    {
      T* v = reinterpret_cast<T*>(as_dispatch_(&typeid(T)));
      if (!v)
        runner::raise_type_error(this, T::proto);
      return v;
    }

    // Specializations for object.

    template<>
    inline
    rObject
    Object::as<Object>()
    {
      return this;
    }

    template<>
    inline
    rObject
    Object::as<Object>() const
    {
      return const_cast<Object*>(this);
    }

    template<>
    inline
    libport::intrusive_ptr<const Object>
    Object::as<const Object>()
    {
      return this;
    }

    template<>
    inline
    libport::intrusive_ptr<const Object>
    Object::as<const Object>() const
    {
      return const_cast<Object*>(this);
    }
  } // namespace object
}

#endif // !OBJECT_OBJECT_HXX
<commit_msg>Fix for recent boost not including tr1 anymore.<commit_after>/*
 * Copyright (C) 2009-2012, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file urbi/object/object.hxx
 ** \brief Definition of object::Object.
 */

#ifndef OBJECT_OBJECT_HXX
# define OBJECT_OBJECT_HXX

# include <ostream>
# include <typeinfo>

# include <boost/bind.hpp>
# include <libport/tr1/type_traits>

# include <libport/containers.hh>
# include <libport/debug.hh>
# include <libport/foreach.hh>
# include <libport/indent.hh>
# include <libport/intrusive-ptr.hh>
# include <libport/typelist.hh>

# include <urbi/object/object.hh>

# include <urbi/kernel/userver.hh>

# include <urbi/runner/raise.hh>

namespace urbi
{
  namespace object
  {
    /*---------.
    | Protos.  |
    `---------*/

    inline
    bool
    Object::protos_has() const
    {
      return proto_ || (protos_ && !protos_->empty());
    }

    inline
    rObject
    Object::protos_get_first() const
    {
      if (proto_)
        return proto_;
      else if (protos_ && !protos_->empty())
        return protos_->front();
      else
        return rObject();
    }

    inline
    Object&
    Object::unsafe_proto_add(const rObject& v)
    {
      if (protos_)
        protos_->push_front(v);
      else
        if (!proto_)
          proto_ = v;
        else
        {
          protos_ = new protos_type;
          protos_->push_back(v);
          protos_->push_back(proto_);
          proto_ = 0;
        }
      return *this;
    }

    inline
    Object&
    Object::proto_remove(const rObject& p)
    {
      aver(p);
      if (!protos_)
      {
        if (proto_ == p)
          proto_ = 0;
      }
      else
        for (protos_type::iterator i = protos_->begin();
           i != protos_->end();
           /* nothing */)
          if (*i == p)
            i = protos_->erase(i);
          else
            ++i;
      return *this;
    }

    /*--------.
    | Slots.  |
    `--------*/

    inline
    bool
    Object::slot_remove(key_type k)
    {
      return slots_.erase(this, k);
    }

    inline
    const Object::slots_implem&
    Object::slots_get() const
    {
      return slots_;
    }

    /*--------.
    | Clone.  |
    `--------*/

    inline rObject
    Object::clone() const
    {
      rObject res = new Object;
      // FIXME: clone should not be const!  This was already noted,
      // did the const come back at some point?
      res->proto_add(const_cast<Object*>(this));
      return res;
    }

    /*--------------------------.
    | Free standing functions.  |
    `--------------------------*/

    template<class F> bool
    for_all_protos(const rObject& r, F& f, Object::objects_set_type& objects)
    {
      if (libport::has(objects, r))
        return false;
      if (f(r))
        return true;
      objects.insert(r);
      if (r->protos_)
      {
        foreach(const rObject& p, *r->protos_)
          if (for_all_protos(p, f, objects))
            return true;
      }
      else if (r->proto_)
        if (for_all_protos(r->proto_, f, objects))
          return true;
      return false;
    }
    template<class F> bool
    for_all_protos(const rObject& r, F f)
    {
      Object::objects_set_type objects;
      return for_all_protos(r, f, objects);
    }

    inline const rObject&
    to_boolean(bool b)
    {
      return b ? true_class : false_class;
    }

    /*---------------.
    | Binding system |
    `---------------*/

    template <bool mem, typename T>
    struct DispatchBind_
    {
      static void
      res(Object* o, const std::string& name, T p)
      {
        o->bindfun_(name, p);
      }
    };

    template <typename T>
    struct DispatchBind_<true, T>
    {
      static void
      res(Object* o, const std::string& name, T p)
      {
        o->bindvar_(name, p);
      }
    };

    template <typename T>
    inline void
    Object::bind(const std::string& name, T p)
    {
      DispatchBind_<LIBPORT_TRAIT_NAMESPACE::is_member_object_pointer<T>::value, T>
        ::res(this, name, p);
    }

    template <typename T>
    inline void
    Object::bindfun_(const std::string& name, T p)
    {
      GD_CATEGORY(Urbi.Object);

      libport::Symbol sym(name);
      rObject v = local_slot_get_value(sym);
      if (!v)
      {
        GD_FINFO_DEBUG("create primitive %s with C++ routine (type: %s)",
                       name, typeid(T).name());
        slot_set_value(sym, primitive(p), true);
      }
      else
      {
        GD_FINFO_DEBUG("extend primitive %s with C++ routine (type: %s)",
                       name, typeid(T).name());
        rPrimitive prim = v->as<Primitive>();
        assert(prim);
        primitive(prim, p);

      }
    }

    template <typename Self, typename T>
    T bindvar_getter_(Self& self, T (Self::*Attr))
    {
      return self.*Attr;
    }

    template <typename T>
    struct Ref
    {
      typedef T& res;
    };

    template <typename T>
    struct Ref<T*>
    {
      typedef T* res;
    };

    template <typename Self, typename T>
    T bindvar_setter_(typename Ref<Self>::res  self, T val, T (Self::*Attr))
    {
      return self.*Attr = val;
    }

    template <typename Self, typename T>
    inline void
    Object::bindvar_(const std::string& name, T (Self::*attr))
    {
      boost::function2<T, Self&, rObject>
        getter(boost::bind(&bindvar_getter_<Self, T>, _1, attr));
      boost::function3<void, Self&, T, rObject>
        setter(boost::bind(&bindvar_setter_<Self, T>, _1, _2, attr));
      slot_set(libport::Symbol(name), primitive(getter)->template as<Object>(),
               primitive(setter)->template as<Object>());
    }
    namespace detail
    {

    template <typename G> rObject make_getter(G g, libport::meta::False)
    {
      return primitive(g);
    }

    template <typename G> rObject make_getter(G g, libport::meta::True)
    {
      typedef typename
        libport::meta::member_function_0_trait<G>::class_type Self;
      typedef typename
        libport::meta::member_function_0_trait<G>::base_return_type T;
      boost::function2<T, Self&, rObject> getter(boost::bind(g, _1));
      return primitive(getter);
    }

    template<typename S> rObject make_setter(S s, libport::meta::True)
    {
      typedef typename
        libport::meta::member_function_1_trait<S>::class_type Self;
      typedef typename
        libport::meta::member_function_1_trait<S>::base_argument_1_type T;
      boost::function3<void, Self&, T, rObject> setter(boost::bind(s, _1, _2));
      return primitive(setter);
    }

    template<typename S> rObject make_setter(S, libport::meta::False)
    {
      return 0;
    }
    }
    template <typename G, typename S>
    inline void
    Object::bind(const std::string& name,
                G g,
                S s)
    {
      GD_CATEGORY(Urbi.Object);
      rObject getter = detail::make_getter(g,
        typename libport::meta::member_function_0_trait<G>::is_valid());
      rObject setter = detail::make_setter(s,
        typename libport::meta::member_function_1_trait<S>::is_valid());
      GD_FINFO_TRACE("Binding %s, g=%s (%s), s=%s (%s)", name, !!g, !!getter,
        !!s, !!setter);
      slot_set(libport::Symbol(name),
               getter, setter);
    }

    bool
    Object::as_check_(const std::type_info* req)
    {
      return req == &typeid(Object);
    }

    // Function heavily inlined, keep as short as possible (no GD_ !).
    template <typename T>
    libport::intrusive_ptr<T>
    Object::as() const
    {
      return const_cast<Object*>(this)->as<T>();
    }

    template <typename T>
    libport::intrusive_ptr<T>
    Object::as()
    {
      return reinterpret_cast<T*>(as_dispatch_(&typeid(T)));
    }

    // Function heavily inlined, keep as short as possible (no GD_ !).
    template <typename T>
    libport::intrusive_ptr<T>
    Object::as_checked() const
    {
      return const_cast<Object*>(this)->as_checked<T>();
    }

    template <typename T>
    libport::intrusive_ptr<T>
    Object::as_checked()
    {
      T* v = reinterpret_cast<T*>(as_dispatch_(&typeid(T)));
      if (!v)
        runner::raise_type_error(this, T::proto);
      return v;
    }

    // Specializations for object.

    template<>
    inline
    rObject
    Object::as<Object>()
    {
      return this;
    }

    template<>
    inline
    rObject
    Object::as<Object>() const
    {
      return const_cast<Object*>(this);
    }

    template<>
    inline
    libport::intrusive_ptr<const Object>
    Object::as<const Object>()
    {
      return this;
    }

    template<>
    inline
    libport::intrusive_ptr<const Object>
    Object::as<const Object>() const
    {
      return const_cast<Object*>(this);
    }
  } // namespace object
}

#endif // !OBJECT_OBJECT_HXX
<|endoftext|>


<commit_before>/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_UTIL_INDEXED_ARRAY_HPP
#define PIC_UTIL_INDEXED_ARRAY_HPP

#include <vector>

#include "../util/math.hpp"

namespace pic {

/**
 * @brief IntCoord
 */
typedef std::vector<int> IntCoord;

/**
 * @brief The IndexedArray class
 */
template <class T>
class IndexedArray
{
public:
    IndexedArray()
    {
    }

    /**
     * @brief bFuncNotNeg
     * @param val
     * @return
     */
    static bool bFuncNotNeg(T val)
    {
        return val > T(0);
    }

    /**
     * @brief bFuncNotZero
     * @param val
     * @return
     */
    static bool bFuncNotZero(T val)
    {
        return (val < T(0)) || (val > T(0));
    }

    /**
     * @brief bFuncNeg
     * @param val
     * @return
     */
    static bool bFuncNeg(T val)
    {
        return (val < T(0));
    }

    /**
     * @brief findSimple collects coordinates of data which satisfies a bool function func.
     * @param data
     * @param nData
     * @param ret
     * @param stride
     */
    static void findSimple(T *data, int nData, bool(*func)(float), IntCoord &ret, int stride = 1)
    {
        for(int i = 0; i < nData; i += stride) {
            if(func(data[i])) {
                ret.push_back(i);
            }
        }
    }

    /**
     * @brief find collects coordinates of data which satisfies a bool function func.
     * @param data
     * @param nData
     * @param param
     * @param ret
     */
    static void find(float *data, int nData, bool(*func)(float,
                     std::vector<float>), std::vector<float> param, IntCoord &ret)
    {
        for(int i = 0; i < nData; i++) {
            if(func(data[i], param)) {
                ret.push_back(i);
            }
        }
    }

    /**
     * @brief mean computes the mean value.
     * @param data
     * @param coord
     * @return
     */
    static T mean(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        T ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            ret += data[coord[i]];
        }

        return ret / T(coord.size());
    }

    /**
     * @brief min computes the min value.
     * @param data
     * @param coord
     * @return
     */
    static T min(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        float ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            int j = coord[i];
            ret = MIN(ret, data[j]);
        }

        return ret;
    }

    /**
     * @brief max computes the max value.
     * @param data
     * @param coord
     * @return
     */
    static T max(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        T ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            int j = coord[i];
            ret = MAX(ret, data[j]);
        }

        return ret;
    }

    /**
     * @brief percentile
     * @param data
     * @param coord
     * @param percent
     * @return
     */
    static T percentile(T *data, IntCoord &coord, float percent)
    {
        if(coord.empty()) {
            return T(0);
        }

        int n = int(coord.size());
        T *tmp = new T[n];

        for(int i = 0; i < n; i++) {
            int j = coord[i];
            tmp[i] = data[j];
        }

        std::sort(tmp, tmp + n);

        percent = CLAMPi(percent, 0.0f, 1.0f);

        T ret = tmp[int(float(n - 1) * percent)];
        delete[] tmp;

        return ret;
    }

    /**
     * @brief scale scales values.
     * @param coord
     * @param scaling
     */
    static void scale(IntCoord &coord, int scale)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            coord.at(i) = coord.at(i) * scale;
        }
    }

    /**
     * @brief log10Mean computes mean in the log10 domain.
     * @param data
     * @param coord
     * @return
     */
    static float log10Mean(float *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return FLT_MAX;
        }

        float delta = 1e-6f;
        float ret = 0.0f;

        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            ret += log10f(data[j] + delta);
        }

        return ret / float(coord.size());
    }

    /**
     * @brief log2Mean computes mean in the log2 domain.
     * @param data
     * @param coord
     * @return
     */
    static float log2Mean(float *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return FLT_MAX;
        }

        float delta = 1e-6f;
        float ret = 0.0f;
        float log2f = logf(2.0f);

        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            ret += logf(data[j] + delta) / log2f;
        }

        return ret / float(coord.size());
    }

    /**
     * @brief negative computes the negative value given a val reference point.
     * @param data
     * @param coord
     * @param referencePoint
     */
    static void negative(T *data, IntCoord &coord, T referencePoint = T(1))
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] = referencePoint - data[j];
        }
    }

    /**
     * @brief add is the additive operator.
     * @param data
     * @param coord
     * @param val
     */
    static void add(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] += val;
        }
    }

    /**
     * @brief sub is the subtractive operator.
     * @param data
     * @param coord
     * @param val
     */
    static void sub(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] -= val;
        }
    }

    /**
     * @brief mul is the multiplicative operator.
     * @param data
     * @param coord
     * @param val
     */
    static void mul(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] *= val;
        }
    }

    /**
     * @brief div is the division operator.
     * @param data
     * @param coord
     * @param val
     */
    static void div(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] /= val;
        }
    }

    /**
     * @brief assign
     * @param dataDst
     * @param coord
     * @param val
     */
    static void assign(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] = val;
        }
    }

    /**
     * @brief Assign
     * @param dataDst
     * @param coord
     * @param dataSrc
     */
    static void assign(T *dataDst, IntCoord &coord, T *dataSrc)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            dataDst[j] = dataSrc[j];
        }
    }
};

} // end namespace pic

#endif /* PIC_UTIL_INDEXED_ARRAY_HPP */

<commit_msg>Update indexed_array.hpp<commit_after>/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_UTIL_INDEXED_ARRAY_HPP
#define PIC_UTIL_INDEXED_ARRAY_HPP

#include <vector>

#include "../util/math.hpp"

namespace pic {

/**
 * @brief IntCoord
 */
typedef std::vector<int> IntCoord;

/**
 * @brief The IndexedArray class
 */
template <class T>
class IndexedArray
{
public:
    IndexedArray()
    {
    }

    /**
     * @brief bFuncNotNeg
     * @param val
     * @return
     */
    static bool bFuncNotNeg(T val)
    {
        return val > T(0);
    }

    /**
     * @brief bFuncNotZero
     * @param val
     * @return
     */
    static bool bFuncNotZero(T val)
    {
        return (val < T(0)) || (val > T(0));
    }

    /**
     * @brief bFuncNeg
     * @param val
     * @return
     */
    static bool bFuncNeg(T val)
    {
        return (val < T(0));
    }

    /**
     * @brief findSimple collects coordinates of data which satisfies a bool function func.
     * @param data
     * @param nData
     * @param ret
     * @param stride
     */
    static void findSimple(T *data, int nData, bool(*func)(float), IntCoord &ret, int stride = 1)
    {
        for(int i = 0; i < nData; i += stride) {
            if(func(data[i])) {
                ret.push_back(i);
            }
        }
    }

    /**
     * @brief find collects coordinates of data which satisfies a bool function func.
     * @param data
     * @param nData
     * @param param
     * @param ret
     */
    static void find(float *data, int nData, bool(*func)(float,
                     std::vector<float>), std::vector<float> param, IntCoord &ret)
    {
        for(int i = 0; i < nData; i++) {
            if(func(data[i], param)) {
                ret.push_back(i);
            }
        }
    }

    /**
     * @brief mean computes the mean value.
     * @param data
     * @param coord
     * @return
     */
    static T mean(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        T ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            int j = coord[i];
            ret += data[];
        }

        return ret / T(coord.size());
    }

    /**
     * @brief min computes the min value.
     * @param data
     * @param coord
     * @return
     */
    static T min(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        float ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            int j = coord[i];
            ret = MIN(ret, data[j]);
        }

        return ret;
    }

    /**
     * @brief max computes the max value.
     * @param data
     * @param coord
     * @return
     */
    static T max(T *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return T(0);
        }

        T ret = data[coord[0]];

        for(unsigned int i = 1; i < coord.size(); i++) {
            int j = coord[i];
            ret = MAX(ret, data[j]);
        }

        return ret;
    }

    /**
     * @brief percentile
     * @param data
     * @param coord
     * @param percent
     * @return
     */
    static T percentile(T *data, IntCoord &coord, float percent)
    {
        if(coord.empty()) {
            return T(0);
        }

        int n = int(coord.size());
        T *tmp = new T[n];

        for(int i = 0; i < n; i++) {
            int j = coord[i];
            tmp[i] = data[j];
        }

        std::sort(tmp, tmp + n);

        percent = CLAMPi(percent, 0.0f, 1.0f);

        T ret = tmp[int(float(n - 1) * percent)];
        delete[] tmp;

        return ret;
    }

    /**
     * @brief scale scales values.
     * @param coord
     * @param scaling
     */
    static void scale(IntCoord &coord, int scale)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            coord.at(i) = coord.at(i) * scale;
        }
    }

    /**
     * @brief log10Mean computes mean in the log10 domain.
     * @param data
     * @param coord
     * @return
     */
    static float log10Mean(float *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return FLT_MAX;
        }

        float delta = 1e-6f;
        float ret = 0.0f;

        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            ret += log10f(data[j] + delta);
        }

        return ret / float(coord.size());
    }

    /**
     * @brief log2Mean computes mean in the log2 domain.
     * @param data
     * @param coord
     * @return
     */
    static float log2Mean(float *data, IntCoord &coord)
    {
        if(coord.empty()) {
            return FLT_MAX;
        }

        float delta = 1e-6f;
        float ret = 0.0f;
        float log2f = logf(2.0f);

        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            ret += logf(data[j] + delta) / log2f;
        }

        return ret / float(coord.size());
    }

    /**
     * @brief negative computes the negative value given a val reference point.
     * @param data
     * @param coord
     * @param referencePoint
     */
    static void negative(T *data, IntCoord &coord, T referencePoint = T(1))
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] = referencePoint - data[j];
        }
    }

    /**
     * @brief add is the additive operator.
     * @param data
     * @param coord
     * @param val
     */
    static void add(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] += val;
        }
    }

    /**
     * @brief sub is the subtractive operator.
     * @param data
     * @param coord
     * @param val
     */
    static void sub(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] -= val;
        }
    }

    /**
     * @brief mul is the multiplicative operator.
     * @param data
     * @param coord
     * @param val
     */
    static void mul(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] *= val;
        }
    }

    /**
     * @brief div is the division operator.
     * @param data
     * @param coord
     * @param val
     */
    static void div(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] /= val;
        }
    }

    /**
     * @brief assign
     * @param dataDst
     * @param coord
     * @param val
     */
    static void assign(T *data, IntCoord &coord, T val)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            data[j] = val;
        }
    }

    /**
     * @brief Assign
     * @param dataDst
     * @param coord
     * @param dataSrc
     */
    static void assign(T *dataDst, IntCoord &coord, T *dataSrc)
    {
        for(unsigned int i = 0; i < coord.size(); i++) {
            int j = coord[i];
            dataDst[j] = dataSrc[j];
        }
    }
};

} // end namespace pic

#endif /* PIC_UTIL_INDEXED_ARRAY_HPP */

<|endoftext|>


<commit_before>#ifndef VSMC_CORE_PARTICLE_HPP
#define VSMC_CORE_PARTICLE_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/internal/resampling.hpp>

namespace vsmc {

/// \brief Particle class representing the whole particle set
/// \ingroup Core
///
/// \tparam T Requirement:
/// \li Constructor compatible with
/// \code T(Particle<T>::size_type N) \endcode
/// \li member function copy method compatible with
/// \code copy(Particle<T>::size_type from, Particle<T>::size_type to) \endcode
template <typename T>
class Particle
{
    public :

    /// The type of the number of particles
    typedef VSMC_SIZE_TYPE size_type;

    /// The type of the particle values
    typedef T value_type;

#ifdef VSMC_USE_SEQUENTIAL_RNG
    /// The type of the sequential pseudo random number generator C++11 engine
    typedef VSMC_SEQRNG_TYPE rng_type;
#else
    /// The type of the Counter-based random number generator
    typedef VSMC_CBRNG_TYPE cbrng_type;

    /// The type of the Counter-based random number generator C++11 engine
    typedef rng::Engine<cbrng_type> rng_type;
#endif

    /// The integer type of the seed
    typedef rng_type::result_type seed_type;

    /// The type of the weight and log weight vectors
    typedef Eigen::VectorXd weight_type;

    /// \brief Construct a Particle object with a given number of particles
    ///
    /// \param N The number of particles
    /// \param seed The seed to the parallel RNG system
    ///
    /// \post All weights are initialized to be euqal to each other
    explicit Particle (size_type N, seed_type seed = VSMC_RNG_SEED) :
        size_(N), value_(N), ess_(N),
        weight_(N), log_weight_(N), inc_weight_(N), replication_(N),
        ess_cached_(false), weight_cached_(false), log_weight_cached_(false),
        resampled_(false), zconst_(0), seed_(seed)
#ifndef VSMC_USE_SEQUENTIAL_RNG
        , prng_(N)
#endif
    {
        reset_rng();
        set_equal_weight();
    }

    /// Size of the particle set
    size_type size () const
    {
        return size_;
    }

    /// Read and write access to particle values
    value_type &value ()
    {
        return value_;
    }

    /// Read only access to particle values
    const value_type &value () const
    {
        return value_;
    }

    /// Read only access to the weights
    const weight_type &weight () const
    {
        if (!weight_cached_) {
            weight_ = log_weight().array().exp();
            double sum = weight_.sum();
            weight_ *= 1 / sum;
            weight_cached_ = true;
        }

        return weight_;
    }

    /// Read only access to the log weights
    const weight_type &log_weight () const
    {
        if (!log_weight_cached_) {
            double max_weight = log_weight_.maxCoeff();
            log_weight_ = log_weight_.array() - max_weight;
            log_weight_cached_ = true;
        }

        return log_weight_;
    }

    /// Set equal weights for all particles
    void set_equal_weight ()
    {
        ess_ = size_;
        weight_.setConstant(1.0 / size_);
        log_weight_.setConstant(0);

        ess_cached_ = true;
        weight_cached_ = true;
        log_weight_cached_ = true;
    }

    /// \brief Set the log weights with an iterator
    ///
    /// \param first The position to start the reading, it shall be valid after
    /// increments of size() times.
    /// \param delta A multiplier appiled to the new log weights
    template <typename InputIter>
    void set_log_weight (InputIter first, double delta = 1)
    {
        size_type i = 0;
        while (i != size_) {
            log_weight_[i] = *first;
            ++first;
            ++i;
        }
        log_weight_ *= delta;
        set_log_weight();
    }

    /// Set the log weights with a pointer
    void set_log_weight (const double *new_weight, double delta = 1)
    {
        Eigen::Map<const weight_type> w(new_weight, size_);
        set_log_weight(w, delta);
    }

    /// Set the log weights with a weight_type object
    void set_log_weight (const weight_type &new_weight, double delta = 1)
    {
        log_weight_ = delta * new_weight.head(size_);
        set_log_weight();
    }

    /// \brief Add to the log weights with an iterator
    ///
    /// \param first The position to start the reading, it shall be valid after
    /// increments of size() times.
    /// \param delta A multiplier appiled to the new incremental log weights
    /// \param add_zconst Whether this incremental weights shall contribute to
    /// the SMC normalizing constant estimate
    template <typename InputIter>
    void add_log_weight (InputIter first, double delta = 1,
            bool add_zconst = true)
    {
        using std::log;

        size_type i = 0;
        while (i != size_) {
            inc_weight_[i] = *first;
            ++first;
            ++i;
        }
        inc_weight_ *= delta;
        log_weight_ += inc_weight_;
        if (add_zconst)
            zconst_ += log(weight().dot(inc_weight_.array().exp().matrix()));
        set_log_weight();
    }

    /// Add to the log weights with a pointer
    void add_log_weight (const double *inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        Eigen::Map<const weight_type> w(inc_weight, size_);
        add_log_weight(w, delta, add_zconst);
    }

    /// Add to the log weights with a weight_object object
    void add_log_weight (const weight_type &inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        using std::log;

        inc_weight_ = delta * inc_weight.head(size_);
        log_weight_ += inc_weight_;
        if (add_zconst)
            zconst_ += log(weight().dot(inc_weight_.array().exp().matrix()));
        set_log_weight();
    }

    /// The current ESS (Effective Sample Size)
    double ess () const
    {
        if (!ess_cached_) {
            ess_ = 1 / weight().squaredNorm();
            ess_cached_ = true;
        }

        return ess_;
    }

    /// Whether resampling was performed when resampling(scheme, threshold) was
    /// last called.
    bool resampled () const
    {
        return resampled_;
    }

    /// Get the value of the logarithm of SMC normalizing constant
    double zconst () const
    {
        return zconst_;
    }

    /// Reset the value of logarithm of SMC normalizing constant to zero
    void reset_zconst ()
    {
        zconst_ = 0;
    }

    /// \brief Perform resampling if ess() < threshold * size()
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param threshold The threshold for resampling
    void resample (ResampleScheme scheme, double threshold)
    {
        assert(replication_.size() == size());

        // call to ess() will normalize weight first
        resampled_ = ess() < threshold * size_;

        if (resampled_) {
            internal::pre_resampling(&value_);
            switch (scheme) {
                case MULTINOMIAL :
                    resample_multinomial();
                    break;
                case RESIDUAL :
                    resample_residual();
                    break;
                case STRATIFIED :
                    resample_stratified();
                    break;
                case SYSTEMATIC :
                    resample_systematic();
                    break;
                case RESIDUAL_STRATIFIED :
                    resample_residual_stratified ();
                    break;
                default :
                    resample_stratified();
                    break;
            }
            resample_do();
            internal::post_resampling(&value_);
        }
    }

    /// \brief Get a C++11 RNG engine
    ///
    /// \param id The position of the particle, 0 to size() - 1
    ///
    /// \return A reference to a C++11 RNG engine unique to particle at
    /// position id, and independent of others if \c VSMC_USE_SEQUENTIAL_RNG is
    /// not defined. Otherwise, it is the same pseudo RNG for any value of \c
    /// id
    rng_type &rng (size_type id)
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        return srng_;
#else
        return prng_[id];
#endif
    }

    /// Reset the RNG system with a given seed
    void reset_rng (seed_type seed)
    {
        seed_ = seed;
        reset_rng();
    }

    /// Reset the parallel RNG system with the last used seed
    void reset_rng ()
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        srng_ = rng_type(seed_);
#else
        for (size_type i = 0; i != size_; ++i)
            prng_[i] = rng_type(seed_ + i);
#endif
    }

    private :

    typedef Eigen::Matrix<size_type, Eigen::Dynamic, 1> replication_type;

    size_type size_;
    value_type value_;
    mutable double ess_;

    mutable weight_type weight_;
    mutable weight_type log_weight_;
    mutable weight_type inc_weight_;
    mutable replication_type replication_;

    mutable bool ess_cached_;
    mutable bool weight_cached_;
    mutable bool log_weight_cached_;

    bool resampled_;
    double zconst_;

    seed_type seed_;
#ifdef VSMC_USE_SEQUENTIAL_RNG
    rng_type srng_;
#else
    std::deque<rng_type> prng_;
#endif

    void set_log_weight ()
    {
        ess_cached_ = false;
        weight_cached_ = false;
        log_weight_cached_ = false;

        assert(weight_.size() == size_);
        assert(log_weight_.size() == size_);
        assert(inc_weight_.size() == size_);
    }

    void resample_multinomial ()
    {
        weight2replication(size_);
    }

    void resample_residual ()
    {
        /// \internal Reuse weight and log_weight. weight: act as the
        /// fractional part of N * weight. log_weight: act as the integral
        /// part of N * weight.  They all will be reset to equal weights after
        /// resampling.  So it is safe to modify them here.

        using std::modf;

        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        weight2replication(weight_.sum());
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_stratified ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_systematic ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_residual_stratified ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_residual_systematic ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void weight2replication (size_type size)
    {
        double tp = weight_.sum();
        double sum_p = 0;
        size_type sum_n = 0;
        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i) {
            if (sum_n < size && weight_[i] > 0) {
                rng::binomial_distribution<size_type> binom(
                        size - sum_n, weight_[i] / (tp - sum_p));
                replication_[i] = binom(rng(i));
            }
            sum_p += weight_[i];
            sum_n += replication_[i];
        }
    }

    void resample_do ()
    {
        // Some times the nuemrical round error can cause the total childs
        // differ from number of particles
        size_type sum = replication_.sum();
        if (sum != size_) {
            size_type id_max;
            replication_.maxCoeff(&id_max);
            replication_[id_max] += size_ - sum;
        }

        size_type from = 0;
        size_type time = 0;
        for (size_type to = 0; to != size_; ++to) {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        set_equal_weight();
    }
}; // class Particle

} // namespace vsmc

#endif // VSMC_CORE_PARTICLE_HPP
<commit_msg>partially revert last commit<commit_after>#ifndef VSMC_CORE_PARTICLE_HPP
#define VSMC_CORE_PARTICLE_HPP

#include <vsmc/internal/common.hpp>
#include <vsmc/internal/resampling.hpp>

namespace vsmc {

/// \brief Particle class representing the whole particle set
/// \ingroup Core
///
/// \tparam T Requirement:
/// \li Constructor compatible with
/// \code T(Particle<T>::size_type N) \endcode
/// \li member function copy method compatible with
/// \code copy(Particle<T>::size_type from, Particle<T>::size_type to) \endcode
template <typename T>
class Particle
{
    public :

    /// The type of the number of particles
    typedef VSMC_SIZE_TYPE size_type;

    /// The type of the particle values
    typedef T value_type;

#ifdef VSMC_USE_SEQUENTIAL_RNG
    /// The type of the sequential pseudo random number generator C++11 engine
    typedef VSMC_SEQRNG_TYPE rng_type;
#else
    /// The type of the Counter-based random number generator
    typedef VSMC_CBRNG_TYPE cbrng_type;

    /// The type of the Counter-based random number generator C++11 engine
    typedef rng::Engine<cbrng_type> rng_type;
#endif

    /// The integer type of the seed
    typedef rng_type::result_type seed_type;

    /// The type of the weight and log weight vectors
    typedef Eigen::VectorXd weight_type;

    /// \brief Construct a Particle object with a given number of particles
    ///
    /// \param N The number of particles
    /// \param seed The seed to the parallel RNG system
    ///
    /// \post All weights are initialized to be euqal to each other
    explicit Particle (size_type N, seed_type seed = VSMC_RNG_SEED) :
        size_(N), value_(N), ess_(N),
        weight_(N), log_weight_(N), inc_weight_(N), replication_(N),
        ess_cached_(false), weight_cached_(false), log_weight_cached_(false),
        resampled_(false), zconst_(0), seed_(seed)
#ifndef VSMC_USE_SEQUENTIAL_RNG
        , prng_(N)
#endif
    {
        reset_rng();
        set_equal_weight();
    }

    /// Size of the particle set
    size_type size () const
    {
        return size_;
    }

    /// Read and write access to particle values
    value_type &value ()
    {
        return value_;
    }

    /// Read only access to particle values
    const value_type &value () const
    {
        return value_;
    }

    /// Read only access to the weights
    const weight_type &weight () const
    {
        if (!weight_cached_) {
            weight_ = log_weight().array().exp();
            double sum = weight_.sum();
            weight_ *= 1 / sum;
            weight_cached_ = true;
        }

        return weight_;
    }

    /// Read only access to the log weights
    const weight_type &log_weight () const
    {
        if (!log_weight_cached_) {
            double max_weight = log_weight_.maxCoeff();
            log_weight_ = log_weight_.array() - max_weight;
            log_weight_cached_ = true;
        }

        return log_weight_;
    }

    /// Set equal weights for all particles
    void set_equal_weight ()
    {
        ess_ = size_;
        weight_.setConstant(1.0 / size_);
        log_weight_.setConstant(0);

        ess_cached_ = true;
        weight_cached_ = true;
        log_weight_cached_ = true;
    }

    /// \brief Set the log weights with a pointer
    ///
    /// \param new_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new log weights
    void set_log_weight (const double *new_weight, double delta = 1)
    {
        Eigen::Map<const weight_type> w(new_weight, size_);
        set_log_weight(w, delta);
    }

    /// Set the log weights with a weight_type object
    void set_log_weight (const weight_type &new_weight, double delta = 1)
    {
        log_weight_ = delta * new_weight.head(size_);
        set_log_weight();
    }

    /// \brief Add to the log weights with a pointer
    ///
    /// \param inc_weight The position to start the reading, it shall be valid
    /// after increments of size() times.
    /// \param delta A multiplier appiled to the new incremental log weights
    /// \param add_zconst Whether this incremental weights shall contribute to
    /// the SMC normalizing constant estimate
    void add_log_weight (const double *inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        Eigen::Map<const weight_type> w(inc_weight, size_);
        add_log_weight(w, delta, add_zconst);
    }

    /// Add to the log weights with a weight_object object
    void add_log_weight (const weight_type &inc_weight, double delta = 1,
            bool add_zconst = true)
    {
        using std::log;

        inc_weight_ = delta * inc_weight.head(size_);
        log_weight_ += inc_weight_;
        if (add_zconst)
            zconst_ += log(weight().dot(inc_weight_.array().exp().matrix()));
        set_log_weight();
    }

    /// The current ESS (Effective Sample Size)
    double ess () const
    {
        if (!ess_cached_) {
            ess_ = 1 / weight().squaredNorm();
            ess_cached_ = true;
        }

        return ess_;
    }

    /// Whether resampling was performed when resampling(scheme, threshold) was
    /// last called.
    bool resampled () const
    {
        return resampled_;
    }

    /// Get the value of the logarithm of SMC normalizing constant
    double zconst () const
    {
        return zconst_;
    }

    /// Reset the value of logarithm of SMC normalizing constant to zero
    void reset_zconst ()
    {
        zconst_ = 0;
    }

    /// \brief Perform resampling if ess() < threshold * size()
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param threshold The threshold for resampling
    void resample (ResampleScheme scheme, double threshold)
    {
        assert(replication_.size() == size());

        // call to ess() will normalize weight first
        resampled_ = ess() < threshold * size_;

        if (resampled_) {
            internal::pre_resampling(&value_);
            switch (scheme) {
                case MULTINOMIAL :
                    resample_multinomial();
                    break;
                case RESIDUAL :
                    resample_residual();
                    break;
                case STRATIFIED :
                    resample_stratified();
                    break;
                case SYSTEMATIC :
                    resample_systematic();
                    break;
                case RESIDUAL_STRATIFIED :
                    resample_residual_stratified ();
                    break;
                default :
                    resample_stratified();
                    break;
            }
            resample_do();
            internal::post_resampling(&value_);
        }
    }

    /// \brief Get a C++11 RNG engine
    ///
    /// \param id The position of the particle, 0 to size() - 1
    ///
    /// \return A reference to a C++11 RNG engine unique to particle at
    /// position id, and independent of others if \c VSMC_USE_SEQUENTIAL_RNG is
    /// not defined. Otherwise, it is the same pseudo RNG for any value of \c
    /// id
    rng_type &rng (size_type id)
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        return srng_;
#else
        return prng_[id];
#endif
    }

    /// Reset the RNG system with a given seed
    void reset_rng (seed_type seed)
    {
        seed_ = seed;
        reset_rng();
    }

    /// Reset the parallel RNG system with the last used seed
    void reset_rng ()
    {
#ifdef VSMC_USE_SEQUENTIAL_RNG
        srng_ = rng_type(seed_);
#else
        for (size_type i = 0; i != size_; ++i)
            prng_[i] = rng_type(seed_ + i);
#endif
    }

    private :

    typedef Eigen::Matrix<size_type, Eigen::Dynamic, 1> replication_type;

    size_type size_;
    value_type value_;
    mutable double ess_;

    mutable weight_type weight_;
    mutable weight_type log_weight_;
    mutable weight_type inc_weight_;
    mutable replication_type replication_;

    mutable bool ess_cached_;
    mutable bool weight_cached_;
    mutable bool log_weight_cached_;

    bool resampled_;
    double zconst_;

    seed_type seed_;
#ifdef VSMC_USE_SEQUENTIAL_RNG
    rng_type srng_;
#else
    std::deque<rng_type> prng_;
#endif

    void set_log_weight ()
    {
        ess_cached_ = false;
        weight_cached_ = false;
        log_weight_cached_ = false;

        assert(weight_.size() == size_);
        assert(log_weight_.size() == size_);
        assert(inc_weight_.size() == size_);
    }

    void resample_multinomial ()
    {
        weight2replication(size_);
    }

    void resample_residual ()
    {
        /// \internal Reuse weight and log_weight. weight: act as the
        /// fractional part of N * weight. log_weight: act as the integral
        /// part of N * weight.  They all will be reset to equal weights after
        /// resampling.  So it is safe to modify them here.

        using std::modf;

        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        weight2replication(weight_.sum());
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_stratified ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_systematic ()
    {
        replication_.setConstant(0);
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size_) {
            while (j < cw * size_ - u && j != size_) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
    }

    void resample_residual_stratified ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                u = unif(rng(j));
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void resample_residual_systematic ()
    {
        using std::modf;

        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i)
            weight_[i] = modf(size_ * weight_[i], log_weight_.data() + i);
        size_type size = weight_.sum();
        weight_ /= size;
        size_type j = 0;
        size_type k = 0;
        rng::uniform_real_distribution<double> unif(0,1);
        double u = unif(rng(0));
        double cw = weight_[0];
        while (j != size) {
            while (j < cw * size - u && j != size) {
                ++replication_[k];
                ++j;
            }
            if (k == size_ - 1)
                break;
            cw += weight_[++k];
        }
        for (size_type i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
    }

    void weight2replication (size_type size)
    {
        double tp = weight_.sum();
        double sum_p = 0;
        size_type sum_n = 0;
        replication_.setConstant(0);
        for (size_type i = 0; i != size_; ++i) {
            if (sum_n < size && weight_[i] > 0) {
                rng::binomial_distribution<size_type> binom(
                        size - sum_n, weight_[i] / (tp - sum_p));
                replication_[i] = binom(rng(i));
            }
            sum_p += weight_[i];
            sum_n += replication_[i];
        }
    }

    void resample_do ()
    {
        // Some times the nuemrical round error can cause the total childs
        // differ from number of particles
        size_type sum = replication_.sum();
        if (sum != size_) {
            size_type id_max;
            replication_.maxCoeff(&id_max);
            replication_[id_max] += size_ - sum;
        }

        size_type from = 0;
        size_type time = 0;
        for (size_type to = 0; to != size_; ++to) {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        set_equal_weight();
    }
}; // class Particle

} // namespace vsmc

#endif // VSMC_CORE_PARTICLE_HPP
<|endoftext|>


<commit_before>/*
 * xtensor-fftw
 * Copyright (c) 2017, Patrick Bos
 *
 * Distributed under the terms of the BSD 3-Clause License.
 *
 * The full license is in the file LICENSE, distributed with this software.
 *
 * basic.hpp:
 * Contains the basic functions needed to do FFTs and inverse FFTs on real and
 * complex arrays. The behavior of these functions mimics that of the numpy.fft
 * module, see https://github.com/egpbos/xtensor-fftw/issues/6.
 *
 */

#ifndef XTENSOR_FFTW_BASIC_HPP
#define XTENSOR_FFTW_BASIC_HPP

#include <xtensor/xarray.hpp>
#include <xtl/xcomplex.hpp>
#include <complex>
#include <type_traits>
#include <fftw3.h>

namespace xt {
  namespace fftw {
    // The implementations must be inline to avoid multiple definition errors due to multiple compilations (e.g. when
    // including this header multiple times in a project, or when it is explicitly compiled itself and included too).

    // Note: multidimensional complex-to-real transforms by default destroy the input data! See:
    // http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data

    // reinterpret_casts below suggested by http://www.fftw.org/fftw3_doc/Complex-numbers.html

    // We use the convention that the inverse fft divides by N, like numpy does.

    // aliases for the fftw precision-dependent types:
    template <typename T> struct fftw_t {
      static_assert(sizeof(T) == 0, "Only specializations of fftw_t can be used");
    };
    template <> struct fftw_t<float> {
      using plan = fftwf_plan;
      using complex = fftwf_complex;
    };
    template <> struct fftw_t<double> {
      using plan = fftw_plan;
      using complex = fftw_complex;
    };
    template <> struct fftw_t<long double> {
      using plan = fftwl_plan;
      using complex = fftwl_complex;
    };
    // and subclass alias for when calling with a complex type:
    template <typename T> struct fftw_t< std::complex<T> > : public fftw_t<T> {};

    // convert std::complex to fftwX_complex with right precision X; non-complex floats stay themselves:
    template <typename regular_or_complex_t>
    using fftw_number_t = std::conditional_t<
        xtl::is_complex<regular_or_complex_t>::value,
        typename fftw_t< xtl::complex_value_type_t<regular_or_complex_t> >::complex,
        xtl::complex_value_type_t<regular_or_complex_t>
    >;

    // short-hand for precision for template arguments
    template <typename in_or_output_t>
    using prec_t = xtl::complex_value_type_t<in_or_output_t>;

    ///////////////////////////////////////////////////////////////////////////////
    // Regular FFT (complex to complex)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Regular FFT: xarray templates
    ////

    template<typename input_t, typename output_t, typename...>
    xt::xarray<output_t> _fft_ (const xt::xarray<input_t> &input) {
      static_assert(sizeof(prec_t<input_t>) == 0, "Only specializations of _fft_ can be used");
    }

    template<typename input_t, typename output_t, typename...>
    xt::xarray<output_t> _ifft_ (const xt::xarray<input_t> &input) {
      static_assert(sizeof(prec_t<input_t>) == 0, "Only specializations of _ifft_ can be used");
    }

    template <
        typename input_t, typename output_t,
        typename fftw_t<input_t>::plan (&fftw_plan_dft)(int, fftw_number_t<input_t> *, fftw_number_t<output_t> *, unsigned int),
        void (&fftw_execute)(typename fftw_t<input_t>::plan), void (&fftw_destroy_plan)(typename fftw_t<input_t>::plan),
        typename = std::enable_if_t<
            std::is_same< prec_t<input_t>, prec_t<output_t> >::value
            && std::is_floating_point< prec_t<input_t> >::value
        >
    >
    xt::xarray<output_t> _fft_(const xt::xarray<input_t> &input) {
      xt::xarray<output_t, layout_type::dynamic> output(input.shape(), input.strides());

      using fftw_input_t = fftw_number_t<input_t>;
      using fftw_output_t = fftw_number_t<output_t>;

      typename fftw_t<input_t>::plan plan = fftw_plan_dft(static_cast<int>(input.size()),
                                                          const_cast<fftw_input_t *>(reinterpret_cast<const fftw_input_t *>(input.raw_data())),
                                                          reinterpret_cast<fftw_output_t *>(output.raw_data()),
                                                          FFTW_ESTIMATE);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output;
    };

    template <
        typename input_t, typename output_t,
        typename fftw_t<input_t>::plan (&fftw_plan_dft)(int, fftw_number_t<input_t> *, fftw_number_t<output_t> *, unsigned int),
        void (&fftw_execute)(typename fftw_t<input_t>::plan), void (&fftw_destroy_plan)(typename fftw_t<input_t>::plan),
        typename = std::enable_if_t<
            std::is_same< prec_t<input_t>, prec_t<output_t> >::value
            && std::is_floating_point< prec_t<input_t> >::value
        >
    >
    xt::xarray<output_t> _ifft_(const xt::xarray<input_t> &input) {
      xt::xarray<output_t, layout_type::dynamic> output(input.shape(), input.strides());

      using fftw_input_t = fftw_number_t<input_t>;
      using fftw_output_t = fftw_number_t<output_t>;

      typename fftw_t<input_t>::plan plan = fftw_plan_dft(static_cast<int>(input.size()),
                                                          const_cast<fftw_input_t *>(reinterpret_cast<const fftw_input_t *>(input.raw_data())),
                                                          reinterpret_cast<fftw_output_t *>(output.raw_data()),
                                                          FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output / output.size();
    };

    inline xt::xarray<std::complex<float> > RFFT (const xt::xarray<float> &input) {
      return _fft_<float, std::complex<float>, fftwf_plan_dft_r2c_1d, fftwf_execute, fftwf_destroy_plan> (input);
    }

    inline xt::xarray<float> IRFFT (const xt::xarray<std::complex<float> > &input) {
      return _ifft_<std::complex<float>, float, fftwf_plan_dft_c2r_1d, fftwf_execute, fftwf_destroy_plan> (input);
    }

    inline xt::xarray<std::complex<double> > RFFT (const xt::xarray<double> &input) {
      return _fft_<double, std::complex<double>, fftw_plan_dft_r2c_1d, fftw_execute, fftw_destroy_plan> (input);
    }

    inline xt::xarray<double> IRFFT (const xt::xarray<std::complex<double> > &input) {
      return _ifft_<std::complex<double>, double, fftw_plan_dft_c2r_1d, fftw_execute, fftw_destroy_plan> (input);
    }

    inline xt::xarray<std::complex<long double> > RFFT (const xt::xarray<long double> &input) {
      return _fft_<long double, std::complex<long double>, fftwl_plan_dft_r2c_1d, fftwl_execute, fftwl_destroy_plan> (input);
    }

    inline xt::xarray<long double> IRFFT (const xt::xarray<std::complex<long double> > &input) {
      return _ifft_<std::complex<long double>, long double, fftwl_plan_dft_c2r_1d, fftwl_execute, fftwl_destroy_plan> (input);
    }

    ////
    // Regular FFT: xtensor templates
    ////

//    template<typename real_t, std::size_t dim, typename fftw_plan_t>
//    xt::xtensor< std::complex<real_t>, dim > _fft_(const xt::xtensor<real_t, dim> &input) {
//      static_assert(sizeof(real_t) == 0, "Only specializations of fft can be used");
//
//      xt::xtensor<std::complex<real_t>, dim> output(input.shape(), input.strides());
//
//      fftw_plan_t plan = fftwXXXXX_plan_dft_r2c_1d(static_cast<int>(input.size()),
//                                              const_cast<real_t *>(input.raw_data()),
//                                              reinterpret_cast<fftwXXXXXXX_complex*>(output.raw_data()),
//                                              FFTW_ESTIMATE);
//
//      fftwXXXXX_execute(plan);
//      fftwXXXXX_destroy_plan(plan);
//      return output;
//    };
//
//    template<typename real_t, std::size_t dim, typename fftw_plan_t>
//    xt::xtensor<real_t, dim> _ifft_(const xt::xtensor< std::complex<real_t>, dim > &input) {
//      static_assert(sizeof(real_t) == 0, "Only specializations of ifft can be used");
//
//      xt::xtensor<real_t, dim> output(input.shape(), input.strides());
//
//      fftw_plan_t plan = fftwXXXXX_plan_dft_c2r_1d(static_cast<int>(input.size()),
//                                                      const_cast<fftwXXXXX_complex *>(reinterpret_cast<const fftwXXXXX_complex *>(input.raw_data())),
//                                                      output.raw_data(),
//                                                      FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
//
//      fftwXXXXX_execute(plan);
//      fftwXXXXX_destroy_plan(plan);
//      return output / output.size();
//    };
    ////
    // Regular FFT: 1D
    ////

    ////
    // Regular FFT: 2D
    ////

    ////
    // Regular FFT: 3D
    ////

    ////
    // Regular FFT: nD
    ////

    ///////////////////////////////////////////////////////////////////////////////
    // Real FFT (real input)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Real FFT: 1D
    ////

    template<typename real_t>
    xt::xarray< std::complex<real_t> > rfft(const xt::xarray<real_t> &input) {
      static_assert(sizeof(real_t) == 0, "Only specializations of fft can be used");
    };
    template<typename real_t>
    xt::xarray<real_t> irfft(const xt::xarray< std::complex<real_t> > &input) {
      static_assert(sizeof(real_t) == 0, "Only specializations of ifft can be used");
    };

    template<>
    inline xt::xarray< std::complex<float> > rfft<float>(const xt::xarray<float> &input) {
      xt::xarray<std::complex<float>, layout_type::dynamic> output(input.shape(), input.strides());

      fftwf_plan plan = fftwf_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                              const_cast<float *>(input.raw_data()),
                                              reinterpret_cast<fftwf_complex*>(output.raw_data()),
                                              FFTW_ESTIMATE);

      fftwf_execute(plan);
      fftwf_destroy_plan(plan);
      return output;
    }

    template<>
    inline xt::xarray<float> irfft<float>(const xt::xarray< std::complex<float> > &input) {
      xt::xarray<float, layout_type::dynamic> output(input.shape(), input.strides());

      fftwf_plan plan = fftwf_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                              const_cast<fftwf_complex *>(reinterpret_cast<const fftwf_complex *>(input.raw_data())),
                                              output.raw_data(),
                                              FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftwf_execute(plan);
      fftwf_destroy_plan(plan);
      return output / output.size();
    }

    template<> inline xt::xarray< std::complex<double> > rfft<double>(const xt::xarray<double> &input) {
      xt::xarray<std::complex<double>, layout_type::dynamic> output(input.shape(), input.strides());

      fftw_plan plan = fftw_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                            const_cast<double *>(input.raw_data()),
                                            reinterpret_cast<fftw_complex*>(output.raw_data()),
                                            FFTW_ESTIMATE);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output;
    }

    template<> inline xt::xarray<double> irfft<double>(const xt::xarray< std::complex<double> > &input) {
      xt::xarray<double, layout_type::dynamic> output(input.shape(), input.strides());

      fftw_plan plan = fftw_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                            const_cast<fftw_complex *>(reinterpret_cast<const fftw_complex *>(input.raw_data())),
                                            output.raw_data(),
                                            FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output / output.size();
    }

    template<> inline xt::xarray< std::complex<long double> > rfft<long double>(const xt::xarray<long double> &input) {
      xt::xarray<std::complex<long double>, layout_type::dynamic> output(input.shape(), input.strides());

      fftwl_plan plan = fftwl_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                              const_cast<long double *>(input.raw_data()),
                                              reinterpret_cast<fftwl_complex*>(output.raw_data()),
                                              FFTW_ESTIMATE);

      fftwl_execute(plan);
      fftwl_destroy_plan(plan);
      return output;
    }

    template<> inline xt::xarray<long double> irfft<long double>(const xt::xarray< std::complex<long double> > &input) {
      xt::xarray<long double, layout_type::dynamic> output(input.shape(), input.strides());

      fftwl_plan plan = fftwl_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                              const_cast<fftwl_complex *>(reinterpret_cast<const fftwl_complex *>(input.raw_data())),
                                              output.raw_data(),
                                              FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftwl_execute(plan);
      fftwl_destroy_plan(plan);
      return output / output.size();
    }

    ////
    // Real FFT: 2D
    ////

    ////
    // Real FFT: 3D
    ////

    ////
    // Real FFT: nD
    ////

    ///////////////////////////////////////////////////////////////////////////////
    // Hermitian FFT (real spectrum)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Hermitian FFT: 1D
    ////

    ////
    // Hermitian FFT: 2D
    ////

    ////
    // Hermitian FFT: 3D
    ////

    ////
    // Hermitian FFT: nD
    ////

  }
}

#endif //XTENSOR_FFTW_BASIC_HPP
<commit_msg>Made templates inline, does not change performance<commit_after>/*
 * xtensor-fftw
 * Copyright (c) 2017, Patrick Bos
 *
 * Distributed under the terms of the BSD 3-Clause License.
 *
 * The full license is in the file LICENSE, distributed with this software.
 *
 * basic.hpp:
 * Contains the basic functions needed to do FFTs and inverse FFTs on real and
 * complex arrays. The behavior of these functions mimics that of the numpy.fft
 * module, see https://github.com/egpbos/xtensor-fftw/issues/6.
 *
 */

#ifndef XTENSOR_FFTW_BASIC_HPP
#define XTENSOR_FFTW_BASIC_HPP

#include <xtensor/xarray.hpp>
#include <xtl/xcomplex.hpp>
#include <complex>
#include <type_traits>
#include <fftw3.h>

namespace xt {
  namespace fftw {
    // The implementations must be inline to avoid multiple definition errors due to multiple compilations (e.g. when
    // including this header multiple times in a project, or when it is explicitly compiled itself and included too).

    // Note: multidimensional complex-to-real transforms by default destroy the input data! See:
    // http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data

    // reinterpret_casts below suggested by http://www.fftw.org/fftw3_doc/Complex-numbers.html

    // We use the convention that the inverse fft divides by N, like numpy does.

    // aliases for the fftw precision-dependent types:
    template <typename T> struct fftw_t {
      static_assert(sizeof(T) == 0, "Only specializations of fftw_t can be used");
    };
    template <> struct fftw_t<float> {
      using plan = fftwf_plan;
      using complex = fftwf_complex;
    };
    template <> struct fftw_t<double> {
      using plan = fftw_plan;
      using complex = fftw_complex;
    };
    template <> struct fftw_t<long double> {
      using plan = fftwl_plan;
      using complex = fftwl_complex;
    };
    // and subclass alias for when calling with a complex type:
    template <typename T> struct fftw_t< std::complex<T> > : public fftw_t<T> {};

    // convert std::complex to fftwX_complex with right precision X; non-complex floats stay themselves:
    template <typename regular_or_complex_t>
    using fftw_number_t = std::conditional_t<
        xtl::is_complex<regular_or_complex_t>::value,
        typename fftw_t< xtl::complex_value_type_t<regular_or_complex_t> >::complex,
        xtl::complex_value_type_t<regular_or_complex_t>
    >;

    // short-hand for precision for template arguments
    template <typename in_or_output_t>
    using prec_t = xtl::complex_value_type_t<in_or_output_t>;

    ///////////////////////////////////////////////////////////////////////////////
    // Regular FFT (complex to complex)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Regular FFT: xarray templates
    ////

    template<typename input_t, typename output_t, typename...>
    inline xt::xarray<output_t> _fft_ (const xt::xarray<input_t> &input) {
      static_assert(sizeof(prec_t<input_t>) == 0, "Only specializations of _fft_ can be used");
    }

    template<typename input_t, typename output_t, typename...>
    inline xt::xarray<output_t> _ifft_ (const xt::xarray<input_t> &input) {
      static_assert(sizeof(prec_t<input_t>) == 0, "Only specializations of _ifft_ can be used");
    }

    template <
        typename input_t, typename output_t,
        typename fftw_t<input_t>::plan (&fftw_plan_dft)(int, fftw_number_t<input_t> *, fftw_number_t<output_t> *, unsigned int),
        void (&fftw_execute)(typename fftw_t<input_t>::plan), void (&fftw_destroy_plan)(typename fftw_t<input_t>::plan),
        typename = std::enable_if_t<
            std::is_same< prec_t<input_t>, prec_t<output_t> >::value
            && std::is_floating_point< prec_t<input_t> >::value
        >
    >
    inline xt::xarray<output_t> _fft_(const xt::xarray<input_t> &input) {
      xt::xarray<output_t, layout_type::dynamic> output(input.shape(), input.strides());

      using fftw_input_t = fftw_number_t<input_t>;
      using fftw_output_t = fftw_number_t<output_t>;

      typename fftw_t<input_t>::plan plan = fftw_plan_dft(static_cast<int>(input.size()),
                                                          const_cast<fftw_input_t *>(reinterpret_cast<const fftw_input_t *>(input.raw_data())),
                                                          reinterpret_cast<fftw_output_t *>(output.raw_data()),
                                                          FFTW_ESTIMATE);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output;
    };

    template <
        typename input_t, typename output_t,
        typename fftw_t<input_t>::plan (&fftw_plan_dft)(int, fftw_number_t<input_t> *, fftw_number_t<output_t> *, unsigned int),
        void (&fftw_execute)(typename fftw_t<input_t>::plan), void (&fftw_destroy_plan)(typename fftw_t<input_t>::plan),
        typename = std::enable_if_t<
            std::is_same< prec_t<input_t>, prec_t<output_t> >::value
            && std::is_floating_point< prec_t<input_t> >::value
        >
    >
    inline xt::xarray<output_t> _ifft_(const xt::xarray<input_t> &input) {
      xt::xarray<output_t, layout_type::dynamic> output(input.shape(), input.strides());

      using fftw_input_t = fftw_number_t<input_t>;
      using fftw_output_t = fftw_number_t<output_t>;

      typename fftw_t<input_t>::plan plan = fftw_plan_dft(static_cast<int>(input.size()),
                                                          const_cast<fftw_input_t *>(reinterpret_cast<const fftw_input_t *>(input.raw_data())),
                                                          reinterpret_cast<fftw_output_t *>(output.raw_data()),
                                                          FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output / output.size();
    };

    inline xt::xarray<std::complex<float> > RFFT (const xt::xarray<float> &input) {
      return _fft_<float, std::complex<float>, fftwf_plan_dft_r2c_1d, fftwf_execute, fftwf_destroy_plan> (input);
    }

    inline xt::xarray<float> IRFFT (const xt::xarray<std::complex<float> > &input) {
      return _ifft_<std::complex<float>, float, fftwf_plan_dft_c2r_1d, fftwf_execute, fftwf_destroy_plan> (input);
    }

    inline xt::xarray<std::complex<double> > RFFT (const xt::xarray<double> &input) {
      return _fft_<double, std::complex<double>, fftw_plan_dft_r2c_1d, fftw_execute, fftw_destroy_plan> (input);
    }

    inline xt::xarray<double> IRFFT (const xt::xarray<std::complex<double> > &input) {
      return _ifft_<std::complex<double>, double, fftw_plan_dft_c2r_1d, fftw_execute, fftw_destroy_plan> (input);
    }

    inline xt::xarray<std::complex<long double> > RFFT (const xt::xarray<long double> &input) {
      return _fft_<long double, std::complex<long double>, fftwl_plan_dft_r2c_1d, fftwl_execute, fftwl_destroy_plan> (input);
    }

    inline xt::xarray<long double> IRFFT (const xt::xarray<std::complex<long double> > &input) {
      return _ifft_<std::complex<long double>, long double, fftwl_plan_dft_c2r_1d, fftwl_execute, fftwl_destroy_plan> (input);
    }

    ////
    // Regular FFT: xtensor templates
    ////

//    template<typename real_t, std::size_t dim, typename fftw_plan_t>
//    xt::xtensor< std::complex<real_t>, dim > _fft_(const xt::xtensor<real_t, dim> &input) {
//      static_assert(sizeof(real_t) == 0, "Only specializations of fft can be used");
//
//      xt::xtensor<std::complex<real_t>, dim> output(input.shape(), input.strides());
//
//      fftw_plan_t plan = fftwXXXXX_plan_dft_r2c_1d(static_cast<int>(input.size()),
//                                              const_cast<real_t *>(input.raw_data()),
//                                              reinterpret_cast<fftwXXXXXXX_complex*>(output.raw_data()),
//                                              FFTW_ESTIMATE);
//
//      fftwXXXXX_execute(plan);
//      fftwXXXXX_destroy_plan(plan);
//      return output;
//    };
//
//    template<typename real_t, std::size_t dim, typename fftw_plan_t>
//    xt::xtensor<real_t, dim> _ifft_(const xt::xtensor< std::complex<real_t>, dim > &input) {
//      static_assert(sizeof(real_t) == 0, "Only specializations of ifft can be used");
//
//      xt::xtensor<real_t, dim> output(input.shape(), input.strides());
//
//      fftw_plan_t plan = fftwXXXXX_plan_dft_c2r_1d(static_cast<int>(input.size()),
//                                                      const_cast<fftwXXXXX_complex *>(reinterpret_cast<const fftwXXXXX_complex *>(input.raw_data())),
//                                                      output.raw_data(),
//                                                      FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
//
//      fftwXXXXX_execute(plan);
//      fftwXXXXX_destroy_plan(plan);
//      return output / output.size();
//    };
    ////
    // Regular FFT: 1D
    ////

    ////
    // Regular FFT: 2D
    ////

    ////
    // Regular FFT: 3D
    ////

    ////
    // Regular FFT: nD
    ////

    ///////////////////////////////////////////////////////////////////////////////
    // Real FFT (real input)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Real FFT: 1D
    ////

    template<typename real_t>
    xt::xarray< std::complex<real_t> > rfft(const xt::xarray<real_t> &input) {
      static_assert(sizeof(real_t) == 0, "Only specializations of fft can be used");
    };
    template<typename real_t>
    xt::xarray<real_t> irfft(const xt::xarray< std::complex<real_t> > &input) {
      static_assert(sizeof(real_t) == 0, "Only specializations of ifft can be used");
    };

    template<>
    inline xt::xarray< std::complex<float> > rfft<float>(const xt::xarray<float> &input) {
      xt::xarray<std::complex<float>, layout_type::dynamic> output(input.shape(), input.strides());

      fftwf_plan plan = fftwf_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                              const_cast<float *>(input.raw_data()),
                                              reinterpret_cast<fftwf_complex*>(output.raw_data()),
                                              FFTW_ESTIMATE);

      fftwf_execute(plan);
      fftwf_destroy_plan(plan);
      return output;
    }

    template<>
    inline xt::xarray<float> irfft<float>(const xt::xarray< std::complex<float> > &input) {
      xt::xarray<float, layout_type::dynamic> output(input.shape(), input.strides());

      fftwf_plan plan = fftwf_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                              const_cast<fftwf_complex *>(reinterpret_cast<const fftwf_complex *>(input.raw_data())),
                                              output.raw_data(),
                                              FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftwf_execute(plan);
      fftwf_destroy_plan(plan);
      return output / output.size();
    }

    template<> inline xt::xarray< std::complex<double> > rfft<double>(const xt::xarray<double> &input) {
      xt::xarray<std::complex<double>, layout_type::dynamic> output(input.shape(), input.strides());

      fftw_plan plan = fftw_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                            const_cast<double *>(input.raw_data()),
                                            reinterpret_cast<fftw_complex*>(output.raw_data()),
                                            FFTW_ESTIMATE);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output;
    }

    template<> inline xt::xarray<double> irfft<double>(const xt::xarray< std::complex<double> > &input) {
      xt::xarray<double, layout_type::dynamic> output(input.shape(), input.strides());

      fftw_plan plan = fftw_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                            const_cast<fftw_complex *>(reinterpret_cast<const fftw_complex *>(input.raw_data())),
                                            output.raw_data(),
                                            FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftw_execute(plan);
      fftw_destroy_plan(plan);
      return output / output.size();
    }

    template<> inline xt::xarray< std::complex<long double> > rfft<long double>(const xt::xarray<long double> &input) {
      xt::xarray<std::complex<long double>, layout_type::dynamic> output(input.shape(), input.strides());

      fftwl_plan plan = fftwl_plan_dft_r2c_1d(static_cast<int>(input.size()),
                                              const_cast<long double *>(input.raw_data()),
                                              reinterpret_cast<fftwl_complex*>(output.raw_data()),
                                              FFTW_ESTIMATE);

      fftwl_execute(plan);
      fftwl_destroy_plan(plan);
      return output;
    }

    template<> inline xt::xarray<long double> irfft<long double>(const xt::xarray< std::complex<long double> > &input) {
      xt::xarray<long double, layout_type::dynamic> output(input.shape(), input.strides());

      fftwl_plan plan = fftwl_plan_dft_c2r_1d(static_cast<int>(input.size()),
                                              const_cast<fftwl_complex *>(reinterpret_cast<const fftwl_complex *>(input.raw_data())),
                                              output.raw_data(),
                                              FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);

      fftwl_execute(plan);
      fftwl_destroy_plan(plan);
      return output / output.size();
    }

    ////
    // Real FFT: 2D
    ////

    ////
    // Real FFT: 3D
    ////

    ////
    // Real FFT: nD
    ////

    ///////////////////////////////////////////////////////////////////////////////
    // Hermitian FFT (real spectrum)
    ///////////////////////////////////////////////////////////////////////////////

    ////
    // Hermitian FFT: 1D
    ////

    ////
    // Hermitian FFT: 2D
    ////

    ////
    // Hermitian FFT: 3D
    ////

    ////
    // Hermitian FFT: nD
    ////

  }
}

#endif //XTENSOR_FFTW_BASIC_HPP
<|endoftext|>


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

#ifndef HW_NIC_HPP
#define HW_NIC_HPP

#include "pci_device.hpp"

#include "../net/inet_common.hpp"
#include "../net/buffer_store.hpp"
#include "../net/ethernet.hpp"

namespace hw {

  /**
   *  A public interface for Ethernet Network cards
   *
   *  This interface assumes network card is of type Ethernet
   */
  class Nic {
  public:

    /** Get a readable name. */
    virtual const char* name() const = 0;

    /** A readable name of the type of device @todo: move to a abstract Device? */
    static const char* device_type()
    { return "NIC"; }

    /**
      The mac address.
      @todo remove depedency for Ethernet (somewhere in the future)
    */
    virtual const net::Ethernet::addr& mac() = 0;

    virtual uint16_t MTU() const noexcept = 0;

    net::BufferStore& bufstore() noexcept
    { return bufstore_; }

    size_t buffers_available()
    { return bufstore_.available(); }

    uint16_t bufsize() const
    { return bufstore_.bufsize(); }

    uint16_t eth_size() const
    { return sizeof(net::Ethernet::header) + sizeof(net::Ethernet::trailer); }

    /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */
    void set_linklayer_out(net::upstream link_out)
    { _link_out = link_out; };

    net::upstream get_linklayer_out()
    { return _link_out; }

    virtual void transmit(net::Packet_ptr pckt) = 0;

    /** Let the driver return a delegate to receive outgoing packets from layer above */
    virtual net::downstream get_physical_out() = 0;

    /** Subscribe to event for when there is more room in the tx queue */
    void on_transmit_queue_available(net::transmit_avail_delg del)
    { transmit_queue_available_event_ = del; }

    virtual size_t transmit_queue_available() = 0;

    virtual size_t receive_queue_waiting() = 0;

    std::string ifname() const {
      return "eth" + std::to_string(N);
    }

  protected:
    /**
     *  Constructor
     *
     *  Constructed by the actual Nic Driver
     */
    Nic(uint32_t bufstore_sz, uint16_t bufsz)
      : bufstore_{ bufstore_sz, bufsz }
    {
      static int id_counter = 0;
      N = id_counter++;
    }

    friend class Devices;

    /** Upstream delegate for linklayer output */
    net::upstream _link_out;
    net::transmit_avail_delg transmit_queue_available_event_ =
      [](auto) { assert(0 && "<NIC> Transmit queue available delegate is not set!"); };

  private:
    net::BufferStore bufstore_;
    int N;

  };

  /** Future drivers may start out like so, */
  class E1000 {
  public:
    inline const char* name() const noexcept
    { return "E1000 Driver"; }
    //...whatever the Nic class implicitly needs
  };

  /** Hopefully somebody will port a driver for this one */
  class RTL8139;

} //< namespace hw

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

#ifndef HW_NIC_HPP
#define HW_NIC_HPP

#include "pci_device.hpp"

#include "../net/inet_common.hpp"
#include "../net/buffer_store.hpp"
#include "mac_addr.hpp"
#include <net/ethernet/header.hpp>

namespace hw {

  /**
   *  A public interface for Ethernet Network cards
   *
   *  This interface assumes network card is of type Ethernet
   */
  class Nic {
  public:

    /** Get a readable name. */
    virtual const char* name() const = 0;

    /** A readable name of the type of device @todo: move to a abstract Device? */
    static const char* device_type()
    { return "NIC"; }

    /**
      The mac address.
    */
    virtual const MAC_addr& mac() = 0;

    virtual uint16_t MTU() const noexcept = 0;

    net::BufferStore& bufstore() noexcept
    { return bufstore_; }

    size_t buffers_available()
    { return bufstore_.available(); }

    uint16_t bufsize() const
    { return bufstore_.bufsize(); }

    /**
     * @todo remove depedency for Ethernet (somewhere in the future)
     */
    uint16_t eth_size() const
    { return sizeof(net::ethernet::Header) + sizeof(net::ethernet::trailer_t); }

    /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */
    void set_linklayer_out(net::upstream link_out)
    { _link_out = link_out; };

    net::upstream get_linklayer_out()
    { return _link_out; }

    virtual void transmit(net::Packet_ptr pckt) = 0;

    /** Let the driver return a delegate to receive outgoing packets from layer above */
    virtual net::downstream get_physical_out() = 0;

    /** Subscribe to event for when there is more room in the tx queue */
    void on_transmit_queue_available(net::transmit_avail_delg del)
    { transmit_queue_available_event_ = del; }

    virtual size_t transmit_queue_available() = 0;

    virtual size_t receive_queue_waiting() = 0;

    std::string ifname() const {
      return "eth" + std::to_string(N);
    }

  protected:
    /**
     *  Constructor
     *
     *  Constructed by the actual Nic Driver
     */
    Nic(uint32_t bufstore_sz, uint16_t bufsz)
      : bufstore_{ bufstore_sz, bufsz }
    {
      static int id_counter = 0;
      N = id_counter++;
    }

    friend class Devices;

    /** Upstream delegate for linklayer output */
    net::upstream _link_out;
    net::transmit_avail_delg transmit_queue_available_event_ =
      [](auto) { assert(0 && "<NIC> Transmit queue available delegate is not set!"); };

  private:
    net::BufferStore bufstore_;
    int N;

  };

  /** Future drivers may start out like so, */
  class E1000 {
  public:
    inline const char* name() const noexcept
    { return "E1000 Driver"; }
    //...whatever the Nic class implicitly needs
  };

  /** Hopefully somebody will port a driver for this one */
  class RTL8139;

} //< namespace hw

#endif // NIC_HPP
<|endoftext|>