LearnTA  0.0.1
equivalence.hh
Go to the documentation of this file.
1 
8 #pragma once
9 
10 #include "elementary_language.hh"
11 #include "backward_regional_elementary_language.hh"
12 #include "timed_condition_set.hh"
13 #include "juxtaposed_zone_set.hh"
14 #include "renaming_relation.hh"
15 
16 namespace learnta {
22  static bool equivalence(const ElementaryLanguage &left,
23  const std::vector<TimedConditionSet> &leftRow,
24  const ElementaryLanguage &right,
25  const std::vector<TimedConditionSet> &rightRow,
26  const std::vector<BackwardRegionalElementaryLanguage> &suffixes,
27  const RenamingRelation &renaming) {
28 #ifdef LEARNTA_DEBUG_EQUIVALENCE
29  BOOST_LOG_TRIVIAL(trace) << "left: " << left;
30  BOOST_LOG_TRIVIAL(trace) << "right: " << right;
31  BOOST_LOG_TRIVIAL(trace) << "leftRowSize: " << leftRow.back().size();
32  // BOOST_LOG_TRIVIAL(trace) << "leftRowBack: " << leftRow.back().front();
33  BOOST_LOG_TRIVIAL(trace) << "rightRowSize: " << rightRow.back().size();
34  BOOST_LOG_TRIVIAL(trace) << "suffix.back(): " << suffixes.back();
35 #endif
36  assert(leftRow.size() == rightRow.size());
37  assert(rightRow.size() == suffixes.size());
38  // Check the compatibility of prefixes up to renaming
39  auto juxtaposition = left.getTimedCondition() ^ right.getTimedCondition();
40  juxtaposition.addRenaming(renaming);
41  if (!juxtaposition.isSatisfiableNoCanonize()) {
42  return false;
43  }
44  // Check the compatibility of symbolic membership up to renaming
45  for (std::size_t i = 0; i < leftRow.size(); ++i) {
46  const auto leftConcatenation = left + suffixes.at(i);
47  const auto rightConcatenation = right + suffixes.at(i);
48  JuxtaposedZoneSet leftJuxtaposition {leftRow.at(i),
49  rightConcatenation.getTimedCondition(),
50  suffixes.at(i).wordSize()};
51  leftJuxtaposition.addRenaming(renaming);
52  JuxtaposedZoneSet rightJuxtaposition {leftConcatenation.getTimedCondition(),
53  rightRow.at(i),
54  suffixes.at(i).wordSize()};
55  rightJuxtaposition.addRenaming(renaming);
56  if (leftJuxtaposition != rightJuxtaposition) {
57  return false;
58  }
59  }
60 
61  return true;
62  }
63 
69  static bool equivalence(const ElementaryLanguage &left,
70  const std::vector<TimedConditionSet> &leftRow,
71  const std::vector<TimedCondition>& leftConcatenation,
72  const ElementaryLanguage &right,
73  const std::vector<TimedConditionSet> &rightRow,
74  const std::vector<TimedCondition>& rightConcatenation,
75  const std::vector<BackwardRegionalElementaryLanguage> &suffixes,
76  const RenamingRelation &renaming) {
77 #ifdef LEARNTA_DEBUG_EQUIVALENCE
78  BOOST_LOG_TRIVIAL(trace) << "left: " << left;
79  BOOST_LOG_TRIVIAL(trace) << "right: " << right;
80  BOOST_LOG_TRIVIAL(trace) << "leftRowSize: " << leftRow.back().size();
81  // BOOST_LOG_TRIVIAL(trace) << "leftRowBack: " << leftRow.back().front();
82  BOOST_LOG_TRIVIAL(trace) << "rightRowSize: " << rightRow.back().size();
83  BOOST_LOG_TRIVIAL(trace) << "suffix.back(): " << suffixes.back();
84 #endif
85  assert(leftRow.size() == rightRow.size());
86  assert(rightRow.size() == suffixes.size());
87  // Check the compatibility of prefixes up to renaming
88  auto juxtaposition = left.getTimedCondition() ^ right.getTimedCondition();
89  juxtaposition.addRenaming(renaming);
90  if (!juxtaposition.isSatisfiableNoCanonize()) {
91  return false;
92  }
93  // Check the compatibility of symbolic membership up to renaming
94  for (std::size_t i = 0; i < leftRow.size(); ++i) {
95  JuxtaposedZoneSet leftJuxtaposition{leftRow.at(i), rightConcatenation.at(i), suffixes.at(i).wordSize()};
96  leftJuxtaposition.addRenaming(renaming);
97  JuxtaposedZoneSet rightJuxtaposition{leftConcatenation.at(i), rightRow.at(i), suffixes.at(i).wordSize()};
98  rightJuxtaposition.addRenaming(renaming);
99  if (leftJuxtaposition != rightJuxtaposition) {
100  return false;
101  }
102  }
103 
104  return true;
105  }
106 
116  static bool equivalence(JuxtaposedZone leftRightJuxtaposition,
117  const std::vector<JuxtaposedZoneSet> &leftJuxtapositions,
118  const std::vector<JuxtaposedZoneSet> &rightJuxtapositions,
119  const RenamingRelation &renaming) {
120  assert(leftJuxtapositions.size() == rightJuxtapositions.size());
121  // Check the compatibility of prefixes up to renaming
122  leftRightJuxtaposition.addRenaming(renaming);
123  if (!leftRightJuxtaposition) {
124  return false;
125  }
126  // Check the compatibility of symbolic membership up to renaming
127  return std::equal(leftJuxtapositions.begin(), leftJuxtapositions.end(),
128  rightJuxtapositions.begin(), rightJuxtapositions.end(),
129  [&renaming] (JuxtaposedZoneSet left, JuxtaposedZoneSet right) {
130  left.addRenaming(renaming);
131  right.addRenaming(renaming);
132  return left == right;
133  });
134  }
135 
136  using RenamingGraph = std::pair<std::vector<std::vector<std::size_t>>, std::vector<std::vector<std::size_t>>>;
137 
146  static inline RenamingGraph toGraph(const TimedCondition &left, const TimedCondition &right) {
147  // Assert the precondition
148  assert(left.isSimple());
149  assert(right.isSimple());
150  std::vector<std::vector<std::size_t>> v1Edges, v2Edges;
151 
152  const auto N = left.size();
153  const auto M = right.size();
154  v1Edges.resize(N);
155  v2Edges.resize(M);
156  std::size_t v1 = 0, v2 = 0;
157  std::vector<std::size_t> currentSameV1, currentSameV2;
158  while (v1 < v1Edges.size() && v2 < v2Edges.size()) {
159  if (left.getUpperBound(v1, N - 1) == right.getUpperBound(v2, M - 1)) {
160  v1Edges.reserve(currentSameV2.size());
161  v2Edges.reserve(currentSameV1.size());
162  std::copy(currentSameV2.begin(), currentSameV2.end(), std::back_inserter(v1Edges.at(v1)));
163  std::for_each(currentSameV2.begin(), currentSameV2.end(), [&](const auto oldV2) {
164  v2Edges.at(oldV2).push_back(v1);
165  });
166  std::copy(currentSameV1.begin(), currentSameV1.end(), std::back_inserter(v2Edges.at(v2)));
167  std::for_each(currentSameV1.begin(), currentSameV1.end(), [&](const auto oldV1) {
168  v1Edges.at(oldV1).push_back(v2);
169  });
170  v1Edges.at(v1).push_back(v2);
171  v2Edges.at(v2).push_back(v1);
172  currentSameV1.push_back(v1);
173  currentSameV2.push_back(v2);
174  if (v1 + 1 < v1Edges.size() && left.getUpperBound(v1, N - 1) == left.getUpperBound(v1 + 1, N - 1)) {
175  v1++;
176  } else {
177  v2++;
178  }
179  } else {
180  currentSameV1.clear();
181  currentSameV2.clear();
182  if (left.getUpperBound(v1, N - 1) < right.getUpperBound(v2, M - 1)) {
183  v2++;
184  } else {
185  v1++;
186  }
187  }
188  }
189 
190  // Sort and remove duplication
191  for (auto& v1Edge: v1Edges) {
192  std::sort(v1Edge.begin(), v1Edge.end());
193  v1Edge.erase(std::unique(v1Edge.begin(), v1Edge.end()), v1Edge.end());
194  }
195  for (auto& v2Edge: v2Edges) {
196  std::sort(v2Edge.begin(), v2Edge.end());
197  v2Edge.erase(std::unique(v2Edge.begin(), v2Edge.end()), v2Edge.end());
198  }
199  return RenamingGraph{v1Edges, v2Edges};
200  }
201 
213  static inline std::vector<RenamingRelation> generateDeterministicCandidates(const TimedCondition& left,
214  const TimedCondition& right,
215  const std::vector<std::size_t>& leftConstrained,
216  const std::vector<std::size_t>& rightConstrained,
217  const RenamingGraph& graph) {
218  // Assert the preconditions
219  assert(is_strict_ascending(leftConstrained));
220  assert(is_strict_ascending(rightConstrained));
221  std::vector<RenamingRelation> candidates;
222  // We first generate full candidates
223  candidates.emplace_back();
224  for (std::size_t j = 0; j < right.size(); ++j) {
225  // We do not construct a renaming equation if there is no edge from the right node, or the target is already determined
226  if (graph.second.at(j).empty() || right.getUpperBound(j, right.size() - 1).second) {
227  continue;
228  }
229  std::vector<RenamingRelation> newCandidates;
230  for (auto candidate: candidates) {
231  // If j - 1 and j has the same value, we use the same left variable
232  if (j > 0 && right.getUpperBound(j - 1, j - 1) == Bounds{0, true}) {
233  candidate.emplace_back(candidate.back().first, j);
234  newCandidates.emplace_back(std::move(candidate));
235  continue;
236  } else {
237  // The least value of the corresponding node
238  const std::size_t lowerBound = candidate.empty() ? 0 : (candidate.back().first + 1);
239  const bool constrained = std::binary_search(rightConstrained.begin(), rightConstrained.end(), j);
240  for (const auto& i: graph.second.at(j)) {
241  // We skip if i - 1 and i has the same value
242  if (i >= lowerBound && constrained == std::binary_search(leftConstrained.begin(), leftConstrained.end(), i) &&
243  (i == 0 || left.getUpperBound(i - 1, i - 1) != Bounds{0, true})) {
244  auto tmpCandidate = candidate;
245  tmpCandidate.emplace_back(i, j);
246  newCandidates.emplace_back(std::move(tmpCandidate));
247  }
248  }
249  }
250  }
251  candidates = std::move(newCandidates);
252  }
253 
254  // Then, we add empty renaming
255  candidates.emplace_back();
256  // Finally, erase non-deterministic renaming
257  candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [&] (const auto& renaming) {
258  return renaming.hasImpreciseClocks(right);
259  }), candidates.end());
260  std::sort(candidates.begin(), candidates.end());
261  candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
262 
263  return candidates;
264  }
265 
273  enum class CellStatus {
274  bottom,
275  top,
276  middle
277  };
278 
284  static inline CellStatus decideStatus(const TimedCondition &concatenation, const TimedConditionSet &cell) {
285  // Assert the precondition
286 #ifndef NDEBUG
287  const auto simpleConcatenations = concatenation.enumerate();
288  assert((cell.size() == 1 && cell.getConditions().front() == concatenation) ||
289  std::any_of(simpleConcatenations.begin(), simpleConcatenations.end(), [&] (const TimedCondition& simple) {
290  return std::none_of(cell.getConditions().begin(), cell.getConditions().end(),
291  [&] (const TimedCondition& disjunct) {
292  return disjunct.includes(simple);
293  });
294  }));
295 #endif
296 
297  if (cell.empty()) {
298  return CellStatus::bottom;
299  } else if (cell.size() == 1 && cell.getConditions().front() == concatenation) {
300  return CellStatus::top;
301  } else {
302  return CellStatus::middle;
303  }
304  }
305 
318  static inline std::pair<std::vector<std::size_t>, std::vector<std::size_t>>
319  makeConstrainedVariables(const std::vector<TimedConditionSet> &leftRow,
320  const std::vector<TimedConditionSet> &rightRow,
321  const std::vector<TimedCondition> &leftConcatenations,
322  const std::vector<TimedCondition> &rightConcatenations,
323  const std::size_t N,
324  const std::size_t M) {
325  std::vector<std::size_t> constrainedV1, constrainedV2;
326  constrainedV1.reserve(N * leftRow.size());
327  constrainedV2.reserve(M * rightRow.size());
328  for (std::size_t i = 0; i < leftRow.size(); ++i) {
329  auto currentV1Constrained =
330  leftRow.at(i).getStrictlyConstrainedVariables(leftConcatenations.at(i), N);
331  auto currentV2Constrained =
332  rightRow.at(i).getStrictlyConstrainedVariables(rightConcatenations.at(i), M);
333  std::move(currentV1Constrained.begin(), currentV1Constrained.end(), std::back_inserter(constrainedV1));
334  std::move(currentV2Constrained.begin(), currentV2Constrained.end(), std::back_inserter(constrainedV2));
335  }
336  std::sort(constrainedV1.begin(), constrainedV1.end());
337  constrainedV1.erase(std::unique(constrainedV1.begin(), constrainedV1.end()), constrainedV1.end());
338  std::sort(constrainedV2.begin(), constrainedV2.end());
339  constrainedV2.erase(std::unique(constrainedV2.begin(), constrainedV2.end()), constrainedV2.end());
340 
341  assert(is_strict_ascending(constrainedV1));
342  assert(is_strict_ascending(constrainedV2));
343 
344  return std::make_pair(constrainedV1, constrainedV2);
345  }
346 
365  static inline std::optional<RenamingRelation> findDeterministicEquivalentRenaming(const ElementaryLanguage &left,
366  const std::vector<TimedConditionSet> &leftRow,
367  const ElementaryLanguage &right,
368  const std::vector<TimedConditionSet> &rightRow,
369  const std::vector<BackwardRegionalElementaryLanguage> &suffixes) {
370  // 0. Asserts the preconditions
371  assert(leftRow.size() == rightRow.size());
372  assert(rightRow.size() == suffixes.size());
373  assert(left.isSimple());
374  assert(right.isSimple());
375 
376  // 0.1. We quickly check if they are clearly not equivalent.
377  if (!std::equal(leftRow.begin(), leftRow.end(), rightRow.begin(), rightRow.end(),
378  [&] (const auto& leftCell, const auto& rightCell) {
379  return leftCell.empty() == rightCell.empty();
380  })) {
381  return std::nullopt;
382  }
383 
384  // 0.2 Compute the concatenations
385  // left + suffix
386  std::vector<TimedCondition> leftConcatenations;
387  leftConcatenations.reserve(suffixes.size());
388  std::transform(suffixes.begin(), suffixes.end(), std::back_inserter(leftConcatenations), [&] (const auto& suffix) {
389  return left.getTimedCondition() + suffix.getTimedCondition();
390  });
391  // right + suffix
392  std::vector<TimedCondition> rightConcatenations;
393  rightConcatenations.reserve(suffixes.size());
394  std::transform(suffixes.begin(), suffixes.end(), std::back_inserter(rightConcatenations), [&] (const auto& suffix) {
395  return right.getTimedCondition() + suffix.getTimedCondition();
396  });
397 
398  // 0.3 Compute the status
399  std::vector<CellStatus> leftStatus;
400  leftStatus.reserve(suffixes.size());
401  std::transform(leftConcatenations.begin(), leftConcatenations.end(),
402  leftRow.begin(), std::back_inserter(leftStatus), decideStatus);
403  std::vector<CellStatus> rightStatus;
404  rightStatus.reserve(suffixes.size());
405  std::transform(rightConcatenations.begin(), rightConcatenations.end(),
406  rightRow.begin(), std::back_inserter(rightStatus), decideStatus);
407 
408  // 0.4. We quickly check if their statuses are not equivalent.
409  if (!std::equal(leftStatus.begin(), leftStatus.end(), rightStatus.begin(), rightStatus.end())) {
410  return std::nullopt;
411  }
412 
413  // 1. Try the empty relation
414  if (equivalence(left, leftRow, leftConcatenations,
415  right, rightRow, rightConcatenations,
416  suffixes, RenamingRelation{})) {
417  return RenamingRelation{};
418  }
419 
420  // 2. Construct the bipartite graph based on the timed conditions.
421  const auto graph = toGraph(left.getTimedCondition(), right.getTimedCondition());
422 
423  // 3. Construct the strictly constrained variables
424  const auto& [leftConstrained, rightConstrained] = makeConstrainedVariables(leftRow, rightRow,
425  leftConcatenations, rightConcatenations,
426  left.wordSize() + 1,
427  right.wordSize() + 1);
428  // 4. Construct the candidate renaming equations
429  auto candidates = generateDeterministicCandidates(left.getTimedCondition(),
430  right.getTimedCondition(),
431  leftConstrained,
432  rightConstrained,
433  graph);
434 
435  // 5. Find an equivalent renaming equation
436  const auto leftRightJuxtaposition = left.getTimedCondition() ^ right.getTimedCondition();
437  // Add implicit constraints
438  std::for_each(candidates.begin(), candidates.end(), [&] (auto &candidate) {
439  if (!candidate.empty()) {
440  candidate.addImplicitConstraints(leftRightJuxtaposition);
441  }
442  });
443  std::vector<JuxtaposedZoneSet> leftJuxtapositions, rightJuxtapositions;
444  leftJuxtapositions.reserve(leftRow.size());
445  rightJuxtapositions.reserve(rightRow.size());
446  for (std::size_t i = 0; i < leftRow.size(); ++i) {
447  leftJuxtapositions.emplace_back(leftRow.at(i), rightConcatenations.at(i), suffixes.at(i).wordSize());
448  rightJuxtapositions.emplace_back(leftConcatenations.at(i), rightRow.at(i), suffixes.at(i).wordSize());
449  }
450  auto it = std::find_if(candidates.begin(), candidates.end(), [&](const auto &candidate) {
451  return equivalence(leftRightJuxtaposition, leftJuxtapositions, rightJuxtapositions, candidate);
452  });
453 
454  if (it != candidates.end()) {
455  return *it;
456  } else {
457  return std::nullopt;
458  }
459  }
460 
479  static inline std::optional<RenamingRelation> findDeterministicEquivalentRenaming(const ElementaryLanguage &left,
480  const std::vector<TimedConditionSet> &leftRow,
481  const std::vector<TimedCondition>& leftConcatenations,
482  const ElementaryLanguage &right,
483  const std::vector<TimedConditionSet> &rightRow,
484  const std::vector<TimedCondition>& rightConcatenations,
485  const std::vector<BackwardRegionalElementaryLanguage> &suffixes) {
486  // 0. Asserts the preconditions
487  assert(leftRow.size() == rightRow.size());
488  assert(rightRow.size() == suffixes.size());
489  assert(left.isSimple());
490  assert(right.isSimple());
491 
492  // 0.1. Compute the status
493  std::vector<CellStatus> leftStatus;
494  leftStatus.reserve(suffixes.size());
495  std::transform(leftConcatenations.begin(), leftConcatenations.end(),
496  leftRow.begin(), std::back_inserter(leftStatus), decideStatus);
497  std::vector<CellStatus> rightStatus;
498  rightStatus.reserve(suffixes.size());
499  std::transform(rightConcatenations.begin(), rightConcatenations.end(),
500  rightRow.begin(), std::back_inserter(rightStatus), decideStatus);
501 
502  // 0.2. We quickly check if their statuses are not equivalent.
503  if (!std::equal(leftStatus.begin(), leftStatus.end(), rightStatus.begin(), rightStatus.end())) {
504  return std::nullopt;
505  }
506 
507  // 1. Try the empty relation
508  if (equivalence(left, leftRow, leftConcatenations,
509  right, rightRow, rightConcatenations,
510  suffixes, RenamingRelation{})) {
511  return RenamingRelation{};
512  }
513 
514  // 2. Construct the bipartite graph based on the timed conditions.
515  const auto graph = toGraph(left.getTimedCondition(), right.getTimedCondition());
516 
517  // 3. Construct the strictly constrained variables
518  const auto& [leftConstrained, rightConstrained] = makeConstrainedVariables(leftRow, rightRow,
519  leftConcatenations, rightConcatenations,
520  left.wordSize() + 1,
521  right.wordSize() + 1);
522  // 4. Construct the candidate renaming equations
523  auto candidates = generateDeterministicCandidates(left.getTimedCondition(),
524  right.getTimedCondition(),
525  leftConstrained,
526  rightConstrained,
527  graph);
528 
529  // 5. Find an equivalent renaming equation
530  const auto leftRightJuxtaposition = left.getTimedCondition() ^ right.getTimedCondition();
531  // Add implicit constraints
532  std::for_each(candidates.begin(), candidates.end(), [&] (auto &candidate) {
533  if (!candidate.empty()) {
534  candidate.addImplicitConstraints(leftRightJuxtaposition);
535  }
536  });
537  std::vector<JuxtaposedZoneSet> leftJuxtapositions, rightJuxtapositions;
538  leftJuxtapositions.reserve(leftRow.size());
539  rightJuxtapositions.reserve(rightRow.size());
540  for (std::size_t i = 0; i < leftRow.size(); ++i) {
541  leftJuxtapositions.emplace_back(leftRow.at(i), rightConcatenations.at(i), suffixes.at(i).wordSize());
542  rightJuxtapositions.emplace_back(leftConcatenations.at(i), rightRow.at(i), suffixes.at(i).wordSize());
543  }
544  auto it = std::find_if(candidates.begin(), candidates.end(), [&](const auto &candidate) {
545  return equivalence(leftRightJuxtaposition, leftJuxtapositions, rightJuxtapositions, candidate);
546  });
547 
548  if (it != candidates.end()) {
549  return *it;
550  } else {
551  return std::nullopt;
552  }
553  }
554 
578  static inline std::optional<RenamingRelation> findEquivalentRenaming(const ElementaryLanguage &left,
579  const std::vector<TimedConditionSet> &leftRow,
580  const ElementaryLanguage &right,
581  const std::vector<TimedConditionSet> &rightRow,
582  const std::vector<BackwardRegionalElementaryLanguage> &suffixes) {
583  // 0. Asserts the preconditions
584  assert(leftRow.size() == rightRow.size());
585  assert(rightRow.size() == suffixes.size());
586  assert(left.isSimple());
587  assert(right.isSimple());
588 
589  // 0.5. Try the empty relation
590  if (equivalence(left, leftRow, right, rightRow, suffixes, RenamingRelation{})) {
591  return RenamingRelation{};
592  }
593 
594  // 1. Construct the bipartite graph based on the timed conditions.
595  const auto graph = toGraph(left.getTimedCondition(), right.getTimedCondition());
596  const auto &v1Edges = graph.first;
597  const auto &v2Edges = graph.second;
598  const auto N = left.wordSize() + 1;
599  const auto M = right.wordSize() + 1;
600 
601  std::vector<TimedCondition> leftConcatenations, rightConcatenations;
602  leftConcatenations.resize(leftRow.size());
603  rightConcatenations.resize(leftRow.size());
604  // 2. Make the set of the strictly constrained variables in the symbolic membership.
605  std::vector<std::size_t> constrainedV1, constrainedV2;
606  for (std::size_t i = 0; i < leftRow.size(); ++i) {
607  leftConcatenations.at(i) = (left + suffixes.at(i)).getTimedCondition();
608  rightConcatenations.at(i) = (right + suffixes.at(i)).getTimedCondition();
609  // 2-1. We quickly check if they are clearly not equivalent.
610  if (leftRow.at(i).empty() != rightRow.at(i).empty()) {
611  // One of them is bottom but another is not
612  return std::nullopt;
613  }
614  auto currentV1Constrained =
615  leftRow.at(i).getStrictlyConstrainedVariables(leftConcatenations.at(i), N);
616  auto currentV2Constrained =
617  rightRow.at(i).getStrictlyConstrainedVariables(rightConcatenations.at(i), M);
618  std::move(currentV1Constrained.begin(), currentV1Constrained.end(), std::back_inserter(constrainedV1));
619  std::move(currentV2Constrained.begin(), currentV2Constrained.end(), std::back_inserter(constrainedV2));
620  }
621  std::sort(constrainedV1.begin(), constrainedV1.end());
622  constrainedV1.erase(std::unique(constrainedV1.begin(), constrainedV1.end()), constrainedV1.end());
623  constrainedV1.erase(
624  std::remove_if(constrainedV1.begin(), constrainedV1.end(), [&](const auto &v1) {
625  return v1Edges.at(v1).empty();
626  }), constrainedV1.end());
627  std::sort(constrainedV2.begin(), constrainedV2.end());
628  constrainedV2.erase(std::unique(constrainedV2.begin(), constrainedV2.end()), constrainedV2.end());
629  constrainedV2.erase(
630  std::remove_if(constrainedV2.begin(), constrainedV2.end(), [&](const auto &v2) {
631  return v2Edges.at(v2).empty();
632  }), constrainedV2.end());
633 
634  // 3. Generate candidate renaming
635  std::deque<RenamingRelation> candidates;
636  candidates.emplace_back();
637  {
638  std::size_t v1Index = 0, v2Index = 0;
639  while (v1Index < constrainedV1.size() && v2Index < constrainedV2.size()) {
640  std::size_t v1 = constrainedV1.at(v1Index);
641  std::size_t v2 = constrainedV2.at(v2Index);
642  // 3-1. We check if we cannot include these vertices
643  if (v1Edges.at(v1).empty()) {
644  v1Index++;
645  // We cannot conclude that they are not equivalent because this non-trivial constraint can be realized from other non-trivial constraints.
646  continue;
647  }
648  if (v2Edges.at(v2).empty()) {
649  v2Index++;
650  continue;
651  }
652  if (!std::binary_search(v1Edges.at(v1).begin(), v1Edges.at(v1).end(), v2)) {
653  if (v1Edges.at(v1).back() >= v2) {
654  v2Index++;
655  } else {
656  v1Index++;
657  }
658  continue;
659  }
660  if (!std::binary_search(v2Edges.at(v2).begin(), v2Edges.at(v2).end(), v1)) {
661  if (v2Edges.at(v2).back() >= v1) {
662  v1Index++;
663  } else {
664  v2Index++;
665  }
666  continue;
667  }
668  std::vector<RenamingRelation> tmp;
669  tmp.reserve(candidates.size() * v2Edges.at(v2).size() * v1Edges.at(v1).size());
670 
671  for (const auto currentV1: v2Edges.at(v2)) {
672  for (const auto currentV2: v1Edges.at(v1)) {
673  const auto currentEdge = std::make_pair(currentV1, currentV2);
674  for (const auto &candidate: candidates) {
675  tmp.emplace_back(candidate);
676  tmp.emplace_back(candidate);
677  tmp.back().emplace_back(currentEdge);
678  tmp.emplace_back();
679  tmp.back().emplace_back(currentEdge);
680  }
681  }
682  }
683 
684  candidates.resize(tmp.size());
685  std::move(tmp.begin(), tmp.end(), candidates.begin());
686  // We increment the indices until reaching the next disjoint part of the bipartite graph
687  while (v1Index < constrainedV1.size() && constrainedV1.at(v1Index) <= v2Edges.at(v2).back()) {
688  v1Index++;
689  }
690  while (v2Index < constrainedV2.size() && constrainedV2.at(v2Index) <= v1Edges.at(v1).back()) {
691  v2Index++;
692  }
693  }
694  }
695 
696  // Reduce the candidates for optimization
697  std::sort(candidates.begin(), candidates.end());
698  candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
699 
700  // 4. Check candidate renaming
701  const auto leftRightJuxtaposition = left.getTimedCondition() ^ right.getTimedCondition();
702  // Add implicit constraints
703  std::for_each(candidates.begin(), candidates.end(), [&] (auto &candidate) {
704  if (!candidate.empty()) {
705  candidate.addImplicitConstraints(leftRightJuxtaposition);
706  }
707  });
708  std::vector<JuxtaposedZoneSet> leftJuxtapositions, rightJuxtapositions;
709  leftJuxtapositions.reserve(leftRow.size());
710  rightJuxtapositions.reserve(leftRow.size());
711  for (std::size_t i = 0; i < leftRow.size(); ++i) {
712  leftJuxtapositions.emplace_back(leftRow.at(i), rightConcatenations.at(i), suffixes.at(i).wordSize());
713  rightJuxtapositions.emplace_back(leftConcatenations.at(i), rightRow.at(i), suffixes.at(i).wordSize());
714  }
715  auto it = std::find_if(candidates.begin(), candidates.end(), [&](const auto &candidate) {
716  return equivalence(leftRightJuxtaposition, leftJuxtapositions, rightJuxtapositions, candidate);
717  });
718  if (it == candidates.end()) {
719  // We add other equations in this case
720  while (!candidates.empty()) {
721  const auto candidate = candidates.front();
722  candidates.pop_front();
723  for (const auto currentV1: constrainedV1) {
724  for (const auto currentV2: v1Edges.at(currentV1)) {
725  auto newCandidate = candidate;
726  const auto edge = std::make_pair(currentV1, currentV2);
727  auto insertIt = std::lower_bound(newCandidate.begin(), newCandidate.end(), edge);
728  if (insertIt == newCandidate.end() || *insertIt != edge) {
729  newCandidate.insert(insertIt, edge);
730  if (equivalence(left, leftRow, right, rightRow, suffixes, newCandidate)) {
731  return std::make_optional(newCandidate);
732  } else {
733  candidates.emplace_back(std::move(newCandidate));
734  }
735  }
736  }
737  }
738  }
739  return std::nullopt;
740  } else {
741  return std::make_optional(*it);
742  }
743  }
744 }
An elementary language.
Definition: elementary_language.hh:23
bool isSimple() const
Returns if this elementary language is simple.
Definition: elementary_language.hh:66
std::size_t wordSize() const
Returns the number of the events in this elementary language.
Definition: elementary_language.hh:73
Definition: juxtaposed_zone_set.hh:13
void addRenaming(const std::vector< std::pair< std::size_t, std::size_t >> &renaming)
Add renaming constraints.
Definition: juxtaposed_zone_set.hh:58
A zone constructed by juxtaposing two zones with or without shared variables.
Definition: juxtaposed_zone.hh:12
void addRenaming(const std::vector< std::pair< std::size_t, std::size_t >> &renaming)
Add renaming constraints.
Definition: juxtaposed_zone.hh:127
Definition: renaming_relation.hh:16
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
bool isSimple() const
Returns if this timed condition is simple.
Definition: timed_condition.hh:98
Bounds getUpperBound(std::size_t i, std::size_t j) const
Returns the upper bound of .
Definition: timed_condition.hh:232
size_t size() const
Return the number of the variables in this timed condition.
Definition: timed_condition.hh:89
void enumerate(std::vector< TimedCondition > &simpleConditions) const
Make a vector of simple timed conditions in this timed condition.
Definition: timed_condition.hh:299
Definition: experiment_runner.hh:23
bool is_strict_ascending(const std::vector< T > &container)
Check if the elements are sorted in the strict ascending order.
Definition: common_types.hh:54
CellStatus
The status of a cell of the observation table.
Definition: equivalence.hh:273
static std::optional< RenamingRelation > findDeterministicEquivalentRenaming(const ElementaryLanguage &left, const std::vector< TimedConditionSet > &leftRow, const std::vector< TimedCondition > &leftConcatenations, const ElementaryLanguage &right, const std::vector< TimedConditionSet > &rightRow, const std::vector< TimedCondition > &rightConcatenations, const std::vector< BackwardRegionalElementaryLanguage > &suffixes)
Return a renaming constraint if two elementary languages are equivalent.
Definition: equivalence.hh:479
static RenamingGraph toGraph(const TimedCondition &left, const TimedCondition &right)
Construct the intermediate bipartite graph for candidate generation from timed conditions.
Definition: equivalence.hh:146
static std::vector< RenamingRelation > generateDeterministicCandidates(const TimedCondition &left, const TimedCondition &right, const std::vector< std::size_t > &leftConstrained, const std::vector< std::size_t > &rightConstrained, const RenamingGraph &graph)
Construct candidate renaming relations that are deterministic, i.e., the corresponding reset only mak...
Definition: equivalence.hh:213
static bool equivalence(JuxtaposedZone leftRightJuxtaposition, const std::vector< JuxtaposedZoneSet > &leftJuxtapositions, const std::vector< JuxtaposedZoneSet > &rightJuxtapositions, const RenamingRelation &renaming)
Return if two elementary languages are equivalent.
Definition: equivalence.hh:116
static std::optional< RenamingRelation > findEquivalentRenaming(const ElementaryLanguage &left, const std::vector< TimedConditionSet > &leftRow, const ElementaryLanguage &right, const std::vector< TimedConditionSet > &rightRow, const std::vector< BackwardRegionalElementaryLanguage > &suffixes)
Construct a renaming constraint if two elementary languages are equivalent.
Definition: equivalence.hh:578
static CellStatus decideStatus(const TimedCondition &concatenation, const TimedConditionSet &cell)
Compute the status of a cell of the observation table.
Definition: equivalence.hh:284
static bool equivalence(const ElementaryLanguage &left, const std::vector< TimedConditionSet > &leftRow, const ElementaryLanguage &right, const std::vector< TimedConditionSet > &rightRow, const std::vector< BackwardRegionalElementaryLanguage > &suffixes, const RenamingRelation &renaming)
Return if two elementary languages are equivalent.
Definition: equivalence.hh:22
static std::pair< std::vector< std::size_t >, std::vector< std::size_t > > makeConstrainedVariables(const std::vector< TimedConditionSet > &leftRow, const std::vector< TimedConditionSet > &rightRow, const std::vector< TimedCondition > &leftConcatenations, const std::vector< TimedCondition > &rightConcatenations, const std::size_t N, const std::size_t M)
Return the constrained variables in the symbolic membership.
Definition: equivalence.hh:319