51#ifndef DOXYGEN_SHOULD_SKIP_THIS
71 dag.addNodes(iter.first());
77 const NodeId node = iter.first();
78 const auto* op = iter.second();
80 for (
const auto arg: op->args()) {
86 dag.addArc(arg_node, node);
94 if (other_node != node) {
dag.addArc(node, other_node); }
100 if (op->implyDeletion()) {
102 if (other_node != node) {
dag.addArc(other_node, node); }
120 HashTable< const IScheduleMultiDim*, const IScheduleMultiDim* > multidim_from2this(
121 from._multidim2id_.size());
126 for (
const auto& [first, second]: from._multidim_location_) {
127 if (second.first ==
nullptr) {
128 const IScheduleMultiDim* new_multidim
129 = from._emplaced_multidims_.exists(first) ? first : first->clone();
130 multidim_from2this.insert(first, new_multidim);
143 const Sequence< NodeId > nodes_sequence = (from._dag_.sizeNodes() == from._node2op_.size())
144 ? from._dag_.topologicalOrder()
145 : from._fullDAG_().topologicalOrder();
150 for (
const auto node: nodes_sequence) {
152 const ScheduleOperator* from_op = from._node2op_.second(node);
153 ScheduleOperator* new_op = from_op->clone();
161 const Sequence< const IScheduleMultiDim* > from_args = from_op->args();
162 Sequence< const IScheduleMultiDim* > new_args(from_args.size());
163 for (
auto from_arg: from_args) {
164 const auto& new_arg = multidim_from2this[from_arg];
168 new_op->updateArgs(new_args);
171 if (new_op->implyDeletion()) {
172 for (
auto new_arg: new_args) {
180 const Sequence< const IScheduleMultiDim* > from_res = from_op->results();
181 const Sequence< const IScheduleMultiDim* > new_res = new_op->results();
182 for (
Idx i =
Idx(0), end = from_res.size(); i < end; ++i) {
183 multidim_from2this.insert(from_res[i], new_res[i]);
195 delete iter.second();
201 const IScheduleMultiDim* multidim = first;
228 _dag_(nb_ops, true, 2 * nb_ops, true), _node2op_(nb_ops), _multidim_location_(2 * nb_ops),
229 _multidim2id_(2 * nb_ops), _emplaced_multidims_(2 * nb_ops), _multidim2nodes_(2 * nb_ops),
230 _deleted_multidim2node_(2 * nb_ops),
231 _version_number_(_newVersionNumber_()) {
232 GUM_CONSTRUCTOR(Schedule)
236 Schedule::Schedule(
const Schedule& from) : _version_number_(from._version_number_) {
241 GUM_CONS_CPY(Schedule)
245 Schedule::Schedule(Schedule&& from) :
246 _dag_(
std::move(from._dag_)), _newId_(from._newId_), _node2op_(
std::move(from._node2op_)),
247 _multidim_location_(
std::move(from._multidim_location_)),
248 _multidim2id_(
std::move(from._multidim2id_)),
249 _emplaced_multidims_(
std::move(from._emplaced_multidims_)),
250 _multidim2nodes_(
std::move(from._multidim2nodes_)),
251 _deleted_multidim2node_(
std::move(from._deleted_multidim2node_)),
252 _version_number_(from._version_number_) {
254 from._newId_ = NodeId(0);
256 from._node2op_.clear();
257 from._multidim_location_.clear();
258 from._multidim2id_.clear();
259 from._emplaced_multidims_.clear();
260 from._multidim2nodes_.clear();
261 from._deleted_multidim2node_.clear();
264 GUM_CONS_MOV(Schedule)
268 Schedule::~Schedule() {
273 GUM_DESTRUCTOR(Schedule)
277 Schedule& Schedule::operator=(
const Schedule& from) {
291 Schedule& Schedule::operator=(Schedule&& from) {
298 _newId_ = from._newId_;
299 _dag_ = std::move(from._dag_);
300 _node2op_ = std::move(from._node2op_);
301 _multidim_location_ = std::move(from._multidim_location_);
302 _multidim2id_ = std::move(from._multidim2id_);
303 _emplaced_multidims_ = std::move(from._emplaced_multidims_);
304 _multidim2nodes_ = std::move(from._multidim2nodes_);
305 _deleted_multidim2node_ = std::move(from._deleted_multidim2node_);
306 _version_number_ = from._version_number_;
309 from._newId_ = NodeId(0);
311 from._node2op_.clear();
312 from._multidim_location_.clear();
313 from._multidim2id_.clear();
314 from._emplaced_multidims_.clear();
315 from._multidim2nodes_.clear();
316 from._deleted_multidim2node_.clear();
323 bool Schedule::operator==(
const Schedule& from)
const {
326 if ((_dag_ != from._dag_) || (_node2op_.size() != from._node2op_.size()))
return false;
327 for (
auto iter = _node2op_.cbegin(); iter != _node2op_.cend(); ++iter)
328 if (!from._node2op_.existsFirst(iter.first()))
return false;
331 HashTable< const ScheduleOperator*, const ScheduleOperator* > this_op2from(_node2op_.size());
332 Bijection< const IScheduleMultiDim*, const IScheduleMultiDim* > this_multidim2from(
333 _multidim2nodes_.size());
339 for (
const Sequence< NodeId > order = (_dag_.sizeNodes() == _node2op_.size())
340 ? _dag_.topologicalOrder()
341 : _fullDAG_().topologicalOrder();
342 const auto node: order) {
344 const ScheduleOperator* this_op = _node2op_.second(node);
345 const ScheduleOperator* from_op = from._node2op_.second(node);
348 if (!this_op->isSameOperator(*from_op))
return false;
351 const Sequence< const IScheduleMultiDim* > this_args = this_op->args();
352 const Sequence< const IScheduleMultiDim* > from_args = from_op->args();
353 if (this_args.size() != from_args.size())
return false;
355 for (Idx i = 0, end = this_args.size(); i < end; ++i) {
356 const auto& [first, second] = _multidim_location_[this_args[i]];
357 const auto& [from_first, from_second] = from._multidim_location_[from_args[i]];
359 if (first !=
nullptr) {
362 if ((from_first ==
nullptr) || (second != from_second)
363 || (from_first != this_op2from[first]))
367 if (from_first !=
nullptr)
return false;
373 if (this_multidim2from.existsFirst(this_args[i])) {
374 if (this_multidim2from.second(this_args[i]) != from_args[i])
return false;
382 if (!this_args[i]->hasSameVariables(*from_args[i])
383 || !this_args[i]->hasSameContent(*from_args[i]))
386 this_multidim2from.insert(this_args[i], from_args[i]);
393 this_op2from.insert(this_op, from_op);
402 const IScheduleMultiDim* Schedule::insertScheduleMultiDim(
const IScheduleMultiDim& multidim) {
407 if (_multidim2id_.existsSecond(multidim.id())) {
409 "A ScheduleMultiDim with Id " << multidim.id() <<
" already exists in the schedule")
411 if (multidim.isAbstract()) {
413 "It is impossible to insert an abstract ScheduleMultiDim " <<
"into a Schedule")
418 const IScheduleMultiDim* new_multidim = multidim.clone();
419 _multidim2nodes_.insert(new_multidim,
NodeSet());
420 _multidim_location_.insert(new_multidim, std::pair< ScheduleOperator*, Idx >(
nullptr, Idx(0)));
421 _multidim2id_.insert(new_multidim, new_multidim->id());
430 void Schedule::emplaceScheduleMultiDim(
const IScheduleMultiDim& multidim) {
435 if (_multidim2id_.existsSecond(multidim.id())) {
437 "A ScheduleMultiDim with Id " << multidim.id() <<
" already exists in the schedule")
439 if (multidim.isAbstract()) {
441 "It is impossible to insert an abstract ScheduleMultiDim " <<
"into a Schedule")
446 _multidim2nodes_.insert(&multidim,
NodeSet());
447 _multidim_location_.insert(&multidim, std::pair< ScheduleOperator*, Idx >(
nullptr, Idx(0)));
448 _multidim2id_.insert(&multidim, multidim.id());
449 _emplaced_multidims_.insert(&multidim);
456 std::string Schedule::_paramString_(Idx i) {
457 if (i == 0)
return "1st";
458 else if (i == 1)
return "2nd";
459 else if (i == 2)
return "3rd";
461 std::stringstream str;
462 str << (i + 1) <<
"th";
467 const ScheduleOperator& Schedule::insertOperation(
const ScheduleOperator& op,
468 const bool are_results_persistent) {
471 const Sequence< const IScheduleMultiDim* >& op_args = op.args();
472 for (Idx i = Idx(0), end = op_args.size(); i < end; ++i) {
473 if (!_multidim2id_.existsSecond(op_args[i]->id())) {
475 "Schedule::insertOperation: the "
476 << _paramString_(i + 1) <<
" (id: " << op_args[i]->
id()
477 <<
") operation's argument does not already belong to"
487 for (Idx i = Idx(0), end = op_args.size(); i < end; ++i) {
488 const IScheduleMultiDim* arg = op_args[i];
489 if (_deleted_multidim2node_.existsFirst(arg)
490 && (_node2op_.second(_deleted_multidim2node_.second(arg))->isExecuted()
491 || op.implyDeletion())) {
493 "Schedule::insertOperation: The operation deletes its "
494 << _paramString_(i + 1) <<
" argument, already deleted by another operation.")
501 if (op.implyDeletion() && op.isExecuted()) {
502 for (Idx i = Idx(0), end = op_args.size(); i < end; ++i) {
503 const auto arg = _multidim2id_.first(op_args[i]->
id());
504 for (
const auto using_node: _multidim2nodes_[arg]) {
505 if (!_node2op_.second(using_node)->isExecuted()) {
507 "Schedule::insertOperation: the operation has"
508 <<
" deleted its " << _paramString_(i + 1)
509 <<
" argument, which is used by another operation"
510 <<
" not executed yet.")
522 ScheduleOperator* new_op = op.clone();
523 Sequence< const IScheduleMultiDim* > new_args(op_args.size());
524 for (Idx i = Idx(0), end = op_args.size(); i < end; ++i) {
526 new_args << _multidim2id_.first(op_args[i]->
id());
532 "the " << _paramString_(i + 1) <<
" argument of the operation is not known by"
536 new_op->updateArgs(new_args);
537 new_op->makeResultsPersistent(are_results_persistent);
540 const NodeId new_node = ++_newId_;
541 _dag_.addNodeWithId(new_node);
542 _node2op_.insert(new_node, new_op);
545 for (
const auto new_arg: new_args) {
546 _multidim2nodes_[new_arg].insert(new_node);
550 if (new_op->implyDeletion()) {
551 for (
const auto new_arg: new_args) {
552 _deleted_multidim2node_.insert(new_arg, new_node);
557 const Sequence< const IScheduleMultiDim* > new_results = new_op->results();
558 for (Idx i = Idx(0), end = new_results.size(); i < end; ++i) {
559 _multidim_location_.insert(new_results[i], std::pair< ScheduleOperator*, Idx >(new_op, i));
560 _multidim2id_.insert(new_results[i], new_results[i]->
id());
561 _multidim2nodes_.insert(new_results[i],
NodeSet());
568 if (new_op->isExecuted()) {
569 _dag_.eraseNode(new_node);
578 for (
const auto arg: new_args) {
582 if (_deleted_multidim2node_.existsFirst(arg)) {
583 const NodeId other_node = _deleted_multidim2node_.second(arg);
584 if (other_node != new_node) { _dag_.addArc(new_node, other_node); }
589 if (
const auto arg_location = _multidim_location_[arg].first; arg_location !=
nullptr) {
590 const NodeId parent_node = _node2op_.first(arg_location);
591 if ((parent_node != new_node) && !arg_location->isExecuted()) {
592 _dag_.addArc(parent_node, new_node);
600 if (new_op->implyDeletion()) {
601 for (
const auto other_node: _multidim2nodes_[arg]) {
602 if ((other_node != new_node) && !_dag_.existsArc(other_node, new_node)
603 && !_node2op_.second(other_node)->isExecuted()) {
604 _dag_.addArc(other_node, new_node);
617 NodeSet Schedule::availableOperations()
const {
619 for (
const auto node: _dag_) {
620 if (!this->operation(node).isExecuted()) {
621 bool all_parents_executed =
true;
622 for (
const auto par: _dag_.parents(node)) {
623 if (!this->operation(par).isExecuted()) {
624 all_parents_executed =
false;
628 if (all_parents_executed) available_nodes.insert(node);
631 return available_nodes;
635 void Schedule::updateAfterExecution(
const NodeId exec_node,
636 std::vector< NodeId >& new_available_nodes,
640 if (!_dag_.existsNode(exec_node)) {
642 "the schedule cannot be updated because Operation of Id "
643 << exec_node <<
" that has been executed does not belong to its DAG.")
648 if (!_dag_.parents(exec_node).empty()) {
650 "the schedule cannot be updated because Operation of Id "
651 << exec_node <<
" is not available yet and should not have been executed.")
655 if (!_node2op_.second(exec_node)->isExecuted()) {
657 "the schedule cannot be updated because Operation of Id "
658 << exec_node <<
" has not been executed yet.")
664 new_available_nodes.clear();
665 for (
const auto child_node: _dag_.children(exec_node)) {
666 if (_dag_.parents(child_node).size() == 1) {
667 new_available_nodes.push_back(child_node);
672 _dag_.eraseNode(exec_node);
674 _version_number_ = _newVersionNumber_();
Exception : The Schedule MultiDim Table is abstract.
Exception : There exists another identical Schedule MultiDim Table.
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
Class containing a schedule of operations to perform on multidims.
static std::atomic< Idx > _overall_version_number_
void _copy_(const Schedule &from)
a function to copy the content of a schedule into another one
void _destroy_()
a function to delete from memory the content of a schedule
Schedule(const Size nb_ops=256)
default constructor (construct an empty sequence)
Bijection< const IScheduleMultiDim *, NodeId > _deleted_multidim2node_
A bijection mapping ScheduleMultiDims to be deleted with the operations that will delete them.
void clear()
empty the schedule, i.e., remove its content
const DAG & dag() const
returns a DAG indicating in which order the operations can be performed
DAG _fullDAG_() const
returns the graph that would obtain when no operation is performed
Bijection< const IScheduleMultiDim *, Idx > _multidim2id_
a bijection between pointers to IScheduleMultiDim and their Ids
Idx _version_number_
a number that identifies the current version of the schedule
HashTable< const IScheduleMultiDim *, NodeSet > _multidim2nodes_
maps the multidims to the set of operations that use them
static Idx _newVersionNumber_()
returns a new distinct version for each schedule
Set< const IScheduleMultiDim * > _emplaced_multidims_
indicates which ScheduleMultiDims were emplaced
Bijection< NodeId, ScheduleOperator * > _node2op_
a mapping between the ids of the operations and their pointer
NodeId _newId_
the highest node id in the graph
DAG _dag_
the DAG of the operations to perform
HashTable< const IScheduleMultiDim *, std::pair< ScheduleOperator *, Idx > > _multidim_location_
a structure to indicate precisely where a ScheduleMultiDim comes from
Exception : The Schedule Operation is not available yet.
Exception : The Schedule Operation has not been executed yet.
Exception : The Schedule MultiDim Table is unknown.
Exception : The Schedule Operation is unknown.
#define GUM_ERROR(type, msg)
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Size Idx
Type for indexes.
Size NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
Class containing a schedule of operations to perform on multidims.