ViennaCL - The Vienna Computing Library  1.6.1
Free open-source GPU-accelerated linear algebra and solver library.
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-2014, 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 PDF 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 
34 
35 namespace viennacl
36 {
37 namespace device_specific
38 {
39 namespace tree_parsing
40 {
41 
44 {
45 public:
48 };
49 
51 template<class Fun>
52 inline void traverse(scheduler::statement const & statement, vcl_size_t root_idx, Fun const & fun, bool inspect)
53 {
54  scheduler::statement_node const & root_node = statement.array()[root_idx];
55  bool recurse = utils::node_leaf(root_node.op)?inspect:true;
56 
57  fun.call_before_expansion(statement, root_idx);
58 
59  //Lhs:
60  if (recurse)
61  {
63  traverse(statement, root_node.lhs.node_index, fun, inspect);
65  fun(statement, root_idx, LHS_NODE_TYPE);
66  }
67 
68  //Self:
69  fun(statement, root_idx, PARENT_NODE_TYPE);
70 
71  //Rhs:
72  if (recurse && root_node.rhs.type_family!=scheduler::INVALID_TYPE_FAMILY)
73  {
75  traverse(statement, root_node.rhs.node_index, fun, inspect);
77  fun(statement, root_idx, RHS_NODE_TYPE);
78  }
79 
80  fun.call_after_expansion(statement, root_idx);
81 }
82 
83 class filter : public traversal_functor
84 {
85 public:
86  typedef bool (*pred_t)(scheduler::statement_node const & node);
87 
88  filter(pred_t pred, std::vector<vcl_size_t> & out) : pred_(pred), out_(out){ }
89 
90  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t) const
91  {
92  scheduler::statement_node const * root_node = &statement.array()[root_idx];
93  if (pred_(*root_node))
94  out_.push_back(root_idx);
95  }
96 private:
97  pred_t pred_;
98  std::vector<vcl_size_t> & out_;
99 };
100 
102 {
103 public:
104  filter_elements(scheduler::statement_node_subtype subtype, std::vector<scheduler::lhs_rhs_element> & out) : subtype_(subtype), out_(out) { }
105 
106  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t) const
107  {
108  scheduler::statement_node const * root_node = &statement.array()[root_idx];
109  if (root_node->lhs.subtype==subtype_)
110  out_.push_back(root_node->lhs);
111  if (root_node->rhs.subtype==subtype_)
112  out_.push_back(root_node->rhs);
113  }
114 private:
116  std::vector<scheduler::lhs_rhs_element> & out_;
117 };
118 
120 inline const char * evaluate(scheduler::operation_node_type type)
121 {
122  using namespace scheduler;
123  // unary expression
124  switch (type)
125  {
126  //Function
127  case OPERATION_UNARY_ABS_TYPE : return "abs";
128  case OPERATION_UNARY_ACOS_TYPE : return "acos";
129  case OPERATION_UNARY_ASIN_TYPE : return "asin";
130  case OPERATION_UNARY_ATAN_TYPE : return "atan";
131  case OPERATION_UNARY_CEIL_TYPE : return "ceil";
132  case OPERATION_UNARY_COS_TYPE : return "cos";
133  case OPERATION_UNARY_COSH_TYPE : return "cosh";
134  case OPERATION_UNARY_EXP_TYPE : return "exp";
135  case OPERATION_UNARY_FABS_TYPE : return "fabs";
136  case OPERATION_UNARY_FLOOR_TYPE : return "floor";
137  case OPERATION_UNARY_LOG_TYPE : return "log";
138  case OPERATION_UNARY_LOG10_TYPE : return "log10";
139  case OPERATION_UNARY_SIN_TYPE : return "sin";
140  case OPERATION_UNARY_SINH_TYPE : return "sinh";
141  case OPERATION_UNARY_SQRT_TYPE : return "sqrt";
142  case OPERATION_UNARY_TAN_TYPE : return "tan";
143  case OPERATION_UNARY_TANH_TYPE : return "tanh";
144 
145  case OPERATION_UNARY_CAST_CHAR_TYPE : return "(char)";
146  case OPERATION_UNARY_CAST_UCHAR_TYPE : return "(uchar)";
147  case OPERATION_UNARY_CAST_SHORT_TYPE : return "(short)";
148  case OPERATION_UNARY_CAST_USHORT_TYPE : return "(ushort)";
149  case OPERATION_UNARY_CAST_INT_TYPE : return "(int)";
150  case OPERATION_UNARY_CAST_UINT_TYPE : return "(uint)";
151  case OPERATION_UNARY_CAST_LONG_TYPE : return "(long)";
152  case OPERATION_UNARY_CAST_ULONG_TYPE : return "(ulong)";
153  case OPERATION_UNARY_CAST_HALF_TYPE : return "(half)";
154  case OPERATION_UNARY_CAST_FLOAT_TYPE : return "(float)";
155  case OPERATION_UNARY_CAST_DOUBLE_TYPE : return "(double)";
156 
157  case OPERATION_BINARY_ELEMENT_ARGFMAX_TYPE : return "argfmax";
158  case OPERATION_BINARY_ELEMENT_ARGMAX_TYPE : return "argmax";
159  case OPERATION_BINARY_ELEMENT_ARGFMIN_TYPE : return "argfmin";
160  case OPERATION_BINARY_ELEMENT_ARGMIN_TYPE : return "argmin";
161  case OPERATION_BINARY_ELEMENT_POW_TYPE : return "pow";
162 
163  //Arithmetic
164  case OPERATION_UNARY_MINUS_TYPE : return "-";
165  case OPERATION_BINARY_ASSIGN_TYPE : return "=";
166  case OPERATION_BINARY_INPLACE_ADD_TYPE : return "+=";
167  case OPERATION_BINARY_INPLACE_SUB_TYPE : return "-=";
168  case OPERATION_BINARY_ADD_TYPE : return "+";
169  case OPERATION_BINARY_SUB_TYPE : return "-";
170  case OPERATION_BINARY_MULT_TYPE : return "*";
171  case OPERATION_BINARY_ELEMENT_PROD_TYPE : return "*";
172  case OPERATION_BINARY_DIV_TYPE : return "/";
173  case OPERATION_BINARY_ELEMENT_DIV_TYPE : return "/";
174  case OPERATION_BINARY_ACCESS_TYPE : return "[]";
175 
176  //Relational
177  case OPERATION_BINARY_ELEMENT_EQ_TYPE : return "isequal";
178  case OPERATION_BINARY_ELEMENT_NEQ_TYPE : return "isnotequal";
179  case OPERATION_BINARY_ELEMENT_GREATER_TYPE : return "isgreater";
180  case OPERATION_BINARY_ELEMENT_GEQ_TYPE : return "isgreaterequal";
181  case OPERATION_BINARY_ELEMENT_LESS_TYPE : return "isless";
182  case OPERATION_BINARY_ELEMENT_LEQ_TYPE : return "islessequal";
183 
184  case OPERATION_BINARY_ELEMENT_FMAX_TYPE : return "fmax";
185  case OPERATION_BINARY_ELEMENT_FMIN_TYPE : return "fmin";
186  case OPERATION_BINARY_ELEMENT_MAX_TYPE : return "max";
187  case OPERATION_BINARY_ELEMENT_MIN_TYPE : return "min";
188  //Unary
189  case OPERATION_UNARY_TRANS_TYPE : return "trans";
190 
191  //Binary
192  case OPERATION_BINARY_INNER_PROD_TYPE : return "iprod";
193  case OPERATION_BINARY_MAT_MAT_PROD_TYPE : return "mmprod";
194  case OPERATION_BINARY_MAT_VEC_PROD_TYPE : return "mvprod";
195  case OPERATION_BINARY_VECTOR_DIAG_TYPE : return "vdiag";
196  case OPERATION_BINARY_MATRIX_DIAG_TYPE : return "mdiag";
197  case OPERATION_BINARY_MATRIX_ROW_TYPE : return "row";
198  case OPERATION_BINARY_MATRIX_COLUMN_TYPE : return "col";
199 
200  default : throw generator_not_supported_exception("Unsupported operator");
201  }
202 }
203 
205 {
206  using namespace scheduler;
207  switch (type)
208  {
209  case OPERATION_UNARY_CAST_CHAR_TYPE : return "char";
210  case OPERATION_UNARY_CAST_UCHAR_TYPE : return "uchar";
211  case OPERATION_UNARY_CAST_SHORT_TYPE : return "short";
212  case OPERATION_UNARY_CAST_USHORT_TYPE : return "ushort";
213  case OPERATION_UNARY_CAST_INT_TYPE : return "int";
214  case OPERATION_UNARY_CAST_UINT_TYPE : return "uint";
215  case OPERATION_UNARY_CAST_LONG_TYPE : return "long";
216  case OPERATION_UNARY_CAST_ULONG_TYPE : return "ulong";
217  case OPERATION_UNARY_CAST_HALF_TYPE : return "half";
218  case OPERATION_UNARY_CAST_FLOAT_TYPE : return "float";
219  case OPERATION_UNARY_CAST_DOUBLE_TYPE : return "double";
220 
221  case OPERATION_UNARY_MINUS_TYPE : return "umin";
222  case OPERATION_BINARY_ASSIGN_TYPE : return "assign";
223  case OPERATION_BINARY_INPLACE_ADD_TYPE : return "ip_add";
224  case OPERATION_BINARY_INPLACE_SUB_TYPE : return "ip_sub";
225  case OPERATION_BINARY_ADD_TYPE : return "add";
226  case OPERATION_BINARY_SUB_TYPE : return "sub";
227  case OPERATION_BINARY_MULT_TYPE : return "mult";
228  case OPERATION_BINARY_ELEMENT_PROD_TYPE : return "eprod";
229  case OPERATION_BINARY_DIV_TYPE : return "div";
230  case OPERATION_BINARY_ELEMENT_DIV_TYPE : return "ediv";
231  case OPERATION_BINARY_ACCESS_TYPE : return "acc";
232  default : return evaluate(type);
233  }
234 }
235 
238 {
239 private:
240  std::map<std::string, std::string> const & accessors_;
241  std::string & str_;
242  mapping_type const & mapping_;
243 
244 public:
245  evaluate_expression_traversal(std::map<std::string, std::string> const & accessors, std::string & str, mapping_type const & mapping) : accessors_(accessors), str_(str), mapping_(mapping){ }
246 
247  void call_before_expansion(scheduler::statement const & statement, vcl_size_t root_idx) const
248  {
249  scheduler::statement_node const & root_node = statement.array()[root_idx];
251  && !utils::node_leaf(root_node.op))
252  str_+=tree_parsing::evaluate(root_node.op.type);
253  str_+="(";
254 
255  }
256 
257  void call_after_expansion(scheduler::statement const & /*statement*/, vcl_size_t /*root_idx*/) const
258  {
259  str_+=")";
260  }
261 
262  void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t leaf) const
263  {
264  scheduler::statement_node const & root_node = statement.array()[root_idx];
265  mapping_type::key_type key = std::make_pair(root_idx, leaf);
266  if (leaf==PARENT_NODE_TYPE)
267  {
268  if (utils::node_leaf(root_node.op))
269  str_ += mapping_.at(key)->evaluate(accessors_);
270  else if (utils::elementwise_operator(root_node.op))
271  str_ += tree_parsing::evaluate(root_node.op.type);
273  str_ += ",";
274  }
275  else
276  {
277  if (leaf==LHS_NODE_TYPE)
278  {
280  str_ += mapping_.at(key)->evaluate(accessors_);
281  }
282 
283  if (leaf==RHS_NODE_TYPE)
284  {
286  str_ += mapping_.at(key)->evaluate(accessors_);
287  }
288  }
289  }
290 };
291 
292 inline std::string evaluate(leaf_t leaf, std::map<std::string, std::string> const & accessors,
293  scheduler::statement const & statement, vcl_size_t root_idx, mapping_type const & mapping)
294 {
295  std::string res;
296  evaluate_expression_traversal traversal_functor(accessors, res, mapping);
297  scheduler::statement_node const & root_node = statement.array()[root_idx];
298 
299  if (leaf==RHS_NODE_TYPE)
300  {
302  tree_parsing::traverse(statement, root_node.rhs.node_index, traversal_functor, false);
303  else
304  traversal_functor(statement, root_idx, leaf);
305  }
306  else if (leaf==LHS_NODE_TYPE)
307  {
309  tree_parsing::traverse(statement, root_node.lhs.node_index, traversal_functor, false);
310  else
311  traversal_functor(statement, root_idx, leaf);
312  }
313  else
314  tree_parsing::traverse(statement, root_idx, traversal_functor, false);
315 
316  return res;
317 }
318 
319 inline void evaluate(utils::kernel_generation_stream & stream, leaf_t leaf, std::map<std::string, std::string> const & accessors,
320  statements_container const & statements, std::vector<mapping_type> const & mappings)
321 {
322  statements_container::data_type::const_iterator sit;
323  std::vector<mapping_type>::const_iterator mit;
324 
325  for (mit = mappings.begin(), sit = statements.data().begin(); sit != statements.data().end(); ++mit, ++sit)
326  stream << evaluate(leaf, accessors, *sit, sit->root(), *mit) << ";" << std::endl;
327 }
328 
329 
332 {
333 public:
334  process_traversal(std::string const & type_key, std::string const & to_process, utils::kernel_generation_stream & stream,
335  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){ }
336 
337  void operator()(scheduler::statement const & /*statement*/, vcl_size_t root_idx, leaf_t leaf) const
338  {
339  mapping_type::const_iterator it = mapping_.find(std::make_pair(root_idx, leaf));
340  if (it!=mapping_.end())
341  {
342  mapped_object * obj = it->second.get();
343  if (obj->type_key()==type_key_)
344  {
345  if (already_processed_.insert(obj->process("#name")).second)
346  stream_ << obj->process(to_process_) << std::endl;
347  }
348  }
349  }
350 
351 private:
352  std::string const & type_key_;
353  std::string const & to_process_;
355  mapping_type const & mapping_;
356  std::set<std::string> & already_processed_;
357 };
358 
359 inline void process(utils::kernel_generation_stream & stream, leaf_t leaf, std::string const & type_key, std::string const & to_process,
360  scheduler::statement const & statement, vcl_size_t root_idx, mapping_type const & mapping, std::set<std::string> & already_processed)
361 {
362  process_traversal traversal_functor(type_key, to_process, stream, mapping, already_processed);
363  scheduler::statement_node const & root_node = statement.array()[root_idx];
364 
365  if (leaf==RHS_NODE_TYPE)
366  {
368  tree_parsing::traverse(statement, root_node.rhs.node_index, traversal_functor, true);
369  else
370  traversal_functor(statement, root_idx, leaf);
371  }
372  else if (leaf==LHS_NODE_TYPE)
373  {
375  tree_parsing::traverse(statement, root_node.lhs.node_index, traversal_functor, true);
376  else
377  traversal_functor(statement, root_idx, leaf);
378  }
379  else
380  {
381  tree_parsing::traverse(statement, root_idx, traversal_functor, true);
382  }
383 }
384 
385 inline void process(utils::kernel_generation_stream & stream, leaf_t leaf, std::string const & type_key, std::string const & to_process,
386  statements_container const & statements, std::vector<mapping_type> const & mappings)
387 {
388  statements_container::data_type::const_iterator sit;
389  std::vector<mapping_type>::const_iterator mit;
390  std::set<std::string> already_processed;
391 
392  for (mit = mappings.begin(), sit = statements.data().begin(); sit != statements.data().end(); ++mit, ++sit)
393  process(stream, leaf, type_key, to_process, *sit, sit->root(), *mit, already_processed);
394 }
395 
396 
398 private:
399  static void append_id(char * & ptr, unsigned int val)
400  {
401  if (val==0)
402  *ptr++='0';
403  else
404  while (val>0)
405  {
406  *ptr++= (char)('0' + (val % 10));
407  val /= 10;
408  }
409  }
410 
411 public:
412  typedef void result_type;
413 
414  statement_representation_functor(symbolic_binder & binder, char *& ptr) : binder_(binder), ptr_(ptr){ }
415 
416  template<class NumericT>
417  inline result_type operator()(NumericT const & /*scal*/) const
418  {
419  *ptr_++='h'; //host
420  *ptr_++='s'; //scalar
422  }
423 
425  template<class NumericT>
426  inline result_type operator()(scalar<NumericT> const & scal) const
427  {
428  *ptr_++='s'; //scalar
430  append_id(ptr_, binder_.get(&traits::handle(scal)));
431  }
432 
434  template<class NumericT>
435  inline result_type operator()(vector_base<NumericT> const & vec) const
436  {
437  *ptr_++='v'; //vector
439  append_id(ptr_, binder_.get(&traits::handle(vec)));
440  }
441 
443  template<class NumericT>
444  inline result_type operator()(implicit_vector_base<NumericT> const & /*vec*/) const
445  {
446  *ptr_++='i'; //implicit
447  *ptr_++='v'; //vector
449  }
450 
452  template<class NumericT>
453  inline result_type operator()(matrix_base<NumericT> const & mat) const
454  {
455  *ptr_++='m'; //Matrix
456  *ptr_++=mat.row_major()?'r':'c';
458  append_id(ptr_, binder_.get(&traits::handle(mat)));
459  }
460 
462  template<class NumericT>
463  inline result_type operator()(implicit_matrix_base<NumericT> const & /*mat*/) const
464  {
465  *ptr_++='i'; //implicit
466  *ptr_++='m'; //matrix
468  }
469 
470  static inline void append(char*& p, const char * str)
471  {
472  vcl_size_t n = std::strlen(str);
473  std::memcpy(p, str, n);
474  p+=n;
475  }
476 
477  inline void operator()(scheduler::statement const & statement, vcl_size_t root_idx, leaf_t leaf_t) const
478  {
479  scheduler::statement_node const & root_node = statement.array()[root_idx];
481  utils::call_on_element(root_node.lhs, *this);
483  utils::call_on_element(root_node.rhs, *this);
484  else if (leaf_t==PARENT_NODE_TYPE)
485  append_id(ptr_,root_node.op.type);
486  }
487 
488 private:
489  symbolic_binder & binder_;
490  char *& ptr_;
491 };
492 
493 inline std::string statements_representation(statements_container const & statements, binding_policy_t binding_policy)
494 {
495  std::vector<char> program_name_vector(256);
496  char* program_name = program_name_vector.data();
497  if (statements.order()==statements_container::INDEPENDENT)
498  *program_name++='i';
499  else
500  *program_name++='s';
501  tools::shared_ptr<symbolic_binder> binder = make_binder(binding_policy);
502  for (statements_container::data_type::const_iterator it = statements.data().begin(); it != statements.data().end(); ++it)
503  tree_parsing::traverse(*it, it->root(), tree_parsing::statement_representation_functor(*binder, program_name),true);
504  *program_name='\0';
505  return std::string(program_name_vector.data());
506 }
507 
508 }
509 }
510 }
511 #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:226
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:152
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:342
bool elementwise_operator(scheduler::op_element const &op)
Definition: utils.hpp:454
This file provides the forward declarations for the main types used within ViennaCL.
statement_node_type_family type_family
Definition: forwards.h:341
container_type const & array() const
Definition: forwards.h:530
std::list< scheduler::statement > const & data() const
Definition: forwards.h:271
bool node_leaf(scheduler::op_element const &op)
Definition: utils.hpp:435
operation_node_type_family type_family
Definition: forwards.h:475
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
Main namespace in ViennaCL. Holds all the basic types such as vector, matrix, etc. and defines operations upon them.
Definition: cpu_ram.hpp:29
statement_node_subtype
Encodes the type of a node in the statement tree.
Definition: forwards.h:266
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:468
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:74
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:180
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.
bool(* pred_t)(scheduler::statement_node const &node)
filter(pred_t pred, std::vector< vcl_size_t > &out)
Internal utils.
bool row_major() const
Definition: matrix_def.hpp:239
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:476
The main class for representing a statement such as x = inner_prod(y,z); at runtime.
Definition: forwards.h:504
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
Main datastructure for an node in the statement tree.
Definition: forwards.h:480
tools::shared_ptr< symbolic_binder > make_binder(binding_policy_t policy)
Definition: forwards.h:240
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)