LearnTA  0.0.1
external_transition_maker.hh
1 
6 #pragma once
7 
8 #include <utility>
9 #include <memory>
10 #include <numeric>
11 
12 #include <boost/unordered_map.hpp>
13 #include <boost/log/trivial.hpp>
14 #include <boost/log/core.hpp>
15 #include <boost/log/expressions.hpp>
16 
17 #include "timed_automaton.hh"
18 #include "renaming_relation.hh"
19 #include "timed_condition_set.hh"
20 
21 namespace learnta {
28  private:
29  // (TargetTAState, RenamingRelation) -> SourceTimedCondition
30  boost::unordered_map<std::pair<std::shared_ptr<TAState>, RenamingRelation>, TimedConditionSet> sourceMap;
31  // (TargetTAState, RenamingRelation) -> TargetTimedCondition
32  boost::unordered_map<std::pair<std::shared_ptr<TAState>, RenamingRelation>, TimedConditionSet> targetMap;
33  public:
39  static std::vector<double> toValuation(TimedCondition condition) {
40  std::vector<double> result;
41  result.resize(condition.size());
42  for (std::size_t i = 0; i < condition.size(); ++i) {
43  const auto lowerBound = condition.getLowerBound(i, condition.size() - 1);
44  const auto upperBound = condition.getUpperBound(i, condition.size() - 1);
45  if (lowerBound.first == -upperBound.first && lowerBound.second && upperBound.second) {
46  // When the bound is a point
47  result.at(i) = upperBound.first;
48  } else {
49  // When the bound is not a point
50  auto middlePoint = (upperBound.first - lowerBound.first) / 2.0;
51  result.at(i) = middlePoint;
52  condition.restrictLowerBound(i, condition.size() - 1, Bounds{-middlePoint, true}, false);
53  condition.restrictUpperBound(i, condition.size() - 1, Bounds{middlePoint, true}, false);
54  }
55  }
56 
57  return result;
58  }
59 
68  void add(const std::shared_ptr<TAState> &targetState, const RenamingRelation &renamingRelation,
69  const TimedCondition &sourceCondition, const TimedCondition &targetCondition) {
70  auto it = sourceMap.find(std::make_pair(targetState, renamingRelation));
71  if (it == sourceMap.end()) {
72  sourceMap[std::make_pair(targetState, renamingRelation)] = TimedConditionSet{sourceCondition};
73  targetMap[std::make_pair(targetState, renamingRelation)] = TimedConditionSet{targetCondition};
74  } else {
75  // TODO: Implement constraint merging to generate a smaller DTA
76  it->second.push_back(sourceCondition);
77  targetMap.at(std::make_pair(targetState, renamingRelation)).push_back(targetCondition);
78  }
79  }
80 
84  [[nodiscard]] std::vector<TATransition> make() const {
85  std::vector<TATransition> result;
86  result.reserve(sourceMap.size());
87 
88  for (const auto &[targetWithRenaming, sourceConditions]: sourceMap) {
89  const auto &[target, currentRenamingRelation] = targetWithRenaming;
90  BOOST_LOG_TRIVIAL(debug) << "currentRenamingRelation: " << currentRenamingRelation;
91  const auto targetConditions = targetMap.at(targetWithRenaming);
92  assert(sourceConditions.size() == targetConditions.size());
93  for (std::size_t i = 0; i < sourceConditions.size(); ++i) {
94  const auto sourceCondition = sourceConditions.getConditions().at(i);
95  const auto targetCondition = targetConditions.getConditions().at(i);
96  // Add implicit renaming relations
97  auto juxtaposedCondition = sourceCondition ^ targetCondition;
98  juxtaposedCondition.addRenaming(currentRenamingRelation);
99  auto newRenamingRelation = RenamingRelation{juxtaposedCondition.makeRenaming()};
100  // Make it unique in terms of the right variables
101  std::sort(newRenamingRelation.begin(), newRenamingRelation.end(), [] (const auto &left, const auto& right) {
102  return left.second < right.second || (left.second == right.second && left.first < right.first);
103  });
104  newRenamingRelation.erase(std::unique(newRenamingRelation.begin(), newRenamingRelation.end(),
105  [] (const auto &left, const auto &right) {
106  return left.second == right.second;
107  }), newRenamingRelation.end());
108  BOOST_LOG_TRIVIAL(debug) << "Constructing a transition with " << sourceCondition << " and "
109  << newRenamingRelation;
110  BOOST_LOG_TRIVIAL(debug) << "target condition: " << targetCondition;
111  // Generate transitions
112  auto resets = newRenamingRelation.toReset(sourceCondition, targetCondition);
113  BOOST_LOG_TRIVIAL(debug) << "Resets: " << resets;
114  result.emplace_back(target.get(), clean(resets), sourceCondition.toGuard());
115  }
116  }
117 
118  return result;
119  }
120 
124  static auto inactiveClockVariables(const RenamingRelation &renamingRelation, const TimedCondition &targetCondition) {
125  std::vector<ClockVariables> inactiveClocks;
126  inactiveClocks.resize(targetCondition.size());
127  const ClockVariables lastClock = targetCondition.size() - 1;
128  std::iota(inactiveClocks.begin(), inactiveClocks.end(), 0);
129  for (const auto &activeClock: renamingRelation.rightVariables()) {
130  inactiveClocks.erase(std::remove(inactiveClocks.begin(), inactiveClocks.end(), activeClock), inactiveClocks.end());
131  }
132  std::unordered_map<ClockVariables, std::size_t> result;
133  for (const auto &inactiveClock: inactiveClocks) {
134  // Check if the clock variable is active because of a constant constraint
135  if (!isPoint(targetCondition.getUpperBound(inactiveClock, lastClock), targetCondition.getLowerBound(inactiveClock, lastClock))) {
136  result[inactiveClock] = fabs(targetCondition.getUpperBound(inactiveClock, lastClock).first);
137  }
138  }
139  BOOST_LOG_TRIVIAL(debug) << "inactiveClockVariables: " << renamingRelation << ", " << targetCondition;
140  for (const auto &[inactiveClock, bound]: result) {
141  BOOST_LOG_TRIVIAL(debug) << "inactiveClockVariables: " << int(inactiveClock) << ", " << bound;
142  }
143 
144  return result;
145  }
146  };
147 }
148 
149 namespace std {
150  static inline std::ostream &operator<<(std::ostream &os, const std::pair<learnta::ClockVariables, std::size_t> &inactiveClockPair) {
151  const auto &[inactiveClock, bound] = inactiveClockPair;
152  os << "x" << int(inactiveClock) << ", " << bound;
153 
154  return os;
155  }
156 
157  static inline std::ostream &operator<<(std::ostream &os, const std::unordered_map<learnta::ClockVariables, std::size_t> &inactiveClocks) {
158  bool isFirst = true;
159  for (const auto &[inactiveClock, bound]: inactiveClocks) {
160  if (!isFirst) {
161  os << ", ";
162  }
163  os << "x" << int(inactiveClock) << ", " << bound;
164  isFirst = false;
165  }
166 
167  return os;
168  }
169 }
A class to make a transition from P to ext(P)
Definition: external_transition_maker.hh:27
std::vector< TATransition > make() const
Generate transitions.
Definition: external_transition_maker.hh:84
static std::vector< double > toValuation(TimedCondition condition)
Construct a reset to a value in the timed condition.
Definition: external_transition_maker.hh:39
void add(const std::shared_ptr< TAState > &targetState, const RenamingRelation &renamingRelation, const TimedCondition &sourceCondition, const TimedCondition &targetCondition)
Add a transition to targetState.
Definition: external_transition_maker.hh:68
static auto inactiveClockVariables(const RenamingRelation &renamingRelation, const TimedCondition &targetCondition)
Return the inactive clock variables after the transition.
Definition: external_transition_maker.hh:124
Definition: renaming_relation.hh:16
auto rightVariables() const
The clock variables on the right hand side of the renaming relation.
Definition: renaming_relation.hh:92
A set of timed conditions to represent non-convex constraints.
Definition: timed_condition_set.hh:18
A timed condition, a finite conjunction of inequalities of the form , where and .
Definition: timed_condition.hh:19
void restrictUpperBound(std::size_t i, std::size_t j, Bounds upperBound, bool force=false)
Restrict the upper bound of .
Definition: timed_condition.hh:263
Bounds getUpperBound(std::size_t i, std::size_t j) const
Returns the upper bound of .
Definition: timed_condition.hh:232
void restrictLowerBound(std::size_t i, std::size_t j, Bounds lowerBound, bool force=false)
Restrict the lower bound of .
Definition: timed_condition.hh:247
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
static bool isPoint(const Bounds &upperBound, const Bounds &lowerBound)
Check if the upper and lower bounds define a point.
Definition: bounds.hh:17
Definition: external_transition_maker.hh:149