Exemple #1
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)
Exemple #2
0
def compile_to_exogenous_axioms(evaluations, domain, streams):
    # TODO: no attribute certified
    import pddl
    fluent_predicates = get_fluents(domain)
    certified_predicates = {
        get_prefix(a)
        for s in streams for a in s.certified
    }
    future_map = {p: 'f-{}'.format(p) for p in certified_predicates}
    augment_evaluations(evaluations, future_map)
    rename_future = lambda a: rename_atom(a, future_map)
    derived_map = {p: 'd-{}'.format(p) for p in certified_predicates}
    rename_derived = lambda a: rename_atom(a, derived_map)

    for action in domain.actions:
        action.precondition = replace_predicates(derived_map,
                                                 action.precondition)
        for effect in action.effects:
            assert (isinstance(effect, pddl.Effect))
            effect.condition = replace_predicates(derived_map,
                                                  effect.condition)
    for axiom in domain.axioms:
        axiom.condition = replace_predicates(derived_map, axiom.condition)

    #fluent_predicates.update(certified_predicates)
    for stream in list(streams):
        if not isinstance(stream, Stream):
            raise NotImplementedError(stream)
        streams.append(
            create_static_stream(stream, evaluations, fluent_predicates,
                                 rename_future))
        stream_atom = streams[-1].certified[0]
        domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate(
            get_prefix(stream_atom), get_args(stream_atom))
        preconditions = [stream_atom] + list(map(rename_derived,
                                                 stream.domain))
        for fact in stream.certified:
            derived_fact = fd_from_fact(rename_derived(fact))
            external_params = derived_fact.args
            internal_params = tuple(p for p in (stream.inputs + stream.outputs)
                                    if p not in derived_fact.args)
            parameters = tuple(
                pddl.TypedObject(p, OBJECT)
                for p in (external_params + internal_params))
            #precondition = pddl.Conjunction(tuple(map(fd_from_fact, [stream_atom] +
            #                                        list(map(rename_derived, stream.domain)))))
            #precondition = pddl.Disjunction([fd_from_fact(fact), precondition]) # TODO: quantifier
            domain.axioms.extend([
                pddl.Axiom(name=derived_fact.predicate,
                           parameters=parameters,
                           num_external_parameters=len(external_params),
                           condition=make_preconditions(preconditions)),
                pddl.Axiom(name=derived_fact.predicate,
                           parameters=parameters[:len(external_params)],
                           num_external_parameters=len(external_params),
                           condition=fd_from_fact(fact)),
            ])
        stream.certified = tuple(
            set(stream.certified) | set(map(rename_future, stream.certified)))
Exemple #3
0
def analyze_goal(problem, use_actions=False, use_axioms=True, use_streams=True, blocked_predicates=[], **kwargs):
    # TODO: instantiate all goal partial states
    # TODO: remove actions/axioms that never could achieve a subgoal
    domain_pddl, constant_map, stream_pddl, stream_map, init, goal = problem
    evaluations = evaluations_from_init(init)
    init = set(fd_from_evaluations(evaluations))

    # from pddlstream.algorithms.scheduling.recover_axioms import recover_axioms_plans
    results, instantiated = examine_instantiated(problem, **kwargs) # TODO: only do if the goals are derived
    if instantiated is None:
        return None
    #optimistic_init = set(instantiated.task.init)

    # This is like backchaining in a relaxed space
    condition_from_effect = defaultdict(set)
    if use_actions:
        # TODO: selectively ignore some conditions (e.g. HandEmpty)
        for action in instantiated.actions:
            for conditional, effect in action.add_effects:
                for condition in (action.precondition + conditional):
                    if condition.predicate not in blocked_predicates:
                        condition_from_effect[effect].add(condition)
            for conditional, effect in action.del_effects:
                for condition in (action.precondition + conditional):
                    if condition.predicate not in blocked_predicates:
                        condition_from_effect[effect.negate()].add(condition)
    if use_axioms:
        # TODO: axiom_rules.handle_axioms(...)
        # print('Axioms:', instantiated.axioms)
        for axiom in instantiated.axioms:
            #axiom = reinstantiate_axiom(axiom)
            #axiom.dump()
            for condition in axiom.condition:
                condition_from_effect[axiom.effect].add(condition)
    if use_streams:
        for result in results:
            for effect in result.certified:
                if get_prefix(effect) == EQ:
                    continue
                for condition in result.domain:
                    condition_from_effect[fd_from_fact(effect)].add(fd_from_fact(condition))

    print('Goals:', list(map(fact_from_fd, instantiated.goal_list)))
    #all_subgoals = iterate_subgoals(instantiated.goal_list, axiom_from_effect)
    all_subgoals = recurse_subgoals(instantiated.goal_list, condition_from_effect)
    filtered_subgoals = [subgoal for subgoal in all_subgoals if subgoal in init] # TODO: return the goals as well?
    external_subgoals = [value_from_obj_expression(fact_from_fd(subgoal))
                         for subgoal in sorted(filtered_subgoals, key=lambda g: g.predicate)
                         if not subgoal.predicate.startswith(INTERNAL_AXIOM)]
    print('Initial:', external_subgoals)

    return external_subgoals # TODO: decompose into simplified components
