7 #include <unordered_map>
8 #include <unordered_set>
16 #include <boost/log/trivial.hpp>
18 #include "common_types.hh"
19 #include "constraint.hh"
20 #include "conjunctive_constraint.hh"
35 std::unordered_map<Alphabet, std::vector<TATransition>>
next;
40 std::unordered_map<Alphabet, std::vector<TATransition>>
next)
48 void addUpperBoundForUnobservableTransitions();
57 void mergeNondeterministicBranchingWithSameTarget();
83 using Resets = std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>>;
91 std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>>
resetVars;
98 std::vector<std::pair<ClockVariables, std::variant<double, ClockVariables>>>
resetVars,
99 std::vector<Constraint>
guard)
107 TATransition(TATransition
const &) =
default;
109 bool operator==(
const TATransition &rhs)
const {
110 return target == rhs.target &&
115 bool operator!=(
const TATransition &rhs)
const {
116 return !(rhs == *
this);
119 ~TATransition() =
default;
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);
127 if (it != resetAsMap.end() && it->second.index() == 0 &&
128 std::get<double>(it->second) == std::floor(std::get<double>(it->second))) {
131 if (assignedValue.index() == 0 &&
132 std::get<double>(assignedValue) == std::floor(std::get<double>(assignedValue))) {
133 resetAsMap[targetVariable] = assignedValue;
137 this->resetVars.clear();
138 this->resetVars.reserve(resetAsMap.size());
139 std::copy(resetAsMap.begin(), resetAsMap.end(), std::back_inserter(this->resetVars));
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);
148 if (it != resetAsMap.end() && it->second.index() == 0 &&
149 std::get<double>(it->second) == std::floor(std::get<double>(it->second))) {
152 if (assignedValue.index() == 1 ||
153 std::get<double>(assignedValue) == std::floor(std::get<double>(assignedValue))) {
154 resetAsMap[targetVariable] = assignedValue;
158 this->resetVars.clear();
159 this->resetVars.reserve(resetAsMap.size());
160 std::copy(resetAsMap.begin(), resetAsMap.end(), std::back_inserter(this->resetVars));
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))) {
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))) {
191 [[nodiscard]]
bool mergeable(
const TATransition& transition)
const {
195 return this->resetVars == transition.
resetVars;
198 [[nodiscard]] TATransition merge(
const TATransition& transition)
const {
199 TATransition result = transition;
200 result.guard =
unionHull(transition.guard, this->guard);
206 inline std::size_t hash_value(
const TATransition &transition) {
207 return boost::hash_value(std::make_tuple(transition.target, transition.resetVars, transition.guard));
226 std::unordered_map<
TAState *, std::shared_ptr<TAState>> &old2new)
const {
230 for (
const auto &oldState:
states) {
231 dest.
states.emplace_back(std::make_shared<TAState>(*oldState));
232 old2new[oldState.get()] = dest.
states.back();
237 dest.
initialStates.emplace_back(old2new[oldInitialState.get()]);
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();
263 std::unordered_map<TAState *, std::shared_ptr<TAState>> old2new;
267 for (
const auto &state: result.
states) {
268 state->isMatch = !state->isMatch;
279 this->
states.push_back(std::make_shared<TAState>(
false));
283 for (
const auto &state: this->
states) {
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();
293 disjunctiveGuardOfUnobservable.push_back(transition.guard);
296 for (
const auto &action: alphabet) {
297 if (disjunctiveGuardOfUnobservable.empty() &&
298 (state->next.find(action) == state->next.end() || state->next.at(action).empty())) {
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()) {
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();
311 disjunctiveGuard.push_back(transition.guard);
313 if (disjunctiveGuard.empty()) {
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);
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);
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);
357 if (it == reducedTransitions.end()) {
358 reducedTransitions.push_back(transition);
361 newNext[action] = reducedTransitions;
363 state->next = newNext;
369 std::unordered_set<TAState *> reachableStates;
370 std::deque<TAState *> currentQueue;
372 reachableStates.insert(initialState.get());
373 currentQueue.push_back(initialState.get());
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);
390 if (reachableStates.size() != this->stateSize()) {
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);
400 assert(this->
stateSize() == reachableStates.size());
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;
414 while (!nonAccepting.empty()) {
415 std::shared_ptr<TAState> current = nonAccepting.front();
416 nonAccepting.pop_front();
418 if (std::find(this->
initialStates.begin(), this->initialStates.end(), current) != this->initialStates.end()) {
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();
427 current->next.clear();
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()};
444 backwardEdges.at(transition.target).insert(state.get());
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());
459 while (!newLiveStates.empty()) {
460 const auto newLiveState = newLiveStates.front();
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);
472 if (liveStates.size() != this->stateSize()) {
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);
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;
505 while (!nonAccepting.empty()) {
506 std::shared_ptr<TAState> current = nonAccepting.front();
507 nonAccepting.pop_front();
509 if (std::find(this->initialStates.begin(), this->initialStates.end(), current) != this->initialStates.end()) {
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();
517 this->states.erase(std::remove(this->states.begin(), this->states.end(), current), this->states.end());
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());
526 if (transitions.empty()) {
527 it = state->next.erase(it);
543 std::unordered_set<ClockVariables> usedClockVariables;
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);
551 for (
const auto &[assignedVar, newValue]: transition.
resetVars) {
552 if (newValue.index() == 1) {
553 usedClockVariables.insert(std::get<ClockVariables>(newValue));
561 std::vector<ClockVariables> usedClockVariablesVec{usedClockVariables.begin(), usedClockVariables.end()};
562 std::sort(usedClockVariablesVec.begin(), usedClockVariablesVec.end());
564 std::unordered_map<ClockVariables, ClockVariables> clockRenaming;
565 for (std::size_t i = 0; i < usedClockVariablesVec.size(); ++i) {
566 clockRenaming[usedClockVariablesVec.at(i)] = i;
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);
577 if (usedClockVariables.find(it->first) == usedClockVariables.end()) {
580 it->first = clockRenaming.at(it->first);
581 if (it->second.index() == 1) {
582 it->second = clockRenaming.at(std::get<ClockVariables>(it->second));
592 for (std::size_t i = 0; i < usedClockVariablesVec.size(); ++i) {
593 this->maxConstraints.at(i) = this->maxConstraints.at(usedClockVariablesVec.at(i));
595 this->maxConstraints.erase(this->maxConstraints.begin() + usedClockVariablesVec.size(),
596 this->maxConstraints.end());
601 this->simplifyTransitions();
602 this->removeTriviallyUnreachableStates();
603 this->removeUnusedClockVariables();
614 this->simplifyTransitions();
615 this->removeTriviallyUnreachableStates();
616 this->removeTriviallyDeadStates();
617 this->removeDeadLoop();
618 this->removeUselessTransitions();
619 this->removeUnusedClockVariables();
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);
643 maxConstants[guard.x] = std::max(maxConstants[guard.x], guard.c);
645 for (
const auto &[resetVar, updatedVarOpt]: transition.
resetVars) {
646 if (resetVar >= maxConstants.size()) {
647 maxConstants.resize(resetVar + 1);
649 if (updatedVarOpt.index() == 1 && std::get<ClockVariables>(updatedVarOpt) >= maxConstants.size()) {
650 maxConstants.resize(std::get<ClockVariables>(updatedVarOpt) + 1);
660 [[nodiscard]]
bool deterministic()
const {
661 return std::all_of(this->states.begin(), this->states.end(), std::mem_fn(&TAState::deterministic));
664 void addUpperBoundForUnobservableTransitions() {
665 std::for_each(this->states.begin(), this->states.end(),
666 std::mem_fn(&TAState::addUpperBoundForUnobservableTransitions));
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));
679 os << std::get<double>(newVar);
685 static inline std::ostream &operator<<(std::ostream &os,
const learnta::TATransition::Resets &resetVars) {
687 for (
const auto &resetVarPair: resetVars) {
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;
705 for (
unsigned int i = 0; i < TA.states.size(); ++i) {
707 isInit[TA.states.at(i).get()] =
708 std::find(TA.initialStates.begin(), TA.initialStates.end(),
709 TA.states.at(i)) != TA.initialStates.end();
711 stateNumber[TA.states.at(i).get()] = i;
713 os <<
"digraph G {\n";
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
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) {
730 os << UNOBSERVABLE_STRING;
733 if (!edge.guard.empty()) {
734 os <<
", guard=\"{" << edge.guard <<
"}\"";
736 if (!edge.resetVars.empty()) {
737 os <<
", reset=\"{" << edge.resetVars <<
"}\"";
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) {
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());
767 for (
const auto &[key, value]: leftMap) {
768 if (value.index() == 0) {
769 result.emplace_back(key, value);
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);
776 result.emplace_back(key, it->second);
781 for (
const auto &[key, value]: rightMap) {
782 if (leftMap.find(key) == leftMap.end()) {
783 result.emplace_back(key, value);
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());
797 for (
const auto &[key, value]: defaultReset) {
798 if (originalMap.find(key) == originalMap.end()) {
799 result.emplace_back(key, value);
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);
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