コード例 #1
0
def recursive_solve_stream_plan(evaluations, streams, functions,
                                stream_results, solve_stream_plan, depth):
    combined_plan, cost = solve_stream_plan(stream_results)
    stream_plan, action_plan = separate_plan(combined_plan,
                                             action_info=None,
                                             terminate=False,
                                             stream_only=False)
    #print('Depth: {}\n'
    #      'Stream plan: {}\n'
    #      'Action plan: {}'.format(depth, stream_plan, action_plan))
    if stream_plan is None:
        return stream_plan, cost, depth
    plan_index = get_stream_plan_index(stream_plan)
    if plan_index == 0:
        return combined_plan, cost, depth
    stream_results, bindings = optimistic_process_stream_plan(
        evaluations, stream_plan)
    double_bindings = {
        v: k
        for k, values in bindings.items() if 2 <= len(values) for v in values
    }
    stream_results += optimistic_process_streams(
        evaluations_from_stream_plan(evaluations, stream_results),
        streams,
        double_bindings=double_bindings)
    stream_results += optimistic_process_streams(
        evaluations_from_stream_plan(evaluations, stream_results), functions)
    return recursive_solve_stream_plan(evaluations, streams, functions,
                                       stream_results, solve_stream_plan,
                                       depth + 1)
コード例 #2
0
ファイル: relaxed.py プロジェクト: m1sk/pddlstream
def relaxed_stream_plan(evaluations, goal_expression, domain, stream_results, negative, unit_costs, **kwargs):
    # TODO: alternatively could translate with stream actions on real opt_state and just discard them
    opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results)
    problem = get_problem(opt_evaluations, goal_expression, domain, unit_costs)
    task = task_from_domain_problem(domain, problem)
    action_plan, action_cost = solve_from_task(task, **kwargs)
    if action_plan is None:
        return None, action_cost
    # TODO: just use solve finite?

    stream_plan = recover_stream_plan(evaluations, goal_expression, domain, stream_results, action_plan,
                                      negative, unit_costs)
    action_plan = obj_from_pddl_plan(action_plan)
    combined_plan = stream_plan + action_plan

    return combined_plan, action_cost
コード例 #3
0
def get_combined_orders(evaluations, stream_plan, action_plan, domain):
    if action_plan is None:
        return None
    # TODO: could just do this within relaxed
    # TODO: do I want to strip the fluents and just do the partial ordering?

    stream_instances = get_stream_instances(stream_plan)
    negative_results = filter(
        lambda r: isinstance(r, PredicateResult) and (r.value == False),
        stream_plan)
    negative_init = set(
        get_init((evaluation_from_fact(f) for r in negative_results
                  for f in r.get_certified()),
                 negated=True))
    #negated_from_name = {r.instance.external.name for r in negative_results}
    opt_evaluations = evaluations_from_stream_plan(evaluations, stream_plan)
    goal_expression = ('and', )
    task = task_from_domain_problem(
        domain,
        get_problem(opt_evaluations, goal_expression, domain, unit_costs=True))

    action_instances = get_action_instances(task, action_plan)
    replace_derived(task, negative_init, action_instances)

    #combined_instances = stream_instances + action_instances
    orders = set()
    for i, a1 in enumerate(action_plan):
        for a2 in action_plan[i + 1:]:
            orders.add((a1, a2))
    # TODO: just store first achiever here
    for i, instance1 in enumerate(stream_instances):
        for j in range(i + 1, len(stream_instances)):
            effects = {e for _, e in instance1.add_effects}
            if effects & set(stream_instances[j].precondition):
                orders.add((stream_plan[i], stream_plan[j]))
    for i, instance1 in enumerate(stream_instances):
        for j, instance2 in enumerate(action_instances):
            effects = {e for _, e in  instance1.add_effects} | \
                      {e.negate() for _, e in  instance1.del_effects}
            if effects & set(instance2.precondition):
                orders.add((stream_plan[i], action_plan[j]))
    return orders
