通过CUDA Thrust查找采样函数的局部最小值

时间:2013-05-31 11:11:18

标签: cuda thrust

我想用Thrust编写程序来计算局部最小值 给定函数,f.i。 sin(x)。我通过有限差分近似函数导数,然后搜索导数变化符号的那些横坐标来做到这一点。我现在想收集当地的最小值。我用“1”标记了当地最小值 和其他点“0”。我做了一个inclusive_scan(用于计算新标签中的位置)。 我的问题是现在用gather_if收集局部最小值(条件模板,地图最小值), 但是代码没有编译,我不知道为什么。

有人可以解释原因吗?

/**
 * Copyright 1993-2012 NVIDIA Corporation.  All rights reserved.
 *
 * Please refer to the NVIDIA end user license agreement (EULA) associated
 * with this source code for terms and conditions that govern your use of
 * this software. Any use, reproduction, disclosure, or distribution of
 * this software and related documentation outside the terms of the EULA
 * is strictly prohibited.
 */

#include <stdio.h>
#include <thrust/device_vector.h>
#include <thrust/gather.h>
#include <thrust/host_vector.h>
#include <thrust/reduce.h>
#include <thrust/copy.h>                                    
#include <thrust/remove.h>
#include <thrust/functional.h>
#include <thrust/iterator/constant_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/scan.h>
#include <sys/time.h>

__host__ __device__ unsigned int bitreverse(unsigned int number) {
    number = ((0xf0f0f0f0 & number) >> 4) | ((0x0f0f0f0f & number) << 4);
    number = ((0xcccccccc & number) >> 2) | ((0x33333333 & number) << 2);
    number = ((0xaaaaaaaa & number) >> 1) | ((0x55555555 & number) << 1);
    return number;
}

struct is_even
{
    __host__ __device__
    bool operator()(const int x) {
        return (x % 2) == 0;
    }
};

struct select_mine
{
    __host__ __device__
    float operator()(const float x) {
        return (x < 0) ? 1.0f : 0.0f;
    }
};

struct bitreverse_functor
{
    __host__ __device__ unsigned int operator()(const unsigned int &x) {
        return bitreverse(x);
    }
};

struct sign
{
    __host__ __device__ float operator()(const float x) {
        if (x > 0.0f)
            return 1.0f;
        if (x < 0.0f)
            return -1.0f;
        return 0.0f;
    }
};

struct sine: public thrust::unary_function<float, float>
{
    __host__ __device__
    float operator()(float x) {
        return sinf(x);
    }
};

struct absolute: public thrust::unary_function<float, float>
{
    __host__ __device__
    float operator()(float x) {
        if (x < 0.0f)
            x = -x;
        return x;
    }
};

struct lokalne_minimum : public thrust::binary_function<float,float,float>
{
    __host__ __device__
    float operator()(float x, float y)
    {
        if (x > 0 && y < 0)
            return 1.0f;
        return 0.0f;
    }
};

struct conv : public thrust::unary_function<float,int>
{
    __host__ __device__
    int operator()(float x)
    {
        return (int)(x);
    }
};

using namespace thrust;

void help(char *arg) {
    fprintf(stderr,
            "Nieprawidlowe uzycie: %s [x1] [x2] [n]\nx1 - zakres od\nx2 - zakres do\nn - liczba podzialow zakresu\n",
            arg);
}

int main(int argc, char **argv) {

    if (argc != 4) {
        help(argv[0]);
        return 1;
    }

    int n = atoi(argv[3]);
    float x1 = (float) atof(argv[1]);
    float x2 = (float) atof(argv[2]);

    if (n < 0 || x2 < x1) {
        help(argv[0]);
        return 1;
    }

    float step = (x2 - x1) / n;

    fprintf(stderr, "Step: %f\n", step);

    thrust::device_vector<float> oxdata(n);
    thrust::device_vector<float> oydata(n);
    thrust::device_vector<float> diff(n);
    thrust::host_vector<float> ixdata(n);

    // FIXME change it
    for (int i = 0; i < n; i++)
        ixdata[i] = x1 + i * step;

    thrust::copy(ixdata.begin(), ixdata.end(), oxdata.begin());

    thrust::transform(oxdata.begin(),oxdata.end(),oydata.begin(),sine());

    thrust::transform(oydata.begin() + 1, oydata.end(), oydata.begin(),
            diff.begin()+1, thrust::minus<float>());

    thrust::copy(diff.begin(), diff.end(), ixdata.begin());

    for (int i = 0; i < n; i++)
        printf ("%f, ", ixdata[i]);
    printf ("\n");

    thrust::transform(diff.begin()+1,diff.end(), diff.begin(),diff.begin(),lokalne_minimum());


    for (int i = 0; i < n; i++)
        printf ("%f, ", ixdata[i]);
    printf ("\n");

    thrust::copy(oydata.begin(), oydata.end(), ixdata.begin());

    for (int i = 0; i < n; i++)
        printf ("%f, ", ixdata[i]);
    printf ("\n");

    thrust::copy(diff.begin(), diff.end(), ixdata.begin());

    for (int i = 0; i < n; i++)
        printf ("%f, ", ixdata[i]);
    printf ("\n");

    //thrust::inclusive_scan(diff.begin(),diff.end(),diff.begin());

    thrust::copy(diff.begin(), diff.end(), ixdata.begin());

    for (int i = 0; i < n; i++)
        printf ("%f, ", ixdata[i]);
    printf ("\n");

    thrust::device_vector<int> minima(n);
    thrust::device_vector<int> stencil(n);
    thrust::host_vector<int> hminima(n);
    thrust::transform(diff.begin(),diff.end(),minima.begin(),conv());

    thrust::copy(minima.begin(),minima.end(),hminima.begin());
    thrust::copy(minima.begin(),minima.end(),stencil.begin());

    for (int i = 0; i < n; i++)
        printf ("%d, ", hminima[i]);
    printf ("\n");

    thrust::inclusive_scan(minima.begin(), minima.end(),minima.begin());

    thrust::copy(minima.begin(),minima.end(),hminima.begin());

    for (int i = 0; i < n; i++)
        printf ("%d, ", hminima[i]);
    printf ("\n");

    //thrust::gather_if(minima.begin(),minima.end(),stencil.begin(),ixdata.begin(),ixdata.begin());

    return 0;
} 

