Exemple #1
0
def compile_to_exogenous_actions(evaluations, domain, streams):
    # TODO: version of this that operates on fluents of length one?
    # TODO: better instantiation when have full parameters
    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)
    future_fn = lambda a: rename_atom(a, future_map)
    new_streams = []
    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
        new_streams.append(create_static_stream(stream, evaluations, fluent_predicates, future_fn))
        stream_atom = new_streams[-1].certified[0]
        add_predicate(domain, make_predicate(get_prefix(stream_atom), get_args(stream_atom)))
        preconditions = [stream_atom] + list(stream.domain)
        effort = 1 # TODO: use stream info
        #effort = 1 if unit_cost else result.instance.get_effort()
        #if effort == INF:
        #    continue
        domain.actions.append(make_action(
            name='call-{}'.format(stream.name),
            parameters=get_args(stream_atom),
            preconditions=preconditions,
            effects=stream.certified,
            cost=effort))
        stream.certified = tuple(set(stream.certified) |
                                 set(map(future_fn, stream.certified)))
    if REPLACE_STREAM:
        streams.extend(new_streams)
    else:
        streams[:] = new_streams
Exemple #2
0
def retrace_instantiation(fact, streams, evaluations, free_parameters,
                          visited_facts, planned_results):
    # Makes two assumptions:
    # 1) Each stream achieves a "primary" fact that uses all of its inputs + outputs
    # 2) Outputs are only free parameters (no constants)
    if (evaluation_from_fact(fact) in evaluations) or (fact in visited_facts):
        return
    visited_facts.add(fact)
    for stream in streams:
        for cert in stream.certified:
            if get_prefix(fact) == get_prefix(cert):
                mapping = get_mapping(get_args(cert),
                                      get_args(fact))  # Should be same anyways
                if not all(p in mapping
                           for p in (stream.inputs + stream.outputs)):
                    # TODO: assumes another effect is sufficient for binding
                    # Create arbitrary objects for inputs/outputs that aren't mentioned
                    # Can lead to incorrect ordering
                    continue

                input_objects = tuple(mapping[p] for p in stream.inputs)
                output_objects = tuple(mapping[p] for p in stream.outputs)
                if not all(out in free_parameters for out in output_objects):
                    # Can only bind if free
                    continue
                instance = stream.get_instance(input_objects)
                for new_fact in instance.get_domain():
                    retrace_instantiation(new_fact, streams, evaluations,
                                          free_parameters, visited_facts,
                                          planned_results)
                planned_results.append(instance.get_result(output_objects))
Exemple #3
0
def retrace_instantiation(fact, streams, evaluations, visited_facts,
                          planned_results):
    if (evaluation_from_fact(fact) in evaluations) or (fact in visited_facts):
        return
    visited_facts.add(fact)
    for stream in streams:
        for cert in stream.certified:
            if get_prefix(fact) == get_prefix(cert):
                mapping = get_mapping(get_args(cert),
                                      get_args(fact))  # Should be same anyways
                if not all(p in mapping
                           for p in (stream.inputs + stream.outputs)):
                    # TODO: assumes another effect is sufficient for binding
                    # Create arbitrary objects for inputs/outputs that aren't mentioned
                    # Can lead to incorrect ordering
                    continue

                input_objects = tuple(mapping[p] for p in stream.inputs)
                output_objects = tuple(mapping[p] for p in stream.outputs)
                if not all(
                        isinstance(out, OptimisticObject)
                        for out in output_objects):
                    # Can only bind if free
                    continue
                instance = stream.get_instance(input_objects)
                for new_fact in instance.get_domain():
                    retrace_instantiation(new_fact, streams, evaluations,
                                          visited_facts, planned_results)
                result = instance.get_result(output_objects)
                planned_results.append(result)
