Example #1
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"
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)
Example #3
0
def convert_condition(condition):
    import pddl
    class_name = condition.__class__.__name__
    if class_name in ('Truth', 'FunctionComparison'):
        # TODO: currently ignoring numeric conditions
        return pddl.Truth()
    elif class_name == 'Atom':
        return pddl.Atom(condition.predicate, convert_args(condition.args))
    elif class_name == 'NegatedAtom':
        return pddl.NegatedAtom(condition.predicate,
                                convert_args(condition.args))
    elif class_name == 'Conjunction':
        return pddl.conditions.Conjunction(
            list(map(convert_condition, condition.parts)))
    elif class_name == 'Disjunction':
        return pddl.Disjunction(list(map(convert_condition, condition.parts)))
    elif class_name == 'ExistentialCondition':
        return pddl.ExistentialCondition(
            convert_parameters(condition.parameters),
            list(map(convert_condition, condition.parts)))
    elif class_name == 'UniversalCondition':
        return pddl.UniversalCondition(
            convert_parameters(condition.parameters),
            list(map(convert_condition, condition.parts)))
    raise NotImplementedError(class_name)
Example #4
0
def get_problem(evaluations, goal_exp, domain, unit_costs=False):
    objects = objects_from_evaluations(evaluations)
    typed_objects = list(
        {make_object(pddl_from_object(obj))
         for obj in objects} - set(domain.constants))
    # TODO: this doesn't include =
    init = [
        fd_from_evaluation(e) for e in evaluations if not is_negated_atom(e)
    ]
    goal = pddl.Truth() if goal_exp is None else parse_goal(goal_exp, domain)
    problem_pddl = None
    if USE_FORBID:
        problem_pddl = get_problem_pddl(evaluations,
                                        goal_exp,
                                        domain.pddl,
                                        temporal=False)
    write_pddl(domain.pddl, problem_pddl)
    return Problem(task_name=domain.name,
                   task_domain_name=domain.name,
                   objects=sorted(typed_objects, key=lambda o: o.name),
                   task_requirements=pddl.tasks.Requirements([]),
                   init=init,
                   goal=goal,
                   use_metric=not unit_costs,
                   pddl=problem_pddl)
Example #5
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)
Example #6
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
Example #7
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
Example #8
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)
Example #9
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)))
Example #10
0
def make_effects(effects):
    return [
        pddl.Effect(parameters=[],
                    condition=pddl.Truth(),
                    literal=fd_from_fact(fact)) for fact in effects
    ]
Example #11
0
def parse_task_pddl(task_pddl, type_dict, predicate_dict):
    iterator = iter(task_pddl)

    define_tag = next(iterator)
    assert define_tag == "define"
    problem_line = next(iterator)
    assert problem_line[0] == "problem" and len(problem_line) == 2
    yield problem_line[1]
    domain_line = next(iterator)
    assert domain_line[0] == ":domain" and len(domain_line) == 2
    yield domain_line[1]

    requirements_opt = next(iterator)
    if requirements_opt[0] == ":requirements":
        requirements = requirements_opt[1:]
        objects_opt = next(iterator)
    else:
        requirements = []
        objects_opt = requirements_opt
    yield pddl.Requirements(requirements)

    if objects_opt[0] == ":objects":
        yield parse_typed_list(objects_opt[1:])
        init = next(iterator)
    else:
        yield []
        init = objects_opt

    assert init[0] == ":init"
    initial = []
    initial_true = set()
    initial_false = set()
    initial_assignments = dict()
    for fact in init[1:]:
        if fact[0] == "=":
            try:
                assignment = parse_assignment(fact)
            except ValueError as e:
                raise SystemExit("Error in initial state specification\n" +
                                 "Reason: %s." % e)
            if not isinstance(assignment.expression, pddl.NumericConstant):
                raise SystemExit("Illegal assignment in initial state " +
                                 "specification:\n%s" % assignment)
            if assignment.fluent in initial_assignments:
                prev = initial_assignments[assignment.fluent]
                if assignment.expression == prev.expression:
                    print("Warning: %s is specified twice" % assignment,
                          "in initial state specification")
                else:
                    raise SystemExit("Error in initial state specification\n" +
                                     "Reason: conflicting assignment for " +
                                     "%s." % assignment.fluent)
            else:
                initial_assignments[assignment.fluent] = assignment
                initial.append(assignment)
        elif fact[0] == "not":
            atom = pddl.Atom(fact[1][0], fact[1][1:])
            check_atom_consistency(atom, initial_false, initial_true, False)
            initial_false.add(atom)
        else:
            atom = pddl.Atom(fact[0], fact[1:])
            check_atom_consistency(atom, initial_true, initial_false)
            initial_true.add(atom)
    initial.extend(initial_true)
    yield initial

    goal = next(iterator)
    goal_cond = pddl.Truth()

    if goal[0] == ":goal":
        if len(goal) == 2:
            goal_cond = parse_condition(goal[1], type_dict, predicate_dict)
        utility = next(iterator)
    else:
        utility = goal

    yield goal_cond

    assert utility[0] == ":utility"
    utility_list = []
    for fact in utility[1:]:
        assert fact[0] == "="
        utility_atom = pddl.Atom(fact[1][0], fact[1][1:])
        utility_value = fact[2]
        utility_list.append((utility_atom, utility_value))
    yield utility_list

    bound = next(iterator)
    assert bound[0] == ":bound" and len(bound) == 2
    yield bound[1]

    use_metric = False

    for entry in iterator:
        if entry[0] == ":use-cost-metric":
            use_metric = True


#     for entry in iterator:
#         if entry[0] == ":metric":
#             if entry[1]=="maximize" and entry[2][0] == "total-utility":
#                 use_metric = True
#             else:
#                 assert False, "Unknown metric."

    yield use_metric

    for entry in iterator:
        assert False, entry
Example #12
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)