Ejemplo n.º 1
0
def instantiate_condition(action, is_static, args_from_predicate):
    parameters = {p.name for p in action.parameters}
    #if not parameters:
    #    yield {}
    #    return
    static_conditions = list(
        filter(is_static, get_literals(get_precondition(action))))
    static_parameters = set(
        filter(is_parameter, flatten(atom.args for atom in static_conditions)))
    if not (parameters <= static_parameters):
        raise NotImplementedError(
            'Could not instantiate action {} due to parameters: {}'.format(
                action.name, str_from_object(parameters - static_parameters)))
    atoms_from_cond = {
        condition: args_from_predicate[condition.predicate,
                                       get_constants(condition)]
        for condition in static_conditions
    }
    conditions, atoms = zip(*atoms_from_cond.items())
    relations = [
        Relation(conditions[index].args, atoms[index])
        for index in compute_order(conditions, atoms)
    ]
    solution = solve_satisfaction(relations)
    for element in solution.body:
        yield solution.get_mapping(element)
Ejemplo n.º 2
0
def extract_axiom_plan(task, goals, negative_from_name, static_state=set()):
    import pddl_to_prolog
    import build_model
    import instantiate
    # TODO: only reinstantiate the negative axioms
    axioms_from_name = get_derived_predicates(task.axioms)
    derived_goals = {l for l in goals if l.predicate in axioms_from_name}
    axiom_from_action = get_necessary_axioms(derived_goals, task.axioms, negative_from_name)
    if not axiom_from_action:
        return []
    conditions_from_predicate = defaultdict(set)
    for axiom, mapping in axiom_from_action.values():
        for literal in get_literals(axiom.condition):
            conditions_from_predicate[literal.predicate].add(literal.rename_variables(mapping))

    original_init = task.init
    original_actions = task.actions
    original_axioms = task.axioms
    # TODO: retrieve initial state based on if helpful
    task.init = {atom for atom in task.init if is_useful_atom(atom, conditions_from_predicate)}
    # TODO: store map from predicate to atom
    task.actions = axiom_from_action.keys()
    task.axioms = []
    # TODO: maybe it would just be better to drop the negative throughout this process until this end
    with Verbose(False):
        model = build_model.compute_model(pddl_to_prolog.translate(task))  # Changes based on init
    task.actions = original_actions
    task.axioms = original_axioms

    opt_facts = instantiate.get_fluent_facts(task, model) | (task.init - static_state)
    mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or (item in opt_facts))
    instantiated_axioms = instantiate_necessary_axioms(model, static_state, mock_fluent, axiom_from_action)
    axiom_plan = extraction_helper(task.init, instantiated_axioms, derived_goals, negative_from_name)
    task.init = original_init
    return axiom_plan
Ejemplo n.º 3
0
def add_stream_costs(node_from_atom, instantiated, unit_efforts, effort_weight):
    # TODO: instantiate axioms with negative on effects for blocking
    # TODO: fluent streams using conditional effects. Special fluent predicate for inputs to constraint
    # This strategy will only work for relaxed to ensure that the current state is applied
    for instance in instantiated.actions:
        # TODO: prune stream actions here?
        # Ignores conditional effect costs
        facts = []
        for precondition in get_literals(instance.action.precondition):
            if precondition.negated:
                continue
            args = [instance.var_mapping.get(arg, arg) for arg in precondition.args]
            literal = precondition.__class__(precondition.predicate, args)
            fact = fact_from_fd(literal)
            if fact in node_from_atom:
                facts.append(fact)
        #effort = COMBINE_OP([0] + [node_from_atom[fact].effort for fact in facts])
        stream_plan = []
        extract_stream_plan(node_from_atom, facts, stream_plan)
        if unit_efforts:
            effort = len(stream_plan)
        else:
            effort = scale_cost(sum([0] + [r.instance.get_effort() for r in stream_plan]))
        if effort_weight is not None:
            instance.cost += effort_weight*effort
        # TODO: bug! The FD instantiator prunes the result.external.stream_fact
        for result in stream_plan:
            # TODO: need to make multiple versions if several ways of achieving the action
            if is_optimizer_result(result):
                fact = substitute_expression(result.external.stream_fact, result.get_mapping())
                atom = fd_from_fact(fact)
                instantiated.atoms.add(atom)
                effect = (tuple(), atom)
                instance.add_effects.append(effect)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
