ViennaCL - The Vienna Computing Library  1.7.1
Free open-source GPU-accelerated linear algebra and solver library.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tree_parsing.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_DEVICE_SPECIFIC_TREE_PARSING_HPP
2 #define VIENNACL_DEVICE_SPECIFIC_TREE_PARSING_HPP
3 
4 /* =========================================================================
5  Copyright (c) 2010-2016, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8  Portions of this software are copyright by UChicago Argonne, LLC.
9 
10  -----------------
11  ViennaCL - The Vienna Computing Library
12  -----------------
13 
14  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15 
16  (A list of authors and contributors can be found in the manual)
17 
18  License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20 
21 
26 #include <set>
27 
28 #include "viennacl/forwards.h"
29 
31 
35 
36 namespace viennacl
37 {
38 namespace device_specific
39 {
40 namespace tree_parsing
41 {
42 
45 {
46 public:
49 };
50 
52 template<class Fun>
53 inline void traverse(scheduler::statement const & statement, vcl_size_t root_idx, Fun const & fun, bool inspect)
54 {
55  scheduler::statement_node const & root_node = statement.array()[root_idx];
56  bool recurse = utils::node_leaf(root_node.op)?inspect:true;
57 
58  fun.call_before_expansion(statement, root_idx);
59 
60  //Lhs:
61  if (recurse)
62  {
64  traverse(statement, root_node.lhs.node_index, fun, inspect);
66  fun(statement, root_idx, LHS_NODE_TYPE);
67  }
68 
69  //Self:
70  fun(statement, root_idx, PARENT_NODE_TYPE);
71 
72  //Rhs:
73  if (recurse && root_node.rhs.type_family!=scheduler::INVALID_TYPE_FAMILY)
74  {
76  traverse(statement, root_node.rhs.node_index, fun, inspect);
78  fun(statement, root_idx, RHS_NODE_TYPE);
79  }
80 
81  fun.call_after_expansion(statement, root_idx);
82 }
83 
84 class filter : public traversal_functor
85 {
86 public:
87  typedef bool (*pred_t)(scheduler::statement_node const & node);
88 
89  filter(pred_t pred, std::vector<vcl_size_t> & out) : pred_(pred), out_(out){ }
90 
91  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t) const
92  {
93  scheduler::statement_node const * root_node = &statement.array()[root_idx];
94  if (pred_(*root_node))
95  out_.push_back(root_idx);
96  }
97 private:
98  pred_t pred_;
99  std::vector<vcl_size_t> & out_;
100 };
101 
103 {
104 public:
105  filter_elements(scheduler::statement_node_subtype subtype, std::vector<scheduler::lhs_rhs_element> & out) : subtype_(subtype), out_(out) { }
106 
107  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t) const
108  {
109  scheduler::statement_node const * root_node = &statement.array()[root_idx];
110  if (root_node->lhs.subtype==subtype_)
111  out_.push_back(root_node->lhs);
112  if (root_node->rhs.subtype==subtype_)
113  out_.push_back(root_node->rhs);
114  }
115 private:
117  std::vector<scheduler::lhs_rhs_element> & out_;
118 };
119 
121 inline const char * evaluate(scheduler::operation_node_type type)
122 {
123  using namespace scheduler;
124  // unary expression
125  switch (type)
126  {
127  //Function
128  case OPERATION_UNARY_ABS_TYPE : return "abs";
129  case OPERATION_UNARY_ACOS_TYPE : return "acos";
130  case OPERATION_UNARY_ASIN_TYPE : return "asin";
131  case OPERATION_UNARY_ATAN_TYPE : return "atan";
132  case OPERATION_UNARY_CEIL_TYPE : return "ceil";
133  case OPERATION_UNARY_COS_TYPE : return "cos";
134  case OPERATION_UNARY_COSH_TYPE : return "cosh";
135  case OPERATION_UNARY_EXP_TYPE : return "exp";
136  case OPERATION_UNARY_FABS_TYPE : return "fabs";
137  case OPERATION_UNARY_FLOOR_TYPE : return "floor";
138  case OPERATION_UNARY_LOG_TYPE : return "log";
139  case OPERATION_UNARY_LOG10_TYPE : return "log10";
140  case OPERATION_UNARY_SIN_TYPE : return "sin";
141  case OPERATION_UNARY_SINH_TYPE : return "sinh";
142  case OPERATION_UNARY_SQRT_TYPE : return "sqrt";
143  case OPERATION_UNARY_TAN_TYPE : return "tan";
144  case OPERATION_UNARY_TANH_TYPE : return "tanh";
145 
146  case OPERATION_UNARY_CAST_CHAR_TYPE : return "(char)";
147  case OPERATION_UNARY_CAST_UCHAR_TYPE : return "(uchar)";
148  case OPERATION_UNARY_CAST_SHORT_TYPE : return "(short)";
149  case OPERATION_UNARY_CAST_USHORT_TYPE : return "(ushort)";
150  case OPERATION_UNARY_CAST_INT_TYPE : return "(int)";
151  case OPERATION_UNARY_CAST_UINT_TYPE : return "(uint)";
152  case OPERATION_UNARY_CAST_LONG_TYPE : return "(long)";
153  case OPERATION_UNARY_CAST_ULONG_TYPE : return "(ulong)";
154  case OPERATION_UNARY_CAST_HALF_TYPE : return "(half)";
155  case OPERATION_UNARY_CAST_FLOAT_TYPE : return "(float)";
156  case OPERATION_UNARY_CAST_DOUBLE_TYPE : return "(double)";
157 
158  case OPERATION_BINARY_ELEMENT_ARGFMAX_TYPE : return "argfmax";
159  case OPERATION_BINARY_ELEMENT_ARGMAX_TYPE : return "argmax";
160  case OPERATION_BINARY_ELEMENT_ARGFMIN_TYPE : return "argfmin";
161  case OPERATION_BINARY_ELEMENT_ARGMIN_TYPE : return "argmin";
162  case OPERATION_BINARY_ELEMENT_POW_TYPE : return "pow";
163 
164  //Arithmetic
165  case OPERATION_UNARY_MINUS_TYPE : return "-";
166  case OPERATION_BINARY_ASSIGN_TYPE : return "=";
167  case OPERATION_BINARY_INPLACE_ADD_TYPE : return "+=";
168  case OPERATION_BINARY_INPLACE_SUB_TYPE : return "-=";
169  case OPERATION_BINARY_ADD_TYPE : return "+";
170  case OPERATION_BINARY_SUB_TYPE : return "-";
171  case OPERATION_BINARY_MULT_TYPE : return "*";
172  case OPERATION_BINARY_ELEMENT_PROD_TYPE : return "*";
173  case OPERATION_BINARY_DIV_TYPE : return "/";
174  case OPERATION_BINARY_ELEMENT_DIV_TYPE : return "/";
175  case OPERATION_BINARY_ACCESS_TYPE : return "[]";
176 
177  //Relational
178  case OPERATION_BINARY_ELEMENT_EQ_TYPE : return "isequal";
179  case OPERATION_BINARY_ELEMENT_NEQ_TYPE : return "isnotequal";
180  case OPERATION_BINARY_ELEMENT_GREATER_TYPE : return "isgreater";
181  case OPERATION_BINARY_ELEMENT_GEQ_TYPE : return "isgreaterequal";
182  case OPERATION_BINARY_ELEMENT_LESS_TYPE : return "isless";
183  case OPERATION_BINARY_ELEMENT_LEQ_TYPE : return "islessequal";
184 
185  case OPERATION_BINARY_ELEMENT_FMAX_TYPE : return "fmax";
186  case OPERATION_BINARY_ELEMENT_FMIN_TYPE : return "fmin";
187  case OPERATION_BINARY_ELEMENT_MAX_TYPE : return "max";
188  case OPERATION_BINARY_ELEMENT_MIN_TYPE : return "min";
189  //Unary
190  case OPERATION_UNARY_TRANS_TYPE : return "trans";
191 
192  //Binary
193  case OPERATION_BINARY_INNER_PROD_TYPE : return "iprod";
194  case OPERATION_BINARY_MAT_MAT_PROD_TYPE : return "mmprod";
195  case OPERATION_BINARY_MAT_VEC_PROD_TYPE : return "mvprod";
196  case OPERATION_BINARY_VECTOR_DIAG_TYPE : return "vdiag";
197  case OPERATION_BINARY_MATRIX_DIAG_TYPE : return "mdiag";
198  case OPERATION_BINARY_MATRIX_ROW_TYPE : return "row";
199  case OPERATION_BINARY_MATRIX_COLUMN_TYPE : return "col";
200 
201  default : throw generator_not_supported_exception("Unsupported operator");
202  }
203 }
204 
206 {
207  using namespace scheduler;
208  switch (type)
209  {
210  case OPERATION_UNARY_CAST_CHAR_TYPE : return "char";
211  case OPERATION_UNARY_CAST_UCHAR_TYPE : return "uchar";
212  case OPERATION_UNARY_CAST_SHORT_TYPE : return "short";
213  case OPERATION_UNARY_CAST_USHORT_TYPE : return "ushort";
214  case OPERATION_UNARY_CAST_INT_TYPE : return "int";
215  case OPERATION_UNARY_CAST_UINT_TYPE : return "uint";
216  case OPERATION_UNARY_CAST_LONG_TYPE : return "long";
217  case OPERATION_UNARY_CAST_ULONG_TYPE : return "ulong";
218  case OPERATION_UNARY_CAST_HALF_TYPE : return "half";
219  case OPERATION_UNARY_CAST_FLOAT_TYPE : return "float";
220  case OPERATION_UNARY_CAST_DOUBLE_TYPE : return "double";
221 
222  case OPERATION_UNARY_MINUS_TYPE : return "umin";
223  case OPERATION_BINARY_ASSIGN_TYPE : return "assign";
224  case OPERATION_BINARY_INPLACE_ADD_TYPE : return "ip_add";
225  case OPERATION_BINARY_INPLACE_SUB_TYPE : return "ip_sub";
226  case OPERATION_BINARY_ADD_TYPE : return "add";
227  case OPERATION_BINARY_SUB_TYPE : return "sub";
228  case OPERATION_BINARY_MULT_TYPE : return "mult";
229  case OPERATION_BINARY_ELEMENT_PROD_TYPE : return "eprod";
230  case OPERATION_BINARY_DIV_TYPE : return "div";
231  case OPERATION_BINARY_ELEMENT_DIV_TYPE : return "ediv";
232  case OPERATION_BINARY_ACCESS_TYPE : return "acc";
233  default : return evaluate(type);
234  }
235 }
236 
239 {
240 private:
241  std::map<std::string, std::string> const & accessors_;
242  std::string & str_;
243  mapping_type const & mapping_;
244 
245 public:
246  evaluate_expression_traversal(std::map<std::string, std::string> const & accessors, std::string & str, mapping_type const & mapping) : accessors_(accessors), str_(str), mapping_(mapping){ }
247 
248  void call_before_expansion(scheduler::statement const & statement, vcl_size_t root_idx) const
249  {
250  scheduler::statement_node const & root_node = statement.array()[root_idx];
252  && !utils::node_leaf(root_node.op))
253  str_+=tree_parsing::evaluate(root_node.op.type);
254  str_+="(";
255 
256  }
257 
258  void call_after_expansion(scheduler::statement const & /*statement*/, vcl_size_t /*root_idx*/) const
259  {
260  str_+=")";
261  }
262 
263  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t leaf) const
264  {
265  scheduler::statement_node const & root_node = statement.array()[root_idx];
266  mapping_type::key_type key = std::make_pair(root_idx, leaf);
267  if (leaf==PARENT_NODE_TYPE)
268  {
269  if (utils::node_leaf(root_node.op))
270  str_ += at(mapping_, key)->evaluate(accessors_);
271  else if (utils::elementwise_operator(root_node.op))
272  str_ += tree_parsing::evaluate(root_node.op.type);
274  str_ += ",";
275  }
276  else
277  {
278  if (leaf==LHS_NODE_TYPE)
279  {
281  str_ += at(mapping_, key)->evaluate(accessors_);
282  }
283 
284  if (leaf==RHS_NODE_TYPE)
285  {
287  str_ += at(mapping_, key)->evaluate(accessors_);
288  }
289  }
290  }
291 };
292 
293 inline std::string evaluate(leaf_t leaf, std::map<std::string, std::string> const & accessors,
294  scheduler::statement const & statement, vcl_size_t root_idx, mapping_type const & mapping)
295 {
296  std::string res;
297  evaluate_expression_traversal traversal_functor(accessors, res, mapping);
298  scheduler::statement_node const & root_node = statement.array()[root_idx];
299 
300  if (leaf==RHS_NODE_TYPE)
301  {
303  tree_parsing::traverse(statement, root_node.rhs.node_index, traversal_functor, false);
304  else
305  traversal_functor(statement, root_idx, leaf);
306  }
307  else if (leaf==LHS_NODE_TYPE)
308  {
310  tree_parsing::traverse(statement, root_node.lhs.node_index, traversal_functor, false);
311  else
312  traversal_functor(statement, root_idx, leaf);
313  }
314  else
315  tree_parsing::traverse(statement, root_idx, traversal_functor, false);
316 
317  return res;
318 }
319 
320 inline void evaluate(utils::kernel_generation_stream & stream, leaf_t leaf, std::map<std::string, std::string> const & accessors,
321  statements_container const & statements, std::vector<mapping_type> const & mappings)
322 {
323  statements_container::data_type::const_iterator sit;
324  std::vector<mapping_type>::const_iterator mit;
325 
326  for (mit = mappings.begin(), sit = statements.data().begin(); sit != statements.data().end(); ++mit, ++sit)
327  stream << evaluate(leaf, accessors, *sit, sit->root(), *mit) << ";" << std::endl;
328 }
329 
330 
333 {
334 public:
335  process_traversal(std::string const & type_key, std::string const & to_process, utils::kernel_generation_stream & stream,
336  mapping_type const & mapping, std::set<std::string> & already_processed) : type_key_(type_key), to_process_(to_process), stream_(stream), mapping_(mapping), already_processed_(already_processed){ }
337 
338  void operator()(scheduler::statement const & /*statement*/, vcl_size_t root_idx, leaf_t leaf) const
339  {
340  mapping_type::const_iterator it = mapping_.find(std::make_pair(root_idx, leaf));
341  if (it!=mapping_.end())
342  {
343  mapped_object * obj = it->second.get();
344  if (obj->type_key()==type_key_)
345  {
346  if (already_processed_.insert(obj->process("#name")).second)
347  stream_ << obj->process(to_process_) << std::endl;
348  }
349  }
350  }
351 
352 private:
353  std::string const & type_key_;
354  std::string const & to_process_;
356  mapping_type const & mapping_;
357  std::set<std::string> & already_processed_;
358 };
359 
360 inline void process(utils::kernel_generation_stream & stream, leaf_t leaf, std::string const & type_key, std::string const & to_process,
361  scheduler::statement const & statement, vcl_size_t root_idx, mapping_type const & mapping, std::set<std::string> & already_processed)
362 {
363  process_traversal traversal_functor(type_key, to_process, stream, mapping, already_processed);
364  scheduler::statement_node const & root_node = statement.array()[root_idx];
365 
366  if (leaf==RHS_NODE_TYPE)
367  {
369  tree_parsing::traverse(statement, root_node.rhs.node_index, traversal_functor, true);
370  else
371  traversal_functor(statement, root_idx, leaf);
372  }
373  else if (leaf==LHS_NODE_TYPE)
374  {
376  tree_parsing::traverse(statement, root_node.lhs.node_index, traversal_functor, true);
377  else
378  traversal_functor(statement, root_idx, leaf);
379  }
380  else
381  {
382  tree_parsing::traverse(statement, root_idx, traversal_functor, true);
383  }
384 }
385 
386 inline void process(utils::kernel_generation_stream & stream, leaf_t leaf, std::string const & type_key, std::string const & to_process,
387  statements_container const & statements, std::vector<mapping_type> const & mappings)
388 {
389  statements_container::data_type::const_iterator sit;
390  std::vector<mapping_type>::const_iterator mit;
391  std::set<std::string> already_processed;
392 
393  for (mit = mappings.begin(), sit = statements.data().begin(); sit != statements.data().end(); ++mit, ++sit)
394  process(stream, leaf, type_key, to_process, *sit, sit->root(), *mit, already_processed);
395 }
396 
397 
399 private:
400  static void append_id(char * & ptr, unsigned int val)
401  {
402  if (val==0)
403  *ptr++='0';
404  else
405  while (val>0)
406  {
407  *ptr++= (char)('0' + (val % 10));
408  val /= 10;
409  }
410  }
411 
412 public:
413  typedef void result_type;
414 
415  statement_representation_functor(symbolic_binder & binder, char *& ptr) : binder_(binder), ptr_(ptr){ }
416 
417  template<class NumericT>
418  inline result_type operator()(NumericT const & /*scal*/) const
419  {
420  *ptr_++='h'; //host
421  *ptr_++='s'; //scalar
423  }
424 
426  template<class NumericT>
427  inline result_type operator()(scalar<NumericT> const & scal) const
428  {
429  *ptr_++='s'; //scalar
431  append_id(ptr_, binder_.get(&traits::handle(scal)));
432  }
433 
435  template<class NumericT>
436  inline result_type operator()(vector_base<NumericT> const & vec) const
437  {
438  *ptr_++='v'; //vector
440  append_id(ptr_, binder_.get(&traits::handle(vec)));
441  }
442 
444  template<class NumericT>
446  {
447  *ptr_++='i'; //implicit
448  *ptr_++='v'; //vector
450  }
451 
453  template<class NumericT>
454  inline result_type operator()(matrix_base<NumericT> const & mat) const
455  {
456  *ptr_++='m'; //Matrix
457  *ptr_++=mat.row_major()?'r':'c';
459  append_id(ptr_, binder_.get(&traits::handle(mat)));
460  }
461 
463  template<class NumericT>
465  {
466  *ptr_++='i'; //implicit
467  *ptr_++='m'; //matrix
469  }
470 
471  static inline void append(char*& p, const char * str)
472  {
473  vcl_size_t n = std::strlen(str);
474  std::memcpy(p, str, n);
475  p+=n;
476  }
477 
478  inline void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t leaf_t) const
479  {
480  scheduler::statement_node const & root_node = statement.array()[root_idx];
482  utils::call_on_element(root_node.lhs, *this);
484  utils::call_on_element(root_node.rhs, *this);
485  else if (leaf_t==PARENT_NODE_TYPE)
486  append_id(ptr_,root_node.op.type);
487  }
488 
489 private:
490  symbolic_binder & binder_;
491  char *& ptr_;
492 };
493 
494 inline std::string statements_representation(statements_container const & statements, binding_policy_t binding_policy)
495 {
496  std::vector<char> program_name_vector(256);
497  char* program_name = &(program_name_vector[0]);
498  if (statements.order()==statements_container::INDEPENDENT)
499  *program_name++='i';
500  else
501  *program_name++='s';
502  tools::shared_ptr<symbolic_binder> binder = make_binder(binding_policy);
503  for (statements_container::data_type::const_iterator it = statements.data().begin(); it != statements.data().end(); ++it)
504  tree_parsing::traverse(*it, it->root(), tree_parsing::statement_representation_functor(*binder, program_name),true);
505  *program_name='\0';
506  return std::string(&(program_name_vector[0]));
507 }
508 
509 }
510 }
511 }
512 #endif
evaluate_expression_traversal(std::map< std::string, std::string > const &accessors, std::string &str, mapping_type const &mapping)
void operator()(scheduler::statement const &statement, vcl_size_t root_idx, leaf_t leaf) const
This class represents a single scalar value on the GPU and behaves mostly like a built-in scalar type...
Definition: forwards.h:227
void call_before_expansion(scheduler::statement const &, vcl_size_t) const
void call_before_expansion(scheduler::statement const &statement, vcl_size_t root_idx) const
void operator()(scheduler::statement const &statement, vcl_size_t root_idx, leaf_t) const
Exception for the case the generator is unable to deal with the operation.
Definition: forwards.h:163
process_traversal(std::string const &type_key, std::string const &to_process, utils::kernel_generation_stream &stream, mapping_type const &mapping, std::set< std::string > &already_processed)
void traverse(scheduler::statement const &statement, vcl_size_t root_idx, Fun const &fun, bool inspect)
Recursively execute a functor on a statement.
statement_node_subtype subtype
Definition: forwards.h:340
bool elementwise_operator(scheduler::op_element const &op)
Definition: utils.hpp:462
This file provides the forward declarations for the main types used within ViennaCL.
statement_node_type_family type_family
Definition: forwards.h:339
container_type const & array() const
Definition: forwards.h:528
std::list< scheduler::statement > const & data() const
Definition: forwards.h:282
bool node_leaf(scheduler::op_element const &op)
Definition: utils.hpp:443
operation_node_type_family type_family
Definition: forwards.h:473
bool(* pred_t)(scheduler::statement_node const &node)
float NumericT
Definition: bisect.cpp:40
result_type operator()(matrix_base< NumericT > const &mat) const
Matrix mapping.
void operator()(scheduler::statement const &statement, vcl_size_t root_idx, leaf_t) const
statement_node_subtype
Encodes the type of a node in the statement tree.
Definition: forwards.h:264
Base class for representing matrices where the individual entries are not all stored explicitly...
Definition: matrix_def.hpp:35
bool elementwise_function(scheduler::op_element const &op)
Definition: utils.hpp:476
Map ViennaCL objects to generator wrappers.
result_type operator()(implicit_vector_base< NumericT > const &) const
Implicit vector mapping.
std::string evaluate(leaf_t leaf, std::map< std::string, std::string > const &accessors, scheduler::statement const &statement, vcl_size_t root_idx, mapping_type const &mapping)
virtual unsigned int get(viennacl::backend::mem_handle const *ph)=0
A shared pointer class similar to boost::shared_ptr. Reimplemented in order to avoid a Boost-dependen...
Definition: shared_ptr.hpp:83
Forwards declaration.
std::size_t vcl_size_t
Definition: forwards.h:75
std::string process(std::string const &in) const
base functor class for traversing a statement
Provides the datastructures for dealing with a single statement such as 'x = y + z;'.
functor for fetching or writing-back the elements in a statement
operation_node_type
Enumeration for identifying the possible operations.
Definition: forwards.h:68
result_type operator()(implicit_matrix_base< NumericT > const &) const
Implicit matrix mapping.
std::map< mapping_key, tools::shared_ptr< mapped_object > > mapping_type
Definition: forwards.h:191
std::string statements_representation(statements_container const &statements, binding_policy_t binding_policy)
void operator()(scheduler::statement const &statement, vcl_size_t root_idx, leaf_t leaf_t) const
result_type operator()(vector_base< NumericT > const &vec) const
Vector mapping.
filter(pred_t pred, std::vector< vcl_size_t > &out)
Internal utils.
bool row_major() const
Definition: matrix_def.hpp:248
result_type operator()(scalar< NumericT > const &scal) const
Scalar mapping.
void call_after_expansion(scheduler::statement const &, vcl_size_t) const
void call_after_expansion(scheduler::statement const &, vcl_size_t) const
operation_node_type type
Definition: forwards.h:474
The main class for representing a statement such as x = inner_prod(y,z); at runtime.
Definition: forwards.h:502
Common base class for representing vectors where the entries are not all stored explicitly.
Definition: vector_def.hpp:36
viennacl::backend::mem_handle & handle(T &obj)
Returns the generic memory handle of an object. Non-const version.
Definition: handle.hpp:41
const char * operator_string(scheduler::operation_node_type type)
void operator()(scheduler::statement const &, vcl_size_t root_idx, leaf_t leaf) const
ValueT const & at(std::map< KeyT, ValueT > const &map, KeyT const &key)
Emulation of C++11's .at() member for std::map<>, const-version.
Definition: forwards.h:142
Main datastructure for an node in the statement tree.
Definition: forwards.h:478
tools::shared_ptr< symbolic_binder > make_binder(binding_policy_t policy)
Definition: forwards.h:251
functor for generating the expression string from a statement
void process(utils::kernel_generation_stream &stream, leaf_t leaf, std::string const &type_key, std::string const &to_process, scheduler::statement const &statement, vcl_size_t root_idx, mapping_type const &mapping, std::set< std::string > &already_processed)
filter_elements(scheduler::statement_node_subtype subtype, std::vector< scheduler::lhs_rhs_element > &out)