我想用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;
}
答案 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();
}