Exemple #4
0
def add_optimizer_effects(instantiated, node_from_atom):
    # TODO: instantiate axioms with negative on effects for blocking
    # TODO: fluent streams using conditional effects. Special fluent predicate for inputs to constraint
    # TODO: bug! The FD instantiator prunes the result.external.stream_fact
    for instance in instantiated.actions:
        # TODO: need to handle case where a negative preconditions is used in an optimizer
        for condition, effect in (instance.add_effects + instance.del_effects):
            for literal in condition:
                fact = fact_from_fd(literal)
                if (fact in node_from_atom) and (node_from_atom[fact].result
                                                 is not None):
                    raise NotImplementedError(literal)
        facts = get_instance_facts(instance, node_from_atom)
        stream_plan = []
        extract_stream_plan(node_from_atom, facts, stream_plan)
        # TODO: can detect if some of these are simultaneous and add them as preconditions
        for result in stream_plan:
            #if isinstance(result.external, ComponentStream):
            if True:  # TODO: integrate sampler and optimizer treatments
                # TODO: need to make multiple versions if several ways of achieving the action
                atom = fd_from_fact(result.stream_fact)
                instantiated.atoms.add(atom)
                effect = (tuple(), atom)
                instance.add_effects.append(effect)
                instance.effect_mappings.append(effect + (None, None))
Exemple #5
0
def instantiate_optimizer_axioms(instantiated, domain, results):
    # Needed for instantiating axioms before adding stream action effects
    # Otherwise, FastDownward will prune these unreachable axioms
    # TODO: compute this first and then apply the eager actions
    stream_init = {
        fd_from_fact(result.stream_fact)
        for result in results if isinstance(result, StreamResult)
    }
    evaluations = list(
        map(evaluation_from_fd, stream_init | instantiated.atoms))
    temp_domain = make_domain(
        predicates=[make_predicate(UNSATISFIABLE, [])],
        axioms=[ax for ax in domain.axioms if ax.name == UNSATISFIABLE])
    temp_problem = get_problem(evaluations, Not((UNSATISFIABLE, )),
                               temp_domain)
    # TODO: UNSATISFIABLE might be in atoms making the goal always infeasible
    with Verbose():
        # TODO: the FastDownward instantiation prunes static preconditions
        use_fd = False if using_optimizers(results) else FD_INSTANTIATE
        new_instantiated = instantiate_task(task_from_domain_problem(
            temp_domain, temp_problem),
                                            use_fd=use_fd,
                                            check_infeasible=False,
                                            prune_static=False)
        assert new_instantiated is not None
    instantiated.axioms.extend(new_instantiated.axioms)
    instantiated.atoms.update(new_instantiated.atoms)
Exemple #6
0
def process_conditional_effect(effect, negative_from_predicate):
    import pddl
    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)
    return new_parts, stream_facts
