LearnTA  0.0.1
timed_automaton.hh
1 #pragma once
2 
3 #include <array>
4 #include <climits>
5 #include <memory>
6 #include <ostream>
7 #include <unordered_map>
8 #include <unordered_set>
9 #include <utility>
10 #include <valarray>
11 #include <vector>
12 #include <queue>
13 #include <optional>
14 #include <cassert>
15 #include <variant>
16 #include <boost/log/trivial.hpp>
17 
18 #include "common_types.hh"
19 #include "constraint.hh"
20 #include "conjunctive_constraint.hh"
21 
22 namespace learnta {
23  struct TATransition;
24 
28  struct TAState {
30  bool isMatch;
35  std::unordered_map<Alphabet, std::vector<TATransition>> next;
36 
37  explicit TAState(bool isMatch = false) : isMatch(isMatch) { next.clear(); }
38 
39  TAState(bool isMatch,
40  std::unordered_map<Alphabet, std::vector<TATransition>> next)
41  : isMatch(isMatch), next(std::move(next)) {}
42 
46  [[nodiscard]] bool deterministic() const;
47 
48  void addUpperBoundForUnobservableTransitions();
49 
56 
57  void mergeNondeterministicBranchingWithSameTarget();
58 
62  [[nodiscard]] bool needSplitting() const;
63 
70 
76  void mergeNondeterministicBranching(const std::unordered_set<ClockVariables> &preciseClocks);
77  };
78 
82  struct TATransition {
83  using Resets = std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>>;
91  std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>> resetVars;
93  std::vector<Constraint> guard;
94 
95  TATransition() = default;
96 
98  std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>> resetVars,
99  std::vector<Constraint> guard)
100  : target(target), resetVars(std::move(resetVars)), guard(std::move(guard)) {}
101 
102  TATransition(TAState *target, ClockVariables resetVar, std::vector<Constraint> guard) :
103  target(target), guard(std::move(guard)) {
104  resetVars.emplace_back(resetVar, 0.0);
105  }
106 
107  TATransition(TATransition const &) = default;
108 
109  bool operator==(const TATransition &rhs) const {
110  return target == rhs.target &&
111  resetVars == rhs.resetVars &&
112  guard == rhs.guard;
113  }
114 
115  bool operator!=(const TATransition &rhs) const {
116  return !(rhs == *this);
117  }
118 
119  ~TATransition() = default;
120 
121  void addPreciseConstantAssignments(const Resets &resets) {
122  std::unordered_map<ClockVariables, std::variant<double, ClockVariables>> resetAsMap {this->resetVars.begin(),
123  this->resetVars.end()};
124  for (const auto &[targetVariable, assignedValue]: resets) {
125  auto it = resetAsMap.find(targetVariable);
126  // Continue if it is already precise
127  if (it != resetAsMap.end() && it->second.index() == 0 &&
128  std::get<double>(it->second) == std::floor(std::get<double>(it->second))) {
129  continue;
130  }
131  if (assignedValue.index() == 0 &&
132  std::get<double>(assignedValue) == std::floor(std::get<double>(assignedValue))) {
133  resetAsMap[targetVariable] = assignedValue;
134  }
135  }
136 
137  this->resetVars.clear();
138  this->resetVars.reserve(resetAsMap.size());
139  std::copy(resetAsMap.begin(), resetAsMap.end(), std::back_inserter(this->resetVars));
140  }
141 
142  void addPreciseAssignments(const Resets &resets) {
143  std::unordered_map<ClockVariables, std::variant<double, ClockVariables>> resetAsMap {this->resetVars.begin(),
144  this->resetVars.end()};
145  for (const auto &[targetVariable, assignedValue]: resets) {
146  auto it = resetAsMap.find(targetVariable);
147  // Continue if it is already precise
148  if (it != resetAsMap.end() && it->second.index() == 0 &&
149  std::get<double>(it->second) == std::floor(std::get<double>(it->second))) {
150  continue;
151  }
152  if (assignedValue.index() == 1 ||
153  std::get<double>(assignedValue) == std::floor(std::get<double>(assignedValue))) {
154  resetAsMap[targetVariable] = assignedValue;
155  }
156  }
157 
158  this->resetVars.clear();
159  this->resetVars.reserve(resetAsMap.size());
160  std::copy(resetAsMap.begin(), resetAsMap.end(), std::back_inserter(this->resetVars));
161  }
162 
166  static std::size_t impreciseConstantAssignSize(const Resets &resets) {
167  std::size_t count = 0;
168  for (const auto &[targetVariable, assignedValue]: resets) {
169  if (assignedValue.index() == 0 &&
170  std::get<double>(assignedValue) != std::floor(std::get<double>(assignedValue))) {
171  ++count;
172  }
173  }
174  return count;
175  }
176 
180  static std::size_t impreciseAssignSize(const Resets &resets) {
181  std::size_t count = 0;
182  for (const auto &[targetVariable, assignedValue]: resets) {
183  if (assignedValue.index() == 1 ||
184  std::get<double>(assignedValue) != std::floor(std::get<double>(assignedValue))) {
185  ++count;
186  }
187  }
188  return count;
189  }
190 
191  [[nodiscard]] bool mergeable(const TATransition& transition) const {
192  if (this->target != transition.target || !adjacent(this->guard, transition.guard)) {
193  return false;
194  }
195  return this->resetVars == transition.resetVars;
196  }
197 
198  [[nodiscard]] TATransition merge(const TATransition& transition) const {
199  TATransition result = transition;
200  result.guard = unionHull(transition.guard, this->guard);
201 
202  return result;
203  }
204  };
205 
206  inline std::size_t hash_value(const TATransition &transition) {
207  return boost::hash_value(std::make_tuple(transition.target, transition.resetVars, transition.guard));
208  }
209 
213  struct TimedAutomaton : public Automaton<TAState> {
215  std::vector<int> maxConstraints;
216 
224  void deepCopy(
225  TimedAutomaton &dest,
226  std::unordered_map<TAState *, std::shared_ptr<TAState>> &old2new) const {
227  // copy states
228  old2new.reserve(stateSize());
229  dest.states.reserve(stateSize());
230  for (const auto &oldState: states) {
231  dest.states.emplace_back(std::make_shared<TAState>(*oldState));
232  old2new[oldState.get()] = dest.states.back();
233  }
234  // copy initial states
235  dest.initialStates.reserve(initialStates.size());
236  for (const auto &oldInitialState: initialStates) {
237  dest.initialStates.emplace_back(old2new[oldInitialState.get()]);
238  }
239  // modify dest of transitions
240  for (auto &state: dest.states) {
241  for (auto &edges: state->next) {
242  for (auto &edge: edges.second) {
243  auto oldTarget = edge.target;
244  edge.target = old2new[oldTarget].get();
245  }
246  }
247  }
249  }
250 
252  [[nodiscard]] inline size_t clockSize() const {
253  return maxConstraints.size();
254  }
255 
261  [[nodiscard]] TimedAutomaton complement(const std::vector<Alphabet> &alphabet) const {
262  TimedAutomaton result;
263  std::unordered_map<TAState *, std::shared_ptr<TAState>> old2new;
264  deepCopy(result, old2new);
265  result.makeComplete(alphabet);
266  assert(this->stateSize() + 1 == result.stateSize());
267  for (const auto &state: result.states) {
268  state->isMatch = !state->isMatch;
269  }
270 
271  return result;
272  }
273 
277  void makeComplete(const std::vector<Alphabet> &alphabet) {
278  // We construct the sink state
279  this->states.push_back(std::make_shared<TAState>(false));
280  if (this->initialStates.empty()) {
281  this->initialStates.push_back(this->states.back());
282  }
283  for (const auto &state: this->states) {
284  // Construct the disjunctive guards of unobservable transitions
285  std::vector<std::vector<Constraint>> disjunctiveGuardOfUnobservable;
286  if (state->next.find(UNOBSERVABLE) != state->next.end()) {
287  disjunctiveGuardOfUnobservable.reserve(state->next.at(UNOBSERVABLE).size());
288  for (const auto &transition: state->next.at(UNOBSERVABLE)) {
289  if (transition.guard.empty()) {
290  disjunctiveGuardOfUnobservable.clear();
291  break;
292  }
293  disjunctiveGuardOfUnobservable.push_back(transition.guard);
294  }
295  }
296  for (const auto &action: alphabet) {
297  if (disjunctiveGuardOfUnobservable.empty() &&
298  (state->next.find(action) == state->next.end() || state->next.at(action).empty())) {
299  // If the transition is empty, we make a transition to the sink state
300  state->next[action].emplace_back();
301  state->next.at(action).back().target = this->states.back().get();
302  } else if (state->next.find(action) != state->next.end() && !state->next.at(action).empty()) {
303  // Take the union of the guards and complement it to obtain the condition to get stuck
304  std::vector<std::vector<Constraint>> disjunctiveGuard = disjunctiveGuardOfUnobservable;
305  disjunctiveGuard.reserve(state->next.at(action).size());
306  for (const auto &transition: state->next.at(action)) {
307  if (transition.guard.empty()) {
308  disjunctiveGuard.clear();
309  break;
310  }
311  disjunctiveGuard.push_back(transition.guard);
312  }
313  if (disjunctiveGuard.empty()) {
314  continue;
315  }
316  const auto complementGuards = negate(disjunctiveGuard);
317  state->next.at(action).reserve(complementGuards.size());
318  for (const auto &guard: complementGuards) {
319  state->next.at(action).emplace_back(this->states.back().get(), learnta::TATransition::Resets{}, guard);
320  }
321  }
322  }
323  }
324  };
325 
328  for (const auto &state: this->states) {
329  for (auto &[action, transitions]: state->next) {
330  for (auto it = transitions.begin(); it != transitions.end(); ++it) {
331  for (auto it2 = std::next(it); it2 != transitions.end();) {
332  if (it->mergeable(*it2)) {
333  *it = it->merge(*it2);
334  it2 = transitions.erase(it2);
335  } else {
336  ++it2;
337  }
338  }
339  }
340  }
341  }
342 
343  return *this;
344  }
345 
348  for (const auto &state: this->states) {
349  std::unordered_map<Alphabet, std::vector<learnta::TATransition>> newNext;
350  for (auto &[action, transitions]: state->next) {
351  std::vector<learnta::TATransition> reducedTransitions;
352  for (const auto &transition: transitions) {
353  auto it = std::find_if(reducedTransitions.begin(), reducedTransitions.end(), [&](const auto &another) {
354  return transition.target == another.target && transition.resetVars == another.resetVars &&
355  isWeaker(another.guard, transition.guard);
356  });
357  if (it == reducedTransitions.end()) {
358  reducedTransitions.push_back(transition);
359  }
360  }
361  newNext[action] = reducedTransitions;
362  }
363  state->next = newNext;
364  }
365  }
366 
369  std::unordered_set<TAState *> reachableStates;
370  std::deque<TAState *> currentQueue;
371  for (const auto &initialState: this->initialStates) {
372  reachableStates.insert(initialState.get());
373  currentQueue.push_back(initialState.get());
374  }
375 
376  // Make the set of trivially reachable states
377  while (!currentQueue.empty()) {
378  const auto currentState = currentQueue.front();
379  currentQueue.pop_front();
380  for (const auto &[action, transitions]: currentState->next) {
381  for (const auto &transition: transitions) {
382  if (reachableStates.find(transition.target) == reachableStates.end()) {
383  reachableStates.insert(transition.target);
384  currentQueue.push_back(transition.target);
385  }
386  }
387  }
388  }
389 
390  if (reachableStates.size() != this->stateSize()) {
391  // remove redundant states
392  BOOST_LOG_TRIVIAL(info) << "There are " << this->stateSize() - reachableStates.size() << " redundant states";
393  for (auto it = this->states.begin(); it != this->states.end();) {
394  if (reachableStates.find(it->get()) == reachableStates.end()) {
395  it = this->states.erase(it);
396  } else {
397  ++it;
398  }
399  }
400  assert(this->stateSize() == reachableStates.size());
401 
402  // Update the max constraints
403  this->maxConstraints = TimedAutomaton::makeMaxConstants(this->states);
404  }
405  }
406 
408  void removeDeadLoop() {
409  std::deque<std::shared_ptr<TAState>> nonAccepting;
410  std::copy_if(this->states.begin(), this->states.end(), std::back_inserter(nonAccepting),
411  [](const std::shared_ptr<TAState> &state) {
412  return !state->isMatch;
413  });
414  while (!nonAccepting.empty()) {
415  std::shared_ptr<TAState> current = nonAccepting.front();
416  nonAccepting.pop_front();
417  // We do not remove the initial states
418  if (std::find(this->initialStates.begin(), this->initialStates.end(), current) != this->initialStates.end()) {
419  continue;
420  }
421  if (std::all_of(current->next.begin(), current->next.end(), [&](const auto &pair) {
422  return std::all_of(pair.second.begin(), pair.second.end(), [&](const auto &transition) {
423  return transition.target == current.get();
424  });
425  })) {
426  // We remove only the transitions for the totality
427  current->next.clear();
428  }
429  }
430  }
431 
436  std::unordered_map<TAState *, std::unordered_set<TAState *>> backwardEdges;
437  for (const auto &state: this->states) {
438  for (const auto &[action, transitions]: state->next) {
439  for (const auto &transition: transitions) {
440  auto it = backwardEdges.find(transition.target);
441  if (it == backwardEdges.end()) {
442  backwardEdges[transition.target] = {state.get()};
443  } else {
444  backwardEdges.at(transition.target).insert(state.get());
445  }
446  }
447  }
448  }
449 
450  // The states potentially reachable to an accepting state
451  std::unordered_set<TAState *> liveStates;
452  std::queue<TAState *> newLiveStates;
453  for (const auto &state: this->states) {
454  if (state->isMatch) {
455  liveStates.insert(state.get());
456  newLiveStates.push(state.get());
457  }
458  }
459  while (!newLiveStates.empty()) {
460  const auto newLiveState = newLiveStates.front();
461  newLiveStates.pop();
462  if (backwardEdges.find(newLiveState) != backwardEdges.end()) {
463  for (const auto &backwardState: backwardEdges.at(newLiveState)) {
464  if (liveStates.find(backwardState) == liveStates.end()) {
465  liveStates.insert(backwardState);
466  newLiveStates.push(backwardState);
467  }
468  }
469  }
470  }
471 
472  if (liveStates.size() != this->stateSize()) {
473  // Remove trivially dead states if exists
474  BOOST_LOG_TRIVIAL(info) << "There are " << this->stateSize() - liveStates.size() << " dead states";
475  this->states.erase(std::remove_if(this->states.begin(), this->states.end(), [&](const auto &state) {
476  return liveStates.find(state.get()) == liveStates.end();
477  }), this->states.end());
478  this->initialStates.erase(
479  std::remove_if(this->initialStates.begin(), this->initialStates.end(), [&](const auto &state) {
480  return liveStates.find(state.get()) == liveStates.end();
481  }), this->initialStates.end());
482  for (const auto &state: this->states) {
483  for (auto it = state->next.begin(); it != state->next.end();) {
484  auto &[action, transitions] = *it;
485  transitions.erase(std::remove_if(transitions.begin(), transitions.end(), [&](const auto &transition) {
486  return liveStates.find(transition.target) == liveStates.end();
487  }), transitions.end());
488  if (it->second.empty()) {
489  it = state->next.erase(it);
490  } else {
491  ++it;
492  }
493  }
494  }
495  }
496  }
497 
500  std::deque<std::shared_ptr<TAState>> nonAccepting;
501  std::copy_if(this->states.begin(), this->states.end(), std::back_inserter(nonAccepting),
502  [](const std::shared_ptr<TAState> &state) {
503  return !state->isMatch;
504  });
505  while (!nonAccepting.empty()) {
506  std::shared_ptr<TAState> current = nonAccepting.front();
507  nonAccepting.pop_front();
508  // We do not remove the initial states
509  if (std::find(this->initialStates.begin(), this->initialStates.end(), current) != this->initialStates.end()) {
510  continue;
511  }
512  if (current->next.empty() || std::all_of(current->next.begin(), current->next.end(), [&](const auto &pair) {
513  return std::all_of(pair.second.begin(), pair.second.end(), [&](const auto &transition) {
514  return transition.target == current.get();
515  });
516  })) {
517  this->states.erase(std::remove(this->states.begin(), this->states.end(), current), this->states.end());
518  // Remove the transition to the removed location
519  for (auto &state: this->states) {
520  for (auto it = state->next.begin(); it != state->next.end();) {
521  auto &[action, transitions] = *it;
522  transitions.erase(std::remove_if(transitions.begin(), transitions.end(), [&](const auto &transition) {
523  return transition.target == current.get();
524  }), transitions.end());
525 
526  if (transitions.empty()) {
527  it = state->next.erase(it);
528  } else {
529  ++it;
530  }
531  }
532  }
533  }
534  }
535 
536  return *this;
537  }
538 
543  std::unordered_set<ClockVariables> usedClockVariables;
544  // Make the set of clock variables
545  for (const auto &state: this->states) {
546  for (const auto &[action, transitions]: state->next) {
547  for (const auto &transition: transitions) {
548  for (const auto &guard: transition.guard) {
549  usedClockVariables.insert(guard.x);
550  }
551  for (const auto &[assignedVar, newValue]: transition.resetVars) {
552  if (newValue.index() == 1) {
553  usedClockVariables.insert(std::get<ClockVariables>(newValue));
554  }
555  }
556  }
557  }
558  }
559 
560  // Construct a map showing how we rename clock variables
561  std::vector<ClockVariables> usedClockVariablesVec{usedClockVariables.begin(), usedClockVariables.end()};
562  std::sort(usedClockVariablesVec.begin(), usedClockVariablesVec.end());
563  // Clock variable x is renamed to clockRenaming.at(x)
564  std::unordered_map<ClockVariables, ClockVariables> clockRenaming;
565  for (std::size_t i = 0; i < usedClockVariablesVec.size(); ++i) {
566  clockRenaming[usedClockVariablesVec.at(i)] = i;
567  }
568 
569  // Rename the clock variables
570  for (const auto &state: this->states) {
571  for (auto &[action, transitions]: state->next) {
572  for (auto &transition: transitions) {
573  for (auto &guard: transition.guard) {
574  guard.x = clockRenaming.at(guard.x);
575  }
576  for (auto it = transition.resetVars.begin(); it != transition.resetVars.end();) {
577  if (usedClockVariables.find(it->first) == usedClockVariables.end()) {
578  it = transition.resetVars.erase(it);
579  } else {
580  it->first = clockRenaming.at(it->first);
581  if (it->second.index() == 1) {
582  it->second = clockRenaming.at(std::get<ClockVariables>(it->second));
583  }
584  ++it;
585  }
586  }
587  }
588  }
589  }
590 
591  // Rename the max constraints
592  for (std::size_t i = 0; i < usedClockVariablesVec.size(); ++i) {
593  this->maxConstraints.at(i) = this->maxConstraints.at(usedClockVariablesVec.at(i));
594  }
595  this->maxConstraints.erase(this->maxConstraints.begin() + usedClockVariablesVec.size(),
596  this->maxConstraints.end());
597  }
598 
601  this->simplifyTransitions();
602  this->removeTriviallyUnreachableStates();
603  this->removeUnusedClockVariables();
604 
605  return *this;
606  }
607 
614  this->simplifyTransitions();
615  this->removeTriviallyUnreachableStates();
616  this->removeTriviallyDeadStates();
617  this->removeDeadLoop();
618  this->removeUselessTransitions();
619  this->removeUnusedClockVariables();
620 
621  return *this;
622  }
623 
629  TimedAutomaton simplifyWithZones();
630 
634  static std::vector<int> makeMaxConstants(const std::vector<std::shared_ptr<TAState>> &states) {
635  std::vector<int> maxConstants;
636  for (const auto &state: states) {
637  for (const auto &[action, transitions]: state->next) {
638  for (const auto &transition: transitions) {
639  for (const auto &guard: transition.guard) {
640  if (guard.x >= maxConstants.size()) {
641  maxConstants.resize(guard.x + 1);
642  }
643  maxConstants[guard.x] = std::max(maxConstants[guard.x], guard.c);
644  }
645  for (const auto &[resetVar, updatedVarOpt]: transition.resetVars) {
646  if (resetVar >= maxConstants.size()) {
647  maxConstants.resize(resetVar + 1);
648  }
649  if (updatedVarOpt.index() == 1 && std::get<ClockVariables>(updatedVarOpt) >= maxConstants.size()) {
650  maxConstants.resize(std::get<ClockVariables>(updatedVarOpt) + 1);
651  }
652  }
653  }
654  }
655  }
656 
657  return maxConstants;
658  }
659 
660  [[nodiscard]] bool deterministic() const {
661  return std::all_of(this->states.begin(), this->states.end(), std::mem_fn(&TAState::deterministic));
662  }
663 
664  void addUpperBoundForUnobservableTransitions() {
665  std::for_each(this->states.begin(), this->states.end(),
666  std::mem_fn(&TAState::addUpperBoundForUnobservableTransitions));
667  }
668  };
669 }
670 
671 namespace std {
672  static inline std::ostream &
673  operator<<(std::ostream &os, const learnta::TATransition::Resets::value_type &resetVarPair) {
674  const auto &[resetVar, newVar] = resetVarPair;
675  os << "x" << int(resetVar) << " := ";
676  if (newVar.index() == 1) {
677  os << "x" << int(std::get<learnta::ClockVariables>(newVar));
678  } else {
679  os << std::get<double>(newVar);
680  }
681 
682  return os;
683  }
684 
685  static inline std::ostream &operator<<(std::ostream &os, const learnta::TATransition::Resets &resetVars) {
686  bool isFirst = true;
687  for (const auto &resetVarPair: resetVars) {
688  if (!isFirst) {
689  os << ", ";
690  }
691  os << resetVarPair;
692  isFirst = false;
693  }
694 
695  return os;
696  }
697 }
698 
699 namespace learnta {
700  static inline std::ostream &operator<<(std::ostream &os,
701  const TimedAutomaton &TA) {
702  std::unordered_map<TAState *, bool> isInit;
703  std::unordered_map<TAState *, unsigned int> stateNumber;
704 
705  for (unsigned int i = 0; i < TA.states.size(); ++i) {
706  // Check if the state is initial for each state
707  isInit[TA.states.at(i).get()] =
708  std::find(TA.initialStates.begin(), TA.initialStates.end(),
709  TA.states.at(i)) != TA.initialStates.end();
710  // Assign a number for each state
711  stateNumber[TA.states.at(i).get()] = i;
712  }
713  os << "digraph G {\n";
714 
715  for (const std::shared_ptr<TAState> &state: TA.states) {
716  os << " loc" << stateNumber.at(state.get())
717  << " [init=" << isInit.at(state.get()) << ", match=" << state->isMatch
718  << "]\n";
719  }
720 
721  for (const std::shared_ptr<TAState> &source: TA.states) {
722  for (const auto &edges: source->next) {
723  for (const TATransition &edge: edges.second) {
724  TAState *target = edge.target;
725  os << " loc" << stateNumber.at(source.get()) << "->loc"
726  << stateNumber.at(target) << " [label=\"";
727  if (edges.first != UNOBSERVABLE) {
728  os << edges.first;
729  } else {
730  os << UNOBSERVABLE_STRING;
731  }
732  os << "\"";
733  if (!edge.guard.empty()) {
734  os << ", guard=\"{" << edge.guard << "}\"";
735  }
736  if (!edge.resetVars.empty()) {
737  os << ", reset=\"{" << edge.resetVars << "}\"";
738  }
739  os << "]\n";
740  }
741  }
742  }
743  os << "}\n";
744  return os;
745  }
746 
747  static inline std::unordered_map<ClockVariables, std::variant<double, ClockVariables>>
748  asMap(const TATransition::Resets &resets) {
749  std::unordered_map<ClockVariables, std::variant<double, ClockVariables>> result;
750  for (const auto &[key, value]: resets) {
751  result[key] = value;
752  }
753 
754  return result;
755  }
756 
757 
761  static inline TATransition::Resets composition(const TATransition::Resets &left, const TATransition::Resets &right) {
762  TATransition::Resets result;
763  const auto leftMap = asMap(left);
764  const auto rightMap = asMap(right);
765  result.reserve(leftMap.size() + rightMap.size());
766  // Composite left and right
767  for (const auto &[key, value]: leftMap) {
768  if (value.index() == 0) {
769  result.emplace_back(key, value);
770  } else {
771  const auto midVar = std::get<ClockVariables>(value);
772  auto it = rightMap.find(midVar);
773  if (it == rightMap.end()) {
774  result.emplace_back(key, value);
775  } else {
776  result.emplace_back(key, it->second);
777  }
778  }
779  }
780  // We directly use right if the value is not updated by left
781  for (const auto &[key, value]: rightMap) {
782  if (leftMap.find(key) == leftMap.end()) {
783  result.emplace_back(key, value);
784  }
785  }
786 
787  return result;
788  }
789 
790  static inline TATransition::Resets
791  addDefault(const TATransition::Resets &original, const TATransition::Resets &defaultReset) {
792  const auto originalMap = asMap(original);
793  const auto defaultMap = asMap(defaultReset);
794  TATransition::Resets result = original;
795  result.reserve(defaultMap.size());
796  // Composite left and right
797  for (const auto &[key, value]: defaultReset) {
798  if (originalMap.find(key) == originalMap.end()) {
799  result.emplace_back(key, value);
800  }
801  }
802 
803  return result;
804  }
805 
806  static inline TATransition::Resets clean(const TATransition::Resets &resets) {
807  auto result = resets;
808  result.erase(std::remove_if(result.begin(), result.end(), [](const auto &resetPair) {
809  return resetPair.second.index() == 1 && resetPair.first == std::get<ClockVariables>(resetPair.second);
810  }), result.end());
811  return result;
812  }
813 }
Definition: experiment_runner.hh:23
static bool adjacent(const std::vector< Constraint > &left, const std::vector< Constraint > &right)
Check if two guards are adjacent.
Definition: constraint.hh:530
static TATransition::Resets composition(const TATransition::Resets &left, const TATransition::Resets &right)
Construct the composition ( ) of the resets.
Definition: timed_automaton.hh:761
static auto unionHull(const std::vector< std::vector< Constraint >> &guards)
Return the strongest guard that is weaker than all of the given guards.
Definition: constraint.hh:440
Definition: external_transition_maker.hh:149
An automaton.
Definition: common_types.hh:18
std::vector< std::shared_ptr< State > > initialStates
The initial states of this automaton.
Definition: common_types.hh:24
std::vector< std::shared_ptr< State > > states
The states of this automaton.
Definition: common_types.hh:19
std::size_t stateSize() const
Returns the number of the states.
Definition: common_types.hh:27
A state of timed automata.
Definition: timed_automaton.hh:28
void mergeNondeterministicBranching()
Make it deterministic by merging transitions.
Definition: timed_automaton.cc:215
std::unordered_map< Alphabet, std::vector< TATransition > > next
A mapping of a character to the transitions.
Definition: timed_automaton.hh:35
void removeTransitionsWithWeakerGuards()
Remove transitions with weaker guards if they have the same target.
Definition: timed_automaton.cc:156
bool deterministic() const
Check if the transitions is deterministic.
Definition: timed_automaton.cc:132
bool needSplitting() const
Check if there is a non-deterministic branching due to different set of imprecise clocks.
Definition: timed_automaton.cc:200
bool isMatch
The value is true if and only if the state is an accepting state.
Definition: timed_automaton.hh:30
A state of timed automata.
Definition: timed_automaton.hh:82
static std::size_t impreciseAssignSize(const Resets &resets)
Return the number of potentially imprecise constant assignments.
Definition: timed_automaton.hh:180
TAState * target
The pointer to the target state.
Definition: timed_automaton.hh:85
static std::size_t impreciseConstantAssignSize(const Resets &resets)
Return the number of imprecise constant assignments.
Definition: timed_automaton.hh:166
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
A timed automaton.
Definition: timed_automaton.hh:213
size_t clockSize() const
Returns the number of clock variables used in the timed automaton.
Definition: timed_automaton.hh:252
void removeDeadLoop()
Remove self loop of non-accepting locations.
Definition: timed_automaton.hh:408
std::vector< int > maxConstraints
The maximum constraints for each clock variables.
Definition: timed_automaton.hh:215
TimedAutomaton mergeAdjacentTransitions()
simplify the transitions by reducing the duplications
Definition: timed_automaton.hh:327
static std::vector< int > makeMaxConstants(const std::vector< std::shared_ptr< TAState >> &states)
Make a vector showing maximum constants for each variable from a set of states.
Definition: timed_automaton.hh:634
TimedAutomaton simplify()
Simplify the timed automaton.
Definition: timed_automaton.hh:600
TimedAutomaton removeUselessTransitions()
Remove self loop of non-accepting locations.
Definition: timed_automaton.hh:499
void removeUnusedClockVariables()
Optimize the timed automaton by removing unused clock variables.
Definition: timed_automaton.hh:542
TimedAutomaton simplifyStrong()
Simplify the timed automaton.
Definition: timed_automaton.hh:613
void removeTriviallyDeadStates()
Remove trivially dead states, i.e., unreachable to any of the accepting states as a graph.
Definition: timed_automaton.hh:435
void deepCopy(TimedAutomaton &dest, std::unordered_map< TAState *, std::shared_ptr< TAState >> &old2new) const
make a deep copy of this timed automaton.
Definition: timed_automaton.hh:224
void makeComplete(const std::vector< Alphabet > &alphabet)
Add transitions to make it complete.
Definition: timed_automaton.hh:277
TimedAutomaton complement(const std::vector< Alphabet > &alphabet) const
Take the complement of this timed automaton.
Definition: timed_automaton.hh:261
void removeTriviallyUnreachableStates()
Remove the transitions that are unreachable from the initial states abstracting the timing constraint...
Definition: timed_automaton.hh:368
void simplifyTransitions()
simplify the transitions by reducing the duplications
Definition: timed_automaton.hh:347