Exemple #4
0
    def add_atom(self, atom):
        if not is_atom(atom):
            return False
        head = atom.head
        if head in self.atoms:
            return False
        self.atoms.add(head)
        # TODO: doing this in a way that will eventually allow constants

        for i, stream in enumerate(self.streams):
            for j, domain_atom in enumerate(stream.domain):
                if get_prefix(head) != get_prefix(domain_atom):
                    continue
                if len(head.args) != len(get_args(domain_atom)):
                    raise ValueError(head, domain_atom)
                if any(
                        isinstance(b, Object) and (a != b)
                        for (a, b) in zip(head.args, get_args(domain_atom))):
                    continue
                self.atoms_from_domain[(i, j)].append(head)
                values = [
                    self.atoms_from_domain[(i, k)] if j != k else [head]
                    for k in range(len(stream.domain))
                ]
                domain = list(map(head_from_fact, stream.domain))
                #domain = stream.domain
                for combo in product(*values):
                    mapping = get_mapping(domain, combo)
                    if mapping is None:
                        continue
                    input_objects = tuple(mapping[p] for p in stream.inputs)
                    self._add_instance(stream, input_objects)
        return True
Exemple #5
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 #6
0
def compile_to_exogenous_axioms(evaluations, domain, streams):
    # TODO: no attribute certified
    # TODO: recover the streams that are required
    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)
    future_fn = lambda a: rename_atom(a, future_map)
    derived_map = {p: 'd-{}'.format(p) for p in certified_predicates}
    derived_fn = lambda a: rename_atom(a, derived_map)
    # TODO: could prune streams that don't need this treatment

    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)
    new_streams = []
    for stream in list(streams):
        if not isinstance(stream, Stream):
            raise NotImplementedError(stream)
        new_streams.append(
            create_static_stream(stream, evaluations, fluent_predicates,
                                 future_fn))
        stream_atom = new_streams[-1].certified[0]
        add_predicate(
            domain,
            make_predicate(get_prefix(stream_atom), get_args(stream_atom)))
        preconditions = [stream_atom] + list(map(derived_fn, stream.domain))
        for certified_fact in stream.certified:
            derived_fact = derived_fn(certified_fact)
            external_params = get_args(derived_fact)
            internal_params = tuple(p for p in (stream.inputs + stream.outputs)
                                    if p not in get_args(derived_fact))
            domain.axioms.extend([
                make_axiom(parameters=external_params,
                           preconditions=[certified_fact],
                           derived=derived_fact),
                make_axiom(parameters=external_params + internal_params,
                           preconditions=preconditions,
                           derived=derived_fact),
            ])
        stream.certified = tuple(
            set(stream.certified) | set(map(future_fn, stream.certified)))
    if REPLACE_STREAM:
        streams.extend(new_streams)
    else:
        streams[:] = new_streams
Exemple #7
0
def get_mapping(atoms1, atoms2):
    assert len(atoms1) == len(atoms2)
    mapping = {}
    for a1, a2 in zip(atoms1, atoms2):
        assert (get_prefix(a1) == get_prefix(a2))
        #for arg1, arg2 in zip(get_args(a1), a2.args): # TODO: this is because eval vs predicate
        for arg1, arg2 in zip(a1.args, a2.args):
            if mapping.get(arg1, arg2) == arg2:
                mapping[arg1] = arg2
            else:
                return None
    return mapping
Exemple #8
0
def fd_from_fact(fact):
    # TODO: convert to evaluation?
    prefix = get_prefix(fact)
    if prefix == NOT:
        return fd_from_fact(fact[1]).negate()
    if prefix == EQ:
        _, head, value = fact
        predicate = get_prefix(head)
        args = list(map(pddl_from_object, get_args(head)))
        fluent = pddl.f_expression.PrimitiveNumericExpression(symbol=predicate, args=args)
        expression = pddl.f_expression.NumericConstant(value)
        return pddl.f_expression.Assign(fluent, expression)
    args = list(map(pddl_from_object, get_args(fact)))
    return pddl.Atom(prefix, args)
