3 #include <utils/printer.h>
4 #include <runner/machineRunner.h>
31 template<
typename LeafType>
59 void insert(
Uid subUid,
Quantifier q, std::vector<std::tuple<LeafType, std::optional<bool>>>& newLeaves) {
62 for(
size_t i = 0; i < newLeaves.size(); ++i) {
63 leaves.emplace_hint(leaves.end(), nextUid++, std::move(std::get<LeafType>(newLeaves[i])));
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]));
81 [[nodiscard]] std::pair<const Uid, LeafType>&
pick() {
82 return *leaves.begin();
89 return leaves.rbegin()->first;
96 return !leaves.empty();
102 [[nodiscard]]
const std::map<Uid, std::shared_ptr<AlternatingTree<LeafType>>>&
getSubTrees() {
111 std::tuple<LeafType, bool> decidedLeaf{std::move(leaves[subUid]), std::move(d)};
112 decidedLeaves.insert({subUid, decidedLeaf});
113 leaves.erase(subUid);
117 auto& [uid, p] = *parent;
118 p->propagate_decide(uid, d);
122 if(leaves.empty() && subTrees.empty()) {
125 auto& [uid, p] = *parent;
126 p->propagate_decide(uid, d);
136 return decision.has_value();
153 return std::shared_ptr<AlternatingTree>(p);
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 {
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>& {
193 template<
typename CharT =
char,
typename Traits = std::
char_traits<CharT>>
195 using Utils::Debug::operator<<;
196 return os << tree.
debug();
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,
' ');
214 <<
", nextUid: " << nextUid
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;
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;
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;
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;
257 decidedSubTrees.clear();
258 decidedLeaves.clear();
259 for(
auto& [_uid, subTree]: subTrees) {
267 quantifier(quantifier),
271 for(
const LeafType& leaf: leaves) {
272 this->leaves.insert({nextUid++, leaf});
276 AlternatingTree(
Quantifier quantifier, std::vector<LeafType>&& leaves) :
277 quantifier(quantifier),
281 for(LeafType& leaf: leaves) {
282 this->leaves.insert({nextUid++, std::move(leaf)});
286 AlternatingTree(
Uid uid,
Quantifier quantifier, std::vector<std::tuple<LeafType, std::optional<bool>>>&& newLeaves, AlternatingTree<LeafType>* parent) :
287 quantifier(quantifier),
289 parent({uid, parent})
291 for(
size_t i = 0; i < newLeaves.size(); ++i) {
292 leaves.emplace_hint(leaves.end(), nextUid++, std::move(std::get<LeafType>(newLeaves[i])));
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]));
302 AlternatingTree(
const AlternatingTree& other) :
303 quantifier(other.quantifier),
304 subTrees(other.subTrees),
305 leaves(other.leaves),
306 decision(other.decision),
310 AlternatingTree(AlternatingTree&& other) :
311 quantifier(other.quantifier),
312 subTrees(std::move(other.subTrees)),
313 leaves(std::move(other.leaves)),
314 decision(other.decision),
318 auto& [uid, p] = *parent;
319 p->subTrees[uid] =
this;
323 void propagate_decide(
Uid subUid,
bool d) {
324 decidedSubTrees.insert({subUid, {subTrees[subUid], d}});
325 subTrees.erase(subUid);
329 auto& [uid, p] = *parent;
330 p->propagate_decide(uid, d);
334 if(leaves.empty() && subTrees.empty()) {
337 auto& [uid, p] = *parent;
338 p->propagate_decide(uid, d);
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 {};
354 std::optional<std::tuple<Uid, AlternatingTree<LeafType>*>> parent;
367 typename MachineType,
368 typename ListenerType,
380 template<
typename MachineType_,
typename ListenerType_,
typename... ListenerConstructorArgs>
384 std::tuple<ListenerConstructorArgs...>
400 typedef std::integral_constant<bool, !std::is_same_v<ListenerType, void>>
IsListened;
403 static constexpr
bool IsListened_v = IsListened::value;
411 static constexpr
bool IsAccepting_v = IsAccepting::value;
419 static constexpr
bool IsAlternating_v = IsAlternating::value;
436 std::tuple<StateType, StorageType, ListenerIdType>,
437 std::tuple<StateType, StorageType>
454 std::tuple<std::vector<ConfigurationType>, std::vector<ConfigurationType>>,
455 std::tuple<std::shared_ptr<AlternatingTree<ConfigurationType>>, std::deque<std::weak_ptr<AlternatingTree<ConfigurationType>>>>
459 "The only allowed value for ListenerConstructorArgs is the default one.");
469 configurations(getInitialConfigurations()),
478 configurations(other.configurations),
479 running(other.running)
487 configurations(std::move(other.configurations)),
488 running(std::move(other.running))
497 MachineRunner_::operator=(other);
498 configurations = other.configurations;
499 running = other.running;
510 MachineRunner_::operator=(std::move(other));
511 configurations = std::move(other.configurations);
512 running = std::move(other.running);
532 return configurations;
535 virtual void step(
size_t nbIter = 1)
override {
536 for(
size_t i = 0; i < nbIter && running; ++i) {
551 #pragma clang diagnostic push
552 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
558 if constexpr (!IsAccepting_v) {
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)) {
571 std::shared_ptr<AlternatingTree<ConfigurationType>> tree = std::get<std::shared_ptr<AlternatingTree<ConfigurationType>>>(configurations);
572 return *tree->getDecision();
575 #pragma clang diagnostic pop
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;
591 return os <<
"running: " << std::boolalpha << running << std::endl
592 <<
"configuration tree: " << std::endl << std::get<0>(configurations)->debug(2) << std::endl
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()});
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, {}});
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()});
628 std::vector<std::tuple<StateType, StorageType>> initialConfigurations;
629 for(
const StateType& state: MachineRunner_::machine.getInitialStates()) {
630 initialConfigurations.push_back({state, {}});
648 std::cout <<
"OneStep begin" << std::endl;
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);
661 if (matchingTransitions.empty()) {
662 MachineRunner_::listener.registerNoTransition(currentId, currentState, currentMemory);
663 haltedConfigurations.push_back({currentState, currentMemory, currentId});
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;
677 bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
678 MachineRunner_::listener.registerPostTransition(
id, currentState, memory, transition, helper, isNewConfigurationRunning);
679 if(isNewConfigurationRunning && currentRunning) {
681 newConfigurations.push_back({newState, memory,
id});
683 haltedConfigurations.push_back({newState, memory,
id});
689 for(
const auto& [currentState, currentMemory]: runningConfigurations) {
690 typename MachineType::TransitionContainer matchingTransitions =
691 MachineRunner_::machine.getMatchingTransitions(currentState, currentMemory);
693 if (matchingTransitions.empty()) {
694 haltedConfigurations.push_back({currentState, currentMemory});
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;
707 bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
708 if(isNewConfigurationRunning && currentRunning) {
710 newConfigurations.push_back({newState, memory});
712 haltedConfigurations.push_back({newState, memory});
718 runningConfigurations = newConfigurations;
720 std::deque<std::shared_ptr<AlternatingTree<ConfigurationType>>> toRun;
721 std::deque<std::weak_ptr<AlternatingTree<ConfigurationType>>> newToExplore;
723 auto& [configurationTree, toExplore] = configurations;
725 if (toExplore.empty()) {
726 toExplore.push_back(configurationTree);
729 while (!toExplore.empty()) {
730 std::weak_ptr<AlternatingTree<ConfigurationType>> tree_w = toExplore.front();
731 toExplore.pop_front();
733 if (tree->decided()) {
736 if (tree->hasLeaves()) {
737 toRun.push_back(tree);
738 newToExplore.push_back(tree);
740 for(
const auto& [_uid, subTree]: tree->getSubTrees()) {
741 toExplore.push_back(subTree);
747 using Utils::Debug::operator<<;
750 std::cout <<
"toRun length: " << toRun.size() << std::endl;
753 toExplore = newToExplore;
754 while(!toRun.empty()) {
756 std::cout <<
" toRun length remaining: " << toRun.size() << std::endl;
758 std::shared_ptr<AlternatingTree<ConfigurationType>> tree = toRun.front();
763 if(!tree->hasLeaves()) {
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;
771 std::cout <<
" picked leaf uid: " << uid << std::endl;
776 std::cout <<
" Too big; uid: " << uid <<
", lastUid: " << lastUid << std::endl;
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);
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);
795 std::vector<std::tuple<ConfigurationType, std::optional<bool>>> newLeaves;
796 for(
auto& matchingTransition: matchingTransitions) {
798 ListenerIdType id = MachineRunner_::listener.registerPreTransition(currentState, memory, currentId);
799 auto& [transition, helper] = matchingTransition;
800 bool currentRunning =
true;
806 bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
807 MachineRunner_::listener.registerPostTransition(
id, currentState, memory, transition, helper, isNewConfigurationRunning);
808 std::optional<bool> decision;
810 std::cout <<
" oldState: " << currentState << std::endl;
811 std::cout <<
" newState: " << newState << std::endl;
812 std::cout <<
" terminated: " << std::boolalpha << (!isNewConfigurationRunning || !currentRunning) << std::endl;
814 if(!isNewConfigurationRunning || !currentRunning) {
815 Machine::Acceptance::NodeType acceptance = MachineRunner_::machine.isAcceptingConfiguration(newState, memory);
817 std::cout <<
" decision: " << Machine::Acceptance::debug(acceptance) << std::endl;
819 decision = Machine::Acceptance::decideForEmptySet(acceptance);
826 newLeaves.push_back({{newState, memory,
id}, decision});
829 (nodeType == Machine::Acceptance::Universal)
832 tree->
insert(uid, quantifier, newLeaves);
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);
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);
847 std::vector<std::tuple<ConfigurationType, std::optional<bool>>> newLeaves;
848 for(
auto& matchingTransition: matchingTransitions) {
850 auto& [transition, helper] = matchingTransition;
851 bool currentRunning =
true;
857 bool isNewConfigurationRunning = !MachineRunner_::machine.isHaltingConfiguration(newState, memory);
858 std::optional<bool> decision;
860 std::cout <<
" oldState: " << currentState << std::endl;
861 std::cout <<
" newState: " << newState << std::endl;
862 std::cout <<
" terminated: " << std::boolalpha << (!isNewConfigurationRunning || !currentRunning) << std::endl;
864 if(!isNewConfigurationRunning || !currentRunning) {
865 Machine::Acceptance::NodeType acceptance = MachineRunner_::machine.isAcceptingConfiguration(newState, memory);
867 std::cout <<
" decision: " << Machine::Acceptance::debug(acceptance) << std::endl;
869 decision = Machine::Acceptance::decideForEmptySet(acceptance);
876 newLeaves.push_back({{newState, memory}, decision});
879 (nodeType == Machine::Acceptance::Universal)
882 tree->
insert(uid, quantifier, newLeaves);
887 std::cout << configurationTree->debug(4) << std::endl;
893 std::cout <<
"OneStep end" << std::endl;