set_symmetric_difference.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_ALGORITHM_SET_SYMMETRIC_DIFFERENCE_HPP
  11. #define BOOST_COMPUTE_ALGORITHM_SET_SYMMETRIC_DIFFERENCE_HPP
  12. #include <iterator>
  13. #include <boost/static_assert.hpp>
  14. #include <boost/compute/algorithm/detail/compact.hpp>
  15. #include <boost/compute/algorithm/detail/balanced_path.hpp>
  16. #include <boost/compute/algorithm/exclusive_scan.hpp>
  17. #include <boost/compute/algorithm/fill_n.hpp>
  18. #include <boost/compute/container/vector.hpp>
  19. #include <boost/compute/detail/iterator_range_size.hpp>
  20. #include <boost/compute/detail/meta_kernel.hpp>
  21. #include <boost/compute/system.hpp>
  22. #include <boost/compute/type_traits/is_device_iterator.hpp>
  23. namespace boost {
  24. namespace compute {
  25. namespace detail {
  26. ///
  27. /// \brief Serial set symmetric difference kernel class
  28. ///
  29. /// Subclass of meta_kernel to perform serial set symmetric
  30. /// difference after tiling
  31. ///
  32. class serial_set_symmetric_difference_kernel : meta_kernel
  33. {
  34. public:
  35. unsigned int tile_size;
  36. serial_set_symmetric_difference_kernel() : meta_kernel("set_symmetric_difference")
  37. {
  38. tile_size = 4;
  39. }
  40. template<class InputIterator1, class InputIterator2,
  41. class InputIterator3, class InputIterator4,
  42. class OutputIterator1, class OutputIterator2>
  43. void set_range(InputIterator1 first1,
  44. InputIterator2 first2,
  45. InputIterator3 tile_first1,
  46. InputIterator3 tile_last1,
  47. InputIterator4 tile_first2,
  48. OutputIterator1 result,
  49. OutputIterator2 counts)
  50. {
  51. m_count = iterator_range_size(tile_first1, tile_last1) - 1;
  52. *this <<
  53. "uint i = get_global_id(0);\n" <<
  54. "uint start1 = " << tile_first1[expr<uint_>("i")] << ";\n" <<
  55. "uint end1 = " << tile_first1[expr<uint_>("i+1")] << ";\n" <<
  56. "uint start2 = " << tile_first2[expr<uint_>("i")] << ";\n" <<
  57. "uint end2 = " << tile_first2[expr<uint_>("i+1")] << ";\n" <<
  58. "uint index = i*" << tile_size << ";\n" <<
  59. "uint count = 0;\n" <<
  60. "while(start1<end1 && start2<end2)\n" <<
  61. "{\n" <<
  62. " if(" << first1[expr<uint_>("start1")] << " == " <<
  63. first2[expr<uint_>("start2")] << ")\n" <<
  64. " {\n" <<
  65. " start1++; start2++;\n" <<
  66. " }\n" <<
  67. " else if(" << first1[expr<uint_>("start1")] << " < " <<
  68. first2[expr<uint_>("start2")] << ")\n" <<
  69. " {\n" <<
  70. result[expr<uint_>("index")] <<
  71. " = " << first1[expr<uint_>("start1")] << ";\n" <<
  72. " index++; count++;\n" <<
  73. " start1++;\n" <<
  74. " }\n" <<
  75. " else\n" <<
  76. " {\n" <<
  77. result[expr<uint_>("index")] <<
  78. " = " << first2[expr<uint_>("start2")] << ";\n" <<
  79. " index++; count++;\n" <<
  80. " start2++;\n" <<
  81. " }\n" <<
  82. "}\n" <<
  83. "while(start1<end1)\n" <<
  84. "{\n" <<
  85. result[expr<uint_>("index")] <<
  86. " = " << first1[expr<uint_>("start1")] << ";\n" <<
  87. " index++; count++;\n" <<
  88. " start1++;\n" <<
  89. "}\n" <<
  90. "while(start2<end2)\n" <<
  91. "{\n" <<
  92. result[expr<uint_>("index")] <<
  93. " = " << first2[expr<uint_>("start2")] << ";\n" <<
  94. " index++; count++;\n" <<
  95. " start2++;\n" <<
  96. "}\n" <<
  97. counts[expr<uint_>("i")] << " = count;\n";
  98. }
  99. event exec(command_queue &queue)
  100. {
  101. if(m_count == 0) {
  102. return event();
  103. }
  104. return exec_1d(queue, 0, m_count);
  105. }
  106. private:
  107. size_t m_count;
  108. };
  109. } //end detail namespace
  110. ///
  111. /// \brief Set symmetric difference algorithm
  112. ///
  113. /// Finds the symmetric difference of the sorted range [first2, last2) from
  114. /// the sorted range [first1, last1) and stores it in range starting at result
  115. /// \return Iterator pointing to end of symmetric difference
  116. ///
  117. /// \param first1 Iterator pointing to start of first set
  118. /// \param last1 Iterator pointing to end of first set
  119. /// \param first2 Iterator pointing to start of second set
  120. /// \param last2 Iterator pointing to end of second set
  121. /// \param result Iterator pointing to start of range in which the symmetric
  122. /// difference will be stored
  123. /// \param queue Queue on which to execute
  124. ///
  125. /// Space complexity:
  126. /// \Omega(2(distance(\p first1, \p last1) + distance(\p first2, \p last2)))
  127. template<class InputIterator1, class InputIterator2, class OutputIterator>
  128. inline OutputIterator
  129. set_symmetric_difference(InputIterator1 first1,
  130. InputIterator1 last1,
  131. InputIterator2 first2,
  132. InputIterator2 last2,
  133. OutputIterator result,
  134. command_queue &queue = system::default_queue())
  135. {
  136. BOOST_STATIC_ASSERT(is_device_iterator<InputIterator1>::value);
  137. BOOST_STATIC_ASSERT(is_device_iterator<InputIterator2>::value);
  138. BOOST_STATIC_ASSERT(is_device_iterator<OutputIterator>::value);
  139. typedef typename std::iterator_traits<InputIterator1>::value_type value_type;
  140. int tile_size = 1024;
  141. int count1 = detail::iterator_range_size(first1, last1);
  142. int count2 = detail::iterator_range_size(first2, last2);
  143. vector<uint_> tile_a((count1+count2+tile_size-1)/tile_size+1, queue.get_context());
  144. vector<uint_> tile_b((count1+count2+tile_size-1)/tile_size+1, queue.get_context());
  145. // Tile the sets
  146. detail::balanced_path_kernel tiling_kernel;
  147. tiling_kernel.tile_size = tile_size;
  148. tiling_kernel.set_range(first1, last1, first2, last2,
  149. tile_a.begin()+1, tile_b.begin()+1);
  150. fill_n(tile_a.begin(), 1, 0, queue);
  151. fill_n(tile_b.begin(), 1, 0, queue);
  152. tiling_kernel.exec(queue);
  153. fill_n(tile_a.end()-1, 1, count1, queue);
  154. fill_n(tile_b.end()-1, 1, count2, queue);
  155. vector<value_type> temp_result(count1+count2, queue.get_context());
  156. vector<uint_> counts((count1+count2+tile_size-1)/tile_size + 1, queue.get_context());
  157. fill_n(counts.end()-1, 1, 0, queue);
  158. // Find individual symmetric differences
  159. detail::serial_set_symmetric_difference_kernel symmetric_difference_kernel;
  160. symmetric_difference_kernel.tile_size = tile_size;
  161. symmetric_difference_kernel.set_range(first1, first2, tile_a.begin(),
  162. tile_a.end(), tile_b.begin(),
  163. temp_result.begin(), counts.begin());
  164. symmetric_difference_kernel.exec(queue);
  165. exclusive_scan(counts.begin(), counts.end(), counts.begin(), queue);
  166. // Compact the results
  167. detail::compact_kernel compact_kernel;
  168. compact_kernel.tile_size = tile_size;
  169. compact_kernel.set_range(temp_result.begin(), counts.begin(), counts.end(), result);
  170. compact_kernel.exec(queue);
  171. return result + (counts.end() - 1).read(queue);
  172. }
  173. } //end compute namespace
  174. } //end boost namespace
  175. #endif // BOOST_COMPUTE_ALGORITHM_SET_SYMMETRIC_DIFFERENCE_HPP