def extract_axiom_plan(task, action_instance, negative_from_name, static_state=set()):
    import pddl_to_prolog
    import build_model
    import axiom_rules
    import instantiate

    axioms_from_name = get_derived_predicates(task.axioms)
    derived_preconditions = {l for l in action_instance.precondition if l.predicate in axioms_from_name}
    nonderived_preconditions = {l for l in action_instance.precondition if l not in derived_preconditions}
    if not conditions_hold(task.init, nonderived_preconditions):
        return None

    axiom_from_action = get_necessary_axioms(action_instance, task.axioms, negative_from_name)
    if not axiom_from_action:
        return []
    conditions_from_predicate = defaultdict(set)
    for axiom, mapping in axiom_from_action.values():
        for literal in get_literals(axiom.condition):
            conditions_from_predicate[literal.predicate].add(literal.rename_variables(mapping))

    original_init = task.init
    original_actions = task.actions
    original_axioms = task.axioms
    task.init = {atom for atom in task.init if is_useful_atom(atom, conditions_from_predicate)}
    # TODO: store map from predicate to atom
    task.actions = axiom_from_action.keys()
    task.axioms = []
    # TODO: maybe it would just be better to drop the negative throughout this process until this end
    with Verbose(False):
        model = build_model.compute_model(pddl_to_prolog.translate(task))  # Changes based on init
    task.actions = original_actions
    task.axioms = original_axioms

    opt_facts = instantiate.get_fluent_facts(task, model) | (task.init - static_state)
    mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or (item in opt_facts))
    instantiated_axioms = instantiate_necessary_axioms(model, static_state, mock_fluent, axiom_from_action)

    goal_list = []
    with Verbose(False):
        helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms(
            [action_instance], instantiated_axioms, goal_list)
    axiom_init = set(axiom_init)
    axiom_effects = {axiom.effect for axiom in helpful_axioms}
    #assert len(axiom_effects) == len(axiom_init)
    for pre in list(derived_preconditions) + list(axiom_effects):
        if (pre not in axiom_init) and (pre.negate() not in axiom_init):
            axiom_init.add(pre.positive().negate())
    axiom_from_atom = get_achieving_axioms(task.init | axiom_init, helpful_axioms, negative_from_name)
    axiom_plan = []  # Could always add all conditions
    success = extract_axioms(axiom_from_atom, derived_preconditions, axiom_plan, negative_from_name)
    task.init = original_init
    #if not success:
    #    return None
    return axiom_plan
Ejemplo n.º 7
0
def get_instance_facts(instance, node_from_atom):
    # TODO: ignores conditional effect conditions
    facts = []
    for precondition in get_literals(instance.action.precondition):
        if precondition.negated:
            continue
        args = apply_mapping(precondition.args, instance.var_mapping)
        literal = precondition.__class__(precondition.predicate, args)
        fact = fact_from_fd(literal)
        if fact in node_from_atom:
            facts.append(fact)
    return facts
Ejemplo n.º 8
0
def compile_fluents_as_attachments(domain, externals):
    import pddl
    state_streams = set(
        filter(lambda e: isinstance(e, Stream) and e.is_fluent(),
               externals))  # is_special
    if not state_streams:
        return externals

    predicate_map = get_predicate_map(state_streams)
    if predicate_map and (get_pyplanners_path() is None):
        # TODO: fluent streams with outputs
        # Could convert the free parameter to a constant
        raise NotImplementedError(
            'Algorithm does not support fluent streams: {}'.format(
                [stream.name for stream in state_streams]))

    domain.constants.append(make_object(PLACEHOLDER.pddl))
    for action in domain.actions:
        for effect in action.effects:
            # TODO: conditional effects
            if any(literal.predicate in predicate_map
                   for literal in get_literals(effect.condition)):
                raise ValueError(
                    'Attachments cannot be in action effects: {}'.format(
                        effect))
        action.attachments = {}
        preconditions = set()
        for literal in get_conjunctive_parts(action.precondition):
            #if not isinstance(literal, pddl.Literal):
            #    raise NotImplementedError('Only literals are supported: {}'.format(literal))
            if not get_predicates(literal) & set(predicate_map):
                preconditions.add(literal)
                continue
            if not isinstance(literal, pddl.Literal):
                raise NotImplementedError(literal)
            # Drops the original precondition
            stream = predicate_map[literal.predicate]
            mapping = remap_certified(literal, stream)
            assert mapping is not None
            action.attachments[literal] = stream
            preconditions.update(
                pddl.Atom(EQ, (mapping[out], PLACEHOLDER.pddl))
                for out in stream.outputs)
            preconditions.update(
                fd_from_fact(substitute_fact(fact, mapping))
                for fact in stream.domain)
        action.precondition = pddl.Conjunction(preconditions).simplified()
        #fn = lambda l: pddl.Truth() if l.predicate in predicate_map else l
        #action.precondition = replace_literals(fn, action.precondition).simplified()
        #action.dump()
    return [
        external for external in externals if external not in state_streams
    ]