コード例 #4
0
ファイル: sequential.py プロジェクト: m1sk/pddlstream
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
コード例 #5
0
ファイル: postprocess.py プロジェクト: m1sk/pddlstream
def locally_optimize(evaluations, store, goal_expression, domain, functions,
                     negative, dynamic_streams):
    action_plan = store.best_plan
    if action_plan is None:
        return None
    print('\nPostprocessing')  # TODO: postprocess current skeleton as well

    task = task_from_domain_problem(
        domain,
        get_problem(evaluations, goal_expression, domain, unit_costs=False))
    plan_instances = get_action_instances(
        task, action_plan) + [get_goal_instance(task.goal)]
    replace_derived(task, set(), plan_instances)
    preimage = filter(lambda a: not a.negated,
                      plan_preimage(plan_instances, []))

    opt_stream_plan = []
    opt_from_obj = {}
    for stream_result in extract_order(evaluations, preimage):
        input_objects = tuple(
            opt_from_obj.get(o, o)
            for o in stream_result.instance.input_objects)
        instance = stream_result.instance.external.get_instance(input_objects)
        #assert(not instance.disabled)
        instance.disabled = False
        opt_results = instance.next_optimistic()
        if not opt_results:
            continue
        opt_result = opt_results[0]
        opt_stream_plan.append(opt_result)
        for obj, opt in zip(stream_result.output_objects,
                            opt_result.output_objects):
            opt_from_obj[obj] = opt

    opt_stream_plan += optimistic_process_streams(
        evaluations_from_stream_plan(evaluations, opt_stream_plan), functions)
    opt_action_plan = [(name, tuple(opt_from_obj.get(o, o) for o in args))
                       for name, args in action_plan]
    pddl_plan = [(name, map(pddl_from_object, args))
                 for name, args in opt_action_plan]
    stream_plan = recover_stream_plan(evaluations,
                                      goal_expression,
                                      domain,
                                      opt_stream_plan,
                                      pddl_plan,
                                      negative,
                                      unit_costs=False)

    stream_plan = reorder_stream_plan(stream_plan)
    stream_plan = get_synthetic_stream_plan(stream_plan, dynamic_streams)
    print('Stream plan: {}\n'
          'Action plan: {}'.format(stream_plan, opt_action_plan))
    opt_cost = 0  # TODO: compute this cost for real

    store.start_time = time.time()
    store.max_cost = store.best_cost
    #sampling_time = 10
    sampling_time = 0
    queue = []
    heappush(queue, (SkeletonKey(0, len(stream_plan)),
                     Skeleton(instantiate_first({}, stream_plan), 0, {},
                              stream_plan, opt_action_plan, opt_cost)))
    greedily_process_queue(queue, evaluations, store, sampling_time)
