10 #include <unordered_set>
12 #include "common_types.hh"
13 #include "timed_automaton.hh"
14 #include "forward_regional_elementary_language.hh"
15 #include "external_transition_maker.hh"
35 std::unordered_set<ClockVariables> preciseClocks;
37 std::vector<ForwardRegionalElementaryLanguage> neighbors;
38 std::size_t clockSize;
40 void assertInvariants()
const {
41 assert(std::all_of(neighbors.begin(), neighbors.end(), [&](
const auto &neighbor) {
42 return neighbor.getWord() == original.getWord();
44 assert(clockSize == original.getTimedCondition().
size());
45 assert(std::all_of(neighbors.begin(), neighbors.end(), [&](
const auto &neighbor) {
46 return neighbor.getTimedCondition().size() == clockSize;
48 assert(std::all_of(neighbors.begin(), neighbors.end(), [&](
const auto &neighbor) {
49 return std::all_of(preciseClocks.begin(), preciseClocks.end(), [&](const auto &preciseClock) {
50 return neighbor.getTimedCondition().getLowerBound(preciseClock, clockSize - 1) ==
51 original.getTimedCondition().getLowerBound(preciseClock, clockSize - 1);
54 assert(std::all_of(neighbors.begin(), neighbors.end(), [&](
const auto &neighbor) {
55 return std::all_of(preciseClocks.begin(), preciseClocks.end(), [&](const auto &preciseClock) {
56 return neighbor.getTimedCondition().getUpperBound(preciseClock, clockSize - 1) ==
57 original.getTimedCondition().getUpperBound(preciseClock, clockSize - 1);
62 NeighborConditions(ForwardRegionalElementaryLanguage &&original,
63 std::vector<ForwardRegionalElementaryLanguage> &&neighbors,
64 const std::unordered_set<ClockVariables> &preciseClocks,
65 size_t clockSize) : original(original), preciseClocks(preciseClocks),
66 neighbors(neighbors), clockSize(clockSize) {
70 NeighborConditions(ForwardRegionalElementaryLanguage &&original,
71 std::vector<ForwardRegionalElementaryLanguage> &&neighbors,
72 std::unordered_set<ClockVariables> &&preciseClocks,
73 size_t clockSize) : original(original), preciseClocks(preciseClocks),
74 neighbors(neighbors), clockSize(clockSize) {
83 void addImplicitPreciseClocks() {
84 BOOST_LOG_TRIVIAL(debug) <<
"explicit precise clocks: ";
85 for (
const auto &preciseClock: preciseClocks) {
86 BOOST_LOG_TRIVIAL(debug) <<
"x" <<
static_cast<int>(preciseClock);
88 for (std::size_t i = 0; i < clockSize; ++i) {
90 if (this->preciseClocks.find(i) != this->preciseClocks.end()) {
93 const auto lowerBound = this->original.getTimedCondition().getLowerBound(i, clockSize - 1);
94 const auto upperBound = this->original.getTimedCondition().getUpperBound(i, clockSize - 1);
95 if (isPoint(upperBound, lowerBound)) {
96 assert(std::all_of(this->neighbors.begin(), this->neighbors.end(), [&] (
const auto& neighbor) {
97 return neighbor.getTimedCondition().getLowerBound(i, clockSize - 1) == lowerBound && neighbor.getTimedCondition().getUpperBound(i, clockSize - 1) == upperBound;
99 this->preciseClocks.insert(i);
102 BOOST_LOG_TRIVIAL(debug) <<
"appended precise clocks: ";
103 for (
const auto &preciseClock: preciseClocks) {
104 BOOST_LOG_TRIVIAL(debug) <<
"x" <<
static_cast<int>(preciseClock);
108 [[nodiscard]]
auto updateNeighborsWithContinuousSuccessors(
const ForwardRegionalElementaryLanguage &originalSuccessor)
const {
109 BOOST_LOG_TRIVIAL(debug) <<
"originalSuccessor: " << originalSuccessor;
111 std::vector<ForwardRegionalElementaryLanguage> newNeighbors;
112 newNeighbors.reserve(neighbors.size());
113 for (
auto neighbor: neighbors) {
114 while (std::all_of(preciseClocks.begin(), preciseClocks.end(), [&](
const auto &preciseClock) {
115 return neighbor.getTimedCondition().getUpperBound(preciseClock, neighbor.getTimedCondition().size() - 1) <=
116 originalSuccessor.getTimedCondition().getUpperBound(preciseClock,
117 originalSuccessor.getTimedCondition().size() - 1);
119 if (std::all_of(preciseClocks.begin(), preciseClocks.end(), [&](
const auto &preciseClock) {
120 return neighbor.getTimedCondition().getLowerBound(preciseClock, neighbor.getTimedCondition().size() - 1) ==
121 originalSuccessor.getTimedCondition().getLowerBound(preciseClock,
122 originalSuccessor.getTimedCondition().size() -
124 neighbor.getTimedCondition().getUpperBound(preciseClock, neighbor.getTimedCondition().size() - 1) ==
125 originalSuccessor.getTimedCondition().getUpperBound(preciseClock,
126 originalSuccessor.getTimedCondition().size() -
129 newNeighbors.push_back(neighbor);
131 neighbor = neighbor.successor();
135 std::sort(newNeighbors.begin(), newNeighbors.end(), [] (
const auto& left,
const auto& right) {
136 return left.hash_value() < right.hash_value();
138 newNeighbors.erase(std::unique(newNeighbors.begin(), newNeighbors.end()), newNeighbors.end());
149 std::unordered_set<ClockVariables> newPreciseClocks;
150 const auto targetClockSize = computeTargetClockSize(transition);
151 for (
const auto &[targetVariable, assignedValue]: transition.
resetVars) {
152 if (targetVariable >= targetClockSize) {
155 if (assignedValue.index() == 1 &&
156 preciseClocks.find(std::get<ClockVariables>(assignedValue)) != preciseClocks.end()) {
158 newPreciseClocks.insert(targetVariable);
159 }
else if (assignedValue.index() == 0 &&
160 std::get<double>(assignedValue) == std::floor(std::get<double>(assignedValue))) {
162 newPreciseClocks.insert(targetVariable);
165 for (
const auto &preciseClock: preciseClocks) {
167 if (preciseClock >= targetClockSize || newPreciseClocks.find(preciseClock) != newPreciseClocks.end()) {
170 auto it = std::find_if(transition.
resetVars.begin(), transition.
resetVars.end(), [&] (
const auto &reset) {
171 return reset.first == preciseClock;
174 newPreciseClocks.insert(preciseClock);
178 assert(newPreciseClocks.size() <= targetClockSize);
179 return newPreciseClocks;
186 return NeighborConditions::preciseClocksAfterReset(this->preciseClocks, transition);
194 for (
auto it = currentPreciseClocks.begin(); it != currentPreciseClocks.end();) {
195 if (*it > this->original.wordSize()) {
196 it = currentPreciseClocks.erase(it);
205 const std::unordered_set<ClockVariables> &preciseClocks) {
206 const auto clockSize = original.getTimedCondition().
size();
207 std::vector<ForwardRegionalElementaryLanguage> neighbors;
210 auto neighborsCondition =
TimedCondition(Zone::top(clockSize + 1));
211 for (std::size_t i = 0; i < clockSize; ++i) {
213 neighborsCondition.restrictLowerBound(i, clockSize - 1,
214 original.getTimedCondition().
getLowerBound(i, clockSize - 1));
215 neighborsCondition.restrictUpperBound(i, clockSize - 1,
216 original.getTimedCondition().
getUpperBound(i, clockSize - 1));
217 for (std::size_t j = i + 1; j < clockSize; ++j) {
218 if ((preciseClocks.find(i) == preciseClocks.end()) ==
219 (preciseClocks.find(j) == preciseClocks.end())) {
221 neighborsCondition.restrictLowerBound(i, j - 1, original.getTimedCondition().
getLowerBound(i, j - 1));
222 neighborsCondition.restrictUpperBound(i, j - 1, original.getTimedCondition().
getUpperBound(i, j - 1));
226 const auto simpleNeighborsCondition = neighborsCondition.enumerate();
227 neighbors.reserve(simpleNeighborsCondition.size());
228 std::transform(simpleNeighborsCondition.begin(), simpleNeighborsCondition.end(), std::back_inserter(neighbors),
229 [&](
const auto &neighborCondition) {
230 return ForwardRegionalElementaryLanguage::fromTimedWord(
231 ElementaryLanguage{original.getWord(), neighborCondition}.sample());
237 NeighborConditions(
const NeighborConditions& conditions) =
default;
238 NeighborConditions(NeighborConditions&& conditions) =
default;
239 NeighborConditions& operator=(
const NeighborConditions& conditions) =
default;
240 NeighborConditions& operator=(NeighborConditions&& conditions) =
default;
241 NeighborConditions(ForwardRegionalElementaryLanguage original,
242 std::unordered_set<ClockVariables> preciseClocks) : original(
std::move(original)),
243 preciseClocks(
std::move(preciseClocks)),
244 neighbors(makeNeighbors(this->original,
245 this->preciseClocks)),
247 this->original.getTimedCondition().size()) {
248 addImplicitPreciseClocks();
249 if (!this->preciseClocks.empty()) {
250 this->neighbors = updateNeighborsWithContinuousSuccessors(this->original);
255 NeighborConditions(ForwardRegionalElementaryLanguage original,
256 const std::vector<ClockVariables> &preciseClocks) : original(
std::move(original)),
258 std::unordered_set<ClockVariables>(
259 preciseClocks.begin(),
260 preciseClocks.end())),
261 neighbors(makeNeighbors(this->original,
262 this->preciseClocks)),
264 this->original.getTimedCondition().size()) {
265 addImplicitPreciseClocks();
266 if (!this->preciseClocks.empty()) {
267 this->neighbors = updateNeighborsWithContinuousSuccessors(this->original);
278 this->preciseClocksAfterReset(transition)};
288 return this->original.getTimedCondition().toGuard();
294 [[nodiscard]]
bool match(
const std::vector<Constraint> &guard)
const {
296 return isWeaker(guard, this->toOriginalGuard());
299 [[nodiscard]]
size_t getClockSize()
const {
307 return this->neighbors.size() == 1;
315 return this->match(transition.
guard);
323 std::vector<std::vector<Constraint>> guards;
324 guards.reserve(this->neighbors.size());
325 std::transform(this->neighbors.begin(), this->neighbors.end(), std::back_inserter(guards),
326 [&](
const auto &neighbor) {
327 return neighbor.getTimedCondition().toGuard();
330 return unionHull(guards);
335 std::vector<ForwardRegionalElementaryLanguage> newNeighbors;
336 newNeighbors.reserve(neighbors.size());
337 std::transform(neighbors.begin(), neighbors.end(), std::back_inserter(newNeighbors), [&](
const auto &neighbor) {
338 return neighbor.successor(action);
340 auto newPreciseClocks = preciseClocks;
341 newPreciseClocks.insert(clockSize);
343 newPreciseClocks, clockSize + 1};
346 [[nodiscard]] NeighborConditions successor()
const {
347 auto originalSuccessor = original.successor();
348 auto newNeighbors = updateNeighborsWithContinuousSuccessors(originalSuccessor);
350 return NeighborConditions{std::move(originalSuccessor), std::move(newNeighbors), preciseClocks, clockSize};
353 void successorAssign() {
354 original.successorAssign();
355 neighbors = updateNeighborsWithContinuousSuccessors(original);
364 std::vector<ClockVariables> impreciseClockVec;
365 impreciseClockVec.reserve(this->clockSize);
366 for (std::size_t clock = 0; clock < this->clockSize; ++clock) {
367 if (this->preciseClocks.find(clock) == this->preciseClocks.end()) {
368 impreciseClockVec.push_back(clock);
372 return impreciseClockVec;
379 return ExternalTransitionMaker::toValuation(this->original.getTimedCondition());
386 auto valuation = ExternalTransitionMaker::toValuation(this->original.getTimedCondition());
387 if (valuation.size() < minSize) {
388 valuation.resize(minSize);
398 auto newNeighborConditions = *
this;
399 newNeighborConditions.original = newNeighborConditions.original.applyResets(resets);
400 for (
auto &neighbor: newNeighborConditions.neighbors) {
401 neighbor = neighbor.applyResets(resets);
403 for (
const auto &[updatedVariable, assignedValue]: resets) {
404 if (assignedValue.index() == 0) {
405 newNeighborConditions.preciseClocks.insert(updatedVariable);
408 BOOST_LOG_TRIVIAL(error) <<
"Unimplemented case";
413 return newNeighborConditions;
420 return transition.
resetVars.size() == 1 &&
421 transition.
resetVars.front().first == this->getClockSize() &&
422 transition.
resetVars.front().second.index() == 0 &&
423 std::get<double>(transition.
resetVars.front().second) == 0.0;
428 BOOST_LOG_TRIVIAL(debug) <<
"original before transition: " << this->original;
429 if (isInternal(transition)) {
430 BOOST_LOG_TRIVIAL(debug) <<
"original after transition: " << this->original.
successor(action);
434 std::string newWord = this->original.getWord();
435 const auto targetClockSize = computeTargetClockSize(transition);
436 assert(targetClockSize > 0);
437 newWord.resize(targetClockSize - 1, this->original.getWord().back());
439 BOOST_LOG_TRIVIAL(debug) <<
"newWord: " << newWord;
440 BOOST_LOG_TRIVIAL(debug) <<
"resetVars: " << transition.
resetVars;
441 BOOST_LOG_TRIVIAL(debug) <<
"targetClockSize: " << targetClockSize;
442 BOOST_LOG_TRIVIAL(debug) <<
"original after transition: "
443 << this->original.applyResets(newWord, transition.
resetVars, targetClockSize);
444 return this->original.applyResets(newWord, transition.
resetVars, targetClockSize);
448 [[nodiscard]]
static std::size_t computeClockSize(
const TAState* state) {
449 std::size_t targetClockSize = 0;
450 for (
const auto &[action, transitions]: state->next) {
451 for (
const auto &cTransition: transitions) {
452 std::for_each(cTransition.guard.begin(), cTransition.guard.end(), [&](
const Constraint &constraint) {
453 targetClockSize = std::max(targetClockSize, static_cast<std::size_t>(constraint.x + 1));
458 return targetClockSize;
461 [[nodiscard]]
static std::size_t computeTargetClockSize(
const TATransition &transition) {
462 return computeClockSize(transition.target);
465 std::ostream &print(std::ostream &os)
const {
466 os << this->original <<
" {";
468 for (
const auto &preciseClock: preciseClocks) {
472 os <<
"x" <<
static_cast<int>(preciseClock);
476 for (
const auto &neighbor: neighbors) {
477 os <<
"\n" << neighbor;
484 bool operator==(
const NeighborConditions &conditions)
const {
485 return original == conditions.original &&
486 preciseClocks == conditions.preciseClocks &&
487 neighbors == conditions.neighbors &&
488 clockSize == conditions.clockSize;
491 bool operator!=(
const NeighborConditions &conditions)
const {
492 return !(conditions == *
this);
495 [[nodiscard]] std::size_t hash_value()
const {
496 return boost::hash_value(std::make_tuple(original,
497 std::vector<ClockVariables>{preciseClocks.begin(), preciseClocks.end()},
498 neighbors, clockSize));
503 return conditions.print(os);
506 static inline std::size_t hash_value(
const NeighborConditions &conditions) {
507 return conditions.hash_value();
A forward regional elementary language.
Definition: forward_regional_elementary_language.hh:23
ForwardRegionalElementaryLanguage successor(char action) const
Construct the discrete successor.
Definition: forward_regional_elementary_language.hh:65
Elementary language with its neighbor conditions.
Definition: neighbor_conditions.hh:30
std::vector< ClockVariables > impreciseClocks() const
Returns the list of imprecise clocks.
Definition: neighbor_conditions.hh:363
std::vector< double > toOriginalValuation() const
Construct the reset to embed to the target condition.
Definition: neighbor_conditions.hh:378
auto toOriginalGuard() const
Return the guard of the original elementary language.
Definition: neighbor_conditions.hh:286
NeighborConditions makeAfterTransition(const Alphabet action, const TATransition &transition) const
Construct the neighbor conditions after a transition.
Definition: neighbor_conditions.hh:276
auto toRelaxedGuard() const
Return the guard of the original elementary language and its neighbors.
Definition: neighbor_conditions.hh:321
NeighborConditions reconstruct(std::unordered_set< ClockVariables > currentPreciseClocks) const
Reconstruct the neighbor conditions with new precise clocks.
Definition: neighbor_conditions.hh:192
bool match(const TATransition &transition) const
Return if the given transition matches with this elementary language.
Definition: neighbor_conditions.hh:313
std::vector< double > toOriginalValuation(const std::size_t minSize) const
Construct the reset to embed to the target condition.
Definition: neighbor_conditions.hh:385
bool precise() const
Returns if the relaxed guard is precise.
Definition: neighbor_conditions.hh:306
static auto preciseClocksAfterReset(const std::unordered_set< ClockVariables > &preciseClocks, const TATransition &transition)
Make precise clocks after applying a reset.
Definition: neighbor_conditions.hh:147
NeighborConditions applyResets(const TATransition::Resets &resets) const
Return the neighbor conditions after applying the given resets.
Definition: neighbor_conditions.hh:397
auto preciseClocksAfterReset(const TATransition &transition) const
Make precise clocks after applying a reset.
Definition: neighbor_conditions.hh:185
bool isInternal(const TATransition &transition) const
Check if the transition from the current neighbor is internal.
Definition: neighbor_conditions.hh:419
bool match(const std::vector< Constraint > &guard) const
Return if the given guard matches with this elementary language.
Definition: neighbor_conditions.hh:294
A timed condition, a finite conjunction of inequalities of the form , where and .
Definition: timed_condition.hh:19
Bounds getUpperBound(std::size_t i, std::size_t j) const
Returns the upper bound of .
Definition: timed_condition.hh:232
Bounds getLowerBound(std::size_t i, std::size_t j) const
Returns the lower bound of .
Definition: timed_condition.hh:219
size_t size() const
Return the number of the variables in this timed condition.
Definition: timed_condition.hh:89
Definition: experiment_runner.hh:23
Definition: external_transition_maker.hh:149
A state of timed automata.
Definition: timed_automaton.hh:82
std::vector< Constraint > guard
The guard for this transition.
Definition: timed_automaton.hh:93
std::vector< std::pair< ClockVariables, std::variant< double, ClockVariables > > > resetVars
The clock variables reset after this transition.
Definition: timed_automaton.hh:91