Exemple #9
0
    def fn(literal, action):
        if literal.predicate not in predicate_map:
            return literal
        # TODO: other checks on only inputs
        stream = predicate_map[literal.predicate]
        mapping = remap_certified(literal, stream)
        if mapping is None:
            # TODO: this excludes typing. This is not entirely safe
            return literal
        output_args = set(mapping[arg] for arg in stream.outputs)
        if isinstance(action, pddl.Action): # TODO: unified Action/Axiom effects
            for effect in action.effects:
                if isinstance(effect, pddl.Effect) and (output_args & set(effect.literal.args)):
                    raise RuntimeError('Fluent stream outputs cannot be in action effects: {}'.format(
                        effect.literal.predicate))
        elif not stream.is_negated:
            axiom = action
            raise RuntimeError('Fluent stream outputs cannot be in an axiom: {}'.format(axiom.name))

        blocked_args = safe_apply_mapping(stream.inputs, mapping)
        blocked_literal = literal.__class__(stream.blocked_predicate, blocked_args).negate()
        if stream.is_negated:
            conditions = [blocked_literal]
            conditions.extend(pddl.Atom(get_prefix(fact), safe_apply_mapping(get_args(fact), mapping)) # fd_from_fact
                              for fact in stream.domain) # TODO: be careful when using imply
            return pddl.Conjunction(conditions) # TODO: prune redundant conditions
        return pddl.Conjunction([literal, blocked_literal])
Exemple #10
0
 def remap_inputs(self, bindings):
     input_objects = remap_objects(self.instance.input_objects, bindings)
     fluent_facts = [(get_prefix(f),) + remap_objects(get_args(f), bindings)
                     for f in self.instance.fluent_facts]
     new_instance = self.external.get_instance(input_objects, fluent_facts=fluent_facts)
     new_instance.opt_index = self.instance.opt_index
     return self.__class__(new_instance, self.output_objects, self.opt_index)
Exemple #11
0
def create_static_stream(stream, evaluations, fluent_predicates, future_fn):
    def static_fn(*input_values):
        instance = stream.get_instance(tuple(map(Object.from_value, input_values)))
        if all(evaluation_from_fact(f) in evaluations for f in instance.get_domain()):
            return None
        return tuple(FutureValue(stream.name, input_values, o) for o in stream.outputs)

    #opt_evaluations = None
    def static_opt_gen_fn(*input_values):
        instance = stream.get_instance(tuple(map(Object.from_value, input_values)))
        if all(evaluation_from_fact(f) in evaluations for f in instance.get_domain()):
            return
        for output_values in stream.opt_gen_fn(*input_values):
            yield output_values
        # TODO: need to replace regular opt_gen_fn to update opt_evaluations
        # if I want to prevent switch from normal to static in opt

    # Focused algorithm naturally biases against using future because of axiom layers
    fluent_domain = list(filter(lambda a: get_prefix(a) in fluent_predicates, stream.domain))
    static_domain = list(filter(lambda a: a not in fluent_domain, stream.domain))
    new_domain = list(map(future_fn, static_domain))
    stream_atom = ('{}-result'.format(stream.name),) + tuple(stream.inputs + stream.outputs)
    new_certified = [stream_atom] + list(map(future_fn, stream.certified))
    static_stream = FutureStream(stream, new_domain, fluent_domain, new_certified)
    if REPLACE_STREAM:
        static_stream.gen_fn = from_fn(static_fn)
        static_stream.opt_gen_fn = static_opt_gen_fn
    return static_stream
Exemple #12
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 #13
0
 def next_results(self, verbose=False):
     start_time = time.time()
     assert not self.enumerated
     self.enumerated = True
     input_values = self.get_input_values()
     value = self.external.fn(*input_values)
     self.value = self.external.codomain(value)
     # TODO: cast the inputs and test whether still equal?
     #if not (type(self.value) is self.external._codomain):
     #if not isinstance(self.value, self.external.codomain):
     if self.value < 0:
         raise ValueError(
             'Function [{}] produced a negative value [{}]'.format(
                 self.external.name, self.value))
     if (self.value is not False) and verbose:
         start_call = 0
         print('{}) {}{}={}'.format(
             start_call, get_prefix(self.external.head),
             str_from_object(self.get_input_values()), self.value))
     results = [
         self._Result(self, self.value, opt_index=None, optimistic=False)
     ]
     #if isinstance(self, PredicateInstance) and (self.value != self.external.opt_fn(*input_values)):
     #    self.update_statistics(start_time, [])
     self.update_statistics(start_time, results)
     new_facts = []
     return results, new_facts