コード例 #6
0
ファイル: relaxed.py プロジェクト: m1sk/pddlstream
def recover_stream_plan(evaluations, goal_expression, domain, stream_results, action_plan, negative,
                        unit_costs, optimize=True):
    import pddl_to_prolog
    import build_model
    import pddl
    import axiom_rules
    import instantiate
    # 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

    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))
    real_task = task_from_domain_problem(domain, get_problem(evaluations, goal_expression, domain, unit_costs))
    function_assignments = {fact.fluent: fact.expression for fact in opt_task.init  # init_facts
                            if isinstance(fact, pddl.f_expression.FunctionAssignment)}
    type_to_objects = instantiate.get_objects_by_type(opt_task.objects, opt_task.types)
    results_from_head = get_results_from_head(opt_evaluations)

    action_instances = []
    for name, args in action_plan: # TODO: negative atoms in actions
        candidates = []
        for action in opt_task.actions:
            if action.name != name:
                continue
            if len(action.parameters) != len(args):
                raise NotImplementedError('Existential quantifiers are not currently '
                                          'supported in preconditions: {}'.format(name))
            variable_mapping = {p.name: a for p, a in zip(action.parameters, args)}
            instance = action.instantiate(variable_mapping, set(),
                                          MockSet(), type_to_objects,
                                          opt_task.use_min_cost_metric, function_assignments)
            assert (instance is not None)
            candidates.append(((action, args), instance))
        if not candidates:
            raise RuntimeError('Could not find an applicable action {}'.format(name))
        action_instances.append(candidates)
    action_instances.append([(None, get_goal_instance(opt_task.goal))])

    axioms_from_name = get_derived_predicates(opt_task.axioms)
    negative_from_name = {n.name: n for n in negative}
    opt_task.actions = []
    opt_state = set(opt_task.init)
    real_state = set(real_task.init)
    preimage_plan = []
    function_plan = set()
    for layer in action_instances:
        for pair, instance in layer:
            nonderived_preconditions = [l for l in instance.precondition if l.predicate not in axioms_from_name]
            #nonderived_preconditions = instance.precondition
            if not conditions_hold(opt_state, nonderived_preconditions):
                continue
            opt_task.init = opt_state
            original_axioms = opt_task.axioms
            axiom_from_action = get_necessary_axioms(instance, original_axioms, negative_from_name)
            opt_task.axioms = []
            opt_task.actions = axiom_from_action.keys()
            # TODO: maybe it would just be better to drop the negative throughout this process until this end
            with Verbose(False):
                model = build_model.compute_model(pddl_to_prolog.translate(opt_task))  # Changes based on init
            opt_task.axioms = original_axioms

            opt_facts = instantiate.get_fluent_facts(opt_task, model) | (opt_state - real_state)
            mock_fluent = MockSet(lambda item: (item.predicate in negative_from_name) or
                                               (item in opt_facts))
            instantiated_axioms = instantiate_necessary_axioms(model, real_state, mock_fluent, axiom_from_action)
            with Verbose(False):
                helpful_axioms, axiom_init, _ = axiom_rules.handle_axioms([instance], instantiated_axioms, [])
            axiom_from_atom = get_achieving_axioms(opt_state, helpful_axioms, axiom_init, negative_from_name)
            axiom_plan = []  # Could always add all conditions
            extract_axioms(axiom_from_atom, instance.precondition, axiom_plan)
            # TODO: test if no derived solution

            # TODO: compute required stream facts in a forward way and allow opt facts that are already known required
            for effects in [instance.add_effects, instance.del_effects]:
                for i, (conditions, effect) in enumerate(effects[::-1]):
                    if any(c.predicate in axioms_from_name for c in conditions):
                        raise NotImplementedError('Conditional effects cannot currently involve derived predicates')
                    if conditions_hold(real_state, conditions):
                        # Holds in real state
                        effects[i] = ([], effect)
                    elif not conditions_hold(opt_state, conditions):
                        # Does not hold in optimistic state
                        effects.pop(i)
                    else:
                        # TODO: handle more general case where can choose to achieve particular conditional effects
                        raise NotImplementedError('Conditional effects cannot currently involve certified predicates')
            #if any(conditions for conditions, _ in instance.add_effects + instance.del_effects):
            #    raise NotImplementedError('Conditional effects are not currently supported: {}'.format(instance.name))

            # TODO: add axiom init to reset state?
            apply_action(opt_state, instance)
            apply_action(real_state, instance)
            preimage_plan.extend(axiom_plan + [instance])
            if not unit_costs and (pair is not None):
                function_plan.update(extract_function_results(results_from_head, *pair))
            break
        else:
            raise RuntimeError('No action instances are applicable')

    preimage = plan_preimage(preimage_plan, set())
    preimage -= set(real_task.init)
    negative_preimage = set(filter(lambda a: a.predicate in negative_from_name, preimage))
    preimage -= negative_preimage
    # visualize_constraints(map(fact_from_fd, preimage))
    # TODO: prune with rules
    # TODO: linearization that takes into account satisfied goals at each level
    # TODO: can optimize for all streams & axioms all at once

    for literal in negative_preimage:
        negative = negative_from_name[literal.predicate]
        instance = negative.get_instance(map(obj_from_pddl, literal.args))
        value = not literal.negated
        if instance.enumerated:
            assert (instance.value == value)
        else:
            function_plan.add(PredicateResult(instance, value, opt_index=instance.opt_index))

    node_from_atom = get_achieving_streams(evaluations, stream_results)
    preimage_facts = list(map(fact_from_fd, filter(lambda l: not l.negated, preimage)))
    stream_plan = []
    extract_stream_plan(node_from_atom, preimage_facts, stream_plan)
    if not optimize: # TODO: detect this based on unique or not
        return stream_plan + list(function_plan)

    # TODO: search in space of partially ordered plans
    # TODO: local optimization - remove one and see if feasible

    reschedule_problem = get_problem(evaluations, And(*preimage_facts), domain, unit_costs=True)
    reschedule_task = task_from_domain_problem(domain, reschedule_problem)
    reschedule_task.actions, stream_result_from_name = get_stream_actions(stream_results)
    new_plan, _ = solve_from_task(reschedule_task, planner='max-astar', debug=False)
    # TODO: investigate admissible heuristics
    if new_plan is None:
        return stream_plan + list(function_plan)

    new_stream_plan = [stream_result_from_name[name] for name, _ in new_plan]
    return new_stream_plan + list(function_plan)
