def add_simple_effect(self, predicate: AtomicFormula, time_spec: TimeSpec = TimeSpec.AT_START, is_delete: bool = False): """ Adds a propositional effect. If the operator already has a non-conjunctive effect then the new and existing effects will be wrapped together within a new conjunctive effect. """ effect = EffectNegative(predicate) if is_delete else EffectSimple( predicate) if self.durative: effect = TimedEffect(time_spec, effect) if self.effect.effect_type == EffectType.CONJUNCTION: self.effect: EffectConjunction self.effect.effects.append(effect) elif self.effect.effect_type == EffectType.EMPTY: self.effect = effect else: self.effect = EffectConjunction(effects=[self.effect, effect])
def add_assign_effect(self, function: AtomicFormula, time_spec: TimeSpec = TimeSpec.AT_START, assign_type: AssignmentType = AssignmentType.ASSIGN, value: float = 1.0): """ Adds a numeric effect. If the operator already has a non-conjunctive effect then the new and existing effects will be wrapped together within a new conjunctive effect. """ value_expr = ExprComposite( [ExprBase(expr_type=ExprBase.ExprType.CONSTANT, constant=value)]) effect = Assignment(assign_type, function, value_expr) if self.durative: effect = TimedEffect(time_spec, effect) if self.effect.effect_type == EffectType.CONJUNCTION: self.effect: EffectConjunction self.effect.effects.append(effect) elif self.effect.effect_type == EffectType.EMPTY: self.effect = effect else: self.effect = EffectConjunction(effects=[self.effect, effect])
def visitDurative_action_effect_conjunction(self, ctx: pddl22Parser.Durative_action_effect_conjunctionContext): effects = [] for effect in ctx.durative_action_effect(): effects.append(self.visit(effect)) return EffectConjunction(effects)
class Operator: """ A class used to represent an operator in the domain. """ def __init__( self, # header formula: AtomicFormula, durative: bool, duration: Duration = None, condition: GoalDescriptor = None, effect: Effect = None, ) -> None: self.formula: AtomicFormula = formula self.durative: bool = durative self.duration: Duration = duration if duration else Duration() self.condition: GoalDescriptor = condition if condition else GoalDescriptor( ) self.effect: Effect = effect if effect else Effect() # ======= # # Setters # # ======= # def set_constant_duration(self, duration: float): lhs = ExprComposite([ ExprBase(expr_type=ExprBase.ExprType.SPECIAL, special_type=ExprBase.SpecialType.DURATION) ]) rhs = ExprComposite([ ExprBase(expr_type=ExprBase.ExprType.CONSTANT, constant=duration) ]) self.duration = DurationInequality( Inequality(comparison_type=Inequality.ComparisonType.EQUALS, lhs=lhs, rhs=rhs)) def add_simple_condition_from_str(self, name: str, parameters: dict[str, str] = {}, constants: dict[str, str] = {}, time_spec: TimeSpec = TimeSpec.AT_START): """ Adds a propositional condition from string using AtomicFormula.from_string() param name: the name of the predicate to add. param parameters: dictionary mapping label to type. param constants: dictionary mapping label to constant value. param time_spec: timing of condition, if durative action. """ self.add_simple_condition( AtomicFormula.from_string(name, parameters, constants), time_spec) def add_simple_condition(self, predicate: AtomicFormula, time_spec: TimeSpec = TimeSpec.AT_START): """ Adds a propositional condition. If the operator already has a non-conjunctive condition then the new and existing conditions will be wrapped together within a new conjunctive condition. """ condition = GoalSimple(predicate) if self.durative: condition = TimedGoal(time_spec, condition) if self.condition.goal_type == GoalType.CONJUNCTION: self.condition: GoalConjunction self.condition.goals.append(condition) elif self.condition.goal_type == GoalType.EMPTY: self.condition = condition else: self.condition = GoalConjunction(goals=[self.condition, condition]) def add_simple_effect_from_str(self, name: str, parameters: dict[str, str] = {}, constants: dict[str, str] = {}, time_spec: TimeSpec = TimeSpec.AT_START, is_delete: bool = False): """ Adds a propositional effect from string using AtomicFormula.from_string() param name: the name of the predicate to add. param parameters: dictionary mapping label to type. param constants: dictionary mapping label to constant value. param time_spec: timing of effect, if durative action. param is_delete: True if the effect is a delete effect. """ self.add_simple_effect( AtomicFormula.from_string(name, parameters, constants), time_spec, is_delete) def add_simple_effect(self, predicate: AtomicFormula, time_spec: TimeSpec = TimeSpec.AT_START, is_delete: bool = False): """ Adds a propositional effect. If the operator already has a non-conjunctive effect then the new and existing effects will be wrapped together within a new conjunctive effect. """ effect = EffectNegative(predicate) if is_delete else EffectSimple( predicate) if self.durative: effect = TimedEffect(time_spec, effect) if self.effect.effect_type == EffectType.CONJUNCTION: self.effect: EffectConjunction self.effect.effects.append(effect) elif self.effect.effect_type == EffectType.EMPTY: self.effect = effect else: self.effect = EffectConjunction(effects=[self.effect, effect]) def add_assign_effect_from_str( self, name: str, parameters: dict[str, str] = {}, constants: dict[str, str] = {}, time_spec: TimeSpec = TimeSpec.AT_START, assign_type: AssignmentType = AssignmentType.ASSIGN, value: float = 1.0): """ Adds a numeric effect from string using AtomicFormula.from_string() param name: the name of the predicate to add. param parameters: dictionary mapping label to type. param constants: dictionary mapping label to constant value. param time_spec: timing of effect, if durative action. param assign_type: the type of numeric assignment (assign, increase, decrease, etc) param value: The amount to be applied. """ self.add_assign_effect( AtomicFormula.from_string(name, parameters, constants), time_spec, assign_type, value) def add_assign_effect(self, function: AtomicFormula, time_spec: TimeSpec = TimeSpec.AT_START, assign_type: AssignmentType = AssignmentType.ASSIGN, value: float = 1.0): """ Adds a numeric effect. If the operator already has a non-conjunctive effect then the new and existing effects will be wrapped together within a new conjunctive effect. """ value_expr = ExprComposite( [ExprBase(expr_type=ExprBase.ExprType.CONSTANT, constant=value)]) effect = Assignment(assign_type, function, value_expr) if self.durative: effect = TimedEffect(time_spec, effect) if self.effect.effect_type == EffectType.CONJUNCTION: self.effect: EffectConjunction self.effect.effects.append(effect) elif self.effect.effect_type == EffectType.EMPTY: self.effect = effect else: self.effect = EffectConjunction(effects=[self.effect, effect]) # ======== # # Printing # # ======== # def __str__(self) -> str: # TODO checking for empty parameters and conditions return ("(durative-action " if self.durative else "(action ") \ + self.formula.name + "\n" \ + " :parameters (" + self.formula.print_pddl(include_types=True).partition(' ')[2][:-1] + ")\n" \ + (" :duration " + str(self.duration) + "\n" if self.durative else "") \ + (" :condition " if self.durative else " :precondition ") \ + str(self.condition) + "\n" \ + " :effect " \ + str(self.effect) + "\n" \ + ")" def print_pddl(self) -> str: return self.formula.print_pddl(include_types=False) # ========= # # Grounding # # ========= # def bind_parameters(self, parameters: list[TypedParameter]) -> 'Operator': """ parameters: list of TypedParameter whose type and label must match the type and label of the operator. returns a copy of the operator whose conditions and effects have been grounded with the given values. """ return Operator(self.formula.bind_parameters(parameters), durative=self.durative, duration=self.duration.bind_parameters(parameters), condition=self.condition.bind_parameters(parameters), effect=self.effect.bind_parameters(parameters))
def visitConditional_effect_conjunction(self, ctx: pddl22Parser.Conditional_effect_conjunctionContext): effects = [] for effect in ctx.p_effect(): effects.append(self.visit(effect)) return EffectConjunction(effects)