Exemple #14
0
def combine_optimizer_plan(stream_plan, functions):
    if not stream_plan:
        return stream_plan
    optimizer = get_optimizer(stream_plan[-1])
    if optimizer is None:
        return stream_plan
    function_plan = list(
        filter(
            lambda r: get_prefix(r.instance.external.head) in optimizer.
            objectives, functions))
    external_plan = stream_plan + function_plan
    if CLUSTER:
        partial_orders = get_partial_orders(external_plan)
        cluster_plans = get_connected_components(external_plan, partial_orders)
    else:
        cluster_plans = [external_plan]
    optimizer_plan = []
    for cluster_plan in cluster_plans:
        if all(isinstance(r, FunctionResult) for r in cluster_plan):
            continue
        #if len(cluster_plan) == 1:
        #    optimizer_plan.append(cluster_plan[0])
        #    continue
        stream = OptimizerStream(optimizer, cluster_plan)
        instance = stream.get_instance(stream.input_objects,
                                       fluent_facts=stream.fluent_facts)
        result = instance.get_result(stream.output_objects)
        optimizer_plan.append(result)
    return optimizer_plan
Exemple #15
0
def check_problem(domain, streams, obj_from_constant):
    for action in domain.actions + domain.axioms:
        for p, c in Counter(action.parameters).items():
            if c != 1:
                raise ValueError('Parameter [{}] for action [{}] is not unique'.format(p.name, action.name))
        # TODO: check that no undeclared parameters & constants
        #action.dump()
    undeclared_predicates = set()
    for stream in streams:
        # TODO: domain.functions
        facts = list(stream.domain)
        if isinstance(stream, Stream):
            facts.extend(stream.certified)
        for fact in facts:
            name = get_prefix(fact)
            if name not in domain.predicate_dict:
                undeclared_predicates.add(name)
            elif len(get_args(fact)) != domain.predicate_dict[name].get_arity(): # predicate used with wrong arity: {}
                print('Warning! predicate used with wrong arity in stream [{}]: {}'.format(stream.name, fact))
        for constant in stream.constants:
            if constant not in obj_from_constant:
                raise ValueError('Undefined constant in stream [{}]: {}'.format(stream.name, constant))
    if undeclared_predicates:
        print('Warning! Undeclared predicates: {}'.format(
            sorted(undeclared_predicates))) # Undeclared predicate: {}
def extract_static_facts(plan, certificate, initial_confs):
    # TODO: use certificate instead
    # TODO: only keep objects used on the plan
    #static_facts = []
    static_facts = [
        f for f in certificate.all_facts
        if get_prefix(get_function(f)) in ['distance', 'trajtrajcollision']
    ]
    for name, actions in partition_plan(plan).items():
        last_element = None
        last_conf = initial_confs[name]
        for i, action in enumerate(actions):
            if action.name == 'print':
                r, n1, e, n2, q1, q2, t = action.args
                static_facts.extend([
                    ('PrintAction', ) + action.args,
                    ('Assigned', r, e),
                    ('Conf', r, q1),
                    ('Conf', r, q2),
                    ('Traj', r, t),
                    ('CTraj', r, t),
                    # (Start ?r ?n1 ?e ?q1) (End ?r ?e ?n2 ?q2)
                    ('Transition', r, q2, last_conf),
                ])
                if last_element is not None:
                    static_facts.append(('Order', e, last_element))
                last_element = e
                last_conf = q1
                # TODO: save collision information
            else:
                raise NotImplementedError(action.name)
        static_facts.extend([
            ('Transition', name, initial_confs[name], last_conf),
        ])
    return static_facts
