【问题标题】:Boost::fusion, Eigen and zip transformationBoost::fusion、Eigen 和 zip 变换
【发布时间】:2013-04-15 09:47:59
【问题描述】:

这个问题是我对boost::fusionanother question 的衍生问题。这个想法是使用boost::fusion 来迭代一个包含 N 维数组的大型 C 风格结构。这些数组的计算由Eigen 完成。通过使用boost::fusion,可以对整个 C 结构应用简单的算术运算,例如标量乘法或向量加法。

在处理二元运算时,我使用boost::fusion::zip 形成单个序列,并使用boost::fusion::for_each 迭代其他序列。

boost::fusion::zip 的问题在于它构造了const 序列,而我需要修改其中一个值(例如,加法的返回值)。因此,我最终使用const_cast 来修改该值(Eigen 向量),但由于某种原因,我不能在add() 函数中使用result_ref。这是为什么呢?

此外,有没有更好(或更简单)的方法来实现我想要做的事情? boost::fusion::zip 可能不是最合适的,但我找不到任何其他简单的方法来做到这一点。

#include <iostream>

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/algorithm/transformation/zip.hpp>
#include <boost/fusion/include/zip.hpp>
#include <boost/bind.hpp>
#include <boost/fusion/container/vector/vector30.hpp>
#include <boost/fusion/include/vector30.hpp>
#include <boost/fusion/sequence/intrinsic/at_c.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>

#include <Eigen/Core>

template <class type_const_ref>
struct remove_const_ref
{
    typedef typename boost::remove_reference <type_const_ref>::type type_const;
    typedef typename boost::remove_const <type_const_ref>::type     type_ref;
    typedef typename boost::remove_const <type_const >::type        type;
};

namespace demo
{
template<typename T, int SIZE1, int SIZE2>
struct data
{
    T ar1[SIZE1][SIZE2];
    T ar2[SIZE1][SIZE2];
};

template<typename T>
struct EigenMap
{
    typedef Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> > type;
};

template<typename T>
struct data_eigen
{
    template <int SIZE1, int SIZE2>
    data_eigen(data<T,SIZE1,SIZE2>& src)
        : ar1(typename EigenMap<T>::type(&src.ar1[0][0], SIZE1*SIZE2)),
          ar2(typename EigenMap<T>::type(&src.ar2[0][0], SIZE1*SIZE2))
    {
    }

    typename EigenMap<T>::type ar1;
    typename EigenMap<T>::type ar2;
};


struct print
{
    template<typename T>
    void operator()(const Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> >& t) const
    {
        std::cout << t.transpose() << std::endl;
    }
};

struct scalarMult
{
    template<typename T, typename U>
    void operator()(T& t, U& u) const
    {
        t *= u;
    }
};

template <typename T>
struct add
{
    template <typename U>
    void operator() (const boost::fusion::vector3<U,U,U>& t) const
    {
        typedef typename remove_const_ref<U>::type_ref vector_ref;
        typedef typename remove_const_ref<U>::type     vector_type;

        // FIXME: find why we cannot use vector_ref
        vector_type result_ref = const_cast<vector_ref>(boost::fusion::at_c<2>(t));
        result_ref = boost::fusion::at_c<0>(t) + boost::fusion::at_c<1>(t);
    }
};

}

BOOST_FUSION_ADAPT_TPL_STRUCT
(
    (T),
    (demo::data_eigen) (T),
    (typename demo::EigenMap<T>::type, ar1)
    (typename demo::EigenMap<T>::type, ar2)
)

int main()
{
    typedef float REALTYPE;
    const int SIZE1 = 2;
    const int SIZE2 = 2;

    // Basic data structure with multidimensional arrays
    demo::data<REALTYPE, SIZE1, SIZE2> d1;
    for (unsigned int i = 0; i < SIZE1; ++i)
        for (unsigned int j = 0; j < SIZE2; ++j)
        {
            d1.ar1[i][j] = (i+1)*(j+1);
            d1.ar2[i][j] = i + j;
        }
    demo::data<REALTYPE, SIZE1, SIZE2> d2;
    demo::data<REALTYPE, SIZE1, SIZE2> d3;
    memset(&d3, 0, sizeof(demo::data<REALTYPE, SIZE1, SIZE2>));

    for (unsigned int i = 0; i < SIZE1; ++i)
        for (unsigned int j = 0; j < SIZE2; ++j)
        {
            d2.ar1[i][j] = 1.0;
            d2.ar2[i][j] = 2.0;
        }

    // Eigen::Map + BOOST_FUSION_ADAPT_TPL_STRUCT
    demo::data_eigen<REALTYPE> eig_d1(d1);
    demo::data_eigen<REALTYPE> eig_d2(d2);
    demo::data_eigen<REALTYPE> eig_d3(d3);

    std::cout << "d1:" << std::endl;
    boost::fusion::for_each(eig_d1, demo::print());
    std::cout << std::endl;

    std::cout << "d2:" << std::endl;
    boost::fusion::for_each(eig_d2, demo::print());
    std::cout << std::endl;

    boost::fusion::for_each(eig_d1, boost::bind<void>(demo::scalarMult(), _1, 2.0));
    std::cout << "d1 = 2 * d1:" << std::endl;
    boost::fusion::for_each(eig_d1, demo::print());
    std::cout << std::endl;

    boost::fusion::for_each(boost::fusion::zip(eig_d1, eig_d2, eig_d3),
                            demo::add<REALTYPE>());
    std::cout << "d3 = d1 + d2:" << std::endl;
    boost::fusion::for_each(eig_d3, demo::print());
    std::cout << std::endl;

    return EXIT_SUCCESS;
}

