JayBeams  0.1
Another project to have fun coding.
ut_conjugate_and_multiply.cpp
Go to the documentation of this file.
5 
6 #include <boost/compute/context.hpp>
7 #include <boost/test/unit_test.hpp>
8 #include <random>
9 #include <sstream>
10 
11 namespace {
12 
13 template <typename precision_t>
14 void check_conjugate_and_multiply_sized(int asize, int bsize) {
15  boost::compute::device device = jb::opencl::device_selector();
16  if (std::is_same<double, precision_t>::value) {
17  if (not device.supports_extension("cl_khr_fp64")) {
18  BOOST_TEST_MESSAGE(
19  "Test disabled, device (" << device.name()
20  << ") does not support cl_khr_fp64, i.e., "
21  "double precision floating point");
22  return;
23  }
24  }
25  boost::compute::context context(device);
26  boost::compute::command_queue queue(context, device);
27 
28  unsigned int seed = std::random_device()();
29  std::mt19937 gen(seed);
30  std::uniform_real_distribution<precision_t> dis(-1000, 1000);
31  auto generator = [&gen, &dis]() { return dis(gen); };
32  BOOST_TEST_MESSAGE("SEED = " << seed);
33 
34  std::vector<std::complex<precision_t>> asrc;
35  jb::testing::create_random_timeseries(generator, asize, asrc);
36  std::vector<std::complex<precision_t>> bsrc(bsize);
37  // Using a random timeseries for the second input makes it too
38  // likely that we will run into numerical errors introduced by
39  // addition and subtration of similar numbers. So we use a somewhat
40  // silly input for the B array, we are interested in the correctness
41  // of the algorithm with respect to data moves and parallelization,
42  // the numerics are as good as they can be (which is to say they can
43  // be bad indeed)...
44  std::fill(bsrc.begin(), bsrc.end(), std::complex<precision_t>(1.0, 1.0));
45 
46  boost::compute::vector<std::complex<precision_t>> a(asize, context);
47  boost::compute::vector<std::complex<precision_t>> b(bsize, context);
48  boost::compute::vector<std::complex<precision_t>> out(asize, context);
49  std::vector<std::complex<precision_t>> actual(asize);
50 
51  boost::compute::copy(asrc.begin(), asrc.end(), a.begin(), queue);
52  boost::compute::copy(bsrc.begin(), bsrc.end(), b.begin(), queue);
53  BOOST_TEST_MESSAGE("copied data to device");
54 
55  auto future = jb::tde::conjugate_and_multiply(
56  a.begin(), a.end(), b.begin(), b.end(), out.begin(), queue);
57  if (not future.valid()) {
58  BOOST_CHECK_EQUAL(asize, 0);
59  return;
60  }
61  if (device.platform().name() == "Portable Computing Language") {
62  // Ugly hack to workaround a bug in the POCL library.
63  queue.finish();
64  } else {
65  queue.enqueue_barrier(boost::compute::wait_list(future.get_event()));
66  }
67  auto done =
68  boost::compute::copy_async(out.begin(), out.end(), actual.begin(), queue);
69 
70  std::vector<std::complex<precision_t>> expected(asize);
71  for (int i = 0; i != asize; ++i) {
72  expected[i] = std::conj(asrc[i]) * bsrc[i];
73  }
74  done.wait();
75 
76  int const tol = 3;
77  bool res = jb::testing::check_collection_close_enough(actual, expected, tol);
78  BOOST_CHECK_MESSAGE(res, "collections are not within tolerance=" << tol);
79 }
80 
81 template <typename precision_t>
82 void check_conjugate_and_multiply() {
83  constexpr std::size_t size = 32768;
84  check_conjugate_and_multiply_sized<precision_t>(size, size);
85 }
86 
87 template <typename precision_t>
88 void check_conjugate_and_multiply_empty() {
89  check_conjugate_and_multiply_sized<precision_t>(0, 0);
90 }
91 
92 template <typename precision_t>
93 void check_conjugate_and_multiply_mismatched() {
94  constexpr std::size_t size = 32768;
95  check_conjugate_and_multiply_sized<precision_t>(size, size / 2);
96 }
97 
98 } // anonymous namespace
99 
100 /**
101  * @test Make sure the jb::tde::conjugate_and_multiply() works as
102  * expected.
103  */
104 BOOST_AUTO_TEST_CASE(conjugate_and_multiply_float) {
105  check_conjugate_and_multiply<float>();
106 }
107 
108 /**
109  * @test Make sure the jb::tde::conjugate_and_multiply() works as
110  * expected.
111  */
112 BOOST_AUTO_TEST_CASE(conjugate_and_multiply_double) {
113  check_conjugate_and_multiply<double>();
114 }
115 
116 /**
117  * @test Verify that jb::tde::conjugate_and_multiply() works for empty
118  * arrays.
119  */
120 BOOST_AUTO_TEST_CASE(conjugate_and_multiply_float_empty) {
121  BOOST_CHECK_NO_THROW(check_conjugate_and_multiply_empty<float>());
122 }
123 
124 /**
125  * @test Verify that jb::tde::conjugate_and_multiply() works for empty
126  * arrays.
127  */
128 BOOST_AUTO_TEST_CASE(conjugate_and_multiply_double_empty) {
129  BOOST_CHECK_NO_THROW(check_conjugate_and_multiply_empty<double>());
130 }
131 
132 /**
133  * @test Verify that jb::tde::conjugate_and_multiply() detects
134  * mismatched arrays.
135  */
136 BOOST_AUTO_TEST_CASE(conjugate_and_multiply_float_error) {
137  BOOST_CHECK_THROW(
138  check_conjugate_and_multiply_mismatched<float>(), std::exception);
139 }
void create_random_timeseries(generator &gen, int nsamples, timeseries &ts)
Create a simple timeseries where the values look like a random.
boost::compute::device device_selector(config const &cfg)
Select an OpenCL device matching the current configuration.
BOOST_AUTO_TEST_CASE(conjugate_and_multiply_float)
bool check_collection_close_enough(collection_t const &a, collection_t const &b, int tol=1, int max_differences_printed=JB_TESTING_MAX_DIFFERENCES_PRINTED)
Given two collections of numbers of the same value type, find the differences that are out of a given...
boost::compute::future< OutputIterator > conjugate_and_multiply(InputIterator a_start, InputIterator a_end, InputIterator b_start, InputIterator b_end, OutputIterator output, boost::compute::command_queue &queue, boost::compute::wait_list const &wait=boost::compute::wait_list())