1 /* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "src/mc/explo/udpor/EventSet.hpp"
7 #include "src/mc/explo/udpor/Configuration.hpp"
8 #include "src/mc/explo/udpor/History.hpp"
9 #include "src/mc/explo/udpor/UnfoldingEvent.hpp"
14 namespace simgrid::mc::udpor {
16 EventSet::EventSet(Configuration&& config) : EventSet(config.get_events()) {}
18 void EventSet::remove(const UnfoldingEvent* e)
20 this->events_.erase(e);
23 void EventSet::subtract(const EventSet& other)
25 this->events_ = std::move(subtracting(other).events_);
28 void EventSet::subtract(const Configuration& config)
30 subtract(config.get_events());
33 EventSet EventSet::subtracting(const EventSet& other) const
35 std::unordered_set<const UnfoldingEvent*> result = this->events_;
37 for (const UnfoldingEvent* e : other.events_)
40 return EventSet(std::move(result));
43 EventSet EventSet::subtracting(const Configuration& config) const
45 return subtracting(config.get_events());
48 EventSet EventSet::subtracting(const UnfoldingEvent* e) const
50 auto result = this->events_;
52 return EventSet(std::move(result));
55 void EventSet::insert(const UnfoldingEvent* e)
57 this->events_.insert(e);
60 void EventSet::form_union(const EventSet& other)
62 this->events_ = std::move(make_union(other).events_);
65 void EventSet::form_union(const Configuration& config)
67 form_union(config.get_events());
70 EventSet EventSet::make_union(const UnfoldingEvent* e) const
72 auto result = this->events_;
74 return EventSet(std::move(result));
77 EventSet EventSet::make_union(const EventSet& other) const
79 std::unordered_set<const UnfoldingEvent*> result = this->events_;
81 for (const UnfoldingEvent* e : other.events_)
84 return EventSet(std::move(result));
87 EventSet EventSet::make_union(const Configuration& config) const
89 return make_union(config.get_events());
92 size_t EventSet::size() const
94 return this->events_.size();
97 bool EventSet::empty() const
99 return this->events_.empty();
102 bool EventSet::contains(const UnfoldingEvent* e) const
104 return this->events_.find(e) != this->events_.end();
107 bool EventSet::is_subset_of(const EventSet& other) const
109 // If there is some element not contained in `other`, then
110 // the set difference will contain that element and the
111 // result won't be empty
112 return subtracting(other).empty();
115 bool EventSet::is_valid_configuration() const
117 /// @invariant: A collection of events `E` is a configuration
118 /// if and only if following while following the history of
119 /// each event `e` of `E` you remain in `E`. In other words, you
120 /// only see events from set `E`
122 /// The simple proof is based on the definition of a configuration
123 /// which requires that all events have their history contained
125 const History history(*this);
126 return this->contains(history);
129 bool EventSet::contains(const History& history) const
131 return std::all_of(history.begin(), history.end(), [=](const UnfoldingEvent* e) { return this->contains(e); });
134 bool EventSet::is_maximal() const
136 const History history(*this);
137 return *this == history.get_all_maximal_events();
140 bool EventSet::is_conflict_free() const
145 std::vector<const UnfoldingEvent*> EventSet::get_topological_ordering() const
147 // This is essentially an implementation of detecting cycles
148 // in a graph with coloring, except it makes a topological
149 // ordering out of it
151 return std::vector<const UnfoldingEvent*>();
154 std::stack<const UnfoldingEvent*> event_stack;
155 std::vector<const UnfoldingEvent*> topological_ordering;
156 EventSet unknown_events = *this;
157 EventSet temporarily_marked_events;
158 EventSet permanently_marked_events;
160 while (not unknown_events.empty()) {
161 EventSet discovered_events;
162 event_stack.push(*unknown_events.begin());
164 while (not event_stack.empty()) {
165 const UnfoldingEvent* evt = event_stack.top();
166 discovered_events.insert(evt);
168 if (not temporarily_marked_events.contains(evt)) {
169 // If this event hasn't yet been marked, do
170 // so now so that if we both see it
171 // again in a child we can detect a cycle
172 temporarily_marked_events.insert(evt);
174 EventSet immediate_causes = evt->get_immediate_causes();
175 if (!immediate_causes.empty() && immediate_causes.is_subset_of(temporarily_marked_events)) {
176 throw std::invalid_argument("Attempted to perform a topological sort on a configuration "
177 "whose contents contain a cycle. The configuration (and the graph "
178 "connecting all of the events) is an invalid event structure");
180 immediate_causes.subtract(discovered_events);
181 immediate_causes.subtract(permanently_marked_events);
182 std::for_each(immediate_causes.begin(), immediate_causes.end(),
183 [&event_stack](const UnfoldingEvent* cause) { event_stack.push(cause); });
185 unknown_events.remove(evt);
186 temporarily_marked_events.remove(evt);
187 permanently_marked_events.insert(evt);
189 // In moving this event to the end of the list,
190 // we are saying this events "happens before" other
191 // events that are added later.
192 if (this->contains(evt)) {
193 topological_ordering.push_back(evt);
196 // Only now do we remove the event, i.e. once
197 // we've processed the same event twice
202 return topological_ordering;
205 std::vector<const UnfoldingEvent*> EventSet::get_topological_ordering_of_reverse_graph() const
207 // The implementation exploits the property that
208 // a topological sorting S^R of the reverse graph G^R
209 // of some graph G is simply the reverse of any
210 // topological sorting S of G.
211 auto topological_events = get_topological_ordering();
212 std::reverse(topological_events.begin(), topological_events.end());
213 return topological_events;
216 } // namespace simgrid::mc::udpor