Exemple #7
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)
Exemple #8
0
def get_stream_instances(stream_plan):
    import pddl
    # TODO: something that inverts the negative items
    stream_instances = [] # TODO: could even apply these to the state directly
    for result in stream_plan:
        name = result.instance.external.name
        precondition = list(map(fd_from_fact, result.instance.get_domain()))
        effects = [([], fd_from_fact(fact)) for fact in result.get_certified() if get_prefix(fact) != EQ]
        cost = None # TODO: effort?
        instance = pddl.PropositionalAction(name, precondition, effects, cost)
        stream_instances.append(instance)
    return stream_instances
Exemple #9
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
    ]
Exemple #10
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)
Exemple #11
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
Exemple #12
0
def add_optimizer_axioms(results, instantiated):
    # Ends up being a little slower than version in optimizer.py when not blocking shared
    # TODO: add this to simultaneous
    import pddl
    results_from_instance = defaultdict(list)
    for result in results:
        results_from_instance[result.instance].append(result)
    optimizer_results = list(filter(is_optimizer_result, results))
    optimizers = {result.external.optimizer for result in optimizer_results}
    for optimizer in optimizers:
        optimizer_facts = {
            substitute_expression(result.external.stream_fact,
                                  result.get_mapping())
            for result in optimizer_results
            if result.external.optimizer is optimizer
        }
        facts_from_arg = defaultdict(list)
        for fact in optimizer_facts:
            for arg in get_args(fact):
                facts_from_arg[arg].append(fact)

        for stream in optimizer.streams:
            if not stream.instance.disabled:
                continue
            constraints = stream.instance.get_constraints()
            output_variables = []
            for out in stream.output_objects:
                assert isinstance(out.param, UniqueOptValue)
                output_variables.append([
                    r.output_objects[out.param.output_index]
                    for r in results_from_instance[out.param.instance]
                ])
            for combo in product(*output_variables):
                mapping = get_mapping(stream.output_objects, combo)
                name = '({})'.join(UNSATISFIABLE)
                blocked = set(substitute_expression(constraints, mapping))
                additional = {
                    fact
                    for arg in combo for fact in facts_from_arg[arg]
                } - blocked
                # TODO: like a partial disable, if something has no outputs, then adding things isn't going to help
                if stream.instance.enumerated and not stream.instance.successes:
                    # Assumes the optimizer is submodular
                    condition = list(map(fd_from_fact, blocked))
                else:
                    condition = list(
                        map(fd_from_fact, blocked | set(map(Not, additional))))
                effect = fd_from_fact((UNSATISFIABLE, ))
                instantiated.axioms.append(
                    pddl.PropositionalAxiom(name, condition, effect))
                instantiated.atoms.add(effect)
Exemple #13
0
def add_optimizer_effects(instantiated, instance, stream_plan):
    # 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
    # TODO: bug! The FD instantiator prunes the result.external.stream_fact
    for result in stream_plan:
        if not is_optimizer_result(result):
            continue
        # TODO: need to make multiple versions if several ways of achieving the action
        atom = fd_from_fact(
            substitute_expression(result.external.stream_fact,
                                  result.get_mapping()))
        instantiated.atoms.add(atom)
        effect = (tuple(), atom)
        instance.add_effects.append(effect)
Exemple #14
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)))
Exemple #15
0
def optimizer_conditional_effects(domain, externals):
    import pddl
    #from pddlstream.algorithms.scheduling.negative import get_negative_predicates
    # TODO: extend this to predicates
    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)
        for effect in action.effects:
            if isinstance(effect, pddl.Effect) and (effect.literal.predicate
                                                    == UNSATISFIABLE):
                condition = effect.condition
                new_parts = []
                stream_fact = None
                for literal in get_conjuctive_parts(condition):
                    if isinstance(literal, pddl.Literal) and (
                            literal.predicate in negative_from_predicate):
                        if stream_fact is not None:
                            raise NotImplementedError()
                        stream = negative_from_predicate[literal.predicate]
                        certified = find_unique(
                            lambda f: get_prefix(f) == literal.predicate,
                            stream.certified)
                        mapping = get_mapping(get_args(certified),
                                              literal.args)
                        stream_fact = substitute_expression(
                            stream.stream_fact, mapping)
                    else:
                        new_parts.append(literal)
                if stream_fact is not None:
                    effect.condition = pddl.Conjunction(new_parts)
                    effect.literal = fd_from_fact(stream_fact)