Exemple #17
0
 def next_results(self, accelerate=1, verbose=False):
     start_time = time.time()
     assert not self.enumerated
     self.enumerated = True
     input_values = self.get_input_values()
     #try:
     value = self.external.fn(*input_values)
     #except TypeError as err:
     #    print('Function [{}] expects {} inputs'.format(self.external.name, len(input_values)))
     #    raise err
     self.value = self.external._codomain(value)
     # TODO: cast the inputs and test whether still equal?
     #if not (type(self.value) is self.external._codomain):
     #if not isinstance(self.value, self.external._codomain):
     #if self.value != value:
     #    raise ValueError('Function [{}] produced a nonintegral value [{}]. '
     #                     'FastDownward only supports integral costs. '
     #                     'To "use" real costs, scale each cost by a large factor, '
     #                     'capturing the most significant bits.'.format(self.external.name, self.value))
     if self.value < 0:
         raise ValueError(
             'Function [{}] produced a negative value [{}]'.format(
                 self.external.name, self.value))
     if (self.value is not False) and verbose:
         print('0) {}{}={}'.format(get_prefix(self.external.head),
                                   str_from_object(self.get_input_values()),
                                   self.value))
     results = [self.external._Result(self, self.value)]
     #if isinstance(self, PredicateInstance) and (self.value != self.external.opt_fn(*input_values)):
     #    self.update_statistics(start_time, [])
     self.update_statistics(start_time, results)
     new_facts = []
     return results, new_facts
Exemple #18
0
def reuse_facts(problem, certificate, skeleton):
    # TODO: repackage streams
    # TODO: recover the full axiom + action plan
    # TODO: recover the plan preimage annotated with use time
    # Some supporting args are quantified out and thus lack some facts
    new_facts = []
    if skeleton is None:
        return new_facts
    reuse_objs = set()
    for action, args in skeleton:
        for arg in args:
            if (arg != WILD) and not is_parameter(arg):
                reuse_objs.add(hash_or_id(arg))

    # The reuse relpose omission is due to the fact that the initial pose was selected
    # (which is populated in the initial state)
    order_predicate = ORDER_PREDICATE.format('')
    domain = parse_domain(problem.domain_pddl)
    fluents = get_fluents(domain)
    for fact in certificate.preimage_facts:
        predicate = get_prefix(fact)
        if (predicate in {order_predicate, EQ}) or (predicate in fluents):
            # Could technically evaluate functions as well
            continue
        if all(
                isinstance(arg, str) or (hash_or_id(arg) in reuse_objs)
                for arg in get_args(fact)):
            new_facts.append(fact)
    return new_facts
Exemple #19
0
def remap_certified(literal, stream):
    certified = find_unique(lambda f: get_prefix(f) == literal.predicate,
                            stream.certified)
    mapping = get_mapping(get_args(certified), literal.args)
    if not all(arg in mapping
               for arg in stream.inputs):  # Certified must contain all inputs
        return None
    return mapping
Exemple #20
0
def visualize_constraints(constraints, filename='constraint_network.pdf', use_functions=True):
    from pygraphviz import AGraph

    graph = AGraph(strict=True, directed=False)
    graph.node_attr['style'] = 'filled'
    #graph.node_attr['fontcolor'] = 'black'
    #graph.node_attr['fontsize'] = 12
    graph.node_attr['colorscheme'] = 'SVG'
    graph.edge_attr['colorscheme'] = 'SVG'
    #graph.graph_attr['rotate'] = 90
    #graph.node_attr['fixedsize'] = True
    graph.node_attr['width'] = 0
    graph.node_attr['height'] = 0.02 # Minimum height is 0.02
    graph.node_attr['margin'] = 0
    graph.graph_attr['rankdir'] = 'RL'
    graph.graph_attr['nodesep'] = 0.05
    graph.graph_attr['ranksep'] = 0.25
    #graph.graph_attr['pad'] = 0
    # splines="false";
    graph.graph_attr['outputMode'] = 'nodesfirst'
    graph.graph_attr['dpi'] = 300

    functions = set()
    negated = set()
    heads = set()
    for fact in constraints:
        prefix = get_prefix(fact)
        if prefix in (EQ, MINIMIZE):
            functions.add(fact[1])
        elif prefix == NOT:
            negated.add(fact[1])
        else:
            heads.add(fact)
    heads.update(functions)
    heads.update(negated)

    objects = {a for head in heads for a in get_args(head)}
    optimistic_objects = filter(lambda o: isinstance(o, OptimisticObject), objects)
    for opt_obj in optimistic_objects:
        graph.add_node(str(opt_obj), shape='circle', color=PARAMETER_COLOR)

    for head in heads:
        if not use_functions and (head in functions):
            continue
        # TODO: prune values w/o free parameters?
        name = str_from_fact(head)
        if head in functions:
            color = COST_COLOR
        elif head in negated:
            color = NEGATED_COLOR
        else:
            color = CONSTRAINT_COLOR
        graph.add_node(name, shape='box', color=color)
        for arg in get_args(head):
            if arg in optimistic_objects:
                graph.add_edge(name, str(arg))
    graph.draw(filename, prog='dot') # neato | dot | twopi | circo | fdp | nop
    return graph
