aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
schedule_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief Class containing a schedule of operations to perform on multidims
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 #ifndef DOXYGEN_SHOULD_SKIP_THIS
28 
29 # include <agrum/agrum.h>
30 
31 namespace gum {
32 
33  /// default constructor (construct an empty sequence)
34  template < typename GUM_SCALAR >
35  Schedule< GUM_SCALAR >::Schedule() {
36  // for debugging purposes
37  GUM_CONSTRUCTOR(Schedule);
38  }
39 
40  /// copy constructor
41  template < typename GUM_SCALAR >
47  // for debugging purposes
49 
50  // we must now copy the operations of "from" into "this"
51  for (const auto& elt: from._node2operation_)
53 
54  // update the set of operations involved with each multidim table
55  for (const auto& elt: from._multidim2operations_)
57  }
58 
59  /// destructor
60  template < typename GUM_SCALAR >
62  // for debugging purposes
64 
65  // remove all the operations that were stored
66 
67  for (const auto& elt: _node2operation_)
68  delete elt.second;
69 
70  // remove the sets of operations involved with each multidim table
71  for (const auto& elt: _multidim2operations_)
72  delete elt.second;
73  }
74 
75  /// copy operator
76  template < typename GUM_SCALAR >
78  // avoid self assignment
79  if (this != &from) {
80  // remove all the operations that were stored
81  for (const auto& elt: _node2operation_)
82  delete elt.second;
83 
84  // remove the sets of operations involved with each multidim table
85  for (const auto& elt: _multidim2operations_)
86  delete elt.second;
87 
88  // fill all the data structures with the elements of from
89  _dag_ = from._dag_;
94 
96 
97  for (const auto& elt: from._node2operation_)
99 
100  // update the set of operations involved with each multidim table
102 
103  for (const auto& elt: from._multidim2operations_)
105  }
106 
107  return *this;
108  }
109 
110  /// inserts an operation to be scheduled
111  template < typename GUM_SCALAR >
113  // create a copy of the operation
115 
116  // create a new node for the operation in the DAG
118 
119  // assign the operation to the new node
122 
123  // get the list of multidims passed in arguments and determine which ones
124  // are abstract. If there are some abstract multidims, then the node we
125  // just created must have parents. Try to add these arcs and, if some
126  // parents have not been created yet, indicate it in the
127  // _operations_with_wrong_parents_ list
128  bool operation_available = true;
129 
130  for (const auto par: operation->multiDimArgs()) {
131  if (par->isAbstract()) {
132  // here we shall have a parent in the graph
133  operation_available = false;
135 
138  } else {
140  break;
141  }
142  }
143  }
144 
145  // if the operation is available to be processed, mark it as such
147 
148  // now we shall find whether, upon executing the operation, new multidim
149  // tables are created
151 
152  for (const auto tab: operation->multiDimResults()) {
153  MultiDimId table_id = tab->id();
154 
156 
159  } else {
161  }
162 
164  }
165 
166  // update _multidim2operations_ with the arguments passed to the newly
167  // added operation
168  for (const auto& par: operation->multiDimArgs()) {
169  MultiDimId table_id = par->id();
170 
173  } else {
175  }
176 
178  }
179 
180  return node_id;
181  }
182 
183  /// updates the set of parents for the nodes whoses parents are not correct
184  /// yet
185  template < typename GUM_SCALAR >
186  void Schedule< GUM_SCALAR >::_updateWrongParents_() const {
187  // parse all the nodes whose parents sets are incorrect
188 
189  auto localWrongs = _operations_with_wrong_parents_; // complete copy of NodeSet
190 
191  for (const auto wrong: localWrongs) {
192  // get the arguments passed to wrong and check that those that are
193  // abstract
194  // multidims belong to the schedule
195  const Sequence< const ScheduleMultiDim< GUM_SCALAR >* >& args
197  bool still_wrong = false;
198 
199  for (const auto arg: args) {
200  if (arg->isAbstract() && !_created_multidims_.exists(arg->id())) {
201  still_wrong = true;
202  break;
203  }
204  }
205 
206  // if the operation is not "still_wrong" anymore, then we should remove
207  // it from _operations_with_wrong_parents_ and update its parents set
208  // appropriately. In addition, if there is no parent, then we should
209  // indicate that the operation is now available
210  if (!still_wrong) {
211  Size nb_parents = 0;
212 
213  for (const auto arg: args)
214  if (arg->isAbstract()) {
216  ++nb_parents;
217  }
218 
219  // check that there is no parent
221 
223  }
224  }
225  }
226 
227  /** @brief adds a constraint indicating that an operation cannot be performed
228  * before another one */
229  template < typename GUM_SCALAR >
231  // first, add the constraint into the graph
233 
234  // if op_to_force was available, it is not anymore
236  }
237 
238  /** @brief adds a constraint indicating that an operation cannot be performed
239  * before another one */
240  template < typename GUM_SCALAR >
244  }
245 
246  /** @brief adds a constraint indicating that an operation cannot be performed
247  * before a set of operations */
248  template < typename GUM_SCALAR >
250  for (const auto op: ops_before)
252  }
253 
254  /** @brief adds a constraint indicating that an operation cannot be performed
255  * before a set of operations */
256  template < typename GUM_SCALAR >
257  void Schedule< GUM_SCALAR >::forceAfter(
259  const Set< const ScheduleOperation< GUM_SCALAR >* >& ops_before) {
260  for (const auto op: ops_before)
261  if (*op != op_to_force) forceAfter(op_to_force, *op);
262  }
263 
264  /** @brief adds a constraint indicating that an operation must be performed
265  * before another one */
266  template < typename GUM_SCALAR >
268  // first, add the constraint into the graph
270 
271  // if op_to_force was available, it is not anymore
273  }
274 
275  /** @brief adds a constraint indicating that an operation must be performed
276  * before another one */
277  template < typename GUM_SCALAR >
278  INLINE void
282  }
283 
284  /** @brief adds a constraint indicating that an operation must be performed
285  * before a set of operations */
286  template < typename GUM_SCALAR >
288  for (const auto op: ops_after)
290  }
291 
292  /** @brief adds a constraint indicating that an operation must be performed
293  * before a set of operations */
294  template < typename GUM_SCALAR >
297  const Set< const ScheduleOperation< GUM_SCALAR >* >& ops_after) {
298  for (typename Set< const ScheduleOperation< GUM_SCALAR >* >::const_iterator iter
299  = ops_after.begin();
300  iter != ops_after.end();
301  ++iter) {
302  if (**iter != op_to_force) { forceBefore(op_to_force, **iter); }
303  }
304  }
305 
306  /// returns the set of operations involving a given multidim table
307  template < typename GUM_SCALAR >
309  const ScheduleMultiDim< GUM_SCALAR >& table) const {
310  return *(_multidim2operations_[table.id()]);
311  }
312 
313  /// returns the set of operations involving a given multidim table
314  template < typename GUM_SCALAR >
316  return *(_multidim2operations_[table_id]);
317  }
318 
319  /// returns a DAG indicating in which order the operations can be performed
320  template < typename GUM_SCALAR >
321  INLINE const DAG& Schedule< GUM_SCALAR >::scheduling_dag() const {
322  // first update the set of parents of the nodes of the graph whose parents
323  // were not set correctly
325  return _dag_;
326  }
327 
328  /// returns the scheduleOperation corresponding to an id in the DAG
329  template < typename GUM_SCALAR >
332  return *(_node2operation_[node_id]);
333  }
334 
335  /// returns the id associated to a given operation
336  template < typename GUM_SCALAR >
338  return _operation2node_[op.id()];
339  }
340 
341  /// returns the association between operations anf nodeIds
342  template < typename GUM_SCALAR >
343  INLINE const NodeProperty< const ScheduleOperation< GUM_SCALAR >* >&
344  Schedule< GUM_SCALAR >::operations() const {
345  return reinterpret_cast< NodeProperty< const ScheduleOperation< GUM_SCALAR >* >& >(
347  }
348 
349  /// returns the set of ScheduleOperations that can be executed at once
350  template < typename GUM_SCALAR >
352  // update the set of parents
354  return _operations_available_;
355  }
356 
357  /// executes a given operation
358  template < typename GUM_SCALAR >
359  void Schedule< GUM_SCALAR >::execute(NodeId id) {
360  // update the parents of the sets of nodes which were not correct
361  // !!! it is important to execute the following method before the execution
362  // of operation id: this guarantees that the children of id with exactly
363  // one parent (i.e., id) are now available to be processed
365 
366  // before executing an operation, check that the operation is available
367 
368  if (_dag_.parents(id).size() != 0) {
369  GUM_ERROR(OperationNotAllowed, "the operation cannot be executed yet")
370  }
371 
372  // actually execute the operation
374 
375  // now update the availability of the children of id: a child is available
376  // if and only if it has only one parent
377  const NodeSet& children = _dag_.children(id);
378 
379  for (const auto child: children)
381 
382  // remove the operation's node and its adjacent arcs
384 
385  _dag_.eraseNode(id);
386 
387  delete _node2operation_[id];
388 
390 
392 
394  }
395 
396  /// executes a given operation
397  template < typename GUM_SCALAR >
400  }
401 
402  /** @bried returns an estimation of the number of elementary operations needed
403  * to perform a given ScheduleOperation */
404  template < typename GUM_SCALAR >
405  INLINE float Schedule< GUM_SCALAR >::nbOperations(NodeId id) const {
406  return _node2operation_[id]->nbOperations();
407  }
408 
409  /** @bried returns an estimation of the number of elementary operations needed
410  * to perform a given ScheduleOperation */
411  template < typename GUM_SCALAR >
413  return op.nbOperations();
414  }
415 
416  /// returns the memory consumption used during the execution of an operation
417  template < typename GUM_SCALAR >
418  INLINE std::pair< long, long > Schedule< GUM_SCALAR >::memoryUsage(NodeId id) const {
419  return _node2operation_[id]->memoryUsage();
420  }
421 
422  /// returns the memory consumption used during the execution of an operation
423  template < typename GUM_SCALAR >
424  INLINE std::pair< long, long >
426  return op.memoryUsage();
427  }
428 
429 } /* namespace gum */
430 
431 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643