def add_effect(tmp_effect, result):
    """tmp_effect has the following structure:
       [ConjunctiveEffect] [UniversalEffect] [ConditionalEffect] SimpleEffect."""

    if isinstance(tmp_effect, pddl.ConjunctiveEffect):
        for effect in tmp_effect.effects:
            add_effect(effect, result)
        return
    else:
        parameters = []
        condition = pddl.Truth()
        if isinstance(tmp_effect, pddl.UniversalEffect):
            parameters = tmp_effect.parameters
            if isinstance(tmp_effect.effect, pddl.ConditionalEffect):
                condition = tmp_effect.effect.condition
                assert isinstance(tmp_effect.effect.effect, pddl.SimpleEffect)
                effect = tmp_effect.effect.effect.effect
            else:
                assert isinstance(tmp_effect.effect, pddl.SimpleEffect)
                effect = tmp_effect.effect.effect
        elif isinstance(tmp_effect, pddl.ConditionalEffect):
            condition = tmp_effect.condition
            assert isinstance(tmp_effect.effect, pddl.SimpleEffect)
            effect = tmp_effect.effect.effect
        else:
            assert isinstance(tmp_effect, pddl.SimpleEffect)
            effect = tmp_effect.effect
        assert isinstance(effect, pddl.Literal)
        # Check for contradictory effects
        condition = condition.simplified()
        new_effect = pddl.Effect(parameters, condition, effect)
        contradiction = pddl.Effect(parameters, condition, effect.negate())

        ### REMOVED CONTRADICTION CHECK
        result.append(new_effect)
예제 #2
0
def instantiate_unsatisfiable(state,
                              action,
                              var_mapping,
                              negative_from_name={}):
    precondition = []
    for effect in action.effects:
        if effect.literal.predicate == UNSATISFIABLE:
            # Condition must be false for plan to succeed
            conditions = set(get_conjunctive_parts(effect.condition))
            negative = {
                literal
                for literal in conditions
                if literal.predicate in negative_from_name
            }
            if not negative:
                continue
            assert len(negative) == 1
            # TODO: handle the case where negative is not used (not (CFree ..))
            normal_conjunction = pddl.Conjunction(conditions - negative)
            # TODO: assumes that can instantiate with just predicate_to_atoms
            normal_effect = pddl.Effect(effect.parameters, normal_conjunction,
                                        effect.literal)
            # TODO: avoid recomputing these
            objects_by_type = instantiate.get_objects_by_type([], [])
            predicate_to_atoms = instantiate.get_atoms_by_predicate(state)
            result = []
            normal_effect.instantiate(var_mapping, state, {effect.literal},
                                      objects_by_type, predicate_to_atoms,
                                      result)
            for _, _, _, mapping in result:
                for literal in negative:
                    new_literal = literal.rename_variables(mapping).negate()
                    assert (not new_literal.free_variables())
                    precondition.append(new_literal)
    return precondition
예제 #3
0
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)
예제 #4
0
def optimizer_conditional_effects(domain, externals):
    import pddl
    #from pddlstream.algorithms.scheduling.negative import get_negative_predicates
    # TODO: extend this to predicates
    if UNIVERSAL_TO_CONDITIONAL:
        negative_streams = list(filter(lambda e: e.is_negated, externals))
    else:
        negative_streams = list(
            filter(lambda e: isinstance(e, ConstraintStream) and e.is_negated,
                   externals))
    negative_from_predicate = get_predicate_map(negative_streams)
    if not negative_from_predicate:
        return
    for action in domain.actions:
        universal_to_conditional(action)
        new_effects = []
        for effect in action.effects:
            if effect.literal.predicate != UNSATISFIABLE:
                new_effects.append(effect)
                continue
            new_parts, stream_facts = process_conditional_effect(
                effect, negative_from_predicate)
            if not stream_facts:
                new_effects.append(effect)
            for stream_fact in stream_facts:
                new_effects.append(
                    pddl.Effect(effect.parameters, pddl.Conjunction(new_parts),
                                stream_fact))
        action.effects = new_effects