Exemple #21
0
def recover_stream_plan(evaluations, current_plan, opt_evaluations,
                        goal_expression, domain, node_from_atom, action_plan,
                        axiom_plans, negative):
    # Universally quantified conditions are converted into negative axioms
    # Existentially quantified conditions are made additional preconditions
    # Universally quantified effects are instantiated by doing the cartesian produce of types (slow)
    # Added effects cancel out removed effects
    # TODO: node_from_atom is a subset of opt_evaluations (only missing functions)
    real_task = task_from_domain_problem(
        domain, get_problem(evaluations, goal_expression, domain))
    opt_task = task_from_domain_problem(
        domain, get_problem(opt_evaluations, goal_expression, domain))
    negative_from_name = get_negative_predicates(negative)

    real_states, combined_plan = recover_negative_axioms(
        real_task, opt_task, axiom_plans, action_plan, negative_from_name)
    function_plan = compute_function_plan(opt_evaluations, action_plan)

    full_preimage = plan_preimage(combined_plan, [])
    stream_preimage = set(full_preimage) - real_states[0]
    negative_preimage = set(
        filter(lambda a: a.predicate in negative_from_name, stream_preimage))
    function_plan.update(
        convert_negative(negative_preimage, negative_from_name, full_preimage,
                         real_states))
    positive_preimage = stream_preimage - negative_preimage

    step_from_fact = {
        fact_from_fd(l): full_preimage[l]
        for l in positive_preimage if not l.negated
    }
    target_facts = {
        fact
        for fact in step_from_fact.keys() if get_prefix(fact) != EQ
    }
    #stream_plan = reschedule_stream_plan(evaluations, target_facts, domain, stream_results)
    # visualize_constraints(map(fact_from_fd, target_facts))

    stream_plan = []
    for result in current_plan:
        if isinstance(result.external, Function) or (result.external
                                                     in negative):
            function_plan.add(
                result)  # Prevents these results from being pruned
        else:
            stream_plan.append(result)
    curr_evaluations = evaluations_from_stream_plan(evaluations,
                                                    stream_plan,
                                                    max_effort=None)
    extraction_facts = target_facts - set(
        map(fact_from_evaluation, curr_evaluations))
    extract_stream_plan(node_from_atom, extraction_facts, stream_plan)
    stream_plan = postprocess_stream_plan(evaluations, domain, stream_plan,
                                          target_facts)
    stream_plan = convert_fluent_streams(stream_plan, real_states, action_plan,
                                         step_from_fact, node_from_atom)

    return stream_plan + list(function_plan)
Exemple #22
0
def enforce_simultaneous(domain, externals):
    axiom_predicates = set()
    for axiom in domain.axioms:
        axiom_predicates.update(get_predicates(axiom.condition))
    for external in externals:
        if (type(external) in [VariableStream, ConstraintStream]) and not external.info.simultaneous:
            predicates = {get_prefix(fact) for fact in external.certified}
            if predicates & axiom_predicates:
                external.info.simultaneous = True
Exemple #23
0
def make_axiom(parameters, preconditions, derived):
    predicate = get_prefix(derived)
    external_parameters = list(get_args(derived))
    internal_parameters = [p for p in parameters if p not in external_parameters]
    parameters = external_parameters + internal_parameters
    return pddl.Axiom(name=predicate,
                      parameters=make_parameters(parameters),
                      num_external_parameters=len(external_parameters),
                      condition=make_preconditions(preconditions))
