aGrUM  0.16.0
schedule_tpl.h
Go to the documentation of this file.
1 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 # include <agrum/agrum.h>
31 
32 namespace gum {
33 
35  template < typename GUM_SCALAR >
37  // for debugging purposes
38  GUM_CONSTRUCTOR(Schedule);
39  }
40 
42  template < typename GUM_SCALAR >
43  Schedule< GUM_SCALAR >::Schedule(const Schedule< GUM_SCALAR >& from) :
44  __dag(from.__dag), __operation2node(from.__operation2node),
45  __created_multidims(from.__created_multidims),
46  __operations_with_wrong_parents(from.__operations_with_wrong_parents),
47  __operations_available(from.__operations_available) {
48  // for debugging purposes
49  GUM_CONS_CPY(Schedule);
50 
51  // we must now copy the operations of "from" into "this"
52  for (const auto& elt : from.__node2operation)
53  __node2operation.insert(elt.first, elt.second->newFactory());
54 
55  // update the set of operations involved with each multidim table
56  for (const auto& elt : from.__multidim2operations)
57  __multidim2operations.insert(elt.first, new NodeSet(*elt.second));
58  }
59 
61  template < typename GUM_SCALAR >
63  // for debugging purposes
64  GUM_DESTRUCTOR(Schedule);
65 
66  // remove all the operations that were stored
67 
68  for (const auto& elt : __node2operation)
69  delete elt.second;
70 
71  // remove the sets of operations involved with each multidim table
72  for (const auto& elt : __multidim2operations)
73  delete elt.second;
74  }
75 
77  template < typename GUM_SCALAR >
78  Schedule< GUM_SCALAR >& Schedule< GUM_SCALAR >::operator=(const Schedule& from) {
79  // avoid self assignment
80  if (this != &from) {
81  // remove all the operations that were stored
82  for (const auto& elt : __node2operation)
83  delete elt.second;
84 
85  // remove the sets of operations involved with each multidim table
86  for (const auto& elt : __multidim2operations)
87  delete elt.second;
88 
89  // fill all the data structures with the elements of from
90  __dag = from.__dag;
91  __operation2node = from.__operation2node;
92  __created_multidims = from.__created_multidims;
93  __operations_with_wrong_parents = from.__operations_with_wrong_parents;
94  __operations_available = from.__operations_available;
95 
96  __node2operation.clear();
97 
98  for (const auto& elt : from.__node2operation)
99  __node2operation.insert(elt.first, elt.second->newFactory());
100 
101  // update the set of operations involved with each multidim table
102  __multidim2operations.clear();
103 
104  for (const auto& elt : from.__multidim2operations)
105  __multidim2operations.insert(elt.first, new NodeSet(*elt.second));
106  }
107 
108  return *this;
109  }
110 
112  template < typename GUM_SCALAR >
113  NodeId
114  Schedule< GUM_SCALAR >::insert(const ScheduleOperation< GUM_SCALAR >& op) {
115  // create a copy of the operation
116  ScheduleOperation< GUM_SCALAR >* operation = op.newFactory();
117 
118  // create a new node for the operation in the DAG
119  NodeId node_id = __dag.addNode();
120 
121  // assign the operation to the new node
122  __node2operation.insert(node_id, operation);
123  __operation2node.insert(operation->id(), node_id);
124 
125  // get the list of multidims passed in arguments and determine which ones
126  // are abstract. If there are some abstract multidims, then the node we
127  // just created must have parents. Try to add these arcs and, if some
128  // parents have not been created yet, indicate it in the
129  // __operations_with_wrong_parents list
130  bool operation_available = true;
131 
132  for (const auto par : operation->multiDimArgs()) {
133  if (par->isAbstract()) {
134  // here we shall have a parent in the graph
135  operation_available = false;
136  MultiDimId multidim_id = par->id();
137 
138  if (__created_multidims.exists(multidim_id)) {
139  __dag.addArc(__created_multidims[multidim_id], node_id);
140  } else {
142  break;
143  }
144  }
145  }
146 
147  // if the operation is available to be processed, mark it as such
148  if (operation_available) __operations_available.insert(node_id);
149 
150  // now we shall find whether, upon executing the operation, new multidim
151  // tables are created
152  NodeSet* involved_ops;
153 
154  for (const auto tab : operation->multiDimResults()) {
155  MultiDimId table_id = tab->id();
156 
157  if (tab->isAbstract()) __created_multidims.insert(table_id, node_id);
158 
159  if (!__multidim2operations.exists(table_id)) {
160  involved_ops = __multidim2operations.insert(table_id, new NodeSet).second;
161  } else {
162  involved_ops = __multidim2operations[table_id];
163  }
164 
165  involved_ops->insert(node_id);
166  }
167 
168  // update __multidim2operations with the arguments passed to the newly
169  // added operation
170  for (const auto& par : operation->multiDimArgs()) {
171  MultiDimId table_id = par->id();
172 
173  if (!__multidim2operations.exists(table_id)) {
174  involved_ops = __multidim2operations.insert(table_id, new NodeSet).second;
175  } else {
176  involved_ops = __multidim2operations[table_id];
177  }
178 
179  involved_ops->insert(node_id);
180  }
181 
182  return node_id;
183  }
184 
187  template < typename GUM_SCALAR >
189  // parse all the nodes whose parents sets are incorrect
190 
191  auto localWrongs =
192  __operations_with_wrong_parents; // complete copy of NodeSet
193 
194  for (const auto wrong : localWrongs) {
195  // get the arguments passed to wrong and check that those that are
196  // abstract
197  // multidims belong to the schedule
198  const Sequence< const ScheduleMultiDim< GUM_SCALAR >* >& args =
199  __node2operation[wrong]->multiDimArgs();
200  bool still_wrong = false;
201 
202  for (const auto arg : args) {
203  if (arg->isAbstract() && !__created_multidims.exists(arg->id())) {
204  still_wrong = true;
205  break;
206  }
207  }
208 
209  // if the operation is not "still_wrong" anymore, then we should remove
210  // it from __operations_with_wrong_parents and update its parents set
211  // appropriately. In addition, if there is no parent, then we should
212  // indicate that the operation is now available
213  if (!still_wrong) {
214  Size nb_parents = 0;
215 
216  for (const auto arg : args)
217  if (arg->isAbstract()) {
218  __dag.addArc(__created_multidims[arg->id()], wrong);
219  ++nb_parents;
220  }
221 
222  // check that there is no parent
223  if (!nb_parents) { __operations_available.insert(wrong); }
224 
226  }
227  }
228  }
229 
232  template < typename GUM_SCALAR >
233  INLINE void Schedule< GUM_SCALAR >::forceAfter(NodeId op_to_force,
234  NodeId op_before) {
235  // first, add the constraint into the graph
236  __dag.addArc(op_before, op_to_force);
237 
238  // if op_to_force was available, it is not anymore
239  __operations_available.erase(op_to_force);
240  }
241 
244  template < typename GUM_SCALAR >
246  const ScheduleOperation< GUM_SCALAR >& op_to_force,
247  const ScheduleOperation< GUM_SCALAR >& op_before) {
248  forceAfter(__operation2node[op_to_force.id()],
249  __operation2node[op_before.id()]);
250  }
251 
254  template < typename GUM_SCALAR >
256  const NodeSet& ops_before) {
257  for (const auto op : ops_before)
258  if (op != op_to_force) forceAfter(op_to_force, op);
259  }
260 
263  template < typename GUM_SCALAR >
265  const ScheduleOperation< GUM_SCALAR >& op_to_force,
266  const Set< const ScheduleOperation< GUM_SCALAR >* >& ops_before) {
267  for (const auto op : ops_before)
268  if (*op != op_to_force) forceAfter(op_to_force, *op);
269  }
270 
273  template < typename GUM_SCALAR >
274  INLINE void Schedule< GUM_SCALAR >::forceBefore(NodeId op_to_force,
275  NodeId op_after) {
276  // first, add the constraint into the graph
277  __dag.addArc(op_to_force, op_after);
278 
279  // if op_to_force was available, it is not anymore
280  __operations_available.erase(op_after);
281  }
282 
285  template < typename GUM_SCALAR >
287  const ScheduleOperation< GUM_SCALAR >& op_to_force,
288  const ScheduleOperation< GUM_SCALAR >& op_after) {
289  forceBefore(__operation2node[op_to_force.id()],
290  __operation2node[op_after.id()]);
291  }
292 
295  template < typename GUM_SCALAR >
297  const NodeSet& ops_after) {
298  for (const auto op : ops_after)
299  if (op != op_to_force) forceBefore(op_to_force, op);
300  }
301 
304  template < typename GUM_SCALAR >
306  const ScheduleOperation< GUM_SCALAR >& op_to_force,
307  const Set< const ScheduleOperation< GUM_SCALAR >* >& ops_after) {
308  for (typename Set< const ScheduleOperation< GUM_SCALAR >* >::const_iterator
309  iter = ops_after.begin();
310  iter != ops_after.end();
311  ++iter) {
312  if (**iter != op_to_force) { forceBefore(op_to_force, **iter); }
313  }
314  }
315 
317  template < typename GUM_SCALAR >
319  const ScheduleMultiDim< GUM_SCALAR >& table) const {
320  return *(__multidim2operations[table.id()]);
321  }
322 
324  template < typename GUM_SCALAR >
325  INLINE const NodeSet&
327  return *(__multidim2operations[table_id]);
328  }
329 
331  template < typename GUM_SCALAR >
332  INLINE const DAG& Schedule< GUM_SCALAR >::scheduling_dag() const {
333  // first update the set of parents of the nodes of the graph whose parents
334  // were not set correctly
336  return __dag;
337  }
338 
340  template < typename GUM_SCALAR >
341  INLINE const ScheduleOperation< GUM_SCALAR >&
343  return *(__node2operation[node_id]);
344  }
345 
347  template < typename GUM_SCALAR >
349  const ScheduleOperation< GUM_SCALAR >& op) const {
350  return __operation2node[op.id()];
351  }
352 
354  template < typename GUM_SCALAR >
355  INLINE const NodeProperty< const ScheduleOperation< GUM_SCALAR >* >&
357  return reinterpret_cast<
358  NodeProperty< const ScheduleOperation< GUM_SCALAR >* >& >(__node2operation);
359  }
360 
362  template < typename GUM_SCALAR >
364  // update the set of parents
366  return __operations_available;
367  }
368 
370  template < typename GUM_SCALAR >
372  // update the parents of the sets of nodes which were not correct
373  // !!! it is important to execute the following method before the execution
374  // of operation id: this guarantees that the children of id with exactly
375  // one parent (i.e., id) are now available to be processed
377 
378  // before executing an operation, check that the operation is available
379 
380  if (__dag.parents(id).size() != 0) {
381  GUM_ERROR(OperationNotAllowed, "the operation cannot be executed yet");
382  }
383 
384  // actually execute the operation
385  __node2operation[id]->execute();
386 
387  // now update the availability of the children of id: a child is available
388  // if and only if it has only one parent
389  const NodeSet& children = __dag.children(id);
390 
391  for (const auto child : children)
392  if (__dag.parents(child).size() == 1) __operations_available.insert(child);
393 
394  // remove the operation's node and its adjacent arcs
395  __dag.eraseChildren(id);
396 
397  __dag.eraseNode(id);
398 
399  delete __node2operation[id];
400 
401  __operation2node.erase(__node2operation[id]->id());
402 
403  __node2operation.erase(id);
404 
406  }
407 
409  template < typename GUM_SCALAR >
410  INLINE void
411  Schedule< GUM_SCALAR >::execute(const ScheduleOperation< GUM_SCALAR >& op) {
412  execute(__operation2node[op.id()]);
413  }
414 
417  template < typename GUM_SCALAR >
418  INLINE float Schedule< GUM_SCALAR >::nbOperations(NodeId id) const {
419  return __node2operation[id]->nbOperations();
420  }
421 
424  template < typename GUM_SCALAR >
426  ScheduleOperation< GUM_SCALAR >& op) const {
427  return op.nbOperations();
428  }
429 
431  template < typename GUM_SCALAR >
432  INLINE std::pair< long, long >
434  return __node2operation[id]->memoryUsage();
435  }
436 
438  template < typename GUM_SCALAR >
439  INLINE std::pair< long, long > Schedule< GUM_SCALAR >::memoryUsage(
440  ScheduleOperation< GUM_SCALAR >& op) const {
441  return op.memoryUsage();
442  }
443 
444 } /* namespace gum */
445 
446 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
NodeSet __operations_available
the set of operations that can be executed at once
Definition: schedule.h:231
void execute(NodeId)
executes a given operation (if this one is available)
NodeProperty< ScheduleOperation< GUM_SCALAR > *> __node2operation
a hashtable assigning to each node of the DAG an operation
Definition: schedule.h:211
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
void erase(const Key &key)
Removes a given element from the hash table.
DAG __dag
the DAG of the operations to perform
Definition: schedule.h:208
Idx MultiDimId
to identify correctly the ids that correspond to ScheduleMultiDim ids
Definition: schedule.h:74
NodeId nodeId(const ScheduleOperation< GUM_SCALAR > &) const
returns the id of the node corresponding to a given ScheduleOperation
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
NodeSet __operations_with_wrong_parents
a list of operations whose parents are not properly set
Definition: schedule.h:228
void erase(const Key &k)
Erases an element from the set.
Definition: set_tpl.h:656
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
void forceAfter(const ScheduleOperation< GUM_SCALAR > &op_to_force, const ScheduleOperation< GUM_SCALAR > &op_before)
adds a constraint indicating that an operation cannot be performed before another one ...
virtual NodeId addNode()
insert a new node and return its id
NodeId insert(const ScheduleOperation< GUM_SCALAR > &)
inserts an operation to be scheduled
const NodeSet & operationsInvolving(const ScheduleMultiDim< GUM_SCALAR > &table) const
returns the set of operations involving a given multidim table
const DAG & scheduling_dag() const
returns a DAG indicating in which order the operations can be performed
const NodeSet & availableOperations() const
returns the set of ScheduleOperations that can be executed at once
~Schedule()
destructor
Schedule< GUM_SCALAR > & operator=(const Schedule< GUM_SCALAR > &)
copy operator
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
Definition: DAG_inl.h:43
void eraseChildren(const NodeId id)
removes all the children of a given node
std::pair< long, long > memoryUsage(NodeId) const
returns the memory consumption used during the execution of an operation
const NodeSet & children(const NodeId id) const
returns the set of nodes with arc outgoing from a given node
void forceBefore(const ScheduleOperation< GUM_SCALAR > &op_to_force, const ScheduleOperation< GUM_SCALAR > &op_after)
adds a constraint indicating that an operation must be performed before another one ...
const ScheduleOperation< GUM_SCALAR > & operation(NodeId) const
returns the scheduleOperation corresponding to an id in the DAG
Schedule()
default constructor (construct an empty sequence)
void clear()
Removes all the elements, if any, from the set.
Definition: set_tpl.h:375
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:701
HashTable< OperationId, NodeId > __operation2node
a hashtable assigning to each operation id a node id in the DAG
Definition: schedule.h:214
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
void __updateWrongParents() const
updates the set of parents for the nodes whoses parents are not correct yet and update accordingly th...
HashTable< MultiDimId, NodeId > __created_multidims
a hashtable assigning to each ScheduleMultiDim resulting from a computation the MultiDimOperation nod...
Definition: schedule.h:218
virtual void eraseNode(const NodeId id)
remove a node and its adjacent arcs from the graph
Definition: diGraph_inl.h:69
float nbOperations(NodeId) const
returns an estimation of the number of elementary operations needed to perform a given ScheduleOperat...
Size NodeId
Type for node ids.
Definition: graphElements.h:98
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:613
const NodeProperty< const ScheduleOperation< GUM_SCALAR > *> & operations() const
resturns the association between operations anf nodeIds
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
HashTable< MultiDimId, NodeSet *> __multidim2operations
for each multidim, store the set of operations involving it
Definition: schedule.h:234