예제 #5
0
def add_effect(tmp_effect, result):
    """tmp_effect has the following structure:
       [ConjunctiveEffect] [UniversalEffect] [ConditionalEffect] SimpleEffect."""

    if isinstance(tmp_effect, pddl.ConjunctiveEffect):
        for effect in tmp_effect.effects:
            add_effect(effect, result)
        return
    else:
        parameters = []
        condition = pddl.Truth()
        if isinstance(tmp_effect, pddl.UniversalEffect):
            parameters = tmp_effect.parameters
            if isinstance(tmp_effect.effect, pddl.ConditionalEffect):
                condition = tmp_effect.effect.condition
                assert isinstance(tmp_effect.effect.effect, pddl.SimpleEffect)
                effect = tmp_effect.effect.effect.effect
            else:
                assert isinstance(tmp_effect.effect, pddl.SimpleEffect)
                effect = tmp_effect.effect.effect
        elif isinstance(tmp_effect, pddl.ConditionalEffect):
            condition = tmp_effect.condition
            assert isinstance(tmp_effect.effect, pddl.SimpleEffect)
            effect = tmp_effect.effect.effect
        else:
            assert isinstance(tmp_effect, pddl.SimpleEffect)
            effect = tmp_effect.effect
        if effect is None:
            # Nothing to add
            return
        assert isinstance(effect, pddl.Literal)
        # Check for contradictory effects
        condition = condition.simplified()
        new_effect = pddl.Effect(parameters, condition, effect)
        contradiction = pddl.Effect(parameters, condition, effect.negate())
        if not contradiction in result:
            result.append(new_effect)
        else:
            # We use add-after-delete semantics, keep positive effect
            if isinstance(contradiction.literal, pddl.NegatedAtom):
                result.remove(contradiction)
                result.append(new_effect)
예제 #6
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
예제 #7
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
예제 #8
0
def universal_to_conditional(action):
    import pddl
    new_parts = []
    unsatisfiable = fd_from_fact((UNSATISFIABLE,))
    for quant in get_conjunctive_parts(action.precondition):
        if isinstance(quant, pddl.UniversalCondition):
            condition = quant.parts[0]
            # TODO: normalize first?
            if isinstance(condition, pddl.Disjunction) or isinstance(condition, pddl.Literal):
                action.effects.append(pddl.Effect(quant.parameters, condition.negate(), unsatisfiable))
                continue
        new_parts.append(quant)
    action.precondition = pddl.Conjunction(new_parts)
예제 #9
0
def optimizer_conditional_effects(domain, externals):
    import pddl
    #from pddlstream.algorithms.scheduling.negative import get_negative_predicates
    # TODO: extend this to predicates
    if UNIVERSAL_TO_CONDITIONAL:
        negative_streams = list(filter(lambda e: e.is_negated(), externals))
    else:
        negative_streams = list(
            filter(
                lambda e: isinstance(e, ConstraintStream) and e.is_negated(),
                externals))
    negative_from_predicate = get_predicate_map(negative_streams)
    if not negative_from_predicate:
        return
    for action in domain.actions:
        universal_to_conditional(action)
        new_effects = []
        for effect in action.effects:
            if effect.literal.predicate != UNSATISFIABLE:
                new_effects.append(effect)
                continue
            new_parts = []
            stream_facts = []
            for disjunctive in get_conjunctive_parts(effect.condition):
                for literal in get_disjunctive_parts(disjunctive):
                    # TODO: assert only one disjunctive part
                    if isinstance(literal, pddl.Literal) and (
                            literal.predicate in negative_from_predicate):
                        stream = negative_from_predicate[literal.predicate]
                        if not isinstance(stream, ConstraintStream):
                            new_parts.append(literal)
                            continue
                        certified = find_unique(
                            lambda f: get_prefix(f) == literal.predicate,
                            stream.certified)
                        mapping = get_mapping(get_args(certified),
                                              literal.args)
                        stream_facts.append(
                            fd_from_fact(
                                substitute_expression(stream.stream_fact,
                                                      mapping)))
                        # TODO: add the negated literal as precondition here?
                    else:
                        new_parts.append(literal)
            if not stream_facts:
                new_effects.append(effect)
            for stream_fact in stream_facts:
                new_effects.append(
                    pddl.Effect(effect.parameters, pddl.Conjunction(new_parts),
                                stream_fact))
        action.effects = new_effects
