LearnTA  0.0.1
timed_automaton_runner.hh
1 
6 #pragma once
7 
8 #include <utility>
9 #include <vector>
10 
11 #include "sul.hh"
12 #include "timed_automaton.hh"
13 
14 namespace learnta {
22  class TimedAutomatonRunner : public SUL {
23  private:
24  TimedAutomaton automaton;
25  TAState *state;
26  std::vector<double> clockValuation;
27  std::size_t numQueries;
28  const bool isEmpty = false;
29  public:
30  explicit TimedAutomatonRunner(TimedAutomaton automaton) : automaton(std::move(automaton)),
31  isEmpty(this->automaton.states.empty()) {
32  if (!isEmpty) {
33  assert(this->automaton.initialStates.size() == 1);
34  this->state = this->automaton.initialStates.at(0).get();
35  this->clockValuation.resize(this->automaton.maxConstraints.size());
36  }
37  numQueries = 0;
38  }
39 
41  void pre() override {
42  if (!isEmpty) {
43  // We assume that the given timed automaton is deterministic
44  assert(this->clockValuation.size() == this->automaton.maxConstraints.size());
45  this->state = this->automaton.initialStates.at(0).get();
46  std::fill(this->clockValuation.begin(), this->clockValuation.end(), 0);
47  }
48  numQueries++;
49  }
50 
51  void post() override {
52  if (!isEmpty) {
53  assert(this->clockValuation.size() == this->automaton.maxConstraints.size());
54  }
55  }
56 
60  static std::vector<double> applyReset(const std::vector<double> &oldValuation, const TATransition::Resets &resets) {
61  auto valuation = oldValuation;
62  for (const auto &[resetVariable, targetVariable]: resets) {
63  if (targetVariable.index() == 1) {
64  valuation.at(resetVariable) = oldValuation.at(std::get<ClockVariables>(targetVariable));
65  } else {
66  valuation.at(resetVariable) = std::get<double>(targetVariable);
67  }
68  }
69 
70  return valuation;
71  }
72 
76  void applyReset(const TATransition::Resets &resets) {
77  this->clockValuation = applyReset(this->clockValuation, resets);
78  }
79 
80  bool step(char action) override {
81  if (isEmpty) {
82  return false;
83  }
84  assert(this->clockValuation.size() == this->automaton.maxConstraints.size());
85  // Skip the operation if we are at the sink state
86  if (this->state == nullptr) {
87  return false;
88  }
89  for (const TATransition &transition: this->state->next[action]) {
90  // Check if the guard is satisfied
91  if (std::all_of(transition.guard.begin(), transition.guard.end(), [&](const Constraint &guard) {
92  return guard.satisfy(this->clockValuation.at(guard.x));
93  })) {
94  // Reset the clock variables
95  this->applyReset(transition.resetVars);
96  this->state = transition.target;
97 
98  return this->state->isMatch;
99  }
100  }
101 
102  // If there is no outgoing transition, we go to the sink state
103  state = nullptr;
104  return false;
105  }
106 
107  bool step(double duration) override {
108  if (isEmpty) {
109  return false;
110  }
111  assert(this->clockValuation.size() == this->automaton.maxConstraints.size());
112  // Skip the operation if we are at the sink state
113  if (this->state == nullptr) {
114  return false;
115  }
116  if (duration == 0) {
117  return this->state->isMatch;
118  }
119  const auto unobservableIt = this->state->next.find(UNOBSERVABLE);
120  if (unobservableIt != this->state->next.end() && !unobservableIt->second.empty()) {
121  // If there are unobservable transitions, we choose the minimum duration to satisfy it
122  Bounds minDuration;
123  auto candidateTransition = unobservableIt->second.end();
124  if (unobservableIt->second.size() == 1) {
125  minDuration = lowerBoundDurationToSatisfy(unobservableIt->second.front().guard, this->clockValuation);
126  candidateTransition = unobservableIt->second.begin();
127  } else {
128  candidateTransition = std::min_element(unobservableIt->second.begin(), unobservableIt->second.end(),
129  [&](const auto &a, const auto &b) {
130  return lowerBoundDurationToSatisfy(a.guard, this->clockValuation) <
131  lowerBoundDurationToSatisfy(b.guard, this->clockValuation);
132  });
133  minDuration = lowerBoundDurationToSatisfy(candidateTransition->guard, this->clockValuation);
134  }
135  if (std::isfinite(minDuration.first) && minDuration.first <= 0 && Bounds{-duration, true} <= minDuration) {
136  // An unobservable transition is available
137  std::transform(this->clockValuation.begin(), this->clockValuation.end(), this->clockValuation.begin(),
138  [&](double value) {
139  return value + -minDuration.first;
140  });
141  // Reset the clock variables
142  // assert the validity of the candidate transition
143  assert(candidateTransition != unobservableIt->second.end());
144  this->applyReset(candidateTransition->resetVars);
145  this->state = candidateTransition->target;
146  return this->step(duration - ((minDuration.first == 0 && !minDuration.second) ? 1.0e-10 : -minDuration.first));
147  } else {
148  BOOST_LOG_TRIVIAL(debug) << "Unobservable transitions are skipped";
149  BOOST_LOG_TRIVIAL(debug) << "std::isfinite(-minDuration): " << std::isfinite(-minDuration.first);
150  BOOST_LOG_TRIVIAL(debug) << "minDuration: " << minDuration.first << ", " << minDuration.second;
151  BOOST_LOG_TRIVIAL(debug) << "duration: " << duration;
152  }
153  }
154  // No unobservable transition is available
155  std::transform(this->clockValuation.begin(), this->clockValuation.end(), this->clockValuation.begin(),
156  [&](double value) {
157  return value + duration;
158  });
159 
160  return this->state->isMatch;
161  }
162 
163  [[nodiscard]] std::size_t count() const override {
164  return numQueries;
165  }
166  };
167 }
Interface of the system under learning.
Definition: sul.hh:14
Class to execute a timed automaton.
Definition: timed_automaton_runner.hh:22
bool step(char action) override
Feed a discrete action.
Definition: timed_automaton_runner.hh:80
std::size_t count() const override
Returns the number of queries.
Definition: timed_automaton_runner.hh:163
static std::vector< double > applyReset(const std::vector< double > &oldValuation, const TATransition::Resets &resets)
Apply the given reset to the clock valuation.
Definition: timed_automaton_runner.hh:60
void applyReset(const TATransition::Resets &resets)
Apply the given reset to the clock valuation.
Definition: timed_automaton_runner.hh:76
bool step(double duration) override
Feed time elapse.
Definition: timed_automaton_runner.hh:107
void post() override
The function should be called after feeding each timed word.
Definition: timed_automaton_runner.hh:51
void pre() override
Reset the configuration.
Definition: timed_automaton_runner.hh:41
Definition: experiment_runner.hh:23
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
A constraint in a guard of transitions.
Definition: constraint.hh:32
A state of timed automata.
Definition: timed_automaton.hh:28
std::unordered_map< Alphabet, std::vector< TATransition > > next
A mapping of a character to the transitions.
Definition: timed_automaton.hh:35
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
A timed automaton.
Definition: timed_automaton.hh:213
std::vector< int > maxConstraints
The maximum constraints for each clock variables.
Definition: timed_automaton.hh:215