1#ifndef GUARD_INCLUDE_PROBFD_ALGORITHMS_TA_TOPOLOGICAL_VALUE_ITERATION_H
2#error "This file should only be included from ta_topological_value_iteration.h"
5#include "probfd/algorithms/utils.h"
7#include "probfd/utils/guards.h"
8#include "probfd/utils/iterators.h"
9#include "probfd/utils/not_implemented.h"
11#include "probfd/cost_function.h"
12#include "probfd/evaluator.h"
13#include "probfd/progress_report.h"
15#include "downward/utils/countdown_timer.h"
21inline void Statistics::print(std::ostream& out)
const
23 out <<
" Expanded state(s): " << expanded_states << std::endl;
24 out <<
" Terminal state(s): " << terminal_states << std::endl;
25 out <<
" Goal state(s): " << goal_states << std::endl;
26 out <<
" Pruned state(s): " << pruned << std::endl;
27 out <<
" Maximal SCCs: " << sccs <<
" (" << singleton_sccs
28 <<
" are singleton)" << std::endl;
29 out <<
" Bellman backups: " << bellman_backups << std::endl;
31 out <<
" Time spent initializing state data: " << initialize_state_timer
33 out <<
" Time spent expanding successors: " << successor_handling_timer
35 out <<
" Time spent handling SCCs: " << scc_handling_timer << std::endl;
36 out <<
" Time spent backtracking: " << backtracking_timer << std::endl;
37 out <<
" Time spent running VI on SCCs: " << vi_timer << std::endl;
38 out <<
" Time spent decomposing ECs: " << decomposition_timer << std::endl;
39 out <<
" Time spent in solvability analysis: " << solvability_timer
43template <
typename State,
typename Action,
bool UseInterval>
44auto TATopologicalValueIteration<State, Action, UseInterval>::StateInfo::
47 return explored ? (stack_id < UNDEF ? ONSTACK : CLOSED) : NEW;
50template <
typename State,
typename Action,
bool UseInterval>
51auto TATopologicalValueIteration<State, Action, UseInterval>::StateInfo::
52 get_ecd_status()
const
54 return explored ? (ecd_stack_id < UNDEF_ECD ? ONSTACK : CLOSED) : NEW;
57template <
typename State,
typename Action,
bool UseInterval>
58TATopologicalValueIteration<State, Action, UseInterval>::ExplorationInfo::
61 StackInfo& stack_info,
62 unsigned int stackidx)
64 , stack_info(stack_info)
70template <
typename State,
typename Action,
bool UseInterval>
71bool TATopologicalValueIteration<State, Action, UseInterval>::ExplorationInfo::
72 next_transition(MDPType& mdp)
77 assert(q_value.scc_successors.empty());
79 return !aops.empty() &&
80 forward_non_loop_transition(mdp, mdp.get_state(state_id));
83template <
typename State,
typename Action,
bool UseInterval>
84bool TATopologicalValueIteration<State, Action, UseInterval>::ExplorationInfo::
85 forward_non_loop_transition(MDPType& mdp,
const State& state)
88 mdp.generate_action_transitions(state, aops.back(), transition);
89 const value_t self_loop_prob = transition.remove_if_normalize(state_id);
91 if (!transition.empty()) {
92 successor = transition.begin();
94 const value_t normalization = 1.0_vt / (1.0_vt - self_loop_prob);
95 const auto cost = normalization * mdp.get_action_cost(aops.back());
96 if (cost != 0.0_vt) has_all_zero =
false;
97 q_value.conv_part = AlgorithmValueType(cost);
103 }
while (!aops.empty());
108template <
typename State,
typename Action,
bool UseInterval>
109bool TATopologicalValueIteration<State, Action, UseInterval>::ExplorationInfo::
112 if (++successor != transition.end()) {
116 const bool exits_only_solvable =
117 q_value.conv_part != AlgorithmValueType(INFINITE_VALUE);
119 const size_t num_scc_succs = q_value.scc_successors.size();
121 if (num_scc_succs == 0) {
125 set_min(stack_info.conv_part, q_value.conv_part);
127 if (exits_only_solvable) {
128 ++stack_info.active_exit_transitions;
129 ++stack_info.active_transitions;
132 const bool leaves_scc = num_scc_succs != transition.size();
134 if (leaves_scc || q_value.conv_part != AlgorithmValueType(0_vt)) {
138 stack_info.add_non_ec_transition(std::move(q_value));
141 stack_info.ec_transitions.emplace_back(std::move(q_value));
144 if (exits_only_solvable) {
146 ++stack_info.active_exit_transitions;
148 ++stack_info.active_transitions;
150 stack_info.transition_flags.emplace_back(
151 exits_only_solvable && leaves_scc,
152 exits_only_solvable);
155 assert(q_value.scc_successors.empty());
160template <
typename State,
typename Action,
bool UseInterval>
161ItemProbabilityPair<StateID>
162TATopologicalValueIteration<State, Action, UseInterval>::ExplorationInfo::
163 get_current_successor()
168template <
typename State,
typename Action,
bool UseInterval>
169template <
typename ValueStore>
170auto TATopologicalValueIteration<State, Action, UseInterval>::QValueInfo::
171 compute_q_value(ValueStore& value_store)
const -> AlgorithmValueType
173 AlgorithmValueType res = conv_part;
175 for (
auto& [state_id, prob] : scc_successors) {
176 res += prob * value_store[state_id];
182template <
typename State,
typename Action,
bool UseInterval>
183TATopologicalValueIteration<State, Action, UseInterval>::StackInfo::StackInfo(
185 AlgorithmValueType& value_ref)
191template <
typename State,
typename Action,
bool UseInterval>
192void TATopologicalValueIteration<State, Action, UseInterval>::StackInfo::
193 add_non_ec_transition(QValueInfo&& info)
195 auto [it, inserted] = non_ec_transitions.insert(std::move(info));
198 set_min(it->conv_part, info.conv_part);
199 info.scc_successors.clear();
203template <
typename State,
typename Action,
bool UseInterval>
204TATopologicalValueIteration<State, Action, UseInterval>::ECDExplorationInfo::
205 ECDExplorationInfo(StackInfo& stack_info,
unsigned stackidx)
206 : stack_info(stack_info)
212template <
typename State,
typename Action,
bool UseInterval>
213bool TATopologicalValueIteration<State, Action, UseInterval>::
214 ECDExplorationInfo::next_transition()
216 assert(!action->scc_successors.empty());
217 assert(action < end);
220 if (++action != end) {
221 successor = action->scc_successors.begin();
222 assert(!action->scc_successors.empty());
233 stack_info.add_non_ec_transition(std::move(*action));
235 if (action != --end) {
236 *action = std::move(*end);
237 assert(!action->scc_successors.empty());
238 successor = action->scc_successors.begin();
247 auto& ect = stack_info.ec_transitions;
248 ect.erase(end, ect.end());
253template <
typename State,
typename Action,
bool UseInterval>
254bool TATopologicalValueIteration<State, Action, UseInterval>::
255 ECDExplorationInfo::next_successor()
257 assert(!action->scc_successors.empty());
258 return ++successor != action->scc_successors.end();
261template <
typename State,
typename Action,
bool UseInterval>
262ItemProbabilityPair<StateID>
263TATopologicalValueIteration<State, Action, UseInterval>::ECDExplorationInfo::
264 get_current_successor()
269template <
typename State,
typename Action,
bool UseInterval>
270Interval TATopologicalValueIteration<State, Action, UseInterval>::solve(
272 EvaluatorType& heuristic,
273 param_type<State> state,
277 storage::PerStateStorage<AlgorithmValueType> value_store;
279 ->solve(mdp, heuristic, mdp.get_state_id(state), value_store, max_time);
282template <
typename State,
typename Action,
bool UseInterval>
284 std::ostream& out)
const
286 statistics_.print(out);
289template <
typename State,
typename Action,
bool UseInterval>
296template <
typename State,
typename Action,
bool UseInterval>
299 const EvaluatorType& heuristic,
308 utils::CountdownTimer timer(max_time);
312 state_information_[init_state_id],
313 value_store[init_state_id]);
316 ExplorationInfo* explore;
319 explore = &exploration_stack_.back();
320 }
while (initialize_state(mdp, heuristic, *explore, value_store) &&
321 successor_loop(mdp, *explore, value_store, timer));
325 const unsigned stack_id = explore->stackidx;
326 const unsigned lowlink = explore->lowlink;
328 assert(stack_id >= lowlink);
330 const bool backtrack_from_scc = stack_id == lowlink;
333 if (backtrack_from_scc) {
334 scc_found(value_store, *explore, stack_id, timer);
337 assert(stack_.empty());
338 assert(exploration_stack_.size() == 1);
339 exploration_stack_.pop_back();
341 if constexpr (UseInterval) {
342 return value_store[init_state_id];
345 value_store[init_state_id],
351 assert(exploration_stack_.size() > 1);
353 timer.throw_if_expired();
355 TimerScope _(statistics_.backtracking_timer);
357 const ExplorationInfo& successor = *explore--;
359 const auto [succ_id, prob] = explore->get_current_successor();
361 if (backtrack_from_scc) {
362 const AlgorithmValueType value = value_store[succ_id];
363 explore->q_value.conv_part += prob * value;
364 explore->exit_interval.
lower =
365 std::min(explore->exit_interval.
lower, value);
366 explore->exit_interval.
upper =
367 std::max(explore->exit_interval.
upper, value);
369 explore->lowlink = std::min(explore->lowlink, lowlink);
370 explore->exit_interval.
lower = std::min(
371 explore->exit_interval.
lower,
372 successor.exit_interval.
lower);
373 explore->exit_interval.
upper = std::max(
374 explore->exit_interval.
upper,
375 successor.exit_interval.
upper);
376 explore->has_all_zero =
377 explore->has_all_zero && successor.has_all_zero;
379 explore->q_value.scc_successors.emplace_back(succ_id, prob);
380 successor.stack_info.parents.emplace_back(
382 explore->stack_info.transition_flags.size());
385 exploration_stack_.pop_back();
387 (!explore->next_successor() && !explore->next_transition(mdp)) ||
388 !successor_loop(mdp, *explore, value_store, timer));
392template <
typename State,
typename Action,
bool UseInterval>
398 double) -> std::unique_ptr<PolicyType>
403template <
typename State,
typename Action,
bool UseInterval>
404void TATopologicalValueIteration<State, Action, UseInterval>::push_state(
406 StateInfo& state_info,
407 AlgorithmValueType& value)
409 const std::size_t stack_size = stack_.size();
410 exploration_stack_.emplace_back(
412 stack_.emplace_back(state_id, value),
414 state_info.explored = 1;
415 state_info.stack_id = stack_size;
418template <
typename State,
typename Action,
bool UseInterval>
419bool TATopologicalValueIteration<State, Action, UseInterval>::successor_loop(
421 ExplorationInfo& explore,
423 utils::CountdownTimer& timer)
425 TimerScope _(statistics_.successor_handling_timer);
428 timer.throw_if_expired();
430 const auto [succ_id, prob] = explore.get_current_successor();
431 assert(succ_id != explore.state_id);
433 StateInfo& succ_info = state_information_[succ_id];
435 switch (succ_info.get_status()) {
437 case StateInfo::NEW: {
438 push_state(succ_id, succ_info, value_store[succ_id]);
442 case StateInfo::CLOSED: {
443 const AlgorithmValueType value = value_store[succ_id];
444 explore.q_value.conv_part += prob * value;
445 explore.exit_interval.lower =
446 std::min(explore.exit_interval.lower, value);
447 explore.exit_interval.upper =
448 std::max(explore.exit_interval.upper, value);
452 case StateInfo::ONSTACK:
453 unsigned succ_stack_id = succ_info.stack_id;
454 explore.lowlink = std::min(explore.lowlink, succ_stack_id);
455 explore.q_value.scc_successors.emplace_back(succ_id, prob);
457 auto& parents = stack_[succ_stack_id].parents;
458 parents.emplace_back(
460 explore.stack_info.transition_flags.size());
462 }
while (explore.next_successor() || explore.next_transition(mdp));
467template <
typename State,
typename Action,
bool UseInterval>
468bool TATopologicalValueIteration<State, Action, UseInterval>::initialize_state(
470 const EvaluatorType& heuristic,
471 ExplorationInfo& exp_info,
475 state_information_[exp_info.state_id].get_status() ==
478 TimerScope _(statistics_.initialize_state_timer);
480 const State state = mdp.get_state(exp_info.state_id);
482 const TerminationInfo state_term = mdp.get_termination_info(state);
483 const value_t t_cost = state_term.get_cost();
484 const value_t estimate = heuristic.evaluate(state);
486 exp_info.stack_info.conv_part = AlgorithmValueType(t_cost);
487 exp_info.exit_interval = Interval(t_cost);
489 AlgorithmValueType& state_value = value_store[exp_info.state_id];
491 if constexpr (UseInterval) {
492 state_value.lower = estimate;
493 state_value.upper = t_cost;
495 state_value = estimate;
498 if (t_cost != INFINITE_VALUE) {
499 ++exp_info.stack_info.active_exit_transitions;
500 ++exp_info.stack_info.active_transitions;
503 if (state_term.is_goal_state()) {
504 ++statistics_.goal_states;
505 }
else if (estimate == t_cost) {
506 ++statistics_.pruned;
510 mdp.generate_applicable_actions(state, exp_info.aops);
512 const size_t num_aops = exp_info.aops.size();
514 exp_info.stack_info.ec_transitions.reserve(num_aops);
516 ++statistics_.expanded_states;
518 if (exp_info.aops.empty()) {
519 ++statistics_.terminal_states;
520 }
else if (exp_info.forward_non_loop_transition(mdp, state)) {
527template <
typename State,
typename Action,
bool UseInterval>
528void TATopologicalValueIteration<State, Action, UseInterval>::scc_found(
530 ExplorationInfo& exp_info,
531 unsigned int stack_idx,
532 utils::CountdownTimer& timer)
534 using namespace std::views;
536 TimerScope _(statistics_.scc_handling_timer);
538 auto scc = stack_ | drop(stack_idx);
540 assert(!scc.empty());
544 if (exp_info.exit_interval.lower == INFINITE_VALUE ||
545 (exp_info.exit_interval.lower == exp_info.exit_interval.upper &&
546 exp_info.has_all_zero)) {
547 for (StackInfo& stk_info : scc) {
548 StateInfo& state_info = state_information_[stk_info.state_id];
549 assert(state_info.get_status() == StateInfo::ONSTACK);
550 update(*stk_info.value, exp_info.exit_interval.lower);
551 state_info.stack_id = StateInfo::UNDEF;
554 stack_.erase(scc.begin(), scc.end());
558 if (scc.size() == 1) {
562 StackInfo& single = scc.front();
563 StateInfo& state_info = state_information_[single.state_id];
564 assert(state_info.get_status() == StateInfo::ONSTACK);
565 update(*single.value, single.conv_part);
566 state_info.stack_id = StateInfo::UNDEF;
567 ++statistics_.singleton_sccs;
572 if (std::ranges::any_of(scc, [](
const StackInfo& stk_info) {
573 return !stk_info.non_ec_transitions.empty();
576 TimerScope _(statistics_.decomposition_timer);
578 scc_.reserve(scc.size());
580 for (
const auto state_id : scc | transform(&StackInfo::state_id)) {
581 scc_.push_back(state_id);
585 find_and_decompose_sccs(timer);
587 for (StackInfo& stack_info : scc) {
588 StateInfo& state_info = state_information_[stack_info.state_id];
589 state_info.stack_id = StateInfo::UNDEF;
590 assert(state_info.get_status() == StateInfo::CLOSED);
593 assert(exploration_stack_ecd_.empty());
596 StackInfo& repr_stk = scc.front();
597 const StateID scc_repr_id = repr_stk.state_id;
598 state_information_[scc_repr_id].stack_id = StateInfo::UNDEF;
601 for (StackInfo& succ_stk : scc | drop(1)) {
602 state_information_[succ_stk.state_id].stack_id = StateInfo::UNDEF;
605 auto& tr = succ_stk.non_ec_transitions;
606 for (
auto it = tr.begin(); it != tr.end();) {
607 repr_stk.add_non_ec_transition(
608 std::move(tr.extract(it++).value()));
612 std::decay_t<decltype(tr)>().swap(tr);
614 set_min(repr_stk.conv_part, succ_stk.conv_part);
616 succ_stk.conv_part = AlgorithmValueType(INFINITE_VALUE);
619 succ_stk.non_ec_transitions.emplace(
621 std::vector{ItemProbabilityPair<StateID>(scc_repr_id, 1.0_vt)});
626 std::vector<std::vector<int>::iterator> scc_index_to_local;
627 std::vector<int> partition;
628 std::vector<int>::iterator solvable_beg;
629 std::vector<int>::iterator solvable_exits_beg;
632 explicit Partition(std::size_t size)
633 : scc_index_to_local(size)
636 for (
unsigned int i = 0; i != size; ++i) {
637 scc_index_to_local[i] = partition.begin() + i;
638 partition[i] =
static_cast<int>(i);
641 solvable_beg = partition.begin();
642 solvable_exits_beg = partition.begin();
645 auto solvable_begin() {
return solvable_beg; }
646 auto solvable_end() {
return partition.end(); }
650 return std::ranges::subrange(solvable_begin(), solvable_end());
654 bool has_solvable()
const
656 return solvable_beg != partition.end();
659 void demote_unsolvable(
int s)
661 assert(scc_index_to_local[s] >= solvable_beg);
662 assert(scc_index_to_local[s] < solvable_exits_beg);
664 auto local = scc_index_to_local[s];
665 std::swap(scc_index_to_local[*solvable_beg], scc_index_to_local[s]);
666 std::swap(*solvable_beg, *local);
670 assert(scc_index_to_local[s] < solvable_beg);
673 void demote_exit_unsolvable(
int s)
675 demote_exit_solvable(s);
676 demote_unsolvable(s);
679 void demote_exit_solvable(
int s)
681 assert(scc_index_to_local[s] >= solvable_exits_beg);
683 auto local = scc_index_to_local[s];
685 scc_index_to_local[*solvable_exits_beg],
686 scc_index_to_local[s]);
687 std::swap(*solvable_exits_beg, *local);
689 ++solvable_exits_beg;
691 assert(scc_index_to_local[s] >= solvable_beg);
692 assert(scc_index_to_local[s] < solvable_exits_beg);
695 bool promote_solvable(
int s)
697 if (!is_unsolvable(s)) {
703 auto local = scc_index_to_local[s];
704 std::swap(scc_index_to_local[*solvable_beg], scc_index_to_local[s]);
705 std::swap(*solvable_beg, *local);
707 assert(scc_index_to_local[s] >= solvable_beg);
708 assert(scc_index_to_local[s] < solvable_exits_beg);
713 void mark_non_exit_states_unsolvable()
715 solvable_beg = solvable_exits_beg;
718 bool is_unsolvable(
int s)
720 return scc_index_to_local[s] < solvable_beg;
725 TimerScope _(statistics_.solvability_timer);
732 Partition partition(scc.size());
734 for (std::size_t i = 0; i != scc.size(); ++i) {
735 StackInfo& info = scc[i];
738 info.active_transitions != 0 ||
739 info.active_exit_transitions == 0);
742 for (
auto& parent_info : info.parents) {
743 parent_info.parent_idx -= stack_idx;
746 if (info.active_exit_transitions == 0) {
747 if (info.active_transitions > 0) {
748 partition.demote_exit_solvable(i);
750 value_store[info.state_id] =
751 AlgorithmValueType(INFINITE_VALUE);
752 partition.demote_exit_unsolvable(i);
757 if (partition.has_solvable()) {
760 timer.throw_if_expired();
764 auto unsolv_it = partition.solvable_begin();
766 partition.mark_non_exit_states_unsolvable();
768 for (
auto it = partition.solvable_end();
769 it != partition.solvable_begin();) {
770 for (
const auto& [parent_idx, tr_idx] :
771 scc[*--it].parents) {
772 StackInfo& pinfo = scc[parent_idx];
774 if (pinfo.transition_flags[tr_idx].is_active) {
775 partition.promote_solvable(parent_idx);
781 if (unsolv_it == partition.solvable_begin())
break;
786 timer.throw_if_expired();
788 StackInfo& scc_elem = scc[*unsolv_it];
791 assert(partition.is_unsolvable(*unsolv_it));
793 value_store[scc_elem.state_id] =
794 AlgorithmValueType(INFINITE_VALUE);
796 for (
const auto& [parent_idx, tr_idx] : scc_elem.parents) {
797 StackInfo& pinfo = scc[parent_idx];
798 auto& transition_flags = pinfo.transition_flags[tr_idx];
801 !transition_flags.is_active_exiting ||
802 transition_flags.is_active);
804 if (partition.is_unsolvable(parent_idx))
continue;
806 if (transition_flags.is_active_exiting) {
807 transition_flags.is_active_exiting =
false;
808 transition_flags.is_active =
false;
810 --pinfo.active_transitions;
811 --pinfo.active_exit_transitions;
813 if (pinfo.active_transitions == 0) {
814 partition.demote_exit_unsolvable(parent_idx);
815 }
else if (pinfo.active_exit_transitions == 0) {
816 partition.demote_exit_solvable(parent_idx);
818 }
else if (transition_flags.is_active) {
819 transition_flags.is_active =
false;
821 --pinfo.active_transitions;
823 if (pinfo.active_transitions == 0) {
824 partition.demote_unsolvable(parent_idx);
828 }
while (++unsolv_it != partition.solvable_begin());
835 TimerScope _(statistics_.vi_timer);
838 AlgorithmValueType* value;
839 AlgorithmValueType conv_part;
840 std::vector<QValueInfo> transitions;
843 std::vector<VIInfo> table;
844 table.reserve(scc.size());
846 for (
auto it = scc.begin(); it != scc.end(); ++it) {
847 auto& t = table.emplace_back(it->value, it->conv_part);
848 auto& tr = it->non_ec_transitions;
849 t.transitions.reserve(tr.size());
850 for (
auto it2 = tr.begin(); it2 != tr.end();) {
851 t.transitions.push_back(std::move(tr.extract(it2++).value()));
858 timer.throw_if_expired();
861 auto it = table.begin();
864 AlgorithmValueType v = it->conv_part;
866 for (
const QValueInfo& info : it->transitions) {
867 set_min(v, info.compute_q_value(value_store));
870 if constexpr (UseInterval) {
872 if (!it->value->bounds_equal()) converged =
false;
874 if (
update(*it->value, v)) converged =
false;
877 ++statistics_.bellman_backups;
878 }
while (++it != table.end());
879 }
while (!converged);
882 stack_.erase(scc.begin(), scc.end());
885template <
typename State,
typename Action,
bool UseInterval>
886void TATopologicalValueIteration<State, Action, UseInterval>::
887 find_and_decompose_sccs(utils::CountdownTimer& timer)
890 for (
const StateID state_id : scc_) {
891 state_information_[state_id].explored = 0;
894 for (
const StateID state_id : scc_) {
895 StateInfo& state_info = state_information_[state_id];
896 if (state_info.get_ecd_status() != StateInfo::NEW)
continue;
898 state_info.explored = 1;
899 state_info.ecd_stack_id = 0;
900 exploration_stack_ecd_.emplace_back(stack_[state_info.stack_id], 0);
901 stack_ecd_.emplace_back(state_id);
904 ECDExplorationInfo* e;
908 e = &exploration_stack_ecd_.back();
909 }
while (initialize_ecd(*e) && push_successor_ecd(*e, timer));
913 const unsigned int stck = e->stackidx;
914 const unsigned int lowlink = e->lowlink;
916 assert(stck >= lowlink);
918 const bool backtracked_from_scc = stck == lowlink;
920 if (backtracked_from_scc) {
924 assert(stack_ecd_.empty());
925 assert(exploration_stack_ecd_.size() == 1);
926 exploration_stack_ecd_.pop_back();
931 assert(exploration_stack_ecd_.size() > 1);
933 timer.throw_if_expired();
935 const ECDExplorationInfo& successor = *e--;
937 if (backtracked_from_scc) {
938 e->leaves_scc =
true;
940 e->lowlink = std::min(e->lowlink, lowlink);
941 e->recurse = e->recurse || successor.recurse;
942 e->remains_scc =
true;
945 exploration_stack_ecd_.pop_back();
946 }
while ((!e->next_successor() && !e->next_transition()) ||
947 !push_successor_ecd(*e, timer));
954 }
while (decomposition_queue_.pop_scc(scc_));
956 assert(scc_.empty());
959template <
typename State,
typename Action,
bool UseInterval>
960bool TATopologicalValueIteration<State, Action, UseInterval>::
961 push_successor_ecd(ECDExplorationInfo& e, utils::CountdownTimer& timer)
964 timer.throw_if_expired();
966 const StateID succ_id = e.get_current_successor().item;
967 StateInfo& succ_info = state_information_[succ_id];
969 switch (succ_info.get_ecd_status()) {
970 case StateInfo::NEW: {
971 const auto stack_size = stack_ecd_.size();
972 succ_info.explored = 1;
973 succ_info.ecd_stack_id = stack_size;
974 exploration_stack_ecd_.emplace_back(
975 stack_[succ_info.stack_id],
977 stack_ecd_.emplace_back(succ_id);
981 case StateInfo::CLOSED: e.leaves_scc =
true;
break;
983 case StateInfo::ONSTACK:
984 e.lowlink = std::min(e.lowlink, succ_info.ecd_stack_id);
985 e.remains_scc =
true;
987 }
while (e.next_successor() || e.next_transition());
992template <
typename State,
typename Action,
bool UseInterval>
993bool TATopologicalValueIteration<State, Action, UseInterval>::initialize_ecd(
994 ECDExplorationInfo& exp_info)
996 StackInfo& stack_info = exp_info.stack_info;
998 if (stack_info.ec_transitions.empty()) {
1002 exp_info.action = stack_info.ec_transitions.begin();
1003 exp_info.end = stack_info.ec_transitions.end();
1004 exp_info.successor = exp_info.action->scc_successors.begin();
1009template <
typename State,
typename Action,
bool UseInterval>
1010void TATopologicalValueIteration<State, Action, UseInterval>::scc_found_ecd(
1011 ECDExplorationInfo& e)
1013 namespace vws = std::views;
1015 auto scc = stack_ecd_ | std::views::drop(e.stackidx);
1017 if (scc.size() == 1) {
1018 state_information_[scc.front()].ecd_stack_id = StateInfo::UNDEF_ECD;
1019 }
else if (e.recurse) {
1020 decomposition_queue_.register_new_scc();
1021 for (
const StateID state_id : scc) {
1022 decomposition_queue_.add_scc_state(state_id);
1023 state_information_[state_id].ecd_stack_id = StateInfo::UNDEF_ECD;
1027 const StateID scc_repr_id = scc.front();
1028 StateInfo& repr_state_info = state_information_[scc_repr_id];
1029 StackInfo& repr_stk = stack_[repr_state_info.stack_id];
1031 repr_state_info.ecd_stack_id = StateInfo::UNDEF_ECD;
1034 for (
const StateID state_id : scc | std::views::drop(1)) {
1035 StateInfo& state_info = state_information_[state_id];
1036 StackInfo& succ_stk = stack_[state_info.stack_id];
1038 state_info.ecd_stack_id = StateInfo::UNDEF_ECD;
1041 auto& tr = succ_stk.non_ec_transitions;
1042 for (
auto it = tr.begin(); it != tr.end();) {
1043 repr_stk.add_non_ec_transition(
1044 std::move(tr.extract(it++).value()));
1048 std::decay_t<decltype(tr)>().swap(tr);
1050 set_min(repr_stk.conv_part, succ_stk.conv_part);
1051 succ_stk.conv_part = AlgorithmValueType(INFINITE_VALUE);
1054 succ_stk.non_ec_transitions.emplace(
1056 std::vector{ItemProbabilityPair<StateID>(scc_repr_id, 1.0_vt)});
1060 stack_ecd_.erase(scc.begin(), scc.end());
1062 assert(stack_ecd_.size() == e.stackidx);
A registry for print functions related to search progress.
Definition progress_report.h:33
Implements a trap-aware variant of Topological Value Iteration.
Definition ta_topological_value_iteration.h:63
Namespace dedicated to trap-aware Topological Value Iteration (TATVI).
Definition ta_topological_value_iteration.h:24
bool update(Interval &lhs, Interval rhs, value_t epsilon=g_epsilon)
Intersects two intervals and assigns the result to the left operand.
bool set_min(Interval &lhs, Interval rhs)
Computes the assignments lhs.lower <- min(lhs.lower, rhs.lower) and lower <- min(lhs....
double value_t
Typedef for the state value type.
Definition aliases.h:7
typename std::conditional_t< is_cheap_to_copy_v< T >, T, const T & > param_type
Alias template defining the best way to pass a parameter of a given type.
Definition type_traits.h:25
Represents a closed interval over the extended reals as a pair of lower and upper bound.
Definition interval.h:12
value_t lower
The Lower bound of the interval.
Definition interval.h:13
value_t upper
The upper bound of the interval.
Definition interval.h:14
A StateID represents a state within a StateIDMap. Just like Fast Downward's StateID type,...
Definition types.h:22
Topological value iteration statistics.
Definition ta_topological_value_iteration.h:29