libmonaa  0.5.2
intermediate_zone.hh
1 #pragma once
2 
3 #include <boost/variant.hpp>
4 #include <iostream>
5 
6 #include "interval.hh"
7 #include "zone.hh"
8 
9 class IntermediateZone : public Zone {
10 private:
11  std::vector<bool> isAllocated;
12  static constexpr ClockVariables initialClock = 1;
13 
14 public:
15  ClockVariables newestClock;
16  // intervals]0]: t
17  // intervals]1]: t'
18  // intervals]2]: t' - t
19  // This is not an intervals but cells of DBMs
20  std::vector<Interval> intervals;
21  bool useInterval;
26  IntermediateZone(const Interval &interval)
27  : intervals({std::move(interval)}) {
28  useInterval = true;
29  intervals[0].lowerBound.first *= -1;
30  newestClock = 1;
31  }
32 
39  IntermediateZone(Zone zone, std::size_t currentNewestClock = 0)
40  : Zone(std::move(zone)) {
41  useInterval = false;
42  // The zone must have at least one variable
43 #ifdef DEBUG
44  assert(value.cols() == value.rows());
45  assert(value.cols() > 1);
46 #endif
47  isAllocated.resize(value.cols(), false);
48  if (currentNewestClock) {
49  newestClock = currentNewestClock;
50  for (ClockVariables x = currentNewestClock + 1; x < value.cols(); x++) {
51  deallocate(x);
52  }
53  } else {
54  newestClock = value.cols() - 1;
55  }
56  isAllocated[0] = true;
57  isAllocated[initialClock] = true;
58  isAllocated[newestClock] = true;
59  }
60 
62  ClockVariables alloc(const std::pair<double, bool> &upperBound,
63  const std::pair<double, bool> &lowerBound) {
64  static constexpr Bounds infinity =
65  Bounds(std::numeric_limits<double>::infinity(), false);
66  ClockVariables newClock;
67 #define likely(x) __builtin_expect(!!(x), 1)
68 #ifdef __GNUC__
69  if (likely(useInterval && intervals.size() == 1)) {
70 #else
71  if (useInterval && intervals.size() == 1) {
72 #endif
73  // use intervals
74  intervals.reserve(3);
75  intervals.emplace_back(std::move(lowerBound), std::move(upperBound));
76  // value(2, 1) <= value(2, 0) + value(0, 1)
77  // value(1, 2) <= value(1, 0) + value(0, 2)
78  intervals.emplace_back(
79  std::min(intervals[0].upperBound + intervals[1].lowerBound,
80  Bounds{0, true}),
81  intervals[1].upperBound + intervals[0].lowerBound);
82  return newestClock = 2;
83  } else if (useInterval) {
84  // convert intervals to a zone
85  useInterval = false;
86  isAllocated.resize(4, true);
87  value.resize(4, 4);
88  value.fill(Bounds(infinity));
89  for (int i = 0; i < 4; i++) {
90  value(i, i) = Bounds{0, true};
91  }
92  value(1, 0) = intervals[0].upperBound;
93  value(0, 1) = intervals[0].lowerBound;
94  value(2, 0) = intervals[1].upperBound;
95  value(0, 2) = intervals[1].lowerBound;
96  value(2, 1) = intervals[2].upperBound;
97  value(1, 2) = intervals[2].lowerBound;
98  value(2, 3) = Bounds{0, true};
99  value(3, 0) = std::move(upperBound);
100  value(0, 3) = std::move(lowerBound);
101  intervals.clear();
102  newClock = 3;
103  } else {
104  const auto newPos =
105  std::find(isAllocated.begin(), isAllocated.end(), false);
106 #ifdef DEBUG
107  assert(value.cols() == value.rows());
108 #endif
109 
110  if (newPos != isAllocated.end()) {
111  // we do not have to alloc
112  newClock = newPos - isAllocated.begin();
113  } else {
114  // we have to alloc
116  // throw "monaa: Unexpected Variable Allocation";
118  value.conservativeResize(value.cols() + 1, value.cols() + 1);
119  newClock = value.cols() - 1;
120  isAllocated.resize(value.cols());
121  value.row(newClock).fill(infinity);
122  value.col(newClock).fill(infinity);
123  value(newClock, newClock) = Bounds(0, true);
124  }
125  isAllocated[newClock] = true;
126  value(newClock, 0) = std::move(upperBound);
127  value(0, newClock) = std::move(lowerBound);
128  value(newClock, newestClock) = Bounds(infinity);
129  value(newestClock, newClock) = {0, true};
130 #ifdef DEBUG
131  assert(value.cols() == value.rows());
132 #endif
133  }
134  for (int i = 0; i < value.rows(); i++) {
135  // for (int x = 0; x < value.cols(); x++) {
136  // value(i, newClock) = std::min(value(i, newClock), value(i, x) +
137  // value(x, newClock));
138  // }
139  value(i, newClock) =
140  std::min(value(i, newClock),
141  (value.row(i) + value.col(newClock).transpose()).minCoeff());
142  }
143  for (int x = 0; x < value.rows(); x++) {
144  for (int j = 0; j < value.cols(); j++) {
145  value(newClock, j) =
146  std::min(value(newClock, j), value(newClock, x) + value(x, j));
147  }
148  }
149  return newestClock = newClock;
150  }
151 
152  void
153  update(const std::vector<boost::variant<double, ClockVariables>> &resetTime) {
154  if (useInterval) {
155  return;
156  }
157 #ifdef DEBUG
158  assert(value.cols() == value.rows());
159 #endif
160  std::fill(isAllocated.begin(), isAllocated.end(), false);
161  isAllocated[0] = true;
162  isAllocated[initialClock] = true;
163  isAllocated[newestClock] = true;
164  for (auto rtime : resetTime) {
165  const ClockVariables *p_x = boost::get<ClockVariables>(&rtime);
166  if (p_x) {
167  isAllocated[*p_x] = true;
168  }
169  }
170  for (ClockVariables x = 1; x < value.cols(); x++) {
171  if (!isAllocated[x]) {
172  deallocate(x);
173  }
174  }
175  }
176 
177  void toAns(Zone &ansZone) const {
178  ansZone = Zone::zero(3);
179  if (useInterval) {
180  if (intervals.size() < 3) {
181  return;
182  }
183  ansZone.value(0, 1) = intervals[0].lowerBound;
184  ansZone.value(1, 0) = intervals[0].upperBound;
185  ansZone.value(0, 2) = intervals[1].lowerBound;
186  ansZone.value(2, 0) = intervals[1].upperBound;
187  ansZone.value(1, 2) = intervals[2].lowerBound;
188  ansZone.value(2, 1) = intervals[2].upperBound;
189  } else {
190  ansZone.value(0, 1) = value(0, 1);
191  ansZone.value(1, 0) = value(1, 0);
192  ansZone.value(0, 2) = value(0, newestClock);
193  ansZone.value(2, 0) = value(newestClock, 0);
194  ansZone.value(1, 2) = value(1, newestClock);
195  ansZone.value(2, 1) = value(newestClock, 1);
196  }
197  }
198 
204  void tighten(const ClockVariables x, const ClockVariables y, Bounds c) {
205  if (useInterval) {
206  if (x == 0 && y == 1) {
207  intervals[0].lowerBound = std::min(intervals[0].lowerBound, c);
208  if (intervals.size() > 1) {
209  // value(0, 2) <= value(0, 1) + value(1, 2)
210  intervals[1].lowerBound =
211  std::min(intervals[1].lowerBound,
212  intervals[0].lowerBound + intervals[2].lowerBound);
213  // value(2, 1) <= value(2, 0) + value(0, 1)
214  intervals[2].upperBound =
215  std::min(intervals[2].upperBound,
216  intervals[1].upperBound + intervals[0].lowerBound);
217  }
218  } else if (x == 1 && y == 0) {
219  intervals[0].upperBound = std::min(intervals[0].upperBound, c);
220  if (intervals.size() > 1) {
221  // value(2, 0) <= value(2, 1) + value(1, 0)
222  intervals[1].upperBound =
223  std::min(intervals[1].upperBound,
224  intervals[2].upperBound + intervals[0].upperBound);
225  // value(1, 2) <= value(1, 0) + value(0, 2)
226  intervals[2].lowerBound =
227  std::min(intervals[2].lowerBound,
228  intervals[0].upperBound + intervals[1].lowerBound);
229  }
230  } else if (x == 0 && y == 2) {
231  intervals[1].lowerBound = std::min(intervals[1].lowerBound, c);
232  intervals[0].lowerBound =
233  std::min(intervals[0].lowerBound,
234  intervals[1].lowerBound + intervals[2].upperBound);
235  intervals[2].lowerBound =
236  std::min(intervals[2].lowerBound,
237  intervals[1].lowerBound + intervals[0].upperBound);
238  } else if (x == 2 && y == 0) {
239  intervals[1].upperBound = std::min(intervals[1].upperBound, c);
240  intervals[0].upperBound =
241  std::min(intervals[0].upperBound,
242  intervals[1].upperBound + intervals[2].lowerBound);
243  intervals[2].upperBound =
244  std::min(intervals[2].upperBound,
245  intervals[1].upperBound + intervals[0].lowerBound);
246  } else if (x == 1 && y == 2) {
247  intervals[2].lowerBound = std::min(intervals[2].lowerBound, c);
248  intervals[0].upperBound =
249  std::min(intervals[0].upperBound,
250  intervals[1].upperBound + intervals[2].lowerBound);
251  intervals[1].lowerBound =
252  std::min(intervals[1].lowerBound,
253  intervals[2].lowerBound + intervals[0].lowerBound);
254  } else if (x == 2 && y == 1) {
255  intervals[2].upperBound = std::min(intervals[2].upperBound, c);
256  intervals[1].upperBound =
257  std::min(intervals[1].upperBound,
258  intervals[2].upperBound + intervals[0].upperBound);
259  intervals[0].lowerBound =
260  std::min(intervals[0].lowerBound,
261  intervals[1].lowerBound + intervals[2].upperBound);
262  }
263  } else {
264  value(x, y) = std::min(value(x, y), c);
265  if (value(x, y) == c && newestClock != initialClock) {
266  close1(x);
267  close1(y);
268  }
269  }
270  }
271 
272  void tighten(const ClockVariables x, const Constraint &c,
273  const ClockVariables reset = 0) {
274  switch (c.odr) {
275  case Constraint::Order::lt:
276  tighten(x, reset, Bounds{c.c, false});
277  break;
278  case Constraint::Order::le:
279  tighten(x, reset, Bounds{c.c, true});
280  break;
281  case Constraint::Order::gt:
282  tighten(reset, x, Bounds{-c.c, false});
283  break;
284  case Constraint::Order::ge:
285  tighten(reset, x, Bounds{-c.c, true});
286  break;
287  }
288  }
289 
290  void tighten(const ClockVariables x, const Constraint &c, const double t) {
291  switch (c.odr) {
292  case Constraint::Order::lt:
293  tighten(x, 0, Bounds{c.c + t, false});
294  break;
295  case Constraint::Order::le:
296  tighten(x, 0, Bounds{c.c + t, true});
297  break;
298  case Constraint::Order::gt:
299  tighten(0, x, Bounds{-c.c - t, false});
300  break;
301  case Constraint::Order::ge:
302  tighten(0, x, Bounds{-c.c - t, true});
303  break;
304  }
305  }
306 
307  void tighten(
308  const std::vector<Constraint> &constraints,
309  const std::vector<boost::variant<double, ClockVariables>> &resetTime) {
310  for (const Constraint &guard : constraints) {
311  const double *p_resetDouble = boost::get<double>(&resetTime[guard.x]);
312  const ClockVariables *p_resetClock =
313  boost::get<ClockVariables>(&resetTime[guard.x]);
314  if (p_resetDouble) {
315  tighten(newestClock, guard, *p_resetDouble);
316  } else {
317  tighten(newestClock, guard, *p_resetClock);
318  }
319  }
320  }
321 
322  void
323  tighten(const std::vector<Constraint> &constraints,
324  const std::vector<boost::variant<double, ClockVariables>> &resetTime,
325  const double t) {
326  for (const Constraint &guard : constraints) {
327  const double *p_resetDouble = boost::get<double>(&resetTime[guard.x]);
328  const ClockVariables *p_resetClock =
329  boost::get<ClockVariables>(&resetTime[guard.x]);
330  if (p_resetDouble) {
331  // This constraint is unsatisfyable
332  if (!guard.satisfy(t - *p_resetDouble)) {
333  if (useInterval) {
334  static constexpr Bounds negInfinity =
335  Bounds(-std::numeric_limits<double>::infinity(), false);
336  intervals[0].lowerBound = negInfinity;
337  } else {
338  makeUnsat();
339  }
340  }
341  } else {
342  switch (guard.odr) {
343  case Constraint::Order::lt:
344  tighten(0, *p_resetClock, Bounds{guard.c - t, false});
345  break;
346  case Constraint::Order::le:
347  tighten(0, *p_resetClock, Bounds{guard.c - t, true});
348  break;
349  case Constraint::Order::gt:
350  tighten(*p_resetClock, 0, Bounds{t - guard.c, false});
351  break;
352  case Constraint::Order::ge:
353  tighten(*p_resetClock, 0, Bounds{t - guard.c, true});
354  break;
355  }
356  }
357  }
358  }
359 
360  bool isSatisfiableCanonized() {
361  if (useInterval) {
362  return std::all_of(intervals.begin(), intervals.end(),
363  [](const Interval &interval) {
364  return interval.upperBound + interval.lowerBound >=
365  Bounds(0.0, true);
366  });
367  } else {
368  return (value + value.transpose()).minCoeff() >= Bounds(0.0, true);
369  }
370  }
371 
372  void deallocate(const ClockVariables x) {
373  static constexpr Bounds infinity =
374  Bounds(std::numeric_limits<double>::infinity(), false);
375  static constexpr Bounds zero = Bounds(0, true);
376  value.col(x).fill(infinity);
377  value.row(x).fill(infinity);
378  value(x, x) = zero;
379  }
380 };
Definition: intermediate_zone.hh:9
ClockVariables alloc(const std::pair< double, bool > &upperBound, const std::pair< double, bool > &lowerBound)
Definition: intermediate_zone.hh:62
void tighten(const ClockVariables x, const ClockVariables y, Bounds c)
add the constraint x - y \le (c,s)
Definition: intermediate_zone.hh:204
IntermediateZone(Zone zone, std::size_t currentNewestClock=0)
construct an intermediate zone from a zone
Definition: intermediate_zone.hh:39
IntermediateZone(const Interval &interval)
construct an intermediate zone from an interval
Definition: intermediate_zone.hh:26
The implementation of the class Interval and related functions.
A constraint in a guard of transitions.
Definition: constraint.hh:16
Class for an interval.
Definition: interval.hh:15
Implementation of a zone with DBM.
Definition: zone.hh:43
void makeUnsat()
make the zone unsatisfiable
Definition: zone.hh:169