c++ thrust::make_zip_iterator -如果迭代器范围不一致会发生什么?

vbopmzt1  于 2023-01-28  发布在  其他
关注(0)|答案(1)|浏览(156)

我目前正在尝试理解下面的boost库示例,它使用具有推力的并行处理。

struct lorenz_system
{
    struct lorenz_functor
    {
        template< class T >
        __host__ __device__
        void operator()( T t ) const
        {
            // unpack the parameter we want to vary and the Lorenz variables
            value_type R = thrust::get< 3 >( t );
            value_type x = thrust::get< 0 >( t );
            value_type y = thrust::get< 1 >( t );
            value_type z = thrust::get< 2 >( t );
            thrust::get< 4 >( t ) = sigma * ( y - x );
            thrust::get< 5 >( t ) = R * x - y - x * z;
            thrust::get< 6 >( t ) = -b * z + x * y ;

        }
    };

    lorenz_system( size_t N , const state_type &beta )
    : m_N( N ) , m_beta( beta ) { }

    template< class State , class Deriv >
    void operator()(  const State &x , Deriv &dxdt , value_type t ) const
    {
        thrust::for_each(
                thrust::make_zip_iterator( thrust::make_tuple(
                        boost::begin( x ) ,
                        boost::begin( x ) + m_N ,
                        boost::begin( x ) + 2 * m_N ,
                        m_beta.begin() ,
                        boost::begin( dxdt ) ,
                        boost::begin( dxdt ) + m_N ,
                        boost::begin( dxdt ) + 2 * m_N  ) ) ,
                thrust::make_zip_iterator( thrust::make_tuple(
                        boost::begin( x ) + m_N ,
                        boost::begin( x ) + 2 * m_N ,
                        boost::begin( x ) + 3 * m_N ,
                        m_beta.begin() ,
                        boost::begin( dxdt ) + m_N ,
                        boost::begin( dxdt ) + 2 * m_N ,
                        boost::begin( dxdt ) + 3 * m_N  ) ) ,
                lorenz_functor() );
    }
    size_t m_N;
    const state_type &m_beta;
};

此示例可在以下位置进行全面探讨:
https://github.com/headmyshoulder/odeint-v2/blob/master/examples/thrust/lorenz_parameters.cu
我对C++还是个新手,但是已经学过C的入门课程,也学过Java的编程。所以,我对这些概念大部分都很熟悉。
我的问题是在第二个操作符overwrite中。据我所知,thrust::for_each()有两个迭代器,一个在它开始的地方,一个在它结束的地方,还有一个函子。当thrust::make_zip_iterator()被调用时,它创建了一个zip_iterator。据我所知,zip_iterator为整个bundle创建了一个移动引用。为此,它要求长度都是相同的。
但是m_beta.begin()出现在两个迭代器中,没有任何变化,这是否意味着m_beta只包含一个值(如果你在GitHub上查看完整的代码,结果是0),因此zip_iterator失败了?
我运行了代码,它工作得很好,所以我对zip_iterator s,或者特别是thrust s还有什么不理解的呢?

iswrvxsc

iswrvxsc1#

在这种情况下(可能在所有并行情况下),Thrust只需要“end”迭代器来计算到“开始”迭代器的距离。

__thrust_exec_check_disable__
template<typename IteratorTuple>
  template <typename OtherIteratorTuple>
  __host__ __device__
    typename zip_iterator<IteratorTuple>::super_t::difference_type
      zip_iterator<IteratorTuple>
        ::distance_to(const zip_iterator<OtherIteratorTuple> &other) const
{
  return get<0>(other.get_iterator_tuple()) - get<0>(get_iterator_tuple());
} // end zip_iterator::distance_to()

也就是说,只使用第一个“结束”迭代器,忽略所有其他迭代器。**这是一个实现细节,因此不应该依赖它。**有人可能会说,至少在调试构建中,应该计算所有迭代器对的差异,如果任何一对迭代器产生与其他迭代器不同的东西,应该抛出异常。
简而言之,问题中的代码可以工作(目前),但应该进行修复,以避免依赖于实现细节,并让读者更清楚地了解m_beta是迭代的,而不仅仅是使用的第一个元素,初学者可能会第一眼就想到这一点。
这是否意味着m_beta只包含一个值[...]?
如果它以这种方式工作,则意味着m_beta具有零个元素,因为结束迭代器是最后一个元素的后一个元素。

相关问题