def simple_from_durative_action(durative_actions, fluents): from pddlstream.algorithms.algorithm import get_predicates import pddl simple_actions = {} for action in durative_actions: parameters = convert_parameters(action.parameters) conditions = list(map(convert_condition, action.condition)) start_effects, end_effects = action.effects over_effects = [] effects = list( map(convert_effects, [start_effects, over_effects, end_effects])) static_condition = pddl.Conjunction( list({ part for condition in conditions for part in get_conjunctive_parts(condition.simplified()) if not isinstance(part, pddl.Truth) and not (get_predicates(part) & fluents) })) # TODO: deal with case where there are fluents actions = [] for i, (condition, effect) in enumerate(safe_zip(conditions, effects)): # TODO: extract the durations by pretending they are action costs actions.append( pddl.Action( SIMPLE_TEMPLATE.format(action.name, i), parameters, len(parameters), pddl.Conjunction([static_condition, condition]).simplified(), effect, None)) #actions[-1].dump() simple_actions[action] = actions return simple_actions
def simple_from_durative_action(durative_actions, fluents): import pddl simple_actions = {} for action in durative_actions: parameters = convert_parameters(action.parameters) conditions = list(map(convert_condition, action.condition)) start_effects, end_effects = action.effects over_effects = [] effects = list( map(convert_effects, [start_effects, over_effects, end_effects])) static_condition = pddl.Conjunction( list({ literal for condition in conditions for literal in get_conjunctive_parts(condition.simplified()) if literal.predicate not in fluents })) actions = [] for i, (condition, effect) in enumerate(safe_zip(conditions, effects)): actions.append( pddl.Action( SIMPLE_TEMPLATE.format(action.name, i), parameters, len(parameters), pddl.Conjunction([static_condition, condition]).simplified(), effect, None)) #actions[-1].dump() simple_actions[action] = actions return simple_actions
def get_stream_action(result, name, unit_cost, effect_scale=1): #from pddl_parser.parsing_functions import parse_action import pddl parameters = [] preconditions = [ fd_from_fact(fact) for fact in result.instance.get_domain() ] precondition = pddl.Conjunction(preconditions) effects = [ pddl.Effect(parameters=[], condition=pddl.Truth(), literal=fd_from_fact(fact)) for fact in result.get_certified() ] effort = 1 if unit_cost else result.instance.get_effort() if effort == INF: return None fluent = pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]) expression = pddl.NumericConstant(int_ceil(effect_scale * effort)) # Integer cost = pddl.Increase(fluent=fluent, expression=expression) # Can also be None return pddl.Action(name=name, parameters=parameters, num_external_parameters=len(parameters), precondition=precondition, effects=effects, cost=cost)
def add_inequality_preconds(self, action, reachable_action_params): if reachable_action_params is None or len(action.parameters) < 2: return action inequal_params = [] combs = itertools.combinations(range(len(action.parameters)), 2) for pos1, pos2 in combs: for params in reachable_action_params[action]: if params[pos1] == params[pos2]: break else: inequal_params.append((pos1, pos2)) if inequal_params: precond_parts = [action.precondition] for pos1, pos2 in inequal_params: param1 = action.parameters[pos1].name param2 = action.parameters[pos2].name new_cond = pddl.NegatedAtom("=", (param1, param2)) precond_parts.append(new_cond) precond = pddl.Conjunction(precond_parts).simplified() return pddl.Action( action.name, action.parameters, action.num_external_parameters, precond, action.effects, action.cost) else: return action
def add_inequality_preconds(self, action, reachable_action_params): if reachable_action_params is None or len(action.parameters) < 2: return action inequal_params = [] combs = itertools.combinations(range(len(action.parameters)), 2) for pos1, pos2 in combs: inequality = True for params in reachable_action_params[action.name]: if params[pos1] == params[pos2]: inequality = False break if inequality: inequal_params.append((pos1, pos2)) if inequal_params: precond_parts = list(action.precondition.parts) for pos1, pos2 in inequal_params: param1 = action.parameters[pos1].name param2 = action.parameters[pos2].name new_cond = pddl.NegatedAtom("=", (param1, param2)) precond_parts.append(new_cond) precond = action.precondition.change_parts(precond_parts) return pddl.Action(action.name, action.parameters, precond, action.effects, action.cost) else: return action
def __init__(self, task, reachable_action_params): self.predicates_to_add_actions = defaultdict(set) self.action_to_heavy_action = {} for act in task.actions: action = self.add_inequality_preconds(act, reachable_action_params) too_heavy_effects = [] create_heavy_act = False heavy_act = action # FOND for nondet_choice in action.effects: too_heavy_nondet_choice = [] for eff in nondet_choice: too_heavy_nondet_choice.append(eff) if eff.parameters: # universal effect create_heavy_act = True too_heavy_nondet_choice.append(eff.copy()) if not eff.literal.negated: predicate = eff.literal.predicate self.predicates_to_add_actions[predicate].add(action) too_heavy_effects.append(too_heavy_nondet_choice) if create_heavy_act: heavy_act = pddl.Action(action.name, action.parameters, action.num_external_parameters, action.precondition, too_heavy_effects, action.observation, action.cost) # heavy_act: duplicated universal effects and assigned unique names # to all quantified variables (implicitly in constructor) self.action_to_heavy_action[action] = heavy_act
def __init__(self, task, reachable_action_params): # print("*'*'*'*DEBUG invariant_finder.BalanceChecker.__init__*'*'*'*") self.predicates_to_add_actions = defaultdict(set) self.action_to_heavy_action = {} for act in task.actions: action = self.add_inequality_preconds(act, reachable_action_params) too_heavy_effects = [] create_heavy_act = False heavy_act = action for eff in action.effects: too_heavy_effects.append(eff) if eff.parameters: # universal effect create_heavy_act = True too_heavy_effects.append(eff.copy()) if isinstance(eff.peffect, pddl.Atom): #not eff.peffect.negated: predicate = eff.peffect.predicate self.predicates_to_add_actions[predicate].add(action) if create_heavy_act: heavy_act = pddl.Action(action.name, action.parameters, action.num_external_parameters, action.precondition, too_heavy_effects, action.cost) # heavy_act: duplicated universal effects and assigned unique names # to all quantified variables (implicitly in constructor) self.action_to_heavy_action[action] = heavy_act
def make_action(name, parameters, preconditions, effects, cost=None): # Usually all parameters are external return pddl.Action(name=name, parameters=make_parameters(parameters), num_external_parameters=len(parameters), precondition=make_preconditions(preconditions), effects=make_effects(effects), cost=make_cost(cost))
def transform_exp_actions(actions, mutex_groups): """ Exponential transformation of actions with sdac into actions with constant action costs. """ mutex_dict = dict() for group in mutex_groups: for elem in group: mutex_dict[elem] = group del_actions = [] new_actions = actions add_actions = [] for action in new_actions: if isinstance(action.cost, pddl_parser.CostNode): del_actions.append(action) if not is_usefull(action): continue at_list = [] consistent_actions = [] used_dict = dict() for atom in action.cost.get_atoms_set(): if atom not in mutex_dict: at_list.append( [atom, pddl.NegatedAtom(atom.predicate, atom.args)]) elif len(mutex_dict[atom]) == 1: at_list.append( [atom, pddl.NegatedAtom(atom.predicate, atom.args)]) elif str(mutex_dict[atom]) not in used_dict: at_list.append(mutex_dict[atom]) used_dict[str(mutex_dict[atom])] = True for combi in itertools.product(*at_list): pre = [] pre.extend(action.precondition) pre.extend(combi) if not is_consistent(combi, action.precondition, mutex_dict): continue if isinstance(action, pddl.Action): action_copy = pddl.Action(action.name, action.parameters, action.num_external_parameters, pre, action.effects, str(action.cost.get_cost(combi))) else: action_copy = pddl.PropositionalAction( action.name, pre, [], str(action.cost.get_cost(combi))) action_copy.add_effects.extend(action.add_effects) action_copy.del_effects.extend(action.del_effects) consistent_actions.append(action_copy) add_actions.extend(consistent_actions) for a in del_actions: new_actions.remove(a) new_actions.extend(add_actions) return new_actions
def get_necessary_axioms(conditions, axioms, negative_from_name): if not conditions or not axioms: return {} axioms_from_name = get_derived_predicates(axioms) atom_queue = [] processed_atoms = set() def add_literals(literals): for lit in literals: atom = lit.positive() if atom not in processed_atoms: atom_queue.append( atom) # Previously was lit.positive() for some reason? processed_atoms.add(atom) import pddl add_literals(conditions) axiom_from_action = {} partial_instantiations = set() while atom_queue: literal = atom_queue.pop() for axiom in axioms_from_name[literal.predicate]: derived_parameters = axiom.parameters[:axiom. num_external_parameters] var_mapping = { p.name: a for p, a in zip(derived_parameters, literal.args) if not is_parameter(a) } key = (axiom, frozenset(var_mapping.items())) if key in partial_instantiations: continue partial_instantiations.add(key) parts = [ l.rename_variables(var_mapping) for l in get_literals(axiom.condition) if l.predicate not in negative_from_name ] # Assumes a conjunction? # new_condition = axiom.condition.uniquify_variables(None, var_mapping) effect_args = [ var_mapping.get(a.name, a.name) for a in derived_parameters ] effect = pddl.Effect([], pddl.Truth(), pddl.conditions.Atom(axiom.name, effect_args)) free_parameters = [ p for p in axiom.parameters if p.name not in var_mapping ] new_action = pddl.Action(axiom.name, free_parameters, len(free_parameters), pddl.Conjunction(parts), [effect], None) # Creating actions so I can partially instantiate (impossible with axioms) axiom_from_action[new_action] = (axiom, var_mapping) add_literals(parts) return axiom_from_action
def get_necessary_axioms(instance, axioms, negative_from_name): import pddl axioms_from_name = get_derived_predicates(axioms) atom_queue = [] processed_atoms = set() def add_literals(literals): for literal in literals: atom = literal.positive() if atom not in processed_atoms: atom_queue.append(literal.positive()) processed_atoms.add(atom) add_literals(instance.precondition) for (cond, _) in (instance.add_effects + instance.del_effects): add_literals(cond) axiom_from_action = {} partial_instantiations = set() while atom_queue: literal = atom_queue.pop() for axiom in axioms_from_name[literal.predicate]: derived_parameters = axiom.parameters[:axiom. num_external_parameters] var_mapping = { p.name: a for p, a in zip(derived_parameters, literal.args) if a[0] != '?' } key = (axiom, frozenset(var_mapping.items())) if key in partial_instantiations: continue partial_instantiations.add(key) parts = [] for literal in get_literals(axiom.condition): if literal.predicate in negative_from_name: continue parts.append(literal.rename_variables(var_mapping)) # new_condition = axiom.condition.uniquify_variables(None, var_mapping) effect_args = [ var_mapping.get(a.name, a.name) for a in derived_parameters ] effect = pddl.Effect([], pddl.Truth(), pddl.conditions.Atom(axiom.name, effect_args)) free_parameters = [ p for p in axiom.parameters if p.name not in var_mapping ] new_action = pddl.Action(axiom.name, free_parameters, 0, pddl.Conjunction(parts), [effect], None) # Creating actions so I can partially instantiate (impossible with axioms) axiom_from_action[new_action] = (axiom, var_mapping) add_literals(parts) return axiom_from_action
def parse_action(alist, type_dict, predicate_dict): if DEBUG: print("parsing action %s" % [alist]) iterator = iter(alist) action_tag = next(iterator) assert action_tag == ":action", "Expected ':action' got '%s'" % action_tag name = next(iterator) parameters_tag_opt = next(iterator) if parameters_tag_opt == ":parameters": parameters = parse_typed_list(next(iterator), only_variables=True) precondition_tag_opt = next(iterator) else: parameters = [] precondition_tag_opt = parameters_tag_opt if precondition_tag_opt == ":precondition": precondition_list = next(iterator) if not precondition_list: # Note that :precondition () is allowed in PDDL. precondition = pddl.Conjunction([]) else: precondition = parse_condition(precondition_list, type_dict, predicate_dict) precondition = precondition.simplified() effect_tag = next(iterator) else: precondition = pddl.Conjunction([]) effect_tag = precondition_tag_opt assert effect_tag == ":effect" effect_list = next(iterator) eff = [] if effect_list: try: cost = parse_effects(effect_list, eff, type_dict, predicate_dict) if cost is None and eff: if DEBUG: print( "adding artificial effect (increase total-cost 1) to %s" % name) cost = pddl.NumericEffect( parse_assignment(['increase', 'total-cost', 1]) ) # artificially add a numeric effect that increases the total cost by one add_effect(cost, eff) assert (isinstance(cost, pddl.NumericEffect) ), "instance of cost is %s " % cost.__class__ except ValueError as e: raise SystemExit("Error in Action %s\nReason: %s." % (name, e)) for rest in iterator: assert False, rest if eff: return pddl.Action(name, parameters, len(parameters), precondition, eff, cost) else: return None
def parse_action(alist, type_dict, predicate_dict): iterator = iter(alist) action_tag = next(iterator) assert action_tag == ":action" name = next(iterator) parameters_tag_opt = next(iterator) if parameters_tag_opt == ":parameters": parameters = parse_typed_list(next(iterator), only_variables=True) precondition_tag_opt = next(iterator) else: parameters = [] precondition_tag_opt = parameters_tag_opt parameters_dict = dict((p.name, p) for p in parameters) if precondition_tag_opt == ":precondition": precondition_list = next(iterator) if not precondition_list: # Note that :precondition () is allowed in PDDL. precondition = pddl.Conjunction([]) else: precondition = parse_condition(precondition_list, type_dict, predicate_dict) precondition = precondition.simplified() effect_tag = next(iterator) else: precondition = pddl.Conjunction([]) effect_tag = precondition_tag_opt assert effect_tag == ":effect" effect_list = next(iterator) eff = [] if effect_list: try: cost = parse_effects(effect_list, eff, type_dict, predicate_dict) except ValueError as e: raise SystemExit("Error in Action %s\nReason: %s." % (name, e)) for rest in iterator: # Parse cost function if rest == ":cost": outer_op = None cost_list = next(iterator) cost = cost_node.CostNode("") cost = cost.parse_cost(cost_list, outer_op, predicate_dict, parameters_dict, cost) break for rest in iterator: assert False, rest if eff: return pddl.Action(name, parameters, len(parameters), precondition, eff, cost) else: return None
def parse_action(alist, type_dict, predicate_dict): iterator = iter(alist) action_tag = next(iterator) assert action_tag == ":action" or action_tag == ':action' name = next(iterator) parameters_tag_opt = next(iterator) if parameters_tag_opt == ":parameters": parameters = parse_typed_list(next(iterator), only_variables=True) precondition_tag_opt = next(iterator) else: parameters = [] precondition_tag_opt = parameters_tag_opt if precondition_tag_opt == ":precondition": precondition_list = next(iterator) if not precondition_list: # Note that :precondition () is allowed in PDDL. precondition = pddl.Conjunction([]) else: precondition = parse_condition(precondition_list, type_dict, predicate_dict) precondition = precondition.simplified() effect_tag = next(iterator) else: precondition = pddl.Conjunction([]) effect_tag = precondition_tag_opt assert effect_tag == ":effect" effect_list = next(iterator) eff = [] if effect_list: try: cost = parse_effects(effect_list, eff, type_dict, predicate_dict) except ValueError as e: raise SystemExit("Error in Action %s\nReason: %s." % (name, e)) next(iterator) == ":duration" duration = next(iterator) if len(duration[2]) == 1: duration = pddl.NumericConstant(int(duration[2])) else: duration = pddl.f_expression.PrimitiveNumericExpression( duration[2][0], duration[2][1:]) for rest in iterator: assert False, rest if eff: return pddl.Action(name, parameters, len(parameters), precondition, eff, cost, duration) else: return None
def parse_action(alist, type_dict, predicate_dict): iterator = iter(alist) action_tag = next(iterator) assert action_tag == ":action" name = next(iterator) parameters_tag_opt = next(iterator) if parameters_tag_opt == ":parameters": parameters = parse_typed_list(next(iterator), only_variables=True) precondition_tag_opt = next(iterator) else: parameters = [] precondition_tag_opt = parameters_tag_opt if precondition_tag_opt == ":precondition": precondition_list = next(iterator) if not precondition_list: # Note that :precondition () is allowed in PDDL. precondition = pddl.Conjunction([]) else: precondition = parse_condition( precondition_list, type_dict, predicate_dict) precondition = precondition.simplified() effect_tag = next(iterator) else: precondition = pddl.Conjunction([]) effect_tag = precondition_tag_opt assert effect_tag == ":effect" effect_list = next(iterator) eff = [] if effect_list: try: cost = parse_effects( effect_list, eff, type_dict, predicate_dict) except ValueError as e: raise SystemExit("Error in Action %s\nReason: %s." % (name, e)) for rest in iterator: assert False, rest # if eff: # return pddl.Action(name, parameters, len(parameters), # precondition, eff, cost) # else: # return None return pddl.Action(name, parameters, len(parameters), precondition, eff, None)
def get_stream_actions(results, unique_binding=False, unit_efforts=True, effort_scale=1): #from pddl_parser.parsing_functions import parse_action import pddl stream_result_from_name = {} stream_actions = [] for i, result in enumerate(results): #if not isinstance(stream_result, StreamResult): if type(result) == FunctionResult: continue effort = get_instance_effort(result.instance, unit_efforts) if effort == INF: continue # TODO: state constraints # TODO: selectively negate axioms result_name = '{}-{}'.format(result.external.name, i) #result_name = '{}_{}_{}'.format(result.external.name, # No spaces & parens # ','.join(map(pddl_from_object, result.instance.input_objects)), # ','.join(map(pddl_from_object, result.output_objects))) assert result_name not in stream_result_from_name stream_result_from_name[result_name] = result preconditions = list(result.instance.get_domain()) effects = list(result.get_certified()) #if ORDER_OUTPUT: # enforce_output_order(result, preconditions, effects) if unique_binding: enforce_single_binding(result, preconditions, effects) if is_optimizer_result( result): # These effects don't seem to be pruned effects.append( substitute_expression(result.external.stream_fact, result.get_mapping())) parameters = [] # Usually all parameters are external stream_actions.append( pddl.Action(name=result_name, parameters=parameters, num_external_parameters=len(parameters), precondition=make_preconditions(preconditions), effects=make_effects(effects), cost=make_cost(effort_scale * effort))) # Can also be None return stream_actions, stream_result_from_name
def visit_action_stmt(self, node): """Visits a PDDL action statement.""" signature = list() # Visit all parameters and create signature. for v in node.parameters: v.accept(self) signatureTuple = self.get_in(v) signature.append(signatureTuple) # Visit the precondition statement. node.precond.accept(self) precond = self.get_in(node.precond) # Visit the effect statement. node.effect.accept(self) effect = self.get_in(node.effect) # Create new PDDL action and store in node. self.set_in(node, pddl.Action(node.name, signature, precond, effect))
def compile_to_exogenous_actions(evaluations, domain, streams): import pddl # 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] parameters = [ pddl.TypedObject(p, OBJECT) for p in get_args(stream_atom) ] # TODO: add to predicates as well? domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate( get_prefix(stream_atom), parameters) 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( pddl.Action(name='call-{}'.format(stream.name), parameters=parameters, num_external_parameters=len(parameters), precondition=make_preconditions(preconditions), effects=make_effects(stream.certified), cost=make_cost(effort))) stream.certified = tuple( set(stream.certified) | set(map(rename_future, stream.certified)))
def compile_to_exogenous_actions(evaluations, domain, streams): import pddl # 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) domain_predicates = {get_prefix(a) for s in streams for a in s.domain} if not (domain_predicates & fluent_predicates): return 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] parameters = [pddl.TypedObject(p, 'object') for p in get_args(stream_atom)] # TODO: add to predicates as well? domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate(get_prefix(stream_atom), parameters) precondition = pddl.Conjunction(tuple(map(fd_from_fact, (stream_atom,) + tuple(stream.domain)))) effects = [pddl.Effect(parameters=[], condition=pddl.Truth(), literal=fd_from_fact(fact)) for fact in stream.certified] effort = 1 # TODO: use stream info #effort = 1 if unit_cost else result.instance.get_effort() #if effort == INF: # continue fluent = pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]) expression = pddl.NumericConstant(int_ceil(effort)) # Integer cost = pddl.Increase(fluent=fluent, expression=expression) # Can also be None domain.actions.append(pddl.Action(name='call-{}'.format(stream.name), parameters=parameters, num_external_parameters=len(parameters), precondition=precondition, effects=effects, cost=cost)) stream.certified = tuple(set(stream.certified) | set(map(rename_future, stream.certified)))
def simplify_actions(opt_evaluations, action_plan, task, actions, unit_costs): # TODO: add ordering constraints to simplify the optimization import pddl import instantiate fluent_facts = MockSet() init_facts = set() type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) results_from_head = get_results_from_head(opt_evaluations) action_from_name = {} function_plan = set() for i, (name, args) in enumerate(action_plan): action = find_unique(lambda a: a.name == name, actions) assert (len(action.parameters) == len(args)) # parameters = action.parameters[:action.num_external_parameters] var_mapping = {p.name: a for p, a in zip(action.parameters, args)} new_name = '{}-{}'.format(name, i) new_parameters = action.parameters[len(args):] new_preconditions = [] action.precondition.instantiate(var_mapping, init_facts, fluent_facts, new_preconditions) new_effects = [] for eff in action.effects: eff.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, new_effects) new_effects = [pddl.Effect([], pddl.Conjunction(conditions), effect) for conditions, effect in new_effects] cost = pddl.Increase(fluent=pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]), expression=pddl.NumericConstant(1)) # cost = None task.actions.append(pddl.Action(new_name, new_parameters, len(new_parameters), pddl.Conjunction(new_preconditions), new_effects, cost)) action_from_name[new_name] = (name, map(obj_from_pddl, args)) if not unit_costs: function_result = extract_function_results(results_from_head, action, args) if function_result is not None: function_plan.add(function_result) return action_from_name, list(function_plan)
def sequential_stream_plan(evaluations, goal_expression, domain, stream_results, negated, unit_costs=True, **kwargs): if negated: raise NotImplementedError() # TODO: compute preimage and make that the goal instead opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results) opt_task = task_from_domain_problem(domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs)) action_plan, action_cost = solve_from_task(opt_task, **kwargs) if action_plan is None: return None, action_cost import instantiate fluent_facts = MockSet() init_facts = set() task = task_from_domain_problem(domain, get_problem(evaluations, goal_expression, domain, unit_costs)) type_to_objects = instantiate.get_objects_by_type(task.objects, task.types) task.actions, stream_result_from_name = get_stream_actions(stream_results) results_from_head = get_results_from_head(opt_evaluations) # TODO: add ordering constraints to simplify the optimization import pddl action_from_name = {} function_plan = set() for i, (name, args) in enumerate(action_plan): action = find_unique(lambda a: a.name == name, domain.actions) assert(len(action.parameters) == len(args)) #parameters = action.parameters[:action.num_external_parameters] var_mapping = {p.name: a for p, a in zip(action.parameters, args)} new_name = '{}-{}'.format(name, i) new_parameters = action.parameters[len(args):] new_preconditions = [] action.precondition.instantiate(var_mapping, init_facts, fluent_facts, new_preconditions) new_effects = [] for eff in action.effects: eff.instantiate(var_mapping, init_facts, fluent_facts, type_to_objects, new_effects) new_effects = [pddl.Effect([], pddl.Conjunction(conditions), effect) for conditions, effect in new_effects] cost = pddl.Increase(fluent=pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[]), expression=pddl.NumericConstant(1)) #cost = None task.actions.append(pddl.Action(new_name, new_parameters, 0, pddl.Conjunction(new_preconditions), new_effects, cost)) action_from_name[new_name] = (name, map(obj_from_pddl, args)) if not unit_costs: function_plan.update(extract_function_results(results_from_head, action, args)) planner = kwargs.get('planner', 'ff-astar') combined_plan, _ = solve_from_task(task, planner=planner, **kwargs) if combined_plan is None: return None, obj_from_pddl_plan(action_plan), INF stream_plan = [] action_plan = [] for name, args in combined_plan: if name in stream_result_from_name: stream_plan.append(stream_result_from_name[name]) else: action_plan.append(action_from_name[name]) stream_plan += list(function_plan) combined_plan = stream_plan + action_plan return combined_plan, action_cost
def parse_action(alist, type_dict, predicate_dict): iterator = iter(alist) action_tag = next(iterator) assert action_tag == ":action" name = next(iterator) parameters_tag_opt = next(iterator) if parameters_tag_opt == ":parameters": parameters = parse_typed_list(next(iterator), only_variables=True) precondition_tag_opt = next(iterator) else: parameters = [] precondition_tag_opt = parameters_tag_opt if precondition_tag_opt == ":precondition": precondition_list = next(iterator) if not precondition_list: # Note that :precondition () is allowed in PDDL. precondition = pddl.Conjunction([]) else: precondition = parse_condition(precondition_list, type_dict, predicate_dict) precondition = precondition.simplified() effect_tag = next(iterator) else: precondition = pddl.Conjunction([]) effect_tag = precondition_tag_opt assert effect_tag == ":effect" effect_list = next(iterator) eff = [] if effect_list: try: cost_eff_pairs = parse_effects(effect_list, eff, type_dict, predicate_dict) if 1 == len(cost_eff_pairs): cost_eff_pairs = [(cost_eff_pairs[0][0], cost_eff_pairs[0][1], '')] else: # Convert floats to fractions to output # TODO : Benchmark this fraction conversion all_fractions = [] # summed = fractions.Fraction(0) for cep in cost_eff_pairs: all_fractions.append( fractions.Fraction(cep[2]).limit_denominator()) # summed += all_fractions[-1] # assert(summed == fractions.Fraction(1)) lcm = functools.reduce( lambda a, b: (a * b) / fractions.gcd(a, b), [f.denominator for f in all_fractions], 1) # Use the fractions and lcm to build the weights cost_eff_pairs = [(cost_eff_pairs[i][0], cost_eff_pairs[i][1], "_DETDUP_%d_WEIGHT_%d_%d" % (i, all_fractions[i].numerator * (lcm / all_fractions[i].denominator), lcm)) for i in range(len(cost_eff_pairs))] except ValueError as e: raise SystemExit("Error in Action %s\nReason: %s." % (name, e)) for rest in iterator: assert False, rest return [ pddl.Action(name + suffix, parameters, len(parameters), precondition, eff, cost) for (cost, eff, suffix) in cost_eff_pairs ]