コード例 #7
0
ファイル: focused_v2.py プロジェクト: m1sk/pddlstream
def solve_focused(problem,
                  stream_info={},
                  action_info={},
                  dynamic_streams=[],
                  max_time=INF,
                  max_cost=INF,
                  unit_costs=False,
                  commit=True,
                  effort_weight=None,
                  eager_layers=1,
                  visualize=False,
                  verbose=True,
                  postprocess=False,
                  **search_kwargs):
    """
    Solves a PDDLStream problem by first hypothesizing stream outputs and then determining whether they exist
    :param problem: a PDDLStream problem
    :param action_info: a dictionary from stream name to ActionInfo for planning and execution
    :param stream_info: a dictionary from stream name to StreamInfo altering how individual streams are handled
    :param max_time: the maximum amount of time to apply streams
    :param max_cost: a strict upper bound on plan cost
    :param commit: if True, it commits to instantiating a particular partial plan-skeleton.
    :param effort_weight: a multiplier for stream effort compared to action costs
    :param eager_layers: the number of eager stream application layers per iteration
    :param visualize: if True, it draws the constraint network and stream plan as a graphviz file
    :param verbose: if True, this prints the result of each stream application
    :param search_kwargs: keyword args for the search subroutine
    :return: a tuple (plan, cost, evaluations) where plan is a sequence of actions
        (or None), cost is the cost of the plan, and evaluations is init but expanded
        using stream applications
    """
    # TODO: return to just using the highest level samplers at the start
    start_time = time.time()
    num_iterations = 0
    best_plan = None
    best_cost = INF
    evaluations, goal_expression, domain, stream_name, externals = parse_problem(
        problem)
    action_info = get_action_info(action_info)
    update_stream_info(externals, stream_info)
    load_stream_statistics(stream_name, externals)
    eager_externals = filter(lambda e: e.info.eager, externals)
    disabled = []
    if visualize:
        clear_visualizations()
    #functions = filter(lambda s: isinstance(s, Function), externals)
    functions = filter(lambda s: type(s) is Function, externals)
    negative = filter(lambda s: type(s) is Predicate and s.is_negative(),
                      externals)
    streams = filter(lambda s: s not in (functions + negative), externals)
    stream_results = []
    depth = 1
    sampling_queue = []
    while elapsed_time(start_time) < max_time:
        search_time = time.time(
        )  # TODO: allocate more sampling effort to maintain the balance
        # TODO: total search time vs most recent search time?
        if stream_results is None:
            stream_plan, action_plan, cost = None, None, INF
        else:
            num_iterations += 1
            print(
                '\nIteration: {} | Depth: {} | Evaluations: {} | Cost: {} | Time: {:.3f}'
                .format(num_iterations, depth, len(evaluations), best_cost,
                        elapsed_time(start_time)))
            # TODO: constrain to use previous plan to some degree
            eagerly_evaluate(evaluations, eager_externals, eager_layers,
                             max_time - elapsed_time(start_time), verbose)
            stream_results += optimistic_process_streams(
                evaluations_from_stream_plan(evaluations, stream_results),
                functions)
            # TODO: warning check if using simultaneous_stream_plan or relaxed_stream_plan with non-eager functions
            solve_stream_plan = relaxed_stream_plan if effort_weight is None else simultaneous_stream_plan
            #solve_stream_plan = sequential_stream_plan if effort_weight is None else simultaneous_stream_plan
            combined_plan, cost = solve_stream_plan(evaluations,
                                                    goal_expression,
                                                    domain,
                                                    stream_results,
                                                    negative,
                                                    max_cost=best_cost,
                                                    unit_costs=unit_costs,
                                                    **search_kwargs)
            combined_plan = reorder_combined_plan(evaluations, combined_plan,
                                                  action_info, domain)
            print('Combined plan: {}'.format(combined_plan))
            stream_plan, action_plan = separate_plan(combined_plan,
                                                     action_info)
            stream_plan = reorder_stream_plan(
                stream_plan)  # TODO: is this strictly redundant?
            stream_plan = get_synthetic_stream_plan(stream_plan,
                                                    dynamic_streams)
            print('Stream plan: {}\n'
                  'Action plan: {}'.format(stream_plan, action_plan))

        if stream_plan is None:
            if disabled or (depth != 0):
                if depth == 0:
                    reset_disabled(disabled)
                stream_results = optimistic_process_streams(
                    evaluations, streams)
                depth = 0  # Recurse on problems
            else:
                break
        elif len(stream_plan) == 0:
            if cost < best_cost:
                best_plan = action_plan
                best_cost = cost
                if best_cost < max_cost:
                    break
            stream_results = None
        else:
            """
            sampling_key = SkeletonKey(0, len(stream_plan))
            sampling_problem = Skeleton({}, stream_plan, action_plan, cost)
            heappush(sampling_queue, (sampling_key, sampling_problem))
            greedily_process_queue(sampling_queue, evaluations, disabled, max_cost, True, 0, verbose)
            depth += 1
            stream_results = None
            """

            if visualize:
                create_visualizations(evaluations, stream_plan, num_iterations)
            option = True
            if option:
                # TODO: can instantiate all but subtract stream_results
                # TODO: can even pass a subset of the fluent state
                # TODO: can just compute the stream plan preimage
                # TODO: replan constraining the initial state and plan skeleton
                # TODO: reuse subproblems
                # TODO: always start from the initial state (i.e. don't update)
                old_evaluations = set(evaluations)
                stream_results, _ = process_stream_plan(
                    evaluations, stream_plan, disabled, verbose)
                new_evaluations = set(evaluations) - old_evaluations
                if stream_results is not None:
                    new_instances = [r.instance for r in stream_results]
                    stream_results = optimistic_process_streams(
                        new_evaluations, streams, new_instances)
            if not commit:
                stream_results = None
            depth += 1

    reset_disabled(disabled)
    if postprocess and (not unit_costs) and (best_plan is not None):
        best_plan = locally_optimize(evaluations, best_plan, goal_expression,
                                     domain, functions, negative,
                                     dynamic_streams, verbose)
    write_stream_statistics(stream_name, externals)
    return revert_solution(best_plan, best_cost, evaluations)