Version: 1.0
forest.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020, the GRAPHGEN contributors, as
2 // shown by the AUTHORS file. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6 
7 #include "forest.h"
8 
9 #include <optional>
10 
11 #include <cassert>
12 
13 #include "drag_compressor.h"
14 #include "forest_optimizer.h"
15 
16 using namespace std;
17 
19  const pixel_set& ps,
20  const constraints& initial_constraints) {
21  // The input BinaryDrag should have just one root!
22  if (bd.roots_.size() > 1) {
23  throw;
24  }
25 
26  // Setup next_tree_ for holding a reference to the start tree in first position
27  next_tree_.push_back(0);
28 
29  // Apply predefined constraints
31  tmp.AddRoot(Reduce(bd.roots_[0], tmp, initial_constraints));
32 
33  // Initialize next trees indexes in each leaf with sequential values.
34  InitNextRec(tmp.roots_[0]);
35 
36  /*********************
37  * START LINE TREE *
38  *********************/
39 
40  // Create start tree constraints and add it to the drag f_.
41  // The root of the start tree will be the first one in the
42  // BinaryDrag vector of roots.
43  {
44  constraints start_constr;
45  using namespace std;
46  for (const auto& p : ps) {
47  if (p.GetDx() < 0)
48  start_constr[p.name_] = 0;
49  }
50  f_.AddRoot(Reduce(tmp.GetRoot(), f_, start_constr));
51  }
52  // Note that the start line tree is generated in a different
53  // way but it is part of the main forest.
54 
55  /********************
56  * MAIN TREES *
57  ********************/
58 
59  // Create all the possible reduced trees storing them into f_
60  CreateReducedDrag(tmp, f_, ps);
61 
62  // Remove duplicate trees and then useless conditions until convergence
63  while (RemoveEqualTrees()) {
64  RemoveUselessConditions();
65  }
66 
67  /********************
68  * END LINE TREES *
69  ********************/
70 
71  // For each tree we need to create at least one end tree with end line constraints.
72  // With BBDT for example we need two end trees for each tree for example. This is
73  // explained below representing borderline cases:
74  //
75  // -4 -3 -2 -1 | w
76  // |
77  // +-------+-------+-------+
78  // | a b | c d | e f |
79  // | g h | i j | k l |
80  // A: +-------+-------+-------+ c = w - 4 (No problem)
81  // | m n | o p | |
82  // | q r | s t | |
83  // +-------+-------+ |
84  // |
85  // +-------+-------+---|---+
86  // | a b | c d | e | f |
87  // | g h | i j | k | l |
88  // B: +-------+-------+---|---+ c = w - 3 (No problem)
89  // | m n | o p | |
90  // | q r | s t | |
91  // +-------+-------+ |
92  // |
93  // +-------+-------+-------+
94  // | a b | c d | e f |
95  // | g h | i j | k l |
96  // C: +-------+-------+-------+ c = w - 2 (This requires one group of end-trees)
97  // | m n | o p |
98  // | q r | s t |
99  // +-------+-------+
100  // |
101  // +-------+---|---+-------+
102  // | a b | c | d | e f |
103  // | g h | i | j | k l |
104  // D: +-------+---|---+-------+ c = w - 1 (This requires one group of end-trees)
105  // | m n | o | p |
106  // | q r | s | t |
107  // +-------+---|---+
108  // |
109  {
110  for (int out_offset = 1;; ++out_offset) {
111  // Create constraints for the last n-th column (n = out_offset)
112  constraints end_constr;
113  for (const auto& p : ps) {
114  if (p.GetDx() >= out_offset)
115  end_constr[p.name_] = 0;
116  }
117  if (end_constr.empty()) {
118  break;
119  }
120 
121  end_forests_.push_back(BinaryDrag<conact>());
122 
123  for (const auto& t : f_.roots_) {
124  end_forests_.back().AddRoot(Reduce(t, end_forests_.back(), end_constr));
125  }
126 
127  assert(f_.roots_.size() == end_forests_.back().roots_.size());
128  }
129 
130  // Initialize the mapping between main trees (including the start line tree) and end trees
131  main_end_tree_mapping_ = vector<vector<size_t>>(end_forests_.size(), vector<size_t>(f_.roots_.size()));
132  for (auto& etm : main_end_tree_mapping_) {
133  iota(etm.begin(), etm.end(), 0);
134  }
135  end_next_tree_ = main_end_tree_mapping_;
136 
137  // For each tree in the end forests the value of the next tree is set to uint32_t max value
138  // max value can be replaced with any value, but all end trees must share the same fake next
139  // to be able to delete equal (useless) end trees.
140  for (auto& f : end_forests_) { // For each end forest
141  for (auto& n : f.nodes_) { // For each node of the forest
142  if (n->isleaf()) {
143  n->data.next = numeric_limits<size_t>::max();
144  }
145  }
146  }
147  }
148 
149  // Removes duplicate end-trees and then useless conditions until convergence
150  while (RemoveEqualEndTrees()) {
151  RemoveEndTreesUselessConditions();
152  }
153 }
154 
155 //void LineForestHandler::RebuildDisjointTrees() {
156 //
157 // vector<BinaryDrag<conact>> new_trees;
158 //
159 // for (auto& t : trees_) {
160 // // Here Reduce() is used just to recreate trees
161 // BinaryDrag<conact> new_t;
162 // new_t.SetRoot(Reduce(t.GetRoot(), new_t, {}));
163 // new_trees.push_back(move(new_t));
164 // }
165 //
166 // trees_ = move(new_trees);
167 //}
168 
169 //void LineForestHandler::RebuildDisjointEndTrees() {
170 //
171 // vector<vector<BinaryDrag<conact>>> new_trees;
172 // for (auto& tg : end_trees_) {
173 // new_trees.emplace_back();
174 // for (auto& t : tg) {
175 // // Here Reduce() is used just to recreate trees
176 // BinaryDrag<conact> new_t;
177 // new_t.SetRoot(Reduce(t.GetRoot(), new_t, {}));
178 // new_trees.back().push_back(move(new_t));
179 // }
180 // }
181 // end_trees_ = new_trees;
182 //
183 //}
184 
185 // See RemoveUselessConditions
187  if (!n->isleaf()) {
188  if (EqualTrees(n->left, n->right)) {
189  changed = true;
190  *n = *n->left;
191  RemoveUselessConditionsRec(n, changed);
192  }
193  else {
194  RemoveUselessConditionsRec(n->left, changed);
195  RemoveUselessConditionsRec(n->right, changed);
196  }
197  }
198 }
199 
200 // Removes useless conditions inside the forest.
201 // That means that the subtree:
202 // a
203 // 0/ \1
204 // c ...
205 // 0/ \1
206 // 5 5
207 // will be transformed into:
208 // a
209 // 0/ \1
210 // 5 ...
211 // these useless condition may appears after the execution of CreateReducedTrees.
213  bool changed;
214  do {
215  changed = false;
216  for (auto& r : f_.roots_) {
217  RemoveUselessConditionsRec(r, changed);
218  }
219  } while (changed);
220 }
222  bool changed;
223  do {
224  changed = false;
225  for (auto& f : end_forests_) {
226  for (auto& t : f.roots_) {
227  RemoveUselessConditionsRec(t, changed);
228  }
229  }
230  } while (changed);
231 }
232 
234  bool changed = false;
235  for (size_t i = 0; i < end_forests_.size(); ++i) {
236  changed |= RemoveTrees(EqualTrees, end_next_tree_[i], end_forests_[i], true, main_end_tree_mapping_[i]);
237  }
238  return changed;
239 }
240 
242  // TODO
243  return false;
244  //return RemoveEndTrees(equivalent_trees);
245 }
246 
248  if (n->isleaf()) {
249  n->data.next = next_tree_[n->data.next];
250  }
251  else {
252  UpdateNext(n->left);
253  UpdateNext(n->right);
254  }
255 }
256 
258  return RemoveTrees(equivalent_trees, next_tree_, f_);
259 }
260 
262  return RemoveTrees(EqualTrees, next_tree_, f_);
263 }
264 
265 // Removes duplicate trees inside the forest
266 bool LineForestHandler::RemoveTrees(bool(*FunctionPtr)(const BinaryDrag<conact>::node* n1, const BinaryDrag<conact>::node* n2),
267  vector<size_t>& next_tree,
268  BinaryDrag<conact>& f,
269  bool are_end_trees,
270  vector<size_t>& mapping) {
271  // Find which trees are identical and mark them in next_tree
272  bool found = false;
273  for (size_t i = 0; i < next_tree.size() - 1; ++i) {
274  if (next_tree[i] == i) {
275  for (size_t j = i + 1; j < next_tree.size(); ++j) {
276  if (next_tree[j] == j) {
277  if (FunctionPtr(f.roots_[i], f.roots_[j])) {
278  next_tree[j] = i;
279  found = true;
280  if (FunctionPtr == equivalent_trees) {
281  IntersectTrees(f.roots_[i], f.roots_[j]);
282  }
283  }
284  }
285  }
286  }
287  }
288  if (!found)
289  return false;
290 
291  // Flatten the trees indexes
292  size_t new_index = 0;
293  for (size_t i = 0; i < next_tree.size(); ++i) {
294  if (next_tree[i] == i) {
295  next_tree[i] = new_index;
296  ++new_index;
297  }
298  else {
299  next_tree[i] = next_tree[next_tree[i]];
300  }
301  }
302 
303  // Remove roots that are now useless
304  new_index = 0;
305  for (size_t i = 0; i < next_tree.size(); ++i) {
306  if (next_tree[i] != new_index) {
307  f.roots_[i] = nullptr;
308  }
309  else {
310  ++new_index;
311  }
312  }
313  f.roots_.erase(remove(begin(f.roots_), end(f.roots_), nullptr), end(f.roots_));
314 
315  if (are_end_trees) {
316  // If we are dealing with end trees then we need to update the
317  // mapping main-end trees because it changed
318  for (size_t i = 0; i < mapping.size(); ++i) {
319  mapping[i] = next_tree[mapping[i]];
320  }
321  }else{
322  // If we are dealing with main trees then we need to update the
323  // id of the next tree because they changed
324  for (auto& r : f.roots_) {
325  UpdateNext(r);
326  }
327  }
328 
329  next_tree.resize(f.roots_.size());
330  iota(begin(next_tree), end(next_tree), 0);
331  return true;
332 }
333 
334 // Initializes leave's next trees (drag) of a tree (drag) with sequential values.
336  if (n->isleaf()) {
337  // Set the next tree to be used for each leaf
338  n->data.next = next_tree_.size();
339  // Setup a structure for managing equal trees
340  next_tree_.push_back(next_tree_.size());
341  }
342  else {
343  InitNextRec(n->left);
344  InitNextRec(n->right);
345  }
346 }
347 
348 // Perform tree pruning by removing useless nodes. Useless nodes are identified looking at given constraints
350  if (n->isleaf()) {
351  return t.make_node(n->data);
352  }
353  else {
354  auto it = constr.find(n->data.condition);
355  if (it != end(constr)) {
356  if (it->second == 0)
357  return Reduce(n->left, t, constr);
358  else
359  return Reduce(n->right, t, constr);
360  }
361  else {
362  return t.make_node(n->data, Reduce(n->left, t, constr), Reduce(n->right, t, constr));
363  }
364  }
365 }
node * GetRoot() const
Returns the last root of the BinaryDrag.
Definition: drag.h:66
void AddRoot(node *r)
Adds a new root to the vector of roots.
Definition: drag.h:61
std::vector< node * > roots_
Definition: drag.h:58
node * make_node(Args &&... args)
Creates and returns a new node updating the nodes_ vector.
Definition: drag.h:53
void IntersectTrees(BinaryDrag< conact >::node *n1, BinaryDrag< conact >::node *n2)
bool EqualTrees(const BinaryDrag< conact >::node *n1, const BinaryDrag< conact >::node *n2)
Checks whether two (sub)trees 'n1' and 'n2' are equal or nor.
bool equivalent_trees(const BinaryDrag< conact >::node *n1, const BinaryDrag< conact >::node *n2)
Definition: conact_tree.cpp:86
void RemoveUselessConditionsRec(BinaryDrag< conact >::node *n, bool &changed)
Definition: forest.cpp:186
std::map< std::string, int > constraints
Definition: forest.h:46
Creates forest of trees pruning original tree.
Definition: forest.h:61
void RemoveUselessConditions()
Definition: forest.cpp:212
void UpdateNext(BinaryDrag< conact >::node *n)
Definition: forest.cpp:247
void RemoveEndTreesUselessConditions()
Definition: forest.cpp:221
static BinaryDrag< conact >::node * Reduce(const BinaryDrag< conact >::node *n, BinaryDrag< conact > &t, const constraints &constr)
Definition: forest.cpp:349
bool RemoveEqualTrees()
Definition: forest.cpp:261
void InitNextRec(BinaryDrag< conact >::node *n)
Definition: forest.cpp:335
bool RemoveEqualEndTrees()
Definition: forest.cpp:233
bool RemoveEquivalentTrees()
Definition: forest.cpp:257
bool RemoveEquivalentEndTrees()
Definition: forest.cpp:241