text: #ifndef LANDMARKS_LANDMARK_FACTORY_ZHU_GIVAN_H
  #define LANDMARKS_LANDMARK_FACTORY_ZHU_GIVAN_H
  
  #include "landmark_factory.h"
  
  #include "../utils/hash.h"
  
  #include <unordered_set>
  #include <utility>
  #include <vector>
  
  namespace landmarks {
  using lm_set = utils::HashSet<FactPair>;
  
  class LandmarkFactoryZhuGivan : public LandmarkFactory {
      class plan_graph_node {
  public:
          lm_set labels;
          inline bool reached() const {
              // NOTE: nodes are always labeled with itself,
              // if they have been reached
              return !labels.empty();
          }
      };
  
      using PropositionLayer = std::vector<std::vector<plan_graph_node>>;
  
      // triggers[i][j] is a list of operators that could reach/change
      // labels on some proposition, after proposition (i,j) has changed
      std::vector<std::vector<std::vector<int>>> triggers;
  
      void compute_triggers(const TaskProxy &task_proxy);
  
      // Note: must include operators that only have conditional effects
      std::vector<int> operators_without_preconditions;
  
      bool operator_applicable(const OperatorProxy &op, const PropositionLayer &state) const;
  
      bool operator_cond_effect_fires(const EffectConditionsProxy &effect_conditions,
                                      const PropositionLayer &layer) const;
  
      // Apply operator and propagate labels to next layer. Returns set of
      // propositions that:
      // (a) have just been reached OR (b) had their labels changed in next
      // proposition layer
      lm_set apply_operator_and_propagate_labels(const OperatorProxy &op,
                                                 const PropositionLayer &current, PropositionLayer &next) const;
  
      // Calculate the union of precondition labels of op, using the
      // labels from current
      lm_set union_of_precondition_labels(const OperatorProxy &op,
                                          const PropositionLayer &current) const;
  
      // Calculate the union of precondition labels of a conditional effect,
      // using the labels from current
      lm_set union_of_condition_labels(const EffectConditionsProxy &effect_conditions,
                                       const PropositionLayer &current) const;
  
      // Relaxed exploration, returns the last proposition layer
      // (the fixpoint) with labels
      PropositionLayer build_relaxed_plan_graph_with_labels(const TaskProxy &task_proxy) const;
  
      // Extract landmarks from last proposition layer and add them to the
      // landmarks graph
      void extract_landmarks(const TaskProxy &task_proxy,
                             Exploration &exploration, const PropositionLayer &last_prop_layer);
  
      // test if layer satisfies goal
      bool satisfies_goal_conditions(const GoalsProxy &goals, const PropositionLayer &layer) const;
  
      // Link operators to its propositions in trigger list.
      void add_operator_to_triggers(const OperatorProxy &op);
  
      virtual void generate_landmarks(const std::shared_ptr<AbstractTask> &task,
                                      Exploration &exploration) override;
  
  public:
      explicit LandmarkFactoryZhuGivan(const options::Options &opts);
  
      virtual bool supports_conditional_effects() const override;
  };
  }
  
  #endif
  