1 个答案:

答案 0 :(得分:1)

这是一个非常晚的答案,用于从未答复的列表中删除此问题。我从Robert Crovella的评论中获利,并在下面显示了一个完整的工作代码,用CUDA Thrust查找采样函数的局部最小值。代码的基本原理如下

函数导数由中心差异近似为thrust::transform;

的应用

函数采样点用{1}作为thrust::transform的应用标记,方法是通过谓词local_minima_check()寻找导数的符号变化;

本地最小值的数量被计为thrust::count;

的应用

本地最小值被隔离为thrust::copy_if的应用。

#include <stdio.h>
#include <thrust/count.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/copy.h>                                    
#include <thrust/iterator/constant_iterator.h>
#include <thrust/iterator/counting_iterator.h>

/**************/
/* COS STRUCT */
/**************/
struct cosine: public thrust::unary_function<float, float>
{
    __host__ __device__ float operator()(float h_x) { return cosf(h_x); }
};

/******************************************/
/* SECOND ORDER CENTRAL DIFFERENCE STRUCT */
/******************************************/
struct second_order_central_difference 
{ 
    __host__ __device__ float operator()(thrust::tuple<float,float,float> t) 
    { 
        float f_1, f0, f1; 

        thrust::tie(f_1,f0,f1) = t; 

        return f_1 - 2.0f * f0 + f1; 
     } 
}; 

/******************************/
/* LOCAL MINIMUM CHECK STRUCT */
/******************************/
struct local_minimum_check:public thrust::binary_function<float,float,float>
{
    __host__ __device__ float operator()(float x, float y)
    {
        if (x < 0 && y > 0) return 1.0f;
        return 0.0f;
    }
};

/****************************************/
/* LOCAL MINIMUM PREDICATE CHECK STRUCT */
/****************************************/
struct pred
{
    __host__ __device__ bool operator()(const int d_x) { return (d_x == 1.f); }
};

void main() {

    // --- Input parameters
    int n = 100;         // Number of sampling points
    float x1 = 3.14f / 2.f;      // (x1,x2) is the sampling interval
    float x2 = 1.5f * 3.14f;

    // --- Calculating the sampling points x
    thrust::host_vector<float> h_x(n);
    float step = (x2 - x1) / n;
    for (int i = 0; i < n; i++) h_x[i] = x1 + (float)i * step;
    thrust::device_vector<float> d_x = h_x; 

    // --- Evaluating the function values y = f(x)
    thrust::device_vector<float> d_y(n);
    thrust::transform(d_x.begin(),d_x.end(),d_y.begin(),cosine());

    // --- Computing first order central finite differences
    //     In Matlab's notation, it calculates d_diff1(1:n-2) = d_y(3:n,:) - d_y(1:n-2,:);
    thrust::device_vector<float> d_diff1(n-2);
    thrust::transform(d_y.begin() + 2, d_y.end(), d_y.begin(), d_diff1.begin(), thrust::minus<float>());

    // --- Computing second order central finite differences
    //     In Matlab's notation, it calculates d_diff2(1:n-2) = d_y(3:n) - 2. * d_y(2:n-1) + d_y(1:n-2);
    thrust::device_vector<float> d_diff2(n-2);
    thrust::transform(thrust::make_zip_iterator(
            thrust::make_tuple(d_y.begin(), d_y.begin() + 1, d_y.begin() + 2)), 
                      thrust::make_zip_iterator(
            thrust::make_tuple(d_y.end() - 2, d_y.end() - 1, d_y.end())), 
                      d_diff2.begin(),second_order_central_difference());

    // --- Setting a flag for all those points for which the derivative changes sign from negative to positive
    thrust::device_vector<float> d_fo_derivative(n-3);
    thrust::transform(d_diff1.begin(), d_diff1.end() - 1, d_diff1.begin() + 1, d_fo_derivative.begin(), local_minimum_check());

    // --- Counting the number of local minima and selecting the local minima coordinates
    int min_number = thrust::count(d_fo_derivative.begin(), d_fo_derivative.end(), 1.f);
    thrust::device_vector<float> d_x_minima(min_number);
    thrust::copy_if(d_x.begin() + 1, d_x.end() - 1, d_fo_derivative.begin(), d_x_minima.begin(), pred());

    for (int i = 0; i < d_x_minima.size(); i++) {
        printf ("Local minimum # %i = %f\n ", i+1, (float)d_x_minima[i]);
    }

    getchar();

}