TuringSim
C++ framework to simulate abstract computing models
nonDeterministicMachineRunner.h
1 #pragma once
2 
3 #include <utils/printer.h>
4 #include <runner/machineRunner.h>
5 
6 #include <deque>
7 #include <cassert>
8 
9 #define DEBUG 0
10 
11 namespace TuringSim::Runner {
31  template<typename LeafType>
33  public:
37  enum class Quantifier {
38  Existential,
39  Universal,
40  };
41 
45  typedef size_t Uid;
46 
59  void insert(Uid subUid, Quantifier q, std::vector<std::tuple<LeafType, std::optional<bool>>>& newLeaves) {
60  leaves.erase(subUid);
61  if(q == quantifier) {
62  for(size_t i = 0; i < newLeaves.size(); ++i) {
63  leaves.emplace_hint(leaves.end(), nextUid++, std::move(std::get<LeafType>(newLeaves[i])));
64  }
65  for(size_t i = 0; i < newLeaves.size(); ++i) {
66  if(std::get<std::optional<bool>>(newLeaves[i])) {
67  decide(nextUid - newLeaves.size() + i, *std::get<std::optional<bool>>(newLeaves[i]));
68  }
69  }
70  }
71  else {
72  new AlternatingTree(subUid, q, std::move(newLeaves), this);
73  }
74  }
75 
81  [[nodiscard]] std::pair<const Uid, LeafType>& pick() {
82  return *leaves.begin();
83  }
84 
88  [[nodiscard]] Uid lastLeafUid() {
89  return leaves.rbegin()->first;
90  }
91 
95  [[nodiscard]] bool hasLeaves() const {
96  return !leaves.empty();
97  }
98 
102  [[nodiscard]] const std::map<Uid, std::shared_ptr<AlternatingTree<LeafType>>>& getSubTrees() {
103  return subTrees;
104  }
105 
110  void decide(Uid subUid, bool d) {
111  std::tuple<LeafType, bool> decidedLeaf{std::move(leaves[subUid]), std::move(d)};
112  decidedLeaves.insert({subUid, decidedLeaf});
113  leaves.erase(subUid);
114  if(d == (quantifier == Quantifier::Existential)) {
115  decision = d;
116  if(parent) {
117  auto& [uid, p] = *parent;
118  p->propagate_decide(uid, d);
119  }
120  }
121  else {
122  if(leaves.empty() && subTrees.empty()) {
123  decision = d;
124  if(parent) {
125  auto& [uid, p] = *parent;
126  p->propagate_decide(uid, d);
127  }
128  }
129  }
130  }
131 
135  [[nodiscard]] bool decided() const noexcept {
136  return decision.has_value();
137  }
138 
142  [[nodiscard]] std::optional<bool> getDecision() const noexcept {
143  return decision;
144  }
145 
151  static std::shared_ptr<AlternatingTree> makeAlternatingTreeRoot(Quantifier quantifier, const std::vector<LeafType>& leaves) {
152  AlternatingTree* p = new AlternatingTree(quantifier, leaves);
153  return std::shared_ptr<AlternatingTree>(p);
154  }
155 
161  template<typename CharT = char, typename Traits = std::char_traits<CharT>>
162  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> debug() const {
163  return debug(0);
164  }
165 
172  template<typename CharT = char, typename Traits = std::char_traits<CharT>>
173  static std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> debug(const Quantifier& q) {
174  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> f =
175  [q](std::basic_ostream<CharT, Traits>& os) -> std::basic_ostream<CharT, Traits>& {
176  switch (q) {
178  return os << "A";
180  return os << "E";
181  }
182  };
183  return f;
184  }
185 
193  template<typename CharT = char, typename Traits = std::char_traits<CharT>>
194  friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const AlternatingTree& tree) {
195  using Utils::Debug::operator<<;
196  return os << tree.debug();
197  }
198 
205  template<typename CharT = char, typename Traits = std::char_traits<CharT>>
206  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> debug(size_t i) const {
207  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> f =
208  [this, i](std::basic_ostream<CharT, Traits>& os) -> std::basic_ostream<CharT, Traits>& {
209  using Utils::Debug::operator<<;
210  std::string indent(i, ' ');
211  os << indent
212  << debug(quantifier)
213  << ", parent: " << Utils::Debug::debug(parent)
214  << ", nextUid: " << nextUid
215  << ", decision: " << Utils::Debug::debug(decision) << std::endl;
216 
217  os << indent << "Leaves:" << std::endl;
218  for(const auto& [uid, leaf]: leaves) {
219  os << indent << " uid: " << uid << std::endl;
220  os << indent << " leaf: " << std::endl;
221  os << indent << " " << Utils::Debug::debug(leaf) << std::endl;
222  }
223 
224  os << indent << "Decided leaves:" << std::endl;
225  for(const auto& [uid, decided_leaf]: decidedLeaves) {
226  auto& [leaf, decision] = decided_leaf;
227  os << indent << " uid: " << uid << std::endl;
228  os << indent << " decision: " << std::boolalpha << decision << std::endl;
229  os << indent << " leaf: " << std::endl;
230  os << indent << " " << Utils::Debug::debug(leaf) << std::endl;
231  }
232 
233  os << indent << "Sub-trees:" << std::endl;
234  for(const auto& [uid, tree]: subTrees) {
235  os << indent << " uid: " << uid << std::endl;
236  os << indent << " tree: " << std::endl;
237  os << tree->debug(i + 4) << std::endl;
238  }
239 
240  os << indent << "Decided sub-trees:" << std::endl;
241  for(const auto& [uid, decided_subTree]: decidedSubTrees) {
242  auto& [subTree, decision] = decided_subTree;
243  os << indent << " uid: " << uid << std::endl;
244  os << indent << " decision: " << std::boolalpha << decision << std::endl;
245  os << indent << " sub-tree: " << std::endl;
246  os << subTree->debug(i + 4) << std::endl;
247  }
248 
249  return os;
250  };
251  return f;
252  }
253 
256  void compact() {
257  decidedSubTrees.clear();
258  decidedLeaves.clear();
259  for(auto& [_uid, subTree]: subTrees) {
260  subTree->compact();
261  }
262  }
263 
264  private:
265  AlternatingTree() = delete;
266  AlternatingTree(Quantifier quantifier, const std::vector<LeafType>& leaves) :
267  quantifier(quantifier),
268  leaves(),
269  parent()
270  {
271  for(const LeafType& leaf: leaves) {
272  this->leaves.insert({nextUid++, leaf});
273  }
274  }
275 
276  AlternatingTree(Quantifier quantifier, std::vector<LeafType>&& leaves) :
277  quantifier(quantifier),
278  leaves(),
279  parent()
280  {
281  for(LeafType& leaf: leaves) {
282  this->leaves.insert({nextUid++, std::move(leaf)});
283  }
284  }
285 
286  AlternatingTree(Uid uid, Quantifier quantifier, std::vector<std::tuple<LeafType, std::optional<bool>>>&& newLeaves, AlternatingTree<LeafType>* parent) :
287  quantifier(quantifier),
288  leaves(),
289  parent({uid, parent})
290  {
291  for(size_t i = 0; i < newLeaves.size(); ++i) {
292  leaves.emplace_hint(leaves.end(), nextUid++, std::move(std::get<LeafType>(newLeaves[i])));
293  }
294  parent->subTrees[uid] = std::shared_ptr<AlternatingTree>(this);
295  for(size_t i = 0; i < newLeaves.size(); ++i) {
296  if(std::get<std::optional<bool>>(newLeaves[i])) {
297  decide(nextUid - newLeaves.size() + i, *std::get<std::optional<bool>>(newLeaves[i]));
298  }
299  }
300  }
301 
302  AlternatingTree(const AlternatingTree& other) :
303  quantifier(other.quantifier),
304  subTrees(other.subTrees),
305  leaves(other.leaves),
306  decision(other.decision),
307  parent()
308  {}
309 
310  AlternatingTree(AlternatingTree&& other) :
311  quantifier(other.quantifier),
312  subTrees(std::move(other.subTrees)),
313  leaves(std::move(other.leaves)),
314  decision(other.decision),
315  parent(other.parent)
316  {
317  if(parent) {
318  auto& [uid, p] = *parent;
319  p->subTrees[uid] = this;
320  }
321  }
322 
323  void propagate_decide(Uid subUid, bool d) {
324  decidedSubTrees.insert({subUid, {subTrees[subUid], d}});
325  subTrees.erase(subUid);
326  if(d == (quantifier == Quantifier::Existential)) {
327  decision = d;
328  if(parent) {
329  auto& [uid, p] = *parent;
330  p->propagate_decide(uid, d);
331  }
332  }
333  else {
334  if(leaves.empty() && subTrees.empty()) {
335  decision = d;
336  if(parent) {
337  auto& [uid, p] = *parent;
338  p->propagate_decide(uid, d);
339  }
340  }
341  }
342  }
343 
344  Uid nextUid = 0;
345  Quantifier quantifier;
346  std::map<Uid, std::shared_ptr<AlternatingTree<LeafType>>> subTrees {};
347  std::map<Uid, std::tuple<std::shared_ptr<AlternatingTree<LeafType>>, bool>> decidedSubTrees {};
348  std::map<Uid, LeafType> leaves;
349  std::map<Uid, std::tuple<LeafType, bool>> decidedLeaves;
350  std::optional<bool> decision {};
351 
354  std::optional<std::tuple<Uid, AlternatingTree<LeafType>*>> parent;
355  };
356 
357 
366  template<
367  typename MachineType,
368  typename ListenerType,
369  typename ListenerConstructorArgs = typename MachineRunnerArgs<MachineType, ListenerType>::ListenerConstructorArgs
370  >
372 
380  template<typename MachineType_, typename ListenerType_, typename... ListenerConstructorArgs>
382  MachineType_,
383  ListenerType_,
384  std::tuple<ListenerConstructorArgs...>
385  > :
386  public MachineRunner<MachineType_, ListenerType_> {
388  public:
389  using typename MachineRunner_::StateType;
390  using typename MachineRunner_::MachineType;
391  using typename MachineRunner_::StorageType;
392  using typename MachineRunner_::ListenerType;
393  using typename MachineRunner_::ListenerIdType;
394  using typename MachineRunner_::TransitionType;
395  using typename MachineRunner_::ApplyHelperType;
396 
400  typedef std::integral_constant<bool, !std::is_same_v<ListenerType, void>> IsListened;
403  static constexpr bool IsListened_v = IsListened::value;
404 
408  typedef typename MachineType::IsAccepting IsAccepting;
411  static constexpr bool IsAccepting_v = IsAccepting::value;
412 
416  typedef typename MachineType::IsAlternating IsAlternating;
419  static constexpr bool IsAlternating_v = IsAlternating::value;
420 
433  typedef
434  std::conditional_t<
435  IsListened_v,
436  std::tuple<StateType, StorageType, ListenerIdType>,
437  std::tuple<StateType, StorageType>
439 
451  typedef
452  std::conditional_t<
453  !IsAlternating_v,
454  std::tuple<std::vector<ConfigurationType>, std::vector<ConfigurationType>>,
455  std::tuple<std::shared_ptr<AlternatingTree<ConfigurationType>>, std::deque<std::weak_ptr<AlternatingTree<ConfigurationType>>>>
457 
458  static_assert(std::is_same_v<std::tuple<ListenerConstructorArgs...>, typename MachineRunnerArgs<MachineType, ListenerType>::ListenerConstructorArgs>,
459  "The only allowed value for ListenerConstructorArgs is the default one.");
460 
467  NonDeterministicMachineRunner(const MachineType& machine, ListenerConstructorArgs... listener) :
468  MachineRunner_(machine, listener...),
469  configurations(getInitialConfigurations()),
470  running(true) {
471  }
472 
477  MachineRunner_(other),
478  configurations(other.configurations),
479  running(other.running)
480  {}
481 
486  MachineRunner_(std::move(other)),
487  configurations(std::move(other.configurations)),
488  running(std::move(other.running))
489  {}
490 
496  if(this != &other) {
497  MachineRunner_::operator=(other);
498  configurations = other.configurations;
499  running = other.running;
500  }
501  return *this;
502  }
503 
509  if(this != &other) {
510  MachineRunner_::operator=(std::move(other));
511  configurations = std::move(other.configurations);
512  running = std::move(other.running);
513  }
514  return *this;
515  }
516 
519  virtual ~NonDeterministicMachineRunner() override {}
520 
524  bool isRunning() const noexcept {
525  return running;
526  }
527 
532  return configurations;
533  }
534 
535  virtual void step(size_t nbIter = 1) override {
536  for(size_t i = 0; i < nbIter && running; ++i) {
537  oneStep();
538  }
539  }
540 
545  virtual void exec() override {
546  while(running) {
547  oneStep();
548  }
549  }
550 
551 #pragma clang diagnostic push
552 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
553 
556  virtual bool accept() {
557  exec();
558  if constexpr (!IsAccepting_v) {
559  return true;
560  }
561  else if constexpr (!IsAlternating_v) {
562  for(const auto& haltedConfiguration: std::get<1>(configurations)) {
563  const StateType& state = std::get<0>(haltedConfiguration);
564  const StorageType& memory = std::get<1>(haltedConfiguration);
565  if(MachineRunner_::machine.isAcceptingConfiguration(state, memory)) {
566  return true;
567  }
568  }
569  return false;
570  } else {
571  std::shared_ptr<AlternatingTree<ConfigurationType>> tree = std::get<std::shared_ptr<AlternatingTree<ConfigurationType>>>(configurations);
572  return *tree->getDecision();
573  }
574  }
575 #pragma clang diagnostic pop
576 
581  template<typename CharT = char, typename Traits = std::char_traits<CharT>>
582  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> debug() const {
583  std::function<std::basic_ostream<CharT, Traits>&(std::basic_ostream<CharT, Traits>&)> f =
584  [this](std::basic_ostream<CharT, Traits>& os) -> std::basic_ostream<CharT, Traits>& {
585  using Utils::Debug::operator<<;
586  if constexpr (!IsAlternating_v) {
587  return os << "running: " << std::boolalpha << running << std::endl
588  << "running configurations: " << Utils::Debug::debug(std::get<0>(configurations)) << std::endl
589  << "halted configurations: " << Utils::Debug::debug(std::get<1>(configurations)) << std::endl;
590  } else {
591  return os << "running: " << std::boolalpha << running << std::endl
592  << "configuration tree: " << std::endl << std::get<0>(configurations)->debug(2) << std::endl
593  << "queue: " << Utils::Debug::debug(std::get<1>(configurations)) << std::endl;
594  }
595  };
596  return f;
597  }
598 
599  protected:
604  if constexpr (!IsAlternating_v && IsListened_v) {
605  std::vector<std::tuple<StateType, StorageType, ListenerIdType>> initialConfigurations;
606  for(const StateType& state: MachineRunner_::machine.getInitialStates()) {
607  initialConfigurations.push_back({state, {}, MachineRunner_::listener.getInitialId()});
608  }
609  return {initialConfigurations, {}};
610  } else if constexpr (!IsAlternating_v && !IsListened_v) {
611  std::vector<std::tuple<StateType, StorageType>> initialConfigurations;
612  for(const StateType& state: MachineRunner_::machine.getInitialStates()) {
613  initialConfigurations.push_back({state, {}});
614  }
615  return {initialConfigurations, {}};
616  } else if constexpr (IsAlternating_v && IsListened_v) {
619  std::vector<std::tuple<StateType, StorageType, ListenerIdType>> initialConfigurations;
620  for(const StateType& state: MachineRunner_::machine.getInitialStates()) {
621  initialConfigurations.push_back({state, {}, MachineRunner_::listener.getInitialId()});
622  }
623  std::shared_ptr<AlternatingTree<ConfigurationType>> tree = AlternatingTree<ConfigurationType>::makeAlternatingTreeRoot(quantifier, initialConfigurations);
624  return {tree, {}};
625  } else {
628  std::vector<std::tuple<StateType, StorageType>> initialConfigurations;
629  for(const StateType& state: MachineRunner_::machine.getInitialStates()) {
630  initialConfigurations.push_back({state, {}});
631  }
632  std::shared_ptr<AlternatingTree<ConfigurationType>> tree = AlternatingTree<ConfigurationType>::makeAlternatingTreeRoot(quantifier, initialConfigurations);
633  return {tree, {}};
634  }
635  }
636 
643  virtual void oneStep() override {
644  if (!running) {
645  return;
646  }
647 #if DEBUG
648  std::cout << "OneStep begin" << std::endl;
649 #endif
650 
651  running = false;
652 
653  if constexpr (!IsAlternating_v) {
654  std::vector<ConfigurationType> newConfigurations;
655  auto& [runningConfigurations, haltedConfigurations] = configurations;
656  if constexpr (IsListened_v) {
657  for(const auto& [currentState, currentMemory, currentId]: runningConfigurations) {
658  typename MachineType::TransitionContainer matchingTransitions =
659  MachineRunner_::machine.getMatchingTransitions(currentState, currentMemory);
660 
661  if (matchingTransitions.empty()) {
662  MachineRunner_::listener.registerNoTransition(currentId, currentState, currentMemory);
663  haltedConfigurations.push_back({currentState, currentMemory, currentId});
664  } else {
665  size_t matchingTransitionsRemaining = matchingTransitions.size();
666  for(auto& matchingTransition: matchingTransitions) {
667  StorageType memory = matchingTransitionsRemaining > 1 ? StorageType(currentMemory) : std::move(currentMemory);
668  matchingTransitionsRemaining--;
669  ListenerIdType id = MachineRunner_::listener.registerPreTransition(currentState, memory, currentId);
670  auto& [transition, helper] = matchingTransition;
671  bool currentRunning = true;
672  StateType newState = transition.apply(
673  currentState,
674  memory,
675  std::move(helper),
676  currentRunning);
677  bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
678  MachineRunner_::listener.registerPostTransition(id, currentState, memory, transition, helper, isNewConfigurationRunning);
679  if(isNewConfigurationRunning && currentRunning) {
680  running = true;
681  newConfigurations.push_back({newState, memory, id});
682  } else {
683  haltedConfigurations.push_back({newState, memory, id});
684  }
685  }
686  }
687  }
688  } else {
689  for(const auto& [currentState, currentMemory]: runningConfigurations) {
690  typename MachineType::TransitionContainer matchingTransitions =
691  MachineRunner_::machine.getMatchingTransitions(currentState, currentMemory);
692 
693  if (matchingTransitions.empty()) {
694  haltedConfigurations.push_back({currentState, currentMemory});
695  } else {
696  size_t matchingTransitionsRemaining = matchingTransitions.size();
697  for(auto& matchingTransition: matchingTransitions) {
698  StorageType memory = matchingTransitionsRemaining > 1 ? StorageType(currentMemory) : std::move(currentMemory);
699  matchingTransitionsRemaining--;
700  auto& [transition, helper] = matchingTransition;
701  bool currentRunning = true;
702  StateType newState = transition.apply(
703  currentState,
704  memory,
705  std::move(helper),
706  currentRunning);
707  bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
708  if(isNewConfigurationRunning && currentRunning) {
709  running = true;
710  newConfigurations.push_back({newState, memory});
711  } else {
712  haltedConfigurations.push_back({newState, memory});
713  }
714  }
715  }
716  }
717  }
718  runningConfigurations = newConfigurations;
719  } else {
720  std::deque<std::shared_ptr<AlternatingTree<ConfigurationType>>> toRun;
721  std::deque<std::weak_ptr<AlternatingTree<ConfigurationType>>> newToExplore;
722 
723  auto& [configurationTree, toExplore] = configurations;
724 
725  if (toExplore.empty()) {
726  toExplore.push_back(configurationTree);
727  }
728 
729  while (!toExplore.empty()) {
730  std::weak_ptr<AlternatingTree<ConfigurationType>> tree_w = toExplore.front();
731  toExplore.pop_front();
732  if (std::shared_ptr<AlternatingTree<ConfigurationType>> tree = tree_w.lock()) {
733  if (tree->decided()) {
734  continue;
735  }
736  if (tree->hasLeaves()) {
737  toRun.push_back(tree);
738  newToExplore.push_back(tree);
739  } else {
740  for(const auto& [_uid, subTree]: tree->getSubTrees()) {
741  toExplore.push_back(subTree);
742  }
743  }
744  }
745  }
746 
747  using Utils::Debug::operator<<;
748 #if DEBUG
749  std::cout << "toRun: " << Utils::Debug::debug(toRun) << std::endl;
750  std::cout << "toRun length: " << toRun.size() << std::endl;
751 #endif
752 
753  toExplore = newToExplore;
754  while(!toRun.empty()) {
755 #if DEBUG
756  std::cout << " toRun length remaining: " << toRun.size() << std::endl;
757 #endif
758  std::shared_ptr<AlternatingTree<ConfigurationType>> tree = toRun.front();
759  toRun.pop_front();
760 #if DEBUG
761  std::cout << " tree: " << Utils::Debug::debug(tree) << std::endl;
762 #endif
763  if(!tree->hasLeaves()) {
764  continue;
765  }
766  size_t lastUid = tree->lastLeafUid();
767  while(tree->hasLeaves() && !tree->decided()) {
768  std::pair<const size_t, ConfigurationType>& leaf = tree->pick();
769  auto& [uid, content] = leaf;
770 #if DEBUG
771  std::cout << " picked leaf uid: " << uid << std::endl;
772  std::cout << " picked leaf content: " << Utils::Debug::debug(content) << std::endl;
773 #endif
774  if(uid > lastUid) {
775 #if DEBUG
776  std::cout << " Too big; uid: " << uid << ", lastUid: " << lastUid << std::endl;
777 #endif
778  break;
779  }
780  if constexpr(IsListened_v) {
781  auto& [currentState, currentMemory, currentId] = content;
782  Machine::Acceptance::NodeType nodeType = MachineRunner_::machine.isAcceptingConfiguration(currentState, currentMemory);
783  if(std::optional<bool> decision = Machine::Acceptance::toBool(nodeType); decision) {
784  tree->decide(uid, *decision);
785  MachineRunner_::listener.registerNoTransition(currentId, currentState, currentMemory);
786  continue;
787  }
788  typename MachineType::TransitionContainer matchingTransitions =
789  MachineRunner_::machine.getMatchingTransitions(currentState, currentMemory);
790  if(matchingTransitions.empty()) {
791  bool decision = Machine::Acceptance::decideForEmptySet(nodeType);
792  tree->decide(uid, decision);
793  MachineRunner_::listener.registerNoTransition(currentId, currentState, currentMemory);
794  } else {
795  std::vector<std::tuple<ConfigurationType, std::optional<bool>>> newLeaves;
796  for(auto& matchingTransition: matchingTransitions) {
797  StorageType memory = currentMemory;
798  ListenerIdType id = MachineRunner_::listener.registerPreTransition(currentState, memory, currentId);
799  auto& [transition, helper] = matchingTransition;
800  bool currentRunning = true;
801  StateType newState = transition.apply(
802  currentState,
803  memory,
804  std::move(helper),
805  currentRunning);
806  bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
807  MachineRunner_::listener.registerPostTransition(id, currentState, memory, transition, helper, isNewConfigurationRunning);
808  std::optional<bool> decision;
809 #if DEBUG
810  std::cout << " oldState: " << currentState << std::endl;
811  std::cout << " newState: " << newState << std::endl;
812  std::cout << " terminated: " << std::boolalpha << (!isNewConfigurationRunning || !currentRunning) << std::endl;
813 #endif
814  if(!isNewConfigurationRunning || !currentRunning) {
815  Machine::Acceptance::NodeType acceptance = MachineRunner_::machine.isAcceptingConfiguration(newState, memory);
816 #if DEBUG
817  std::cout << " decision: " << Machine::Acceptance::debug(acceptance) << std::endl;
818 #endif
819  decision = Machine::Acceptance::decideForEmptySet(acceptance);
820  } else {
821  running = true;
822  }
823 #if DEBUG
824  std::cout << " decision: " << Utils::Debug::debug(decision) << std::endl;
825 #endif
826  newLeaves.push_back({{newState, memory, id}, decision});
827  }
829  (nodeType == Machine::Acceptance::Universal)
832  tree->insert(uid, quantifier, newLeaves);
833  }
834  } else {
835  auto& [currentState, currentMemory] = content;
836  Machine::Acceptance::NodeType nodeType = MachineRunner_::machine.isAcceptingConfiguration(currentState, currentMemory);
837  if(std::optional<bool> decision = Machine::Acceptance::toBool(nodeType); decision) {
838  tree->decide(uid, *decision);
839  continue;
840  }
841  typename MachineType::TransitionContainer matchingTransitions =
842  MachineRunner_::machine.getMatchingTransitions(currentState, currentMemory);
843  if(matchingTransitions.empty()) {
844  bool decision = Machine::Acceptance::decideForEmptySet(nodeType);
845  tree->decide(uid, decision);
846  } else {
847  std::vector<std::tuple<ConfigurationType, std::optional<bool>>> newLeaves;
848  for(auto& matchingTransition: matchingTransitions) {
849  StorageType memory = currentMemory;
850  auto& [transition, helper] = matchingTransition;
851  bool currentRunning = true;
852  StateType newState = transition.apply(
853  currentState,
854  memory,
855  std::move(helper),
856  currentRunning);
857  bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
858  std::optional<bool> decision;
859 #if DEBUG
860  std::cout << " oldState: " << currentState << std::endl;
861  std::cout << " newState: " << newState << std::endl;
862  std::cout << " terminated: " << std::boolalpha << (!isNewConfigurationRunning || !currentRunning) << std::endl;
863 #endif
864  if(!isNewConfigurationRunning || !currentRunning) {
865  Machine::Acceptance::NodeType acceptance = MachineRunner_::machine.isAcceptingConfiguration(newState, memory);
866 #if DEBUG
867  std::cout << " decision: " << Machine::Acceptance::debug(acceptance) << std::endl;
868 #endif
869  decision = Machine::Acceptance::decideForEmptySet(acceptance);
870  } else {
871  running = true;
872  }
873 #if DEBUG
874  std::cout << " decision: " << Utils::Debug::debug(decision) << std::endl;
875 #endif
876  newLeaves.push_back({{newState, memory}, decision});
877  }
879  (nodeType == Machine::Acceptance::Universal)
882  tree->insert(uid, quantifier, newLeaves);
883  }
884 
885  }
886 #if DEBUG
887  std::cout << configurationTree->debug(4) << std::endl;
888 #endif
889  }
890  }
891  }
892 #if DEBUG
893  std::cout << "OneStep end" << std::endl;
894 #endif
895  }
896 
901 
905  bool running;
906  };
907 }
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::isRunning
bool isRunning() const noexcept
Test if the machine is still running.
Definition: nonDeterministicMachineRunner.h:524
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::getInitialConfigurations
ConfigurationSetType getInitialConfigurations()
Get initial configurations.
Definition: nonDeterministicMachineRunner.h:603
TuringSim::Runner::NonDeterministicMachineRunner
A class to run a simulate the execution of a non-deterministic Machine.
Definition: nonDeterministicMachineRunner.h:371
TuringSim::Runner::MachineRunner::ApplyHelperType
MachineType::ApplyHelperType ApplyHelperType
The type of transitions apply helpers of the machine.
Definition: machineRunner.h:163
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::oneStep
virtual void oneStep() override
Execute one step of the machine.
Definition: nonDeterministicMachineRunner.h:643
TuringSim::Runner::AlternatingTree::Uid
size_t Uid
The keys of leaves and sub-Trees.
Definition: nonDeterministicMachineRunner.h:45
TuringSim::Runner::AlternatingTree::operator<<
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const AlternatingTree &tree)
Debug printer for the alternating tree.
Definition: nonDeterministicMachineRunner.h:194
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::operator=
constexpr NonDeterministicMachineRunner & operator=(const NonDeterministicMachineRunner &other)
Copy a runner.
Definition: nonDeterministicMachineRunner.h:495
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::IsAccepting
MachineType::IsAccepting IsAccepting
std::true_type if the machine is accepting or alternating, std::false_type otherwise.
Definition: nonDeterministicMachineRunner.h:408
TuringSim::Runner::MachineRunner::TransitionType
MachineType::TransitionType TransitionType
The type of transitions of the machine.
Definition: machineRunner.h:158
TuringSim::Runner::AlternatingTree::decide
void decide(Uid subUid, bool d)
Decide a leaf.
Definition: nonDeterministicMachineRunner.h:110
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::operator=
constexpr NonDeterministicMachineRunner & operator=(NonDeterministicMachineRunner &&other)
Move a runner.
Definition: nonDeterministicMachineRunner.h:508
TuringSim::Runner
The namespace of machine runners.
Definition: deterministicMachineRunner.h:5
TuringSim::Runner::AlternatingTree::pick
std::pair< const Uid, LeafType > & pick()
Pick a leaf with its uid.
Definition: nonDeterministicMachineRunner.h:81
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::debug
std::function< std::basic_ostream< CharT, Traits > &(std::basic_ostream< CharT, Traits > &)> debug() const
Debug printer for runner state.
Definition: nonDeterministicMachineRunner.h:582
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::IsListened
std::integral_constant< bool, !std::is_same_v< ListenerType, void > > IsListened
std::true_type if the runner has a listener, std::false_type otherwise.
Definition: nonDeterministicMachineRunner.h:400
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::ConfigurationType
std::conditional_t< IsListened_v, std::tuple< StateType, StorageType, ListenerIdType >, std::tuple< StateType, StorageType > > ConfigurationType
A 2- or 3- tuple containing the a configuration.
Definition: nonDeterministicMachineRunner.h:438
TuringSim::Runner::AlternatingTree::getSubTrees
const std::map< Uid, std::shared_ptr< AlternatingTree< LeafType > > > & getSubTrees()
Get sub trees.
Definition: nonDeterministicMachineRunner.h:102
TuringSim::Runner::MachineRunner::StateType
MachineType::StateType StateType
The type of states of the machine.
Definition: machineRunner.h:148
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::exec
virtual void exec() override
Run the machine until it halts.
Definition: nonDeterministicMachineRunner.h:545
TuringSim::Runner::AlternatingTree::decided
bool decided() const noexcept
Whether the node is decided.
Definition: nonDeterministicMachineRunner.h:135
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::step
virtual void step(size_t nbIter=1) override
Execute a given number of steps of the machine, one step by default.
Definition: nonDeterministicMachineRunner.h:535
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::configurations
ConfigurationSetType configurations
Store the configuration during the execution, with the id leading to it.
Definition: nonDeterministicMachineRunner.h:900
TuringSim::Runner::AlternatingTree::Quantifier
Quantifier
The quantifier for each node of an alternating tree.
Definition: nonDeterministicMachineRunner.h:37
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::ConfigurationSetType
std::conditional_t< !IsAlternating_v, std::tuple< std::vector< ConfigurationType >, std::vector< ConfigurationType > >, std::tuple< std::shared_ptr< AlternatingTree< ConfigurationType > >, std::deque< std::weak_ptr< AlternatingTree< ConfigurationType > > > > > ConfigurationSetType
The structure containing the configurations.
Definition: nonDeterministicMachineRunner.h:456
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::NonDeterministicMachineRunner
constexpr NonDeterministicMachineRunner(NonDeterministicMachineRunner &&other)
Move a runner.
Definition: nonDeterministicMachineRunner.h:485
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::NonDeterministicMachineRunner
constexpr NonDeterministicMachineRunner(const NonDeterministicMachineRunner &other)
Copy a runner.
Definition: nonDeterministicMachineRunner.h:476
TuringSim::Runner::AlternatingTree::lastLeafUid
Uid lastLeafUid()
The last uid of the leaves.
Definition: nonDeterministicMachineRunner.h:88
TuringSim::Runner::AlternatingTree::Quantifier::Existential
@ Existential
The node is existential.
TuringSim::Runner::AlternatingTree::debug
static std::function< std::basic_ostream< CharT, Traits > &(std::basic_ostream< CharT, Traits > &)> debug(const Quantifier &q)
Debug printer for a quantifier.
Definition: nonDeterministicMachineRunner.h:173
TuringSim::Runner::AlternatingTree::insert
void insert(Uid subUid, Quantifier q, std::vector< std::tuple< LeafType, std::optional< bool >>> &newLeaves)
Replace a uid with a a leaf of new leaves.
Definition: nonDeterministicMachineRunner.h:59
TuringSim::Runner::AlternatingTree::debug
std::function< std::basic_ostream< CharT, Traits > &(std::basic_ostream< CharT, Traits > &)> debug(size_t i) const
Debug printer for the alternating tree, with initial indentation.
Definition: nonDeterministicMachineRunner.h:206
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::~NonDeterministicMachineRunner
virtual ~NonDeterministicMachineRunner() override
Destroy the runner.
Definition: nonDeterministicMachineRunner.h:519
TuringSim::Runner::MachineRunner::ListenerType
ListenerType_ ListenerType
The type of the listener.
Definition: machineRunner.h:142
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::NonDeterministicMachineRunner
NonDeterministicMachineRunner(const MachineType &machine, ListenerConstructorArgs... listener)
Construct a MachineRunner from a Machine.
Definition: nonDeterministicMachineRunner.h:467
TuringSim::Runner::AlternatingTree::makeAlternatingTreeRoot
static std::shared_ptr< AlternatingTree > makeAlternatingTreeRoot(Quantifier quantifier, const std::vector< LeafType > &leaves)
Build a new alternating tree, with provided leaves and quantifier.
Definition: nonDeterministicMachineRunner.h:151
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::IsAlternating
MachineType::IsAlternating IsAlternating
std::true_type if the machine is alternating, std::false_type otherwise.
Definition: nonDeterministicMachineRunner.h:416
TuringSim::Runner::AlternatingTree::hasLeaves
bool hasLeaves() const
Whether the node has leaves.
Definition: nonDeterministicMachineRunner.h:95
TuringSim::Runner::MachineRunnerArgs::ListenerConstructorArgs
std::tuple< ListenerType & > ListenerConstructorArgs
The tuple of parameters of a runner, excluding the machine parameter.
Definition: machineRunner.h:101
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::getConfigurationSet
const ConfigurationSetType & getConfigurationSet() const
Get a const reference to the set of configurations.
Definition: nonDeterministicMachineRunner.h:531
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::running
bool running
Whether the machine is sill running.
Definition: nonDeterministicMachineRunner.h:905
TuringSim::Runner::AlternatingTree::compact
void compact()
Remove decided items, since they are useless, except for documentation.
Definition: nonDeterministicMachineRunner.h:256
TuringSim::Runner::NonDeterministicMachineRunner< MachineType_, ListenerType_, std::tuple< ListenerConstructorArgs... > >::accept
virtual bool accept()
Check the acceptance of the word.
Definition: nonDeterministicMachineRunner.h:556
TuringSim::Runner::AlternatingTree::Quantifier::Universal
@ Universal
The node is universal.
TuringSim::Utils::Debug::debug
std::function< std::basic_ostream< CharT, Traits > &(std::basic_ostream< CharT, Traits > &)> debug(const T &s)
Generic debug printing function.
Definition: printer.h:34
TuringSim::Runner::MachineRunner::ListenerIdType
ListenerType::IdType ListenerIdType
The type of identifiers used by the listener.
Definition: machineRunner.h:169
TuringSim::Runner::AlternatingTree::getDecision
std::optional< bool > getDecision() const noexcept
Get the optional decision.
Definition: nonDeterministicMachineRunner.h:142
TuringSim::Runner::AlternatingTree::debug
std::function< std::basic_ostream< CharT, Traits > &(std::basic_ostream< CharT, Traits > &)> debug() const
Debug printer for the alternating tree.
Definition: nonDeterministicMachineRunner.h:162
TuringSim::Runner::AlternatingTree
Represent a tree of properties with alternating quantifiers.
Definition: nonDeterministicMachineRunner.h:32
TuringSim::Runner::MachineRunner::StorageType
MachineType::StorageType StorageType
The type of the memory of the machine.
Definition: machineRunner.h:153
TuringSim::Runner::MachineRunner
A class to run a simulate the execution of a Machine.
Definition: machineRunner.h:132
TuringSim::Runner::MachineRunner::MachineType
MachineType_ MachineType
The type of the simulated machine.
Definition: machineRunner.h:137