예제 #10
0
 def visit_effect_stmt(self, node):
     """ Visits a PDDL effect statement."""
     formula = node.formula
     effect = pddl.Effect()
     # For now we only allow 'and' in the effect.
     if formula.key == 'and':
         for c in formula.children:
             # Call helper.
             self.add_effect(effect, c)
     else:
         # Call helper.
         self.add_effect(effect, formula)
     # Store effect in node.
     self.set_in(node, effect)
예제 #11
0
def remove_duration_variable(task):
    def recurse(condition, act, time, duration, pnes):
        if isinstance(condition, pddl.FunctionComparison):
            parts = [
                exp.remove_duration_variable(act, time, duration, pnes)
                for exp in condition.parts
            ]
            return condition.__class__(condition.comparator, parts)
            # return pddl.FunctionComparison(condition.comparator,parts)
        else:
            new_parts = [
                recurse(part, act, time, duration, pnes)
                for part in condition.parts
            ]
            return condition.change_parts(new_parts)

    for act in task.durative_actions:
        assert len(act.duration[1]) == 0, "at end durations are not supported"
        assert len(act.duration[0]) == 1 and act.duration[0][0][0] == "="
        duration = act.duration[0][0][1]
        duration_functions = []

        # remove from action conditions
        condition = []
        for time, cond in enumerate(act.condition):
            condition.append(
                recurse(cond, act, time, duration, duration_functions))
        act.condition = condition

        for time in range(2):
            for eff in act.effects[time]:
                # remove from effect condition
                condition = []
                for eff_time, cond in enumerate(eff.condition):
                    condition.append(
                        recurse(cond, act, eff_time, duration,
                                duration_functions))
                eff.condition = condition
                # remove from effect
                if isinstance(eff.peffect, pddl.FunctionAssignment):
                    assign = eff.peffect
                    assign.expression = assign.expression.remove_duration_variable(
                        act, time, duration, duration_functions)
        for pne in duration_functions:
            assign = pddl.Assign(pne, duration)
            condition = [pddl.Truth(), pddl.Truth(), pddl.Truth()]
            effect = pddl.Effect([], condition, assign)
            act.effects[0].append(effect)
            task.function_symbols[pne.symbol] = "number"
예제 #12
0
def convert_effects(effects):
    import pddl
    new_effects = make_effects([('_noop',)]) # To ensure the action has at least one effect
    for effect in effects:
        class_name = effect.__class__.__name__
        if class_name == 'Effect':
            peffect_name = effect.peffect.__class__.__name__
            if peffect_name in ('Increase', 'Decrease'):
                # TODO: currently ignoring numeric conditions
                continue
            new_effects.append(pddl.Effect(convert_parameters(effect.parameters),
                                           pddl.Conjunction(list(map(convert_condition, effect.condition))).simplified(),
                                           convert_condition(effect.peffect)))
        else:
            raise NotImplementedError(class_name)
    return new_effects
예제 #13
0
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)))
예제 #14
0
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)
예제 #15
0
def make_effects(effects):
    return [
        pddl.Effect(parameters=[],
                    condition=pddl.Truth(),
                    literal=fd_from_fact(fact)) for fact in effects
    ]
예제 #16
0
def reinstantiate_action(state, instance, negative_from_name={}):
    # Recomputes the instances with without any pruned preconditions
    # TODO: making the assumption that no negative derived predicates
    action = instance.action
    var_mapping = instance.var_mapping
    init_facts = set()
    fluent_facts = MockSet()
    precondition = []
    try:
        action.precondition.instantiate(var_mapping, init_facts, fluent_facts,
                                        precondition)
    except pddl.conditions.Impossible:
        return None
    effects = []
    effect_from_literal = {
        literal: (cond, effect, effect_mapping)
        for cond, literal, effect, effect_mapping in instance.effect_mappings
    }
    for effect in action.effects:
        if effect.literal.predicate == UNSATISFIABLE:
            # Condition must be false for plan to succeed
            conditions = set(get_conjunctive_parts(effect.condition))
            negative = {
                literal
                for literal in conditions
                if literal.predicate in negative_from_name
            }
            if not negative:
                continue
            assert len(negative) == 1
            # TODO: handle the case where negative is not used (not (CFree ..))
            normal_conjunction = pddl.Conjunction(conditions - negative)
            # TODO: assumes that can instantiate with just predicate_to_atoms
            normal_effect = pddl.Effect(effect.parameters, normal_conjunction,
                                        effect.literal)
            # TODO: avoid recomputing these
            objects_by_type = instantiate.get_objects_by_type([], [])
            predicate_to_atoms = instantiate.get_atoms_by_predicate(state)
            result = []
            normal_effect.instantiate(var_mapping, state, {effect.literal},
                                      objects_by_type, predicate_to_atoms,
                                      result)
            for _, _, _, mapping in result:
                for literal in negative:
                    new_literal = literal.rename_variables(mapping).negate()
                    assert (not new_literal.free_variables())
                    precondition.append(new_literal)

    for literal in instance.applied_effects:
        cond, effect, effect_mapping = effect_from_literal[literal]
        if effect is None:  # Stream effect
            #effects.append((cond, literal, cond, effect))
            continue
        else:
            effect._instantiate(effect_mapping, init_facts, fluent_facts,
                                effects)

    new_effects = []
    for cond, effect, e, m in effects:
        precondition.extend(cond)
        new_effects.append(([], effect, e, m))
    return pddl.PropositionalAction(instance.name, precondition, new_effects,
                                    instance.cost, action, var_mapping)
