2016-06-07 4 views
0

Ich bin gerade dabei, Code von C++ nach CUDA zu übertragen, während ich mit thrust::device_vector s arbeite. Jetzt gibt es eine Funktion, um den Gradienten zu berechnen, wo ich auch Zugriff auf nicht nur das aktuelle Element, sondern auch die umgebenden Elemente haben muss. In dem ursprünglichen Code schrieb ich folgende:Berechnen des Gradienten über einen Schub :: device_vector

void calc_grad(Complex *grad, const Complex *data, const int size) 
{ 
    for (int i = 1; i < size - 1; i++) { 
     grad[i] = 0.5 * (data[i + 1] - data[i - 1]); 
    } 
    grad[0] = data[1] - data[0]; 
    grad[size - 1] = data[size - 1] - data[size - 2]; 
} 

Ist es möglich, ein functor für Schub aus, dass zu schaffen, so dass ich es in thrust::transform() anrufen kann? Bis jetzt kann ich immer nur auf ein Element zugreifen, ohne die umgebenden Elemente zu erhalten. Oder ist es sowieso nicht möglich, je nach Element vorher und nachher, welche geändert werden?

Die Formel für den Code kam aus der matlab Funktion gradient, hier gezeigt: http://se.mathworks.com/help/matlab/ref/gradient.html?requestedDomain=www.mathworks.com

+1

Sie sollten wirklich einige Zeit mit dem Lesen der Schub Dokumentation verbringen: https://thrust.github.io/doc/group__transformations.html#gaa41d309b53fa03bf13fe35a184148400 – talonmies

+0

Diese Funktion ist nicht das tut, was meine Funktion tut. Gibt es noch andere ähnliche Funktionen? –

+0

Sie können jedes beliebige Bestellgenauigkeitsschema aus sukzessiven Differenzen berechnen, die mit 'benachbarten_Unterschieden' ​​berechnet wurden, einschließlich der zentralen Differenz zweiter Ordnung, die Sie hier gezeigt haben. – talonmies

Antwort

4

Ein einzelner Thrust::transform() größten Teil Ihrer Arbeit tun. Alles, was Sie tun müssen, ist die Daten ein wenig zu verschieben, so dass grad[i], data[i-1] und data[i+1] ausgerichtet sind.

thrust::transform(data.begin()+2, 
        data.end(), 
        data.begin(), 
        grad.begin()+1, 
        (_1 - _2) * 0.5); 

Dann können Sie mit den Grenzfällen befassen.

bearbeiten

Und Sie können auch die Grenzfälle in einer transformieren. Mit der folgenden Form der Transformation sollte Ihr Funktor Grad den Index der Daten, mit denen er zu tun hat, durch den ersten Funktorparameter kennen. Basierend auf dem Index kann er dann 2 der 3 Elemente aus dem zweiten Funktorparameter auswählen, der ein Tupel ist, um die korrekte Berechnung durchzuführen.

Alles hier ist nicht getestet. Ich bin mir nicht sicher, ob data.begin()-1 funktioniert. Sie können auch auf dem Complex Typ vorsichtig sein.

thrust::transform(
    thrust::make_counting_iterator(int(0)), 
    thrust::make_counting_iterator(int(0)) + size, 
    thrust::make_zip_iterator(
     thrust::make_tuple(
      data.begin()-1, 
      data.begin(), 
      data.begin()+1)), 
    grad.begin(), 
    Grad(size) 
); 

Der Funktor ist so etwas.

struct Grad { 
    int size_; 
    Grad(int s) : 
     size_(s) { 
    } 
    template<typename T, typename Tuple> 
    __host__ __device__ 
    inline T operator()(const int& idx, const Tuple& d) { 
    if (idx == 0) { 
     return d.get<2>() - d.get<1>(); 
    } else if (idx == size_ - 1) { 
     return d.get<1>() - d.get<0>(); 
    } else { 
     return 0.5 * (d.get<2>() - d.get<0>()); 
    } 
    } 
}; 
+0

Grenzfälle: 'grad [0] = Daten [1] -Daten [0]; grad [size-1] = grad [size-1] -grad [size-2]; oder gibt es dafür einen schnelleren Weg? –

+0

@arc_lupus Ich habe die Antwort bearbeitet. Es sollte die gleiche Leistung wie die erste haben, wenn es funktioniert. – kangshiyin

Verwandte Themen