2014-04-30 2 views
0

GPU에서 여러 변수의 "수학"기능을 계산하는 함수가 필요합니다. 나는 추력과 그것의 zip_iterator을 사용하여 튜플에서 변수를 묶고, 함수기를 for_each으로 구현했습니다. 하지만 다른 "수학"기능을 계산할 수있는 보편적 인 기능을 원합니다. 그래서 함수에서이 펑터를 전달해야합니다.추력의 함수 안에 다형성 펑터 사용

이 작업을 수행하기 위해 나는 operator()(Tuple t)의 다른 버전을 가진 펑터의 간단한 계층 구조 (기본 클래스 만있는)를 구현해야합니다. 예를 들어, 펑을 다음과 같이 할 수있다 :

struct Func { 
    template <typename Tuple> 
    __host__ __device__ 
    void operator()(Tuple arg) { 
     thrust::get<1>(arg) = 0; 
    } 
}; 

strust f1 : public Func { 
    ... 
}; 

strust f2 : public Func { 
    ... 
}; 

문제는 내가 제대로 기능에 펑터를 요구 패스 할 수있는 방법이며, 어떻게 이러한 함수를 정의? 이 기능은 같이 할 수있다 :

thrust::host_vector evaluateFunction(Func func, thrust::host_vector point) { 
    thrust::host_vector result(point.size()); 

    thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(point.begin(), result.begin())), 
    thrust::make_zip_iterator(thrust::make_tuple(point.end(), result.end())), 
       func); 
    return result; 
} 

그러나 이러한 정의와 나는 그것으로 f1 또는 f2를 전달할 수 없습니다. 올바르게 정의하려면 어떻게해야합니까?

+1

특정 시나리오에서 사용할 특히 "수학"기능을 식별하는 방법? 나는 당신이 * function *을 * functor *로 전달 (또는 식별)해야한다고 말할 것이다. –

+0

필자는 필요한 "수학"함수를 펑터로 구현할 수 있고 주어진 벡터의 모든 요소에 대해이 '수학'함수를 계산하는 함수를 구현할 수 있다고 생각했습니다. 따라서이 함수는 보편적이지만 수학 함수 (functor로 구현 됨)를 전달해야합니다. – lexxa2000

+0

펑터를'thrust :: for_each'에 넘겨 줄 것입니다.각 수학 함수에 대해 개별 (개별) 펑터를 전달하려는 경우 각 요소에 동일한 수학 함수를 적용하려는 경우 문제가 무엇인지 알 수 없습니다. 각 요소에 다른 펑터를 전달하려면이를 수행 할 수 없습니다. 그러나 각 요소에 대해 동일한 펑터를 전달하고 각 요소에 대해 다른 수학 계산을 할 수는 있지만 가능하면 원하는 요소를 식별 할 수있는 몇 가지 메소드가 있어야합니다. 계산하기. 나는 당신의 질문이 분명하다고 생각하지 않습니다. –

답변

1

functor에서 평가를 위해 사용자 정의 또는 사용자 선택 기능을 밀어 넣기를 원하는 것처럼 보입니다. 이를 바탕으로 가능한 대답은 here 게시 내용과 매우 유사하다고 생각합니다. 그러나 다른 의견도 보내 드리겠습니다.

    나는 당신이 실제로 이것에 대해 질문했다,하지만 난 호스트 클래스, 결국 근본적으로 불가능할 것 thrust::device_vector에 사용하기 위해 장치에 전달됩니다의 객체로 표현 polymorphism 생각 생각하지 않는다
  1. 때문에 It is not allowed to pass as an argument to a __global__ function an object of a class with virtual functions.하지만 완전히 명확하지는 않습니다. 호스트에 적절한 객체 배열을 만든 다음 thrust::device_vector에서 해당 객체를 다형 적으로 사용하려고하면 어떻게 될 것입니까? 최소한, 나는 밀림을 통해 자신의 길과 싸울 수 없었다. 물론 가상 함수 테이블을 올바르게 할당 할 수 있도록 객체가 장치에서 올바르게 생성되었다고 가정하면 장치 코드에서 다형성을 사용할 수 있습니다. This question and comments도 관심의 대상이 될 수 있습니다. 장치 개체에 다형성을 사용하는 예를 보려면 내 대답 here을 살펴보십시오. 그것은 당신이 그것에 수행하고자하는 기능을 정의하기 위해 객체 자체를 사용하는 아이디어를 보여줍니다. (다시 말하지만, 나는 그것이 당신이 염두에 두었던 것이라고 생각하지 않습니다.)
  2. 편집 한 질문에 따라, 함수의 주소를 전달하여 functor에서 사용하려는 것처럼 보입니다. it is not allowed to take the address of a __device__ function in host code.이 제한은 유행 후에 장치 코드에서 사용하기 위해 장치 기능 포인터의 테이블을 채우는 "초기화 커널"을 호출하여 작동 할 수 있기 때문에 CUDA에서는 불가능합니다 (적어도 간단한 방법으로) 하지만 그물 효과는 아래 3에서 제안한 것보다 낫지 않다고 생각합니다.
  3. 장치 코드에서 사용하기 위해 사용자가 선택할 수있는 함수 색인을 전달할 수 있습니다.

다음이 마지막 아이디어를 보여주는 예는 다음과 같습니다

#include <thrust/device_vector.h> 
#include <thrust/sequence.h> 
#include <thrust/copy.h> 
#include <thrust/for_each.h> 
#include <thrust/iterator/zip_iterator.h> 
#include <iostream> 
#include <math.h> 


__host__ __device__ float f1(float x) 
{ 
    return sinf(x); 
} 

__host__ __device__ float f2(float x) 
{ 
    return cosf(x); 
} 



struct select_functor 
{ 
    unsigned fn; 

    select_functor(unsigned _fn) : fn(_fn) {}; 
    template <typename Tuple> 
    __host__ __device__ 
    void operator()(const Tuple &t) { 
    if (fn == 1) thrust::get<1>(t) = f1(thrust::get<0>(t)); 
    else if (fn == 2) thrust::get<1>(t) = f2(thrust::get<0>(t)); 
    else thrust::get<1>(t) = 0; 
    } 
}; 


int main(void) 
{ 
    unsigned ufn = 1; 
    const unsigned N = 8; 
    thrust::device_vector<float> data(N), result(N); 
    // initilaize to some values 
    thrust::sequence(data.begin(), data.end(), 0.0f, (float)(6.283/(float)N)); 
    std::cout<< "x: " << std::endl; 
    thrust::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " ")); 
    thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn)); 
    std::cout<< std::endl << "sin(x): " << std::endl; 
    thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " ")); 
    ufn = 2; 
    thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn)); 
    std::cout<< std::endl << "cos(x): " << std::endl; 
    thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " ")); 
    std::cout<< std::endl; 
    return 0; 
} 
+0

고맙습니다. @ 로버트, 당신의 조언은 매우 유용합니다! – lexxa2000