예제 #17
0
def add_effect(tmp_effect, result):  # adds effect from tmp_effect to result
    """tmp_effect has the following structure:
       [ConjunctiveEffect] [UniversalEffect] [ConditionalEffect] SimpleEffect."""

    if isinstance(tmp_effect, pddl.ConjunctiveEffect):
        for effect in tmp_effect.effects:
            add_effect(effect, result)
        return
    else:
        parameters = []
        condition = pddl.Truth()
        if isinstance(tmp_effect, pddl.UniversalEffect):
            #             print ("universal effect: ", tmp_effect)
            parameters = tmp_effect.parameters
            if isinstance(tmp_effect.effect, pddl.ConditionalEffect):
                condition = tmp_effect.effect.condition
                assert isinstance(tmp_effect.effect.effect, pddl.SimpleEffect)\
                     or isinstance(tmp_effect.effect.effect, pddl.NumericEffect)
                effect = tmp_effect.effect.effect.effect
            else:
                assert isinstance(tmp_effect.effect, pddl.SimpleEffect)\
                     or isinstance(tmp_effect.effect, pddl.NumericEffect), "Effect is not primitive but %s" % tmp_effect.effect.effect.__class__
                effect = tmp_effect.effect.effect
        elif isinstance(tmp_effect, pddl.ConditionalEffect):
            #             print ("conditional effect: ", tmp_effect)
            condition = tmp_effect.condition
            assert isinstance(tmp_effect.effect, pddl.SimpleEffect)
            effect = tmp_effect.effect.effect
        elif isinstance(tmp_effect, pddl.SimpleEffect):
            #             print ("simple effect: ", tmp_effect)
            effect = tmp_effect.effect
            assert isinstance(effect, pddl.Literal)
        else:
            #             print ("numeric effect: ", tmp_effect)
            effect = tmp_effect.effect
            assert isinstance(effect, pddl.FunctionAssignment)
        # Check for contradictory effects
        condition = condition.simplified()
        new_effect = pddl.Effect(parameters, condition, effect)
        if isinstance(effect, pddl.FunctionAssignment):
            # The check for multiple effects on the same variable loops through all effects over and over again.
            # If this raises performance issues it has to be reconsidered
            #            print("Check for same effect on numeric variable %s" % effect.fluent)
            conflict = False
            for other_effect in result:
                if isinstance(other_effect, pddl.FunctionAssignment):
                    #                    print("comparing to %s -> Conflict? %s" % (other_effect.fluent, (effect.fluent == other_effect.fluent)))
                    if (effect.fluent == other_effect.fluent):
                        conflict = True
                        break
            if conflict:
                print(
                    "Warning, multiple effects on numeric variable %s, ignoring %s"
                    % (other_effect.fluent, effect.fluent))
            else:
                result.append(new_effect)
        else:
            assert isinstance(effect, pddl.Literal)
            contradiction = pddl.Effect(parameters, condition, effect.negate())
            if not contradiction in result:
                result.append(new_effect)
            else:
                # We use add-after-delete semantics, keep positive effect
                if isinstance(contradiction.peffect, pddl.NegatedAtom):
                    result.remove(contradiction)
                    result.append(new_effect)
예제 #18
0
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