Ejemplo n.º 9
0
def instantiate_domain(task, prune_static=True):
    fluent_predicates = get_fluents(task)
    is_static = lambda a: isinstance(a, pddl.Atom) and (a.predicate not in fluent_predicates)

    fluent_facts = MockSet(lambda a: not prune_static or not is_static(a))
    init_facts = set(task.init)
    function_assignments = get_function_assignments(task)
    type_to_objects = instantiate.get_objects_by_type(task.objects, task.types)

    constants_from_predicate = defaultdict(set)
    for action in task.actions + task.axioms:
        for atom in filter(is_static, get_literals(get_precondition(action))):
            constants = tuple((i, a) for i, a in enumerate(atom.args) if not is_parameter(a))
            constants_from_predicate[atom.predicate].add(constants)

    predicate_to_atoms = defaultdict(set)
    args_from_predicate = defaultdict(set)
    for atom in filter(is_static, task.init):  # TODO: compute which predicates might involve constants
        predicate_to_atoms[atom.predicate].add(atom)
        args_from_predicate[atom.predicate].add(atom.args)
        for constants in constants_from_predicate[atom.predicate]:
            if all(atom.args[i] == o for i, o in constants):
                args_from_predicate[atom.predicate, constants].add(atom.args)

    instantiated_actions = []
    for action in task.actions:
        for variable_mapping in instantiate_condition(action, is_static, args_from_predicate):
            inst_action = action.instantiate(variable_mapping, init_facts, fluent_facts, type_to_objects,
                                             task.use_min_cost_metric, function_assignments, predicate_to_atoms)
            if inst_action:
                instantiated_actions.append(inst_action)
    instantiated_axioms = []
    for axiom in task.axioms:
        for variable_mapping in instantiate_condition(axiom, is_static, args_from_predicate):
            inst_axiom = axiom.instantiate(variable_mapping, init_facts, fluent_facts)
            if inst_axiom:
                instantiated_axioms.append(inst_axiom)

    reachable_facts, reachable_operators = get_achieving_axioms(init_facts, instantiated_actions + instantiated_axioms)
    atoms = {atom for atom in (init_facts | set(reachable_facts)) if isinstance(atom, pddl.Atom)}
    relaxed_reachable = all(literal_holds(init_facts, goal) or goal in reachable_facts
                            for goal in instantiate_goal(task.goal))
    reachable_actions = [action for action in reachable_operators
                         if isinstance(action, pddl.PropositionalAction)]
    reachable_axioms = [axiom for axiom in reachable_operators
                        if isinstance(axiom, pddl.PropositionalAxiom)]
    return relaxed_reachable, atoms, reachable_actions, reachable_axioms
Ejemplo n.º 10
0
def compile_fluent_attachments(domain, externals):
    import pddl
    state_streams = set(
        filter(lambda e: isinstance(e, Stream) and e.is_fluent(),
               externals))  # is_special
    predicate_map = get_predicate_map(state_streams)
    if predicate_map and not os.path.exists(PYPLANNERS_PATH):
        raise NotImplementedError(
            'Algorithm does not support fluent streams: {}'.format(
                [stream.name for stream in predicate_map.values()]))
    for action in domain.actions:
        for effect in action.effects:
            # TODO: conditional effects
            if any(literal.predicate in predicate_map
                   for literal in get_literals(effect.condition)):
                raise ValueError(effect)
        action.attachments = {}
        preconditions = []
        for literal in get_conjunctive_parts(action.precondition):
            if not isinstance(literal, pddl.Literal):
                raise NotImplementedError(literal)
            if literal.predicate in predicate_map:
                stream = predicate_map[literal.predicate]
                if not stream.is_test():
                    raise NotImplementedError(stream)
                assert remap_certified(literal, stream) is not None
                action.attachments[literal] = stream
            else:
                preconditions.append(literal)
        action.precondition = pddl.Conjunction(preconditions).simplified()
        #fn = lambda l: pddl.Truth() if l.predicate in predicate_map else l
        #action.precondition = replace_literals(fn, action.precondition).simplified()
        #action.dump()
    return [
        external for external in externals if external not in state_streams
    ]