Turi Create  4.0
optimization_node_info.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_SFRAME_QUERY_ENGINE_QUERY_NODE_INFO_H_
7 #define TURI_SFRAME_QUERY_ENGINE_QUERY_NODE_INFO_H_
8 
9 #include <core/storage/query_engine/operators/operator.hpp>
10 #include <core/storage/query_engine/operators/operator_properties.hpp>
11 #include <core/storage/query_engine/planning/planner_node.hpp>
12 #include <memory>
13 #include <set>
14 
15 namespace turi { namespace query_eval {
16 
17 struct node_info;
18 typedef std::shared_ptr<node_info> node_info_ptr;
19 typedef std::shared_ptr<const node_info> cnode_info_ptr;
20 
21 /** The node_info is the struct over which the optimizations are
22  * performed. It is here to make the query optimization and
23  * execution easy to write and work with.
24  *
25  */
26 struct node_info {
27 
28  node_info(std::shared_ptr<planner_node> _pnode)
29  : pnode(_pnode)
30  , type(pnode->operator_type)
32  {
33 
34  }
35 
36  /** The planner node we are working with.
37  */
38  std::shared_ptr<planner_node> pnode;
39 
40  /** The type of the planner node.
41  */
43 
44  /** The attributes from the operator class.
45  */
47 
48  /** Used internally to track and build the graph. Used for the
49  * query optimizer.
50  */
51  std::vector<node_info_ptr> inputs, outputs;
52 
53  ////////////////////////////////////////////////////////////////////////////////
54  // Buffer stuff used in the optimization
55 
56  bool node_visited = false;
57 
58  // Marked as discarded; typically because another node replaced it.
59  bool node_discarded = false;
60 
61  ////////////////////////////////////////////////////////////////////////////////
62  // Handy methods for the optimization
63 
64  private: mutable size_t _num_columns = size_t(-1);
65  public:
66 
67  /** The number of output columns. Cached.
68  */
69  size_t num_columns() const {
70  if(_num_columns == size_t(-1))
71  _num_columns = infer_planner_node_num_output_columns(pnode);
72 
73  return _num_columns;
74  }
75 
76  bool is_source_node() const { return query_eval::is_source_node(attributes); }
77 
78  bool is_linear_transform() const { return query_eval::is_linear_transform(attributes); }
79 
80  bool is_sublinear_transform() const { return query_eval::is_sublinear_transform(attributes); }
81 
82  size_t length() const { return size_t(infer_planner_node_length(pnode)); }
83 
84  ////////////////////////////////////////////////////////////////////////////////
85  // Shortcut functions for accessing the parameters.
86 
87  const flexible_type& p(const std::string& s) const {
88  auto it = this->pnode->operator_parameters.find(s);
89  ASSERT_MSG(it != this->pnode->operator_parameters.end(),
90  (std::string("Parameter ") + s + " not valid in node of type "
91  + planner_node_type_to_name(this->type)).c_str());
92 
93 
94  return it->second;
95  }
96 
97  bool has_p(const std::string& s) const {
98  auto it = this->pnode->operator_parameters.find(s);
99  return (it != this->pnode->operator_parameters.end());
100  }
101 
102  template <typename T>
103  const T& any_p(const std::string& s) const {
104  auto it = this->pnode->any_operator_parameters.find(s);
105  ASSERT_MSG(it != this->pnode->any_operator_parameters.end(),
106  (std::string("Any-parameter ") + s + " not valid in node of type "
107  + planner_node_type_to_name(this->type)).c_str());
108 
109  return it->second.as<T>();
110  }
111 
112  bool has_any_p(const std::string& s) const {
113  auto it = this->pnode->any_operator_parameters.find(s);
114  return (it != this->pnode->any_operator_parameters.end());
115  }
116 
117  ////////////////////////////////////////////////////////////////////////////////
118  // Convenience functions
119 
120  inline bool input_type_present(planner_node_type t, size_t threshhold = 1) const {
121  size_t count = 0;
122 
123  for(const auto& n : inputs) {
124  if(n->type == t) {
125  ++count;
126  if(threshhold == 1 || count >= threshhold)
127  return true;
128  }
129  }
130 
131  return false;
132  }
133 
134  ////////////////////////////////////////////////////////////////////////////////
135  // Debugging tool
136 
137  private:
138 #ifndef NDEBUG
139  inline void _debug_check_consistency(std::set<const node_info*>& seen) const {
140  if(seen.count(this))
141  return;
142  seen.insert(this);
143 
144  DASSERT_TRUE(pnode->operator_type == type);
145  DASSERT_EQ(pnode->inputs.size(), inputs.size());
146  DASSERT_TRUE(is_source_node() || !inputs.empty());
147 
148  if(attributes.num_inputs != -1)
149  DASSERT_EQ(inputs.size(), attributes.num_inputs);
150 
152 
153  {
154  // Make sure that all inputs and outputs are consistent.
155  std::map<const node_info*, size_t> input_counts;
156  for(size_t i = 0; i < inputs.size(); ++i)
157  input_counts[inputs[i].get()] += 1;
158 
159  for(size_t i = 0; i < inputs.size(); ++i) {
160 
161  DASSERT_TRUE(pnode->inputs[i] == inputs[i]->pnode);
162  size_t n_present = 0;
163  for(const auto& out : inputs[i]->outputs) {
164 
165  if(out.get() == this)
166  ++n_present;
167  }
168 
169  DASSERT_EQ(n_present, input_counts.at(inputs[i].get()));
170  }
171  }
172 
173  {
174  // Make sure that all inputs and outputs are consistent.
175  std::map<const node_info*, size_t> output_counts;
176  for(size_t i = 0; i < outputs.size(); ++i)
177  output_counts[outputs[i].get()] += 1;
178 
179  for(size_t i = 0; i < outputs.size(); ++i) {
180  size_t n_present = 0;
181  for(const auto& out : outputs[i]->inputs) {
182  if(out.get() == this)
183  ++n_present;
184  }
185  DASSERT_EQ(n_present, output_counts.at(outputs[i].get()));
186  }
187 
188  }
189 
190  for(size_t i = 0; i < outputs.size(); ++i) {
191  outputs[i]->_debug_check_consistency(seen);
192  }
193 
194  for(size_t i = 0; i < inputs.size(); ++i) {
195  inputs[i]->_debug_check_consistency(seen);
196  }
197  }
198 #endif
199  public:
200  inline void _debug_check_consistency() const {
201 #ifndef NDEBUG
202  std::set<const node_info*> seen;
203  _debug_check_consistency(seen);
204 #endif
205  }
206 };
207 
208 }}
209 
210 #endif
bool is_linear_transform(const query_operator_attributes &attr)
int64_t infer_planner_node_length(std::shared_ptr< planner_node > pnode)
std::string planner_node_type_to_name(planner_node_type type)
int num_inputs
Number of inputs expected to the operator.
Definition: operator.hpp:56
std::vector< node_info_ptr > inputs
size_t infer_planner_node_num_output_columns(std::shared_ptr< planner_node > pnode)
query_operator_attributes planner_node_type_to_attributes(planner_node_type type)
bool is_sublinear_transform(const query_operator_attributes &attr)
std::shared_ptr< planner_node > pnode
bool is_source_node(const query_operator_attributes &attr)
#define DASSERT_TRUE(cond)
Definition: assertions.hpp:364
query_operator_attributes attributes