1#ifndef DOWNWARD_TASK_PROXY_H
2#define DOWNWARD_TASK_PROXY_H
4#include "downward/abstract_task.h"
5#include "downward/operator_id.h"
6#include "downward/state_id.h"
7#include "downward/task_id.h"
9#include "downward/algorithms/int_packer.h"
10#include "downward/utils/collections.h"
11#include "downward/utils/hash.h"
12#include "downward/utils/system.h"
24class AxiomEffectProxy;
25class AxiomEffectConditionsProxy;
26class AxiomEffectsProxy;
28class EffectConditionsProxy;
33class OperatorEffectProxy;
34class OperatorEffectConditionsProxy;
35class OperatorEffectsProxy;
38class PartialOperatorsProxy;
39class PreconditionsProxy;
42class PlanningTaskProxy;
47namespace causal_graph {
51using PackedStateBin = int_packer::IntPacker::Bin;
104concept SizedSubscriptable =
requires(
const T c, std::size_t s) {
106 { c.size() } -> std::convertible_to<std::size_t>;
109template <SizedSubscriptable T>
117 using iterator_category = std::random_access_iterator_tag;
119 typename std::remove_cvref_t<decltype(std::declval<T>().operator[](
121 using difference_type = int;
122 using pointer =
const value_type*;
123 using reference = value_type;
125 ProxyIterator() =
default;
127 ProxyIterator(
const T& collection, std::size_t pos)
128 : collection(&collection)
133 reference operator*()
const {
return (*collection)[pos]; }
135 ProxyIterator<T> operator++(
int)
142 ProxyIterator<T> operator--(
int)
149 ProxyIterator<T>& operator++()
155 ProxyIterator<T>& operator--()
161 reference operator[](difference_type n)
const {
return *(
this + n); }
163 ProxyIterator<T>& operator+=(difference_type n)
169 ProxyIterator<T>& operator-=(difference_type n)
175 friend ProxyIterator<T>
176 operator+(
const ProxyIterator<T>& lhs, difference_type rhs)
178 return ProxyIterator<T>(*lhs.collection, lhs.pos + rhs);
181 friend ProxyIterator<T>
182 operator+(difference_type lhs,
const ProxyIterator<T>& rhs)
184 return ProxyIterator<T>(*rhs.collection, rhs.pos + lhs);
187 friend ProxyIterator<T>
188 operator-(
const ProxyIterator<T>& lhs, difference_type rhs)
190 return ProxyIterator<T>(*lhs.collection, lhs.pos - rhs);
193 friend difference_type
194 operator-(
const ProxyIterator<T>& lhs,
const ProxyIterator<T>& rhs)
196 return lhs.pos - rhs.pos;
200 operator==(
const ProxyIterator<T>& lhs,
const ProxyIterator<T>& rhs)
202 assert(lhs.collection == rhs.collection);
203 return lhs.pos == rhs.pos;
207 operator<=>(
const ProxyIterator<T>& lhs,
const ProxyIterator<T>& rhs)
209 assert(lhs.collection == rhs.collection);
210 return lhs.pos <=> rhs.pos;
215class ProxyCollection :
public std::ranges::view_interface<ProxyCollection<T>> {
219 static_assert(std::random_access_iterator<ProxyIterator<T>>);
220 return ProxyIterator<T>(*
static_cast<const T*
>(
this), 0);
225 static_assert(std::random_access_iterator<ProxyIterator<T>>);
226 return ProxyIterator<T>(*
static_cast<const T*
>(
this), size());
229 std::size_t size()
const {
return static_cast<const T*
>(
this)->size(); }
233 const PlanningTask* task;
237 FactProxy(
const PlanningTask& task,
int var_id,
int value);
238 FactProxy(
const PlanningTask& task,
const FactPair& fact);
239 ~FactProxy() =
default;
241 VariableProxy get_variable()
const;
243 int get_value()
const {
return fact.value; }
245 FactPair get_pair()
const {
return fact; }
247 std::string get_name()
const {
return task->get_fact_name(fact); }
249 bool operator==(
const FactProxy& other)
const
251 assert(task == other.task);
252 return fact == other.fact;
255 bool operator!=(
const FactProxy& other)
const {
return !(*
this == other); }
257 bool is_mutex(
const FactProxy& other)
const
259 return task->are_facts_mutex(fact, other.fact);
263class FactsProxyIterator {
264 const PlanningTask* task;
269 FactsProxyIterator(
const PlanningTask& task,
int var_id,
int value)
275 ~FactsProxyIterator() =
default;
277 FactProxy operator*()
const {
return FactProxy(*task, var_id, value); }
279 FactsProxyIterator& operator++()
281 assert(var_id < task->get_num_variables());
282 int num_facts = task->get_variable_domain_size(var_id);
283 assert(value < num_facts);
285 if (value == num_facts) {
292 bool operator==(
const FactsProxyIterator& other)
const
294 assert(task == other.task);
295 return var_id == other.var_id && value == other.value;
298 bool operator!=(
const FactsProxyIterator& other)
const
300 return !(*
this == other);
314 const PlanningTask* task;
317 explicit FactsProxy(
const PlanningTask& task)
321 ~FactsProxy() =
default;
323 FactsProxyIterator begin()
const {
return FactsProxyIterator(*task, 0, 0); }
325 FactsProxyIterator end()
const
327 return FactsProxyIterator(*task, task->get_num_variables(), 0);
332 const PlanningTask* task;
336 VariableProxy(
const PlanningTask& task,
int id)
341 ~VariableProxy() =
default;
343 bool operator==(
const VariableProxy& other)
const
345 assert(task == other.task);
346 return id == other.id;
349 bool operator!=(
const VariableProxy& other)
const
351 return !(*
this == other);
354 int get_id()
const {
return id; }
356 std::string get_name()
const {
return task->get_variable_name(
id); }
358 int get_domain_size()
const {
return task->get_variable_domain_size(
id); }
360 FactProxy get_fact(
int index)
const
362 assert(index < get_domain_size());
363 return FactProxy(*task,
id, index);
366 bool is_derived()
const
368 int axiom_layer = task->get_variable_axiom_layer(
id);
369 return axiom_layer != -1;
372 int get_axiom_layer()
const
374 int axiom_layer = task->get_variable_axiom_layer(
id);
380 assert(axiom_layer >= 0);
384 int get_default_axiom_value()
const
386 assert(is_derived());
387 return task->get_variable_default_axiom_value(
id);
391class VariablesProxy :
public ProxyCollection<VariablesProxy> {
392 const PlanningTask* task;
395 explicit VariablesProxy(
const PlanningTask& task)
399 ~VariablesProxy() =
default;
401 std::size_t size()
const {
return task->get_num_variables(); }
403 VariableProxy operator[](std::size_t index)
const
405 assert(index < size());
406 return VariableProxy(*task, index);
409 FactsProxy get_facts()
const {
return FactsProxy(*task); }
412class AxiomPreconditionsProxy
413 :
public ProxyCollection<AxiomPreconditionsProxy> {
414 const PlanningTask* task;
418 AxiomPreconditionsProxy(
const PlanningTask& task,
int axiom_index)
420 , axiom_index(axiom_index)
424 std::size_t size()
const
426 return task->get_num_axiom_preconditions(axiom_index);
429 FactProxy operator[](std::size_t fact_index)
const
431 assert(fact_index < size());
434 task->get_axiom_precondition(axiom_index, fact_index));
438class OperatorPreconditionsProxy
439 :
public ProxyCollection<OperatorPreconditionsProxy> {
440 const PlanningTask* task;
444 OperatorPreconditionsProxy(
const PlanningTask& task,
int op_index)
450 std::size_t size()
const
452 return task->get_num_operator_preconditions(op_index);
455 FactProxy operator[](std::size_t fact_index)
const
457 assert(fact_index < size());
460 task->get_operator_precondition(op_index, fact_index));
464class PreconditionsProxy :
public ProxyCollection<PreconditionsProxy> {
465 std::variant<AxiomPreconditionsProxy, OperatorPreconditionsProxy> proxy;
468 PreconditionsProxy(AxiomPreconditionsProxy proxy)
473 PreconditionsProxy(OperatorPreconditionsProxy proxy)
478 std::size_t size()
const
480 return std::visit([](
const auto& arg) {
return arg.size(); }, proxy);
483 FactProxy operator[](std::size_t fact_index)
const
486 [fact_index](
const auto& arg) {
487 return arg.operator[](fact_index);
493class AxiomEffectConditionsProxy
494 :
public ProxyCollection<AxiomEffectConditionsProxy> {
495 const PlanningTask* task;
500 AxiomEffectConditionsProxy(
501 const PlanningTask& task,
505 , axiom_index(axiom_index)
506 , eff_index(eff_index)
510 std::size_t size()
const
512 return task->get_num_axiom_effect_conditions(axiom_index, eff_index);
515 FactProxy operator[](std::size_t index)
const
517 assert(index < size());
520 task->get_axiom_effect_condition(axiom_index, eff_index, index));
524class OperatorEffectConditionsProxy
525 :
public ProxyCollection<OperatorEffectConditionsProxy> {
526 const AbstractTask* task;
531 OperatorEffectConditionsProxy(
532 const AbstractTask& task,
537 , eff_index(eff_index)
541 std::size_t size()
const
543 return task->get_num_operator_effect_conditions(op_index, eff_index);
546 FactProxy operator[](std::size_t index)
const
548 assert(index < size());
551 task->get_operator_effect_condition(op_index, eff_index, index));
555class EffectConditionsProxy :
public ProxyCollection<EffectConditionsProxy> {
556 std::variant<AxiomEffectConditionsProxy, OperatorEffectConditionsProxy>
560 EffectConditionsProxy(AxiomEffectConditionsProxy proxy)
565 EffectConditionsProxy(OperatorEffectConditionsProxy proxy)
570 std::size_t size()
const
572 return std::visit([](
const auto& arg) {
return arg.size(); }, proxy);
575 FactProxy operator[](std::size_t fact_index)
const
578 [fact_index](
const auto& arg) {
579 return arg.operator[](fact_index);
585class AxiomEffectProxy {
586 const PlanningTask* task;
591 AxiomEffectProxy(
const PlanningTask& task,
int axiom_index,
int eff_index)
593 , axiom_index(axiom_index)
594 , eff_index(eff_index)
598 AxiomEffectConditionsProxy get_conditions()
const
600 return AxiomEffectConditionsProxy(*task, axiom_index, eff_index);
603 FactProxy get_fact()
const
605 return FactProxy(*task, task->get_axiom_effect(axiom_index, eff_index));
609class OperatorEffectProxy {
610 const AbstractTask* task;
615 OperatorEffectProxy(
const AbstractTask& task,
int op_index,
int eff_index)
618 , eff_index(eff_index)
622 OperatorEffectConditionsProxy get_conditions()
const
624 return OperatorEffectConditionsProxy(*task, op_index, eff_index);
627 FactProxy get_fact()
const
629 return FactProxy(*task, task->get_operator_effect(op_index, eff_index));
634 std::variant<AxiomEffectProxy, OperatorEffectProxy> proxy;
637 EffectProxy(AxiomEffectProxy proxy)
642 EffectProxy(OperatorEffectProxy proxy)
647 EffectConditionsProxy get_conditions()
const
650 [](
const auto& arg) {
651 return EffectConditionsProxy(arg.get_conditions());
656 FactProxy get_fact()
const
659 [](
const auto& arg) {
return arg.get_fact(); },
664class AxiomEffectsProxy :
public ProxyCollection<AxiomEffectsProxy> {
665 const PlanningTask* task;
669 AxiomEffectsProxy(
const PlanningTask& task,
int op_index)
675 std::size_t size()
const {
return task->get_num_axiom_effects(op_index); }
677 AxiomEffectProxy operator[](std::size_t eff_index)
const
679 assert(eff_index < size());
680 return AxiomEffectProxy(*task, op_index, eff_index);
684class OperatorEffectsProxy :
public ProxyCollection<OperatorEffectsProxy> {
685 const AbstractTask* task;
689 OperatorEffectsProxy(
const AbstractTask& task,
int op_index)
695 std::size_t size()
const
697 return task->get_num_operator_effects(op_index);
700 OperatorEffectProxy operator[](std::size_t eff_index)
const
702 assert(eff_index < size());
703 return OperatorEffectProxy(*task, op_index, eff_index);
707class EffectsProxy :
public ProxyCollection<EffectsProxy> {
708 std::variant<AxiomEffectsProxy, OperatorEffectsProxy> proxy;
711 EffectsProxy(AxiomEffectsProxy proxy)
716 EffectsProxy(OperatorEffectsProxy proxy)
721 std::size_t size()
const
723 return std::visit([](
const auto& arg) {
return arg.size(); }, proxy);
726 EffectProxy operator[](std::size_t eff_index)
const
729 [eff_index](
const auto& arg) {
730 return EffectProxy(arg.operator[](eff_index));
737 const PlanningTask* task;
741 AxiomProxy(
const PlanningTask& task,
int index)
747 bool operator==(
const AxiomProxy& other)
const
749 assert(task == other.task);
750 return index == other.index;
753 bool operator!=(
const AxiomProxy& other)
const {
return !(*
this == other); }
755 AxiomPreconditionsProxy get_preconditions()
const
757 return AxiomPreconditionsProxy(*task, index);
760 AxiomEffectsProxy get_effects()
const
762 return AxiomEffectsProxy(*task, index);
765 int get_cost()
const {
return 0; }
767 std::string get_name()
const {
return task->get_axiom_name(index); }
769 int get_id()
const {
return index; }
772class PartialOperatorProxy {
774 const PlanningTask* task;
778 PartialOperatorProxy(
const PlanningTask& task,
int index)
784 OperatorPreconditionsProxy get_preconditions()
const
786 return OperatorPreconditionsProxy(*task, index);
789 std::string get_name()
const {
return task->get_operator_name(index); }
791 int get_id()
const {
return index; }
798 OperatorID get_ancestor_operator_id(
const PlanningTask* ancestor_task)
const
800 return OperatorID(task->convert_operator_index(index, ancestor_task));
803 friend bool operator==(
804 const PartialOperatorProxy& left,
805 const PartialOperatorProxy& right)
807 assert(left.task == right.task);
808 return left.index == right.index;
812class OperatorProxy :
public PartialOperatorProxy {
814 OperatorProxy(
const AbstractTask& task,
int index)
815 : PartialOperatorProxy(task, index)
819 OperatorEffectsProxy get_effects()
const
821 return OperatorEffectsProxy(
822 *
static_cast<const AbstractTask*
>(task),
828 return static_cast<const AbstractTask*
>(task)->get_operator_cost(index);
832class AxiomOrOperatorProxy {
833 std::variant<AxiomProxy, OperatorProxy> proxy;
836 AxiomOrOperatorProxy(AxiomProxy proxy)
841 AxiomOrOperatorProxy(OperatorProxy proxy)
846 operator AxiomProxy()
const
849 return std::get<AxiomProxy>(proxy);
852 operator OperatorProxy()
const
855 return std::get<OperatorProxy>(proxy);
858 bool is_axiom()
const {
return proxy.index() == 0; }
860 bool operator==(
const AxiomOrOperatorProxy& other)
const
862 return proxy == other.proxy;
865 bool operator!=(
const AxiomOrOperatorProxy& other)
const
867 return proxy != other.proxy;
870 PreconditionsProxy get_preconditions()
const
873 [](
const auto& arg) {
874 return PreconditionsProxy(arg.get_preconditions());
879 EffectsProxy get_effects()
const
882 [](
const auto& arg) {
return EffectsProxy(arg.get_effects()); },
889 [](
const auto& arg) {
return arg.get_cost(); },
893 std::string get_name()
const
896 [](
const auto& arg) {
return arg.get_name(); },
902 return std::visit([](
const auto& arg) {
return arg.get_id(); }, proxy);
906class AxiomsProxy :
public ProxyCollection<AxiomsProxy> {
907 const PlanningTask* task;
910 explicit AxiomsProxy(
const PlanningTask& task)
915 std::size_t size()
const {
return task->get_num_axioms(); }
917 AxiomProxy operator[](std::size_t index)
const
919 assert(index < size());
920 return AxiomProxy(*task, index);
924class OperatorsProxy :
public ProxyCollection<OperatorsProxy> {
925 const AbstractTask* task;
928 explicit OperatorsProxy(
const AbstractTask& task)
933 std::size_t size()
const {
return task->get_num_operators(); }
935 OperatorProxy operator[](std::size_t index)
const
937 assert(index < size());
938 return OperatorProxy(*task, index);
941 OperatorProxy operator[](OperatorID
id)
const
943 return (*
this)[
id.get_index()];
947class PartialOperatorsProxy :
public ProxyCollection<PartialOperatorsProxy> {
948 const PlanningTask* task;
951 explicit PartialOperatorsProxy(
const PlanningTask& task)
956 std::size_t size()
const {
return task->get_num_operators(); }
958 PartialOperatorProxy operator[](std::size_t index)
const
960 assert(index < size());
961 return PartialOperatorProxy(*task, index);
964 PartialOperatorProxy operator[](OperatorID
id)
const
966 return (*
this)[
id.get_index()];
970class GoalsProxy :
public ProxyCollection<GoalsProxy> {
971 const PlanningTask* task;
974 explicit GoalsProxy(
const PlanningTask& task)
979 std::size_t size()
const {
return task->get_num_goals(); }
981 FactProxy operator[](std::size_t index)
const
983 assert(index < size());
984 return FactProxy(*task, task->get_goal_fact(index));
988template <
typename Effect>
989bool does_fire(
const EffectProxy& effect,
const State& state);
991class State :
public ProxyCollection<State> {
1002 const PlanningTask* task;
1003 const StateRegistry* registry;
1005 const PackedStateBin* buffer;
1016 mutable std::shared_ptr<std::vector<int>> values;
1017 const int_packer::IntPacker* state_packer;
1023 const PlanningTask& task,
1024 const StateRegistry& registry,
1026 const PackedStateBin* buffer);
1029 const PlanningTask& task,
1030 const StateRegistry& registry,
1032 const PackedStateBin* buffer,
1033 std::vector<int>&& values);
1035 State(
const PlanningTask& task, std::vector<int>&& values);
1037 bool operator==(
const State& other)
const;
1038 bool operator!=(
const State& other)
const;
1042 void unpack()
const;
1044 std::size_t size()
const;
1045 FactProxy operator[](std::size_t var_id)
const;
1046 FactProxy operator[](VariableProxy var)
const;
1048 PlanningTaskProxy get_task()
const;
1052 const StateRegistry* get_registry()
const;
1055 StateID get_id()
const;
1060 const std::vector<int>& get_unpacked_values()
const;
1064 const PackedStateBin* get_buffer()
const;
1074 State get_unregistered_successor(
const OperatorProxy& op)
const;
1076 template <
typename Effects>
1077 State get_unregistered_successor(
const Effects& effects)
const
1080 std::vector<int> new_values = get_unpacked_values();
1082 for (
const auto effect : effects) {
1083 if (does_fire(effect, *
this)) {
1084 FactPair effect_fact = effect.get_fact().get_pair();
1085 new_values[effect_fact.var] = effect_fact.value;
1089 this->apply_axioms(new_values);
1090 return State(*task, std::move(new_values));
1094 void apply_axioms(std::vector<int>& values)
const;
1098inline void feed(HashState& hash_state,
const State& state)
1109 feed(hash_state, state.get_unpacked_values());
1113class PlanningTaskProxy {
1115 const PlanningTask* task;
1118 explicit PlanningTaskProxy(
const PlanningTask& task)
1122 ~PlanningTaskProxy() =
default;
1124 void subscribe_to_task_destruction(
1125 subscriber::Subscriber<PlanningTask>* subscriber)
const
1127 task->subscribe(subscriber);
1130 TaskID get_id()
const {
return TaskID(task); }
1132 VariablesProxy get_variables()
const {
return VariablesProxy(*task); }
1134 PartialOperatorsProxy get_partial_operators()
const
1136 return PartialOperatorsProxy(*task);
1139 AxiomsProxy get_axioms()
const {
return AxiomsProxy(*task); }
1141 GoalsProxy get_goals()
const {
return GoalsProxy(*task); }
1143 State create_state(std::vector<int>&& state_values)
const
1145 return State(*task, std::move(state_values));
1150 const StateRegistry& registry,
1152 const PackedStateBin* buffer)
const
1154 return State(*task, registry,
id, buffer);
1159 const StateRegistry& registry,
1161 const PackedStateBin* buffer,
1162 std::vector<int>&& state_values)
const
1164 return State(*task, registry,
id, buffer, std::move(state_values));
1167 State get_initial_state()
const
1169 return create_state(task->get_initial_state_values());
1183 State convert_ancestor_state(
const State& ancestor_state)
const
1185 PlanningTaskProxy ancestor_task_proxy = ancestor_state.get_task();
1187 ancestor_state.unpack();
1188 std::vector<int> state_values = ancestor_state.get_unpacked_values();
1189 task->convert_ancestor_state_values(
1191 ancestor_task_proxy.task);
1192 return create_state(std::move(state_values));
1195 explicit operator TaskProxy()
const;
1198class TaskProxy :
public PlanningTaskProxy {
1200 explicit TaskProxy(
const AbstractTask& task)
1201 : PlanningTaskProxy(task)
1204 ~TaskProxy() =
default;
1206 OperatorsProxy get_operators()
const
1208 return OperatorsProxy(*
static_cast<const AbstractTask*
>(task));
1211 const causal_graph::CausalGraph& get_causal_graph()
const;
1214inline PlanningTaskProxy::operator TaskProxy()
const
1216 return TaskProxy(*
static_cast<const AbstractTask*
>(task));
1219inline FactProxy::FactProxy(
const PlanningTask& task,
const FactPair& fact)
1223 assert(fact.var >= 0 && fact.var < task.get_num_variables());
1224 assert(fact.value >= 0 && fact.value < get_variable().get_domain_size());
1227inline FactProxy::FactProxy(
const PlanningTask& task,
int var_id,
int value)
1228 : FactProxy(task, FactPair(var_id, value))
1232inline VariableProxy FactProxy::get_variable()
const
1234 return VariableProxy(*task, fact.var);
1237template <
typename Effect>
1238inline bool does_fire(
const Effect& effect,
const State& state)
1240 for (FactProxy condition : effect.get_conditions()) {
1241 if (state[condition.get_variable()] != condition)
return false;
1246inline bool State::operator==(
const State& other)
const
1248 assert(task == other.task);
1249 if (registry != other.registry) {
1250 std::cerr <<
"Comparing registered states with unregistered states "
1251 <<
"or registered states from different registries is "
1252 <<
"treated as an error because it is likely not "
1253 <<
"intentional." << std::endl;
1254 utils::exit_with(utils::ExitCode::SEARCH_CRITICAL_ERROR);
1258 return id == other.id;
1262 assert(other.values);
1263 return *values == *other.values;
1267inline bool State::operator!=(
const State& other)
const
1269 return !(*
this == other);
1272inline void State::unpack()
const
1275 int num_variables = size();
1287 values = std::make_shared<std::vector<int>>(num_variables);
1288 for (
int var = 0; var < num_variables; ++var) {
1289 (*values)[var] = state_packer->get(buffer, var);
1294inline std::size_t State::size()
const
1296 return num_variables;
1299inline FactProxy State::operator[](std::size_t var_id)
const
1301 assert(var_id < size());
1303 return FactProxy(*task, var_id, (*values)[var_id]);
1306 assert(state_packer);
1307 return FactProxy(*task, var_id, state_packer->get(buffer, var_id));
1311inline FactProxy State::operator[](VariableProxy var)
const
1313 return (*
this)[var.get_id()];
1316inline PlanningTaskProxy State::get_task()
const
1318 return PlanningTaskProxy(*task);
1321inline const StateRegistry* State::get_registry()
const
1326inline StateID State::get_id()
const
1331inline const PackedStateBin* State::get_buffer()
const
1339 std::cerr <<
"Accessing the packed values of an unregistered state is "
1340 <<
"treated as an error." << std::endl;
1341 utils::exit_with(utils::ExitCode::SEARCH_CRITICAL_ERROR);
1346inline const std::vector<int>& State::get_unpacked_values()
const
1349 std::cerr <<
"Accessing the unpacked values of a state without "
1350 <<
"unpacking them first is treated as an error. Please "
1351 <<
"use State::unpack first." << std::endl;
1352 utils::exit_with(utils::ExitCode::SEARCH_CRITICAL_ERROR);