 
 }
 
-Point3D reduce(PointCloud<Point3D> &cloud, func& f) {
+Point3D reduce(PointCloud<Point3D> &cloud, func& f, double identity_element) {
 
     Point3D *d_points;
     Point3D *d_result;
-    Point3D *d_reduce;
 
     auto num_points = cloud.points.size();
+
+    auto size = next_power_of_two(num_points);
 
     func* h_f;
     func* d_f;

    cudaMemcpyFromSymbol( &h_f[0], f, sizeof(func));
    cudaMemcpy(d_f,h_f,sizeof(func),cudaMemcpyHostToDevice);

    cudaMalloc(&d_reduce, sizeof(Point3D) * cloud.points.size());
    cudaMalloc((void**) &d_result, sizeof(Point3D));
    cudaMalloc((void**) &d_points, sizeof(Point3D) * cloud.points.size());
    cudaMemcpy(d_points, &cloud.points[0], sizeof(Point3D) * cloud.points.size(), cudaMemcpyHostToDevice);

    int N = cloud.points.size();

    reduce<<<1,N>>>(d_points, num_points, d_result, d_f, d_reduce);

    cudaDeviceSynchronize();


}
__device__ func max_func = max_d;

double max_identity_element = - DBL_MAX;

Point3D reduce_max(PointCloud<Point3D> &cloud) {
    return reduce(cloud, max_func, max_identity_element);
}


__device__ double min_d(double n, double m) {
    return (m < n) ? m : n;
}
__device__ func min_func = min_d;

double min_identity_element = DBL_MAX;

Point3D reduce_min(PointCloud<Point3D> &cloud) {
    return reduce(cloud, min_func, min_identity_element);
}