简体   繁体   English

thrust::make_zip_iterator - 不一致的迭代器范围会发生什么?

[英]thrust::make_zip_iterator - What happens with inconsistent iterator ranges?

I am currently trying to understand the following example of the boost library that uses parallel processing with thrust.我目前正在尝试理解以下使用 thrust 并行处理的 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;
};

This example can be fully explored at:可以在以下位置充分探索此示例:

https://github.com/headmyshoulder/odeint-v2/blob/master/examples/thrust/lorenz_parameters.cu https://github.com/headmyshoulder/odeint-v2/blob/master/examples/thrust/lorenz_parameters.cu

I am still pretty new to C++, but have done introductory courses in C, and also learned programming in Java. So, I am mostly familiar with the concepts.我对C++还很陌生,但是在C上过入门课程,也在Java学过编程。所以,我对这些概念基本熟悉。

My question would be in the second operator overwrite.我的问题是在第二个运算符覆盖中。 As far as I understand, thrust::for_each() takes two iterators, one where it starts and one where it ends, as well as a functor.据我所知, thrust::for_each()有两个迭代器,一个在开始处,一个在结束处,还有一个仿函数。 When thrust::make_zip_iterator() gets called, it creates a zip_iterator .thrust::make_zip_iterator()被调用时,它会创建一个zip_iterator As far as I understand, zip_iterator creates a moving reference for the entire bundle.据我了解, zip_iterator为整个包创建了一个移动引用。 For this, it requires that the length are all the same.为此,它要求长度都相同。

However m_beta.begin() appears in both iterators with no change whatsoever.然而m_beta.begin()出现在两个迭代器中,没有任何变化。 Shouldn't this mean that m_beta consists of only one value (which is 0, if you check the full code on GitHub) and therefore the zip_iterator fails?这不应该意味着m_beta只包含一个值(如果您查看 GitHub 上的完整代码,则为 0)因此zip_iterator失败了吗?

I ran the code and it works beautifully though, so what am I not understanding about zip_iterator s, or specifically thrust's?我运行了代码,但它运行得很好,所以我对zip_iterator或特别是 thrust 有什么不了解的?

In this case (probably in all parallel cases) Thrust only needs the "end" iterator to compute the distance to the "begin" iterator.在这种情况下(可能在所有并行情况下)Thrust 只需要“结束”迭代器来计算到“开始”迭代器的距离。 For the zip iterator this is implemented at the moment as对于 zip 迭代器,目前实现

__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()

Ie only the first "end" iterator is used, all others are ignored.即只使用第一个“结束”迭代器,所有其他的都被忽略。 This is an implementation detail and should therefore not be relied upon.这是一个实现细节,因此不应依赖。 One could argue that at least in a debug build the difference should be computed for all pairs of iterators and an exception should be thrown if any pair produces something different from the others.有人可能会争辩说,至少在调试构建中,应该为所有迭代器对计算差异,并且如果任何一对产生与其他迭代器不同的东西,则应该抛出异常。

In short the code in the question works (for now), but it should be fixed to avoid relying on implementation details and to make it clearer to the reader that m_beta is iterated over and not just the first element used, as a beginner might think at first glance.简而言之,问题中的代码(目前)有效,但应该修复它以避免依赖实现细节,并让读者更清楚m_beta被迭代,而不仅仅是使用的第一个元素,正如初学者可能认为的那样第一眼看去。

Shouldn't this mean that m_beta consists of only one value [...]?这不应该意味着m_beta只包含一个值 [...] 吗?

If it would work that way it would mean that m_beta had zero elements because the end iterator is one past the last element.如果它以这种方式工作,则意味着m_beta具有零个元素,因为结束迭代器是最后一个元素之后的一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM