def create_domain(goal_facts): domain = make_domain() for fact in goal_facts: # TODO: consider removing this annoying check name = get_prefix(fact) parameters = ['?x{}'.format(i) for i in range(len(get_args(fact)))] add_predicate(domain, make_predicate(name, parameters)) return domain
def compile_to_exogenous_actions(evaluations, domain, streams): # TODO: version of this that operates on fluents of length one? # TODO: better instantiation when have full parameters fluent_predicates = get_fluents(domain) certified_predicates = {get_prefix(a) for s in streams for a in s.certified} future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) future_fn = lambda a: rename_atom(a, future_map) new_streams = [] for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) # TODO: could also just have conditions asserting that one of the fluent conditions fails new_streams.append(create_static_stream(stream, evaluations, fluent_predicates, future_fn)) stream_atom = new_streams[-1].certified[0] add_predicate(domain, make_predicate(get_prefix(stream_atom), get_args(stream_atom))) preconditions = [stream_atom] + list(stream.domain) effort = 1 # TODO: use stream info #effort = 1 if unit_cost else result.instance.get_effort() #if effort == INF: # continue domain.actions.append(make_action( name='call-{}'.format(stream.name), parameters=get_args(stream_atom), preconditions=preconditions, effects=stream.certified, cost=effort)) stream.certified = tuple(set(stream.certified) | set(map(future_fn, stream.certified))) if REPLACE_STREAM: streams.extend(new_streams) else: streams[:] = new_streams
def compile_to_exogenous_axioms(evaluations, domain, streams): # TODO: no attribute certified # TODO: recover the streams that are required import pddl fluent_predicates = get_fluents(domain) certified_predicates = { get_prefix(a) for s in streams for a in s.certified } future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) future_fn = lambda a: rename_atom(a, future_map) derived_map = {p: 'd-{}'.format(p) for p in certified_predicates} derived_fn = lambda a: rename_atom(a, derived_map) # TODO: could prune streams that don't need this treatment for action in domain.actions: action.precondition = replace_predicates(derived_map, action.precondition) for effect in action.effects: assert (isinstance(effect, pddl.Effect)) effect.condition = replace_predicates(derived_map, effect.condition) for axiom in domain.axioms: axiom.condition = replace_predicates(derived_map, axiom.condition) #fluent_predicates.update(certified_predicates) new_streams = [] for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) new_streams.append( create_static_stream(stream, evaluations, fluent_predicates, future_fn)) stream_atom = new_streams[-1].certified[0] add_predicate( domain, make_predicate(get_prefix(stream_atom), get_args(stream_atom))) preconditions = [stream_atom] + list(map(derived_fn, stream.domain)) for certified_fact in stream.certified: derived_fact = derived_fn(certified_fact) external_params = get_args(derived_fact) internal_params = tuple(p for p in (stream.inputs + stream.outputs) if p not in get_args(derived_fact)) domain.axioms.extend([ make_axiom(parameters=external_params, preconditions=[certified_fact], derived=derived_fact), make_axiom(parameters=external_params + internal_params, preconditions=preconditions, derived=derived_fact), ]) stream.certified = tuple( set(stream.certified) | set(map(future_fn, stream.certified))) if REPLACE_STREAM: streams.extend(new_streams) else: streams[:] = new_streams
def add_unsatisfiable_to_goal(domain, goal_expression): import pddl from pddlstream.language.optimizer import UNSATISFIABLE add_predicate(domain, make_predicate(UNSATISFIABLE, [])) negated_atom = pddl.NegatedAtom(UNSATISFIABLE, tuple()) for action in domain.actions: if negated_atom not in action.precondition.parts: action.precondition = pddl.Conjunction( [action.precondition, negated_atom]).simplified() return And(goal_expression, Not((UNSATISFIABLE, )))
def add_unsatisfiable_to_goal(domain, goal_expression, negate_actions=False): import pddl add_predicate(domain, make_predicate(UNSATISFIABLE, [])) if negate_actions: negated_atom = pddl.NegatedAtom(UNSATISFIABLE, tuple()) for action in domain.actions: if negated_atom not in action.precondition.parts: action.precondition = pddl.Conjunction( [action.precondition, negated_atom]).simplified() return And(goal_expression, Not((UNSATISFIABLE, )))
def compile_to_exogenous_actions(evaluations, domain, streams): # TODO: automatically derive fluents # TODO: version of this that operates on fluents of length one? # TODO: better instantiation when have full parameters # TODO: conversion from stream cost to real cost units? # TODO: any predicates derived would need to be replaced as well fluent_predicates = get_fluents(domain) certified_predicates = { get_prefix(a) for s in streams for a in s.certified } future_map = {p: 'f-{}'.format(p) for p in certified_predicates} augment_evaluations(evaluations, future_map) rename_future = lambda a: rename_atom(a, future_map) for stream in list(streams): if not isinstance(stream, Stream): raise NotImplementedError(stream) # TODO: could also just have conditions asserting that one of the fluent conditions fails streams.append( create_static_stream(stream, evaluations, fluent_predicates, rename_future)) stream_atom = streams[-1].certified[0] add_predicate( domain, make_predicate(get_prefix(stream_atom), get_args(stream_atom))) preconditions = [stream_atom] + list(stream.domain) effort = 1 # TODO: use stream info #effort = 1 if unit_cost else result.instance.get_effort() #if effort == INF: # continue domain.actions.append( make_action(name='call-{}'.format(stream.name), parameters=get_args(stream_atom), preconditions=preconditions, effects=stream.certified, cost=effort)) stream.certified = tuple( set(stream.certified) | set(map(rename_future, stream.certified)))
def add_plan_constraints(constraints, domain, evaluations, goal_exp, internal=False): if (constraints is None) or (constraints.skeletons is None): return goal_exp import pddl # TODO: unify this with the constraint ordering # TODO: can constrain to use a plan prefix prefix = get_internal_prefix(internal) assigned_predicate = ASSIGNED_PREDICATE.format(prefix) bound_predicate = BOUND_PREDICATE.format(prefix) group_predicate = GROUP_PREDICATE.format(prefix) order_predicate = ORDER_PREDICATE.format(prefix) new_facts = [] for group in constraints.groups: for value in constraints.groups[group]: # TODO: could make all constants groups (like an equality group) fact = (group_predicate, to_obj(group), to_obj(value)) new_facts.append(fact) new_actions = [] new_goals = [] for num, skeleton in enumerate(constraints.skeletons): actions, orders = skeleton incoming_orders, _ = neighbors_from_orders(orders) order_facts = [(order_predicate, to_obj('n{}'.format(num)), to_obj('t{}'.format(step))) for step in range(len(actions))] for step, (name, args) in enumerate(actions): # TODO: could also just remove the free parameter from the action new_action = deepcopy( find_unique(lambda a: a.name == name, domain.actions)) local_from_global = { a: p.name for a, p in safe_zip(args, new_action.parameters) if is_parameter(a) } ancestors, descendants = get_ancestors(step, orders), get_descendants( step, orders) parallel = set(range( len(actions))) - ancestors - descendants - {step} parameters = set(filter(is_parameter, args)) ancestor_parameters = parameters & set( filter(is_parameter, (p for idx in ancestors for p in actions[idx][1]))) #descendant_parameters = parameters & set(filter(is_parameter, (p for idx in descendants for p in actions[idx][1]))) parallel_parameters = parameters & set( filter(is_parameter, (p for idx in parallel for p in actions[idx][1]))) #bound_preconditions = [Imply(bound, assigned) for bound, assigned in safe_zip(bound_facts, assigned_facts)] bound_condition = pddl.Conjunction([ pddl.Disjunction( map(fd_from_fact, [ Not((bound_predicate, to_constant(p))), (assigned_predicate, to_constant(p), local_from_global[p]) ])) for p in parallel_parameters ]) existing_preconditions = [(assigned_predicate, to_constant(p), local_from_global[p]) for p in ancestor_parameters] constant_pairs = [(a, p.name) for a, p in safe_zip(args, new_action.parameters) if is_constant(a)] group_preconditions = [ (group_predicate if is_hashable(a) and (a in constraints.groups) else EQ, to_obj(a), p) for a, p in constant_pairs ] order_preconditions = [ order_facts[idx] for idx in incoming_orders[step] ] new_preconditions = existing_preconditions + group_preconditions + order_preconditions + [ Not(order_facts[step]) ] new_action.precondition = pddl.Conjunction([ new_action.precondition, bound_condition, make_preconditions(new_preconditions) ]).simplified() new_parameters = parameters - ancestors bound_facts = [(bound_predicate, to_constant(p)) for p in new_parameters] assigned_facts = [(assigned_predicate, to_constant(p), local_from_global[p]) for p in new_parameters] new_effects = bound_facts + assigned_facts + [order_facts[step]] new_action.effects.extend(make_effects(new_effects)) # TODO: should also negate the effects of all other sequences here new_actions.append(new_action) #new_action.dump() new_goals.append( And(*[order_facts[idx] for idx in incoming_orders[GOAL_INDEX]])) add_predicate(domain, make_predicate(order_predicate, ['?num', '?step'])) if constraints.exact: domain.actions[:] = [] domain.actions.extend(new_actions) new_goal_exp = And(goal_exp, Or(*new_goals)) for fact in new_facts: add_fact(evaluations, fact, result=INTERNAL_EVALUATION) return new_goal_exp
def add_plan_constraints(constraints, domain, evaluations, goal_exp, internal=False): if (constraints is None) or (constraints.skeletons is None): return goal_exp import pddl # TODO: can search over skeletons first and then fall back # TODO: unify this with the constraint ordering # TODO: can constrain to use a plan prefix prefix = '_' if internal else '' assigned_predicate = ASSIGNED_PREDICATE.format(prefix) group_predicate = GROUP_PREDICATE.format(prefix) order_predicate = ORDER_PREDICATE.format(prefix) for group in constraints.groups: for value in constraints.groups[group]: # TODO: could make all constants groups (like an equality group) fact = (group_predicate, to_obj(group), to_obj(value)) add_fact(evaluations, fact, result=INTERNAL_EVALUATION) new_actions = [] new_goals = [] for num, skeleton in enumerate(constraints.skeletons): # TODO: change the prefix for these order_facts = [(order_predicate, to_obj('n{}'.format(num)), to_obj('t{}'.format(step))) for step in range(len(skeleton) + 1)] add_fact(evaluations, order_facts[0], result=INTERNAL_EVALUATION) new_goals.append(order_facts[-1]) bound_parameters = set() for step, (name, args) in enumerate(skeleton): # TODO: could also just remove the free parameter from the action new_action = deepcopy( find_unique(lambda a: a.name == name, domain.actions)) constant_pairs = [(a, p.name) for a, p in safe_zip(args, new_action.parameters) if not is_parameter(a) and a != WILD] skeleton_parameters = list(filter(is_parameter, args)) existing_parameters = [ p for p in skeleton_parameters if p in bound_parameters ] local_from_global = { a: p.name for a, p in safe_zip(args, new_action.parameters) if is_parameter(a) } group_preconditions = [ (group_predicate if is_hashable(a) and (a in constraints.groups) else EQ, to_obj(a), p) for a, p in constant_pairs ] new_preconditions = make_assignment_facts(assigned_predicate, local_from_global, existing_parameters) + \ group_preconditions + [order_facts[step]] new_action.precondition = pddl.Conjunction([ new_action.precondition, make_preconditions(new_preconditions) ]).simplified() new_effects = make_assignment_facts(assigned_predicate, local_from_global, skeleton_parameters) \ + [Not(order_facts[step]), order_facts[step + 1]] new_action.effects.extend(make_effects(new_effects)) # TODO: should also negate the effects of all other sequences here new_actions.append(new_action) bound_parameters.update(skeleton_parameters) #new_action.dump() add_predicate(domain, make_predicate(order_predicate, ['?num', '?step'])) if constraints.exact: domain.actions[:] = [] domain.actions.extend(new_actions) new_goal_exp = And(goal_exp, Or(*new_goals)) return new_goal_exp