void NearestNeighbourSearch<T, CloudType>::checkSizesKnn(const Matrix& query, const IndexMatrix& indices, const Matrix& dists2, const Index k, const unsigned optionFlags, const Vector* maxRadii) const { const bool allowSelfMatch(optionFlags & NearestNeighbourSearch<T, CloudType>::ALLOW_SELF_MATCH); if (allowSelfMatch) { if (k > cloud.cols()) throw runtime_error((boost::format("Requesting more points (%1%) than available in cloud (%2%)") % k % cloud.cols()).str()); } else { if (k > cloud.cols()-1) throw runtime_error((boost::format("Requesting more points (%1%) than available in cloud minus 1 (%2%) (as self match is forbidden)") % k % (cloud.cols()-1)).str()); } if (query.rows() < dim) throw runtime_error((boost::format("Query has less dimensions (%1%) than requested for cloud (%2%)") % query.rows() % dim).str()); if (indices.rows() != k) throw runtime_error((boost::format("Index matrix has a different number of rows (%1%) than k (%2%)") % indices.rows() % k).str()); if (indices.cols() != query.cols()) throw runtime_error((boost::format("Index matrix has a different number of columns (%1%) than query (%2%)") % indices.rows() % query.cols()).str()); if (dists2.rows() != k) throw runtime_error((boost::format("Distance matrix has a different number of rows (%1%) than k (%2%)") % dists2.rows() % k).str()); if (dists2.cols() != query.cols()) throw runtime_error((boost::format("Distance matrix has a different number of columns (%1%) than query (%2%)") % dists2.rows() % query.cols()).str()); if (maxRadii && (maxRadii->size() != query.cols())) throw runtime_error((boost::format("Maximum radii vector has not the same length (%1%) than query has columns (%2%)") % maxRadii->size() % k).str()); const unsigned maxOptionFlagsValue(ALLOW_SELF_MATCH|SORT_RESULTS); if (optionFlags > maxOptionFlagsValue) throw runtime_error((boost::format("OR-ed value of option flags (%1%) is larger than maximal valid value (%2%)") % optionFlags % maxOptionFlagsValue).str()); }
unsigned long OpenCLSearch<T>::knn(const Matrix& query, IndexMatrix& indices, Matrix& dists2, const Index k, const T epsilon, const unsigned optionFlags, const T maxRadius) const { checkSizesKnn(query, indices, dists2, k); const bool collectStatistics(creationOptionFlags & NearestNeighbourSearch<T>::TOUCH_STATISTICS); // check K if (k > MAX_K) throw runtime_error("number of neighbors too large for OpenCL"); // check consistency of query wrt cloud if (query.stride() != cloud.stride() || query.rows() != cloud.rows()) throw runtime_error("query is not of the same dimensionality as the point cloud"); // map query if (!(query.Flags & Eigen::DirectAccessBit) || (query.Flags & Eigen::RowMajorBit)) throw runtime_error("wrong memory mapping in query data"); const size_t queryCLSize(query.cols() * query.stride() * sizeof(T)); cl::Buffer queryCL(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, queryCLSize, const_cast<T*>(&query.coeff(0,0))); knnKernel.setArg(1, sizeof(cl_mem), &queryCL); // map indices assert((indices.Flags & Eigen::DirectAccessBit) && (!(indices.Flags & Eigen::RowMajorBit))); const int indexStride(indices.stride()); const size_t indicesCLSize(indices.cols() * indexStride * sizeof(int)); cl::Buffer indicesCL(context, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, indicesCLSize, &indices.coeffRef(0,0)); knnKernel.setArg(2, sizeof(cl_mem), &indicesCL); // map dists2 assert((dists2.Flags & Eigen::DirectAccessBit) && (!(dists2.Flags & Eigen::RowMajorBit))); const int dists2Stride(dists2.stride()); const size_t dists2CLSize(dists2.cols() * dists2Stride * sizeof(T)); cl::Buffer dists2CL(context, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, dists2CLSize, &dists2.coeffRef(0,0)); knnKernel.setArg(3, sizeof(cl_mem), &dists2CL); // set resulting parameters knnKernel.setArg(4, k); knnKernel.setArg(5, (1 + epsilon)*(1 + epsilon)); knnKernel.setArg(6, maxRadius*maxRadius); knnKernel.setArg(7, optionFlags); knnKernel.setArg(8, indexStride); knnKernel.setArg(9, dists2Stride); knnKernel.setArg(10, cl_uint(cloud.cols())); // if required, map visit count vector<cl_uint> visitCounts; const size_t visitCountCLSize(query.cols() * sizeof(cl_uint)); cl::Buffer visitCountCL; if (collectStatistics) { visitCounts.resize(query.cols()); visitCountCL = cl::Buffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, visitCountCLSize, &visitCounts[0]); knnKernel.setArg(11, sizeof(cl_mem), &visitCountCL); } // execute query queue.enqueueNDRangeKernel(knnKernel, cl::NullRange, cl::NDRange(query.cols()), cl::NullRange); queue.enqueueMapBuffer(indicesCL, true, CL_MAP_READ, 0, indicesCLSize, 0, 0); queue.enqueueMapBuffer(dists2CL, true, CL_MAP_READ, 0, dists2CLSize, 0, 0); if (collectStatistics) queue.enqueueMapBuffer(visitCountCL, true, CL_MAP_READ, 0, visitCountCLSize, 0, 0); queue.finish(); // if required, collect statistics if (collectStatistics) { unsigned long totalVisitCounts(0); for (size_t i = 0; i < visitCounts.size(); ++i) totalVisitCounts += (unsigned long)visitCounts[i]; return totalVisitCounts; } else return 0; }