1 #ifndef VEXCL_LOGICAL_HPP 2 #define VEXCL_LOGICAL_HPP 3 4 /* 5 The MIT License 6 7 Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com> 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 */ 27 28 /** 29 * \file vexcl/logical.hpp 30 * \author Denis Demidov <dennis.demidov@gmail.com> 31 * \brief Implementation of any_of and all_of primitives. 32 */ 33 34 #include <vector> 35 #include <vexcl/operations.hpp> 36 37 namespace vex { 38 39 /// Functor that checks if any element in a vector expression is true. 40 /** 41 * Example: 42 \code 43 vex::any_of any_of(ctx); 44 bool have_zeros = any_of(x == 0); 45 \endcode 46 */ 47 class any_of { 48 public: any_of(const std::vector<backend::command_queue> & queue=current_context ().queue ())49 any_of(const std::vector<backend::command_queue> &queue 50 #ifndef VEXCL_NO_STATIC_CONTEXT_CONSTRUCTORS 51 = current_context().queue() 52 #endif 53 ) : queue(queue) 54 { 55 result.reserve(queue.size()); 56 for(auto q = queue.begin(); q != queue.end(); ++q) 57 result.push_back( backend::device_vector<char>(*q, 1) ); 58 } 59 60 template <class Expr> operator ()(const Expr & expr) const61 bool operator()(const Expr &expr) const { 62 using namespace detail; 63 64 get_expression_properties prop; 65 extract_terminals()(expr, prop); 66 67 for(unsigned d = 0; d < queue.size(); ++d) { 68 if (size_t psize = prop.part_size(d)) { 69 backend::kernel& k = make_kernel(queue[d], expr); 70 k.push_arg(psize); 71 extract_terminals()(expr, 72 set_expression_argument( 73 k, d, prop.part_start(d), empty_state() 74 ) 75 ); 76 k.push_arg(result[d]); 77 k(queue[d]); 78 } 79 } 80 81 for(unsigned d = 0; d < queue.size(); ++d) { 82 if (prop.part_size(d)) { 83 char r; 84 result[d].read(queue[d], 0, 1, &r, true); 85 if (r) return true; 86 } 87 } 88 return false; 89 } 90 91 private: 92 std::vector<backend::command_queue> queue; 93 std::vector<backend::device_vector<char>> result; 94 95 template <class Expr> make_kernel(const backend::command_queue & q,const Expr & expr)96 static backend::kernel& make_kernel( 97 const backend::command_queue &q, 98 const Expr &expr 99 ) 100 { 101 using namespace detail; 102 static kernel_cache cache; 103 104 auto kernel = cache.find(q); 105 106 if (kernel == cache.end()) { 107 backend::source_generator src(q); 108 109 output_terminal_preamble gpre(src, q, "prm", empty_state()); 110 boost::proto::eval(boost::proto::as_child(expr), gpre); 111 112 src.begin_kernel("vexcl_any_of_kernel"); 113 src.begin_kernel_parameters(); 114 src.parameter<size_t>("n"); 115 116 extract_terminals()(expr, 117 declare_expression_parameter( 118 src, q, "prm", empty_state() 119 ) 120 ); 121 122 src.template parameter< global_ptr<char> >("result"); 123 124 src.end_kernel_parameters(); 125 src.new_line() << "for(ulong idx = 0; idx < n; ++idx)"; 126 src.open("{"); 127 128 output_local_preamble lpre(src, q, "prm", empty_state()); 129 boost::proto::eval(boost::proto::as_child(expr), lpre); 130 131 src.new_line() << "if ("; 132 133 vector_expr_context expr_ctx(src, q, "prm", empty_state()); 134 boost::proto::eval(boost::proto::as_child(expr), expr_ctx); 135 136 src << ")"; 137 src.open("{"); 138 src.new_line() << "result[0] = 1;"; 139 src.new_line() << "return;"; 140 src.close("}"); 141 142 src.close("}"); 143 src.new_line() << "result[0] = 0;"; 144 src.end_kernel(); 145 146 kernel = cache.insert(q, backend::kernel( 147 q, src.str(), "vexcl_any_of_kernel" 148 )); 149 kernel->second.config(1, 1); 150 } 151 152 return kernel->second; 153 } 154 }; 155 156 /// Functor that checks if all elements in a vector expression are true. 157 /** 158 * Example: 159 \code 160 vex::all_of all_of(ctx); 161 bool odds_only = all_of(x % 2 == 1); 162 \endcode 163 */ 164 class all_of : public any_of { 165 public: all_of(const std::vector<backend::command_queue> & queue=current_context ().queue ())166 all_of(const std::vector<backend::command_queue> &queue 167 #ifndef VEXCL_NO_STATIC_CONTEXT_CONSTRUCTORS 168 = current_context().queue() 169 #endif 170 ) : any_of(queue) {} 171 172 template <class Expr> operator ()(const Expr & expr) const173 bool operator()(const Expr &expr) const { 174 return !any_of::operator()(!expr); 175 } 176 }; 177 178 } // namespace vexcl 179 180 181 #endif 182