【问题讨论】:

    标签: c++ boost constants eigen boost-fusion


    【解决方案1】:

    我相信你需要使用的是zip_view

    您的for_each 调用将是:

    typedef demo::data_eigen<REALTYPE>& vector_ref;                                             
    typedef boost::fusion::vector<vector_ref,vector_ref,vector_ref> my_zip;                     
    
    boost::fusion::for_each(boost::fusion::zip_view<my_zip>(my_zip(eig_d1, eig_d2, eig_d3)), demo::add());
    

    你的 add 函子就是:

    struct add
    {
        template <typename ZipView>
        void operator() (const ZipView& t) const            //CHANGED
        {
            boost::fusion::at_c<2>(t) = boost::fusion::at_c<0>(t) + boost::fusion::at_c<1>(t);
        }
    };
    

    以下代码已使用 g++ 4.8.0 测试,输出结果与您的相同:

    #include <iostream>
    
    #include <boost/bind.hpp>
    
    #include <boost/fusion/include/at_c.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/for_each.hpp>
    #include <boost/fusion/include/zip_view.hpp>
    #include <boost/fusion/include/vector.hpp>
    
    #include <Eigen/Core>
    
    
    
    namespace demo
    {
    template<typename T, int SIZE1, int SIZE2>
    struct data
    {
        T ar1[SIZE1][SIZE2];
        T ar2[SIZE1][SIZE2];
    };
    
    template<typename T>
    struct EigenMap
    {
        typedef Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> > type;
    };
    
    template<typename T>
    struct data_eigen
    {
        template <int SIZE1, int SIZE2>
        data_eigen(data<T,SIZE1,SIZE2>& src)
            : ar1(typename EigenMap<T>::type(&src.ar1[0][0], SIZE1*SIZE2)),
              ar2(typename EigenMap<T>::type(&src.ar2[0][0], SIZE1*SIZE2))
        {
        }
    
        typename EigenMap<T>::type ar1;
        typename EigenMap<T>::type ar2;
    };
    
    
    struct print
    {
        template<typename T>
        void operator()(const Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> >& t) const
        {
            std::cout << t.transpose() << std::endl;
        }
    };
    
    struct scalarMult
    {
        template<typename T, typename U>
        void operator()(T& t, U& u) const
        {
            t *= u;
        }
    };
    
    struct add
    {
        template <typename ZipView>
        void operator() (const ZipView& t) const            //CHANGED
        {
            boost::fusion::at_c<2>(t) = boost::fusion::at_c<0>(t) + boost::fusion::at_c<1>(t);
        }
    };
    
    }
    
    BOOST_FUSION_ADAPT_TPL_STRUCT
    (
        (T),
        (demo::data_eigen) (T),
        (typename demo::EigenMap<T>::type, ar1)
        (typename demo::EigenMap<T>::type, ar2)
    )
    
    int main()
    {
        typedef float REALTYPE;
        const int SIZE1 = 2;
        const int SIZE2 = 2;
    
        // Basic data structure with multidimensional arrays
        demo::data<REALTYPE, SIZE1, SIZE2> d1;
        for (unsigned int i = 0; i < SIZE1; ++i)
            for (unsigned int j = 0; j < SIZE2; ++j)
            {
                d1.ar1[i][j] = (i+1)*(j+1);
                d1.ar2[i][j] = i + j;
            }
        demo::data<REALTYPE, SIZE1, SIZE2> d2;
        demo::data<REALTYPE, SIZE1, SIZE2> d3;
        memset(&d3, 0, sizeof(demo::data<REALTYPE, SIZE1, SIZE2>));
    
        for (unsigned int i = 0; i < SIZE1; ++i)
            for (unsigned int j = 0; j < SIZE2; ++j)
            {
                d2.ar1[i][j] = 1.0;
                d2.ar2[i][j] = 2.0;
            }
    
        // Eigen::Map + BOOST_FUSION_ADAPT_TPL_STRUCT
        demo::data_eigen<REALTYPE> eig_d1(d1);
        demo::data_eigen<REALTYPE> eig_d2(d2);
        demo::data_eigen<REALTYPE> eig_d3(d3);
    
        std::cout << "d1:" << std::endl;
        boost::fusion::for_each(eig_d1, demo::print());
        std::cout << std::endl;
    
        std::cout << "d2:" << std::endl;
        boost::fusion::for_each(eig_d2, demo::print());
        std::cout << std::endl;
    
        boost::fusion::for_each(eig_d1, boost::bind<void>(demo::scalarMult(), _1, 2.0));
        std::cout << "d1 = 2 * d1:" << std::endl;
        boost::fusion::for_each(eig_d1, demo::print());
        std::cout << std::endl;
    
        typedef demo::data_eigen<REALTYPE>& vector_ref;                                             //ADDITION
        typedef boost::fusion::vector<vector_ref,vector_ref,vector_ref> my_zip;                     //ADDITION
    
        boost::fusion::for_each(boost::fusion::zip_view<my_zip>(my_zip(eig_d1, eig_d2, eig_d3)),    //CHANGED
                                demo::add());
        std::cout << "d3 = d1 + d2:" << std::endl;
        boost::fusion::for_each(eig_d3, demo::print());
        std::cout << std::endl;
    
        return EXIT_SUCCESS;
    }
    

    【讨论】:

    • 这正是我想要的,非常感谢!所以我想这就像在没有const 约束的情况下做你自己的zip
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    相关资源
    最近更新 更多