Exemple #24
0
def partition_facts(domain, facts):
    fluents = get_fluents(domain)
    static_facts = []
    fluent_facts = []
    for fact in facts:
        if get_prefix(get_function(fact)).lower() in fluents:
            fluent_facts.append(fact)
        else:
            static_facts.append(fact)
    return static_facts, fluent_facts
Exemple #25
0
def get_predicate_map(state_streams):
    predicate_map = {}
    for state_stream in state_streams:
        for fact in state_stream.certified:
            predicate = get_prefix(fact)
            if predicate in predicate_map:
                # TODO: could make a disjunctive condition instead
                raise NotImplementedError('Only one fluent stream can certify a predicate: {}'.format(predicate))
            predicate_map[predicate] = state_stream
    return predicate_map
Exemple #26
0
def get_predicate_map(state_streams):
    predicate_map = {}
    for state_stream in state_streams:
        for fact in state_stream.certified:
            predicate = get_prefix(fact)
            if predicate in predicate_map:
                # TODO: could make a conjunction condition instead
                raise NotImplementedError()
            predicate_map[predicate] = state_stream
    return predicate_map
Exemple #27
0
def get_formula_operators(formula):
    if formula is None:
        return set()
    prefix = get_prefix(formula)
    if prefix not in OPERATORS:
        return set()
    operators = {prefix}
    for subformula in formula[1:]:
        operators.update(get_formula_operators(subformula))
    return operators
Exemple #28
0
def make_cost(cost):
    if cost is None:
        return cost
    fluent = pddl.PrimitiveNumericExpression(symbol=TOTAL_COST, args=[])
    try:
        expression = pddl.NumericConstant(cost)
    except TypeError:
        expression = pddl.PrimitiveNumericExpression(
            symbol=get_prefix(cost), args=list(map(pddl_from_object, get_args(cost))))
    return pddl.Increase(fluent=fluent, expression=expression)
Exemple #29
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)
    certified_predicates = {
        get_prefix(a)
        for s in streams for a in s.certified
    }
    future_map = {p: 'f-{}'.format(p) for p in certified_predicates}
    augment_evaluations(evaluations, future_map)
    rename_future = lambda a: rename_atom(a, future_map)
    for stream in list(streams):
        if not isinstance(stream, Stream):
            raise NotImplementedError(stream)
        # TODO: could also just have conditions asserting that one of the fluent conditions fails
        streams.append(
            create_static_stream(stream, evaluations, fluent_predicates,
                                 rename_future))
        stream_atom = streams[-1].certified[0]
        parameters = [
            pddl.TypedObject(p, OBJECT) for p in get_args(stream_atom)
        ]
        # TODO: add to predicates as well?
        domain.predicate_dict[get_prefix(stream_atom)] = pddl.Predicate(
            get_prefix(stream_atom), parameters)
        preconditions = [stream_atom] + list(stream.domain)
        effort = 1  # TODO: use stream info
        #effort = 1 if unit_cost else result.instance.get_effort()
        #if effort == INF:
        #    continue
        domain.actions.append(
            pddl.Action(name='call-{}'.format(stream.name),
                        parameters=parameters,
                        num_external_parameters=len(parameters),
                        precondition=make_preconditions(preconditions),
                        effects=make_effects(stream.certified),
                        cost=make_cost(effort)))
        stream.certified = tuple(
            set(stream.certified) | set(map(rename_future, stream.certified)))
Exemple #30
0
def parse_common(lisp_list, stream_map, stream_info):
    assert (2 <= len(lisp_list) <= 3)
    head = tuple(lisp_list[1])
    assert (is_head(head))
    name = get_prefix(head)
    fn = get_procedure_fn(stream_map, name)
    domain = []
    if len(lisp_list) == 3:
        domain = list_from_conjunction(lisp_list[2])
    info = stream_info.get(name, None)
    return head, fn, domain, info