libmonaa  0.5.2
kmp_skip_value.hh
1 #pragma once
2 
3 #include <numeric>
4 #include <unordered_map>
5 
6 #include "intersection.hh"
7 #include "ta2za.hh"
8 #include "timed_automaton.hh"
9 #include "zone_automaton.hh"
10 
17 class KMPSkipValue {
18 private:
19  std::unordered_map<const TAState *, int> beta;
20 
21 public:
22  KMPSkipValue(const TimedAutomaton &TA, int m) {
23  ZoneAutomaton ZA2;
24  TimedAutomaton A2;
25  boost::unordered_map<std::pair<TAState *, TAState *>,
26  std::shared_ptr<TAState>>
27  toIState;
28  // A0 is the automaton in A_{+n}^* in the paper. What we do is: 1) construct
29  // a dummy accepting state, and 2) construct m-dummy states to the original
30  // initial states
31  TimedAutomaton A0;
32  std::unordered_map<TAState *, std::shared_ptr<TAState>> old2new0;
33  TA.deepCopy(A0, old2new0);
34  // Vector of extended initial states. if the accepting state is
35  // extendedInitialStates[n], the TA reads n-additional events.
36  std::vector<std::shared_ptr<TAState>> extendedInitialStates(m + 1);
37  std::generate(extendedInitialStates.begin(), extendedInitialStates.end(), std::make_shared<TAState>);
38 
39  for (const auto& initialState : A0.initialStates) {
40  for (auto it = initialState->next.begin(); it != initialState->next.end();
41  it++) {
42  for (TATransition edge : it->second) {
43  // We can modify edge because it is copied
44  const Alphabet c = it->first;
45  widen(edge.guard);
46  extendedInitialStates[0]->next[c].push_back(std::move(edge));
47  }
48  }
49  }
50 
51  std::vector<ClockVariables> allClocks(TA.clockSize());
52  std::iota(allClocks.begin(), allClocks.end(), 0);
53  for (int i = 1; i <= m; ++i) {
54  for (char c = 1; c < CHAR_MAX; ++c) {
55  extendedInitialStates[i]->next[c].push_back(
56  {extendedInitialStates[i - 1].get(), allClocks, {}});
57  }
58  }
59  auto dummyAcceptingState = std::make_shared<TAState>(true);
60  // add self loop
61  for (char c = 1; c < CHAR_MAX; ++c) {
62  dummyAcceptingState->next[c].push_back(
63  {dummyAcceptingState.get(), {}, {}});
64  }
65  for (auto &state : A0.states) {
66  for (auto & it : state->next) {
67  for (TATransition edge : it.second) {
68  const auto target = edge.target;
69  // We can modify edge because it is copied
70  if (target && target->isMatch) {
71  edge.target = dummyAcceptingState.get();
72  widen(edge.guard);
73  it.second.emplace_back(std::move(edge));
74  }
75  }
76  }
77  }
78  A0.states.reserve(A0.states.size() + 1 + (m + 1));
79  A0.states.push_back(dummyAcceptingState);
80  A0.states.insert(A0.states.end(), extendedInitialStates.begin(),
81  extendedInitialStates.end());
82 
83  // As is the automaton in A_{s}^* in the paper. What we do is to construct a
84  // dummy state for each state s.
85  TimedAutomaton As;
86  std::unordered_map<TAState *, std::shared_ptr<TAState>> old2newS;
87  old2newS.reserve(TA.states.size());
88  TA.deepCopy(As, old2newS);
89  std::unordered_map<std::shared_ptr<TAState>, std::shared_ptr<TAState>>
90  toDummyState;
91  toDummyState.reserve(TA.states.size());
92  for (const auto& state : As.states) {
93  toDummyState[state] = std::make_shared<TAState>();
94  state->next[0].push_back({toDummyState[state].get(), {}, {}});
95  // add self loop
96  for (char c = 1; c < CHAR_MAX; ++c) {
97  toDummyState[state]->next[c].push_back(
98  {toDummyState[state].get(), {}, {}});
99  }
100  }
101  As.states.reserve(As.states.size() * 2);
102  for (const auto& dummyState : toDummyState) {
103  As.states.push_back(dummyState.second);
104  }
105 
106  intersectionTA(A0, As, A2, toIState);
107 
108  // Calculate KMP-type skip value
109  for (const auto& origState : TA.states) {
110  for (auto &stateAs : As.states) {
111  stateAs->isMatch = stateAs == old2newS[origState.get()] ||
112  stateAs == toDummyState[old2newS[origState.get()]];
113  }
114  // Find the minimum n such that the intersection of the two languages is
115  // not empty.
116  for (int n = 1; n <= m; n++) {
117  A0.initialStates = {extendedInitialStates[n]};
118  updateInitAccepting(A0, As, A2, toIState);
119  std::sort(A2.initialStates.begin(), A2.initialStates.end());
120  ta2za(A2, ZA2);
122  if (!ZA2.empty()) {
123  beta[origState.get()] = n;
124  break;
125  }
126  }
127  // When the emptiness checking always failed, we set m
128  beta.insert(std::make_pair(origState.get(), m));
129  }
130  }
131 
132  inline int at(const TAState *s) const { return beta.at(s); }
133  inline int operator[](const TAState *s) const { return beta.at(s); }
134  inline int at(const std::shared_ptr<TAState>& s) const { return beta.at(s.get()); }
135  inline int operator[](const std::shared_ptr<TAState>& s) const {
136  return beta.at(s.get());
137  }
138 };
The skip value function based on the KMP algorithm for string matching.
Definition: kmp_skip_value.hh:17
std::vector< std::shared_ptr< State > > states
The states of this automaton.
Definition: common_types.hh:14
std::vector< std::shared_ptr< State > > initialStates
The initial states of this automaton.
Definition: common_types.hh:19
A state of timed automata.
Definition: timed_automaton.hh:19
A state of timed automata.
Definition: timed_automaton.hh:42
std::vector< Constraint > guard
The guard for this transition.
Definition: timed_automaton.hh:48
TAState * target
The pointer to the target state.
Definition: timed_automaton.hh:44
A timed automaton.
Definition: timed_automaton.hh:54
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:68
size_t clockSize() const
Returns the number of clock variables used in the timed automaton.
Definition: timed_automaton.hh:95
Definition: zone_automaton.hh:55
void updateInitAccepting(const std::vector< std::shared_ptr< TAState >> taInitialStates)
Propagate accepting states from the original timed automaton.
Definition: zone_automaton.hh:116
bool empty() const
emptiness check of the language
Definition: zone_automaton.hh:136