示例#1
0
def locally_optimize(evaluations, store, goal_expression, domain, functions, negative,
                     dynamic_streams, visualize, sampling_time=0):
    action_plan = store.best_plan
    if action_plan is None:
        return None
    print('\nPostprocessing | Cost: {} | Total Time: {:.3f}'.format(store.best_cost, store.elapsed_time()))
    # TODO: postprocess current skeletons as well

    task = task_from_domain_problem(domain, get_problem(evaluations, goal_expression, domain, unit_costs=False))
    opt_stream_plan, opt_from_obj = recover_opt_stream_plan(evaluations, action_plan, task)
    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, tuple(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 = get_synthetic_stream_plan(reorder_stream_plan(stream_plan), dynamic_streams)


    # TODO: need to make this just streams
    opt_evaluations = apply_streams(evaluations, stream_plan)
    opt_cost = get_plan_cost(opt_evaluations, opt_action_plan, domain, unit_costs=False)
    dump_plans(stream_plan, opt_action_plan, opt_cost)
    if visualize:
        log_plans(stream_plan, action_plan, None)
        create_visualizations(evaluations, stream_plan, None)

    store.start_time = time.time()
    store.max_cost = store.best_cost
    queue = SkeletonQueue(store, evaluations, goal_expression, domain)
    queue.new_skeleton(stream_plan, opt_action_plan, opt_cost)
    queue.greedily_process()
    queue.timed_process(sampling_time)
示例#2
0
def solve_skeleton(evaluations={}, opt_solutions=[], max_time=INF, success_cost=0,
                   max_complexity=INF, reorder=False, visualize=True):
    store = SolutionStore(evaluations=evaluations, max_time=max_time, success_cost=success_cost, verbose=True)
    skeleton_queue = SkeletonQueue(store, domain=None, disable=True)

    for opt_solution in opt_solutions:
        # TODO: add and then process later
        stream_plan, opt_plan, cost = opt_solution

        # stream_plan = replan_with_optimizers(evaluations, stream_plan, domain, externals) or stream_plan
        stream_plan = combine_optimizers(evaluations, stream_plan)
        # stream_plan = get_synthetic_stream_plan(stream_plan, # evaluations
        #                                       [s for s in synthesizers if not s.post_only])
        # stream_plan = recover_optimistic_outputs(stream_plan)
        if reorder:
            # TODO: this blows up memory wise for long stream plans
            stream_plan = reorder_stream_plan(store, stream_plan)

        num_optimistic = sum(r.optimistic for r in stream_plan) if stream_plan else 0
        action_plan = opt_plan.action_plan if is_plan(opt_plan) else opt_plan
        print('Stream plan ({}, {}, {:.3f}): {}\nAction plan ({}, {:.3f}): {}'.format(
            get_length(stream_plan), num_optimistic, compute_plan_effort(stream_plan), stream_plan,
            get_length(action_plan), cost, str_from_plan(action_plan)))
        if is_plan(stream_plan) and visualize:
            num_iterations = 0
            log_plans(stream_plan, action_plan, num_iterations)
            #create_visualizations(evaluations, stream_plan, num_iterations)
            visualize_stream_plan(stream_plan)

        ################

        # # optimizer_plan = replan_with_optimizers(evaluations, stream_plan, domain, optimizers)
        # optimizer_plan = None
        # if optimizer_plan is not None:
        #     # TODO: post process a bound plan
        #     print('Optimizer plan ({}, {:.3f}): {}'.format(
        #         get_length(optimizer_plan), compute_plan_effort(optimizer_plan), optimizer_plan))
        #     skeleton_queue.new_skeleton(optimizer_plan, opt_plan, cost)

        # TODO: these are quite different
        #skeleton_queue.process(stream_plan, opt_plan, cost, complexity_limit=INF, max_time=INF)
        skeleton_queue.process(stream_plan, opt_plan, cost, complexity_limit=max_complexity, max_time=0)
    return store.extract_solution()
示例#3
0
def solve_abstract(problem,
                   constraints=PlanConstraints(),
                   stream_info={},
                   replan_actions=set(),
                   unit_costs=False,
                   success_cost=INF,
                   max_time=INF,
                   max_iterations=INF,
                   max_memory=INF,
                   initial_complexity=0,
                   complexity_step=1,
                   max_complexity=INF,
                   max_skeletons=INF,
                   search_sample_ratio=0,
                   bind=True,
                   max_failures=0,
                   unit_efforts=False,
                   max_effort=INF,
                   effort_weight=None,
                   reorder=True,
                   visualize=False,
                   verbose=True,
                   **search_kwargs):
    """
    Solves a PDDLStream problem by first planning with optimistic stream outputs and then querying streams
    :param problem: a PDDLStream problem
    :param constraints: PlanConstraints on the set of legal solutions
    :param stream_info: a dictionary from stream name to StreamInfo altering how individual streams are handled
    :param replan_actions: the actions declared to induce replanning for the purpose of deferred stream evaluation

    :param unit_costs: use unit action costs rather than numeric costs
    :param success_cost: the exclusive (strict) upper bound on plan cost to successfully terminate

    :param max_time: the maximum runtime
    :param max_iterations: the maximum number of search iterations
    :param max_memory: the maximum amount of memory

    :param initial_complexity: the initial stream complexity limit
    :param complexity_step: the increase in the stream complexity limit per iteration
    :param max_complexity: the maximum stream complexity limit

    :param max_skeletons: the maximum number of plan skeletons (max_skeletons=None indicates not adaptive)
    :param search_sample_ratio: the desired ratio of sample time / search time when max_skeletons!=None
    :param bind: if True, propagates parameter bindings when max_skeletons=None
    :param max_failures: the maximum number of stream failures before switching phases when max_skeletons=None

    :param unit_efforts: use unit stream efforts rather than estimated numeric efforts
    :param max_effort: the maximum amount of stream effort
    :param effort_weight: a multiplier for stream effort compared to action costs
    :param reorder: if True, reorder stream plans to minimize the expected sampling overhead

    :param visualize: if True, draw the constraint network and stream plan as a graphviz file
    :param verbose: if True, print 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 (INF if no plan), and evaluations is init expanded
        using stream applications
    """
    # TODO: select whether to search or sample based on expected success rates
    # TODO: no optimizers during search with relaxed_stream_plan
    # TODO: locally optimize only after a solution is identified
    # TODO: replan with a better search algorithm after feasible
    # TODO: change the search algorithm and unit costs based on the best cost
    use_skeletons = (max_skeletons is not None)
    #assert implies(use_skeletons, search_sample_ratio > 0)
    eager_disabled = (effort_weight is None
                      )  # No point if no stream effort biasing
    num_iterations = eager_calls = 0
    complexity_limit = initial_complexity

    evaluations, goal_exp, domain, externals = parse_problem(
        problem,
        stream_info=stream_info,
        constraints=constraints,
        unit_costs=unit_costs,
        unit_efforts=unit_efforts)
    identify_non_producers(externals)
    enforce_simultaneous(domain, externals)
    compile_fluent_streams(domain, externals)
    # TODO: make effort_weight be a function of the current cost
    # if (effort_weight is None) and not has_costs(domain):
    #     effort_weight = 1

    load_stream_statistics(externals)
    if visualize and not has_pygraphviz():
        visualize = False
        print(
            'Warning, visualize=True requires pygraphviz. Setting visualize=False'
        )
    if visualize:
        reset_visualizations()
    streams, functions, negative, optimizers = partition_externals(
        externals, verbose=verbose)
    eager_externals = list(filter(lambda e: e.info.eager, externals))
    positive_externals = streams + functions + optimizers
    has_optimizers = bool(optimizers)  # TODO: deprecate
    assert implies(has_optimizers, use_skeletons)

    ################

    store = SolutionStore(evaluations,
                          max_time,
                          success_cost,
                          verbose,
                          max_memory=max_memory)
    skeleton_queue = SkeletonQueue(store, domain, disable=not has_optimizers)
    disabled = set()  # Max skeletons after a solution
    while (not store.is_terminated()) and (
            num_iterations < max_iterations) and (complexity_limit <=
                                                  max_complexity):
        num_iterations += 1
        eager_instantiator = Instantiator(
            eager_externals, evaluations)  # Only update after an increase?
        if eager_disabled:
            push_disabled(eager_instantiator, disabled)
        if eager_externals:
            eager_calls += process_stream_queue(
                eager_instantiator,
                store,
                complexity_limit=complexity_limit,
                verbose=verbose)

        ################

        print(
            '\nIteration: {} | Complexity: {} | Skeletons: {} | Skeleton Queue: {} | Disabled: {} | Evaluations: {} | '
            'Eager Calls: {} | Cost: {:.3f} | Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'
            .format(num_iterations, complexity_limit,
                    len(skeleton_queue.skeletons), len(skeleton_queue),
                    len(disabled), len(evaluations), eager_calls,
                    store.best_cost, store.search_time, store.sample_time,
                    store.elapsed_time()))
        optimistic_solve_fn = get_optimistic_solve_fn(
            goal_exp,
            domain,
            negative,
            replan_actions=replan_actions,
            reachieve=use_skeletons,
            max_cost=min(store.best_cost, constraints.max_cost),
            max_effort=max_effort,
            effort_weight=effort_weight,
            **search_kwargs)
        # TODO: just set unit effort for each stream beforehand
        if (max_skeletons is None) or (len(skeleton_queue.skeletons) <
                                       max_skeletons):
            disabled_axioms = create_disabled_axioms(
                skeleton_queue) if has_optimizers else []
            if disabled_axioms:
                domain.axioms.extend(disabled_axioms)
            stream_plan, opt_plan, cost = iterative_plan_streams(
                evaluations,
                positive_externals,
                optimistic_solve_fn,
                complexity_limit,
                max_effort=max_effort)
            for axiom in disabled_axioms:
                domain.axioms.remove(axiom)
        else:
            stream_plan, opt_plan, cost = OptSolution(
                INFEASIBLE, INFEASIBLE, INF)  # TODO: apply elsewhere

        ################

        #stream_plan = replan_with_optimizers(evaluations, stream_plan, domain, externals) or stream_plan
        stream_plan = combine_optimizers(evaluations, stream_plan)
        #stream_plan = get_synthetic_stream_plan(stream_plan, # evaluations
        #                                       [s for s in synthesizers if not s.post_only])
        #stream_plan = recover_optimistic_outputs(stream_plan)
        if reorder:
            # TODO: this blows up memory wise for long stream plans
            stream_plan = reorder_stream_plan(store, stream_plan)

        num_optimistic = sum(r.optimistic
                             for r in stream_plan) if stream_plan else 0
        action_plan = opt_plan.action_plan if is_plan(opt_plan) else opt_plan
        print('Stream plan ({}, {}, {:.3f}): {}\nAction plan ({}, {:.3f}): {}'.
              format(get_length(stream_plan), num_optimistic,
                     compute_plan_effort(stream_plan), stream_plan,
                     get_length(action_plan), cost,
                     str_from_plan(action_plan)))
        if is_plan(stream_plan) and visualize:
            log_plans(stream_plan, action_plan, num_iterations)
            create_visualizations(evaluations, stream_plan, num_iterations)

        ################

        if (stream_plan is INFEASIBLE) and (not eager_instantiator) and (
                not skeleton_queue) and (not disabled):
            break
        if not is_plan(stream_plan):
            print('No plan: increasing complexity from {} to {}'.format(
                complexity_limit, complexity_limit + complexity_step))
            complexity_limit += complexity_step
            if not eager_disabled:
                reenable_disabled(evaluations, domain, disabled)

        #print(stream_plan_complexity(evaluations, stream_plan))
        if not use_skeletons:
            process_stream_plan(store,
                                domain,
                                disabled,
                                stream_plan,
                                opt_plan,
                                cost,
                                bind=bind,
                                max_failures=max_failures)
            continue

        ################

        #optimizer_plan = replan_with_optimizers(evaluations, stream_plan, domain, optimizers)
        optimizer_plan = None
        if optimizer_plan is not None:
            # TODO: post process a bound plan
            print('Optimizer plan ({}, {:.3f}): {}'.format(
                get_length(optimizer_plan),
                compute_plan_effort(optimizer_plan), optimizer_plan))
            skeleton_queue.new_skeleton(optimizer_plan, opt_plan, cost)

        allocated_sample_time = (search_sample_ratio * store.search_time) - store.sample_time \
            if len(skeleton_queue.skeletons) <= max_skeletons else INF
        if skeleton_queue.process(stream_plan, opt_plan, cost,
                                  complexity_limit,
                                  allocated_sample_time) is INFEASIBLE:
            break

    ################

    summary = store.export_summary()
    summary.update({
        'iterations': num_iterations,
        'complexity': complexity_limit,
        'skeletons': len(skeleton_queue.skeletons),
    })
    print('Summary: {}'.format(str_from_object(
        summary, ndigits=3)))  # TODO: return the summary

    write_stream_statistics(externals, verbose)
    return store.extract_solution()
示例#4
0
def constraint_satisfaction(stream_pddl, stream_map, init, terms, stream_info={},
                            costs=True, max_cost=INF, success_cost=INF, max_time=INF,
                            unit_efforts=False, max_effort=INF,
                            max_skeletons=INF, search_sample_ratio=1, verbose=True, **search_args):
    # Approaches
    # 1) Existential quantification of bindings in goal conditions
    # 2) Backtrack useful streams and then schedule. Create arbitrary outputs for not mentioned.
    # 3) Construct all useful streams and then associate outputs with bindings
    #    Useful stream must satisfy at least one fact. How should these assignments be propagated though?
    #    Make an action that maps each stream result to unbound values?
    # TODO: include functions again for cost-sensitive satisfaction
    # TODO: convert init into streams to bind certain facts
    # TODO: investigate constraint satisfaction techniques for binding instead
    # TODO: could also instantiate all possible free parameters even if not useful
    # TODO: effort that is a function of the number of output parameters (degrees of freedom)
    # TODO: use a CSP solver instead of a planner internally
    # TODO: max_iterations?
    if not terms:
        return {}, 0, init
    constraints, negated, functions = partition_facts(set(map(obj_from_existential_expression, terms)))
    if not costs:
        functions = []
    evaluations = evaluations_from_init(init)
    goal_facts = set(filter(lambda f: evaluation_from_fact(f) not in evaluations, constraints))
    free_parameters = sorted(get_parameters(goal_facts))
    print('Parameters:', free_parameters)

    externals = parse_stream_pddl(stream_pddl, stream_map, stream_info, unit_efforts=unit_efforts)
    stream_results = extract_streams(evaluations, externals, goal_facts)
    function_plan = plan_functions(negated + functions, externals)
    plan_skeleton = [Assignment(free_parameters)]
    cost = get_optimistic_cost(function_plan)
    if max_cost < cost:
        return None, INF, init
    # TODO: detect connected components
    # TODO: eagerly evaluate fully bound constraints

    # TODO: consider other results if this fails
    domain = create_domain(goal_facts)
    init_evaluations = evaluations.copy()
    store = SolutionStore(evaluations, max_time=max_time, success_cost=success_cost, verbose=verbose)
    queue = SkeletonQueue(store, domain, disable=False)
    num_iterations = search_time = sample_time = 0
    planner = 'ff-astar'  # TODO: toggle within reschedule_stream_plan
    #last_clusters = set()
    #last_success = True
    while not store.is_terminated():
        num_iterations += 1
        start_time = time.time()
        print('\nIteration: {} | Skeletons: {} | Skeleton Queue: {} | Evaluations: {} | '
              'Cost: {:.3f} | Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'.format(
            num_iterations, len(queue.skeletons), len(queue),
            len(evaluations), store.best_cost, search_time, sample_time, store.elapsed_time()))
        external_plan = None
        if len(queue.skeletons) < max_skeletons:
            domain.axioms[:] = create_disabled_axioms(queue, use_parameters=False)
            #dominated = are_domainated(last_clusters, clusters)
            #last_clusters = clusters
            #if last_success or not dominated: # Could also keep a history of results
            stream_plan = reschedule_stream_plan(init_evaluations, goal_facts, domain, stream_results,
                                                 unique_binding=True, unsatisfiable=True,
                                                 max_effort=max_effort, planner=planner, **search_args)
            if stream_plan is not None:
                external_plan = reorder_stream_plan(combine_optimizers(
                    init_evaluations, stream_plan + list(function_plan)))
        print('Stream plan ({}, {:.3f}): {}'.format(
            get_length(external_plan), compute_plan_effort(external_plan), external_plan))
        last_success = (external_plan is not None)
        search_time += elapsed_time(start_time)

        # Once a constraint added for a skeleton, it should only be relaxed
        start_time = time.time()
        if last_success: # Only works if create_disable_axioms never changes
            allocated_sample_time = (search_sample_ratio * search_time) - sample_time
        else:
            allocated_sample_time = INF
        queue.process(external_plan, plan_skeleton, cost=cost,
                      complexity_limit=INF,  max_time=allocated_sample_time)
        sample_time += elapsed_time(start_time)
        if not last_success and not queue:
            break
        # TODO: exhaustively compute all plan skeletons and add to queue within the focused algorithm

    write_stream_statistics(externals, verbose)
    action_plan, cost, facts = revert_solution(store.best_plan, store.best_cost, evaluations)
    bindings = bindings_from_plan(plan_skeleton, action_plan)
    return bindings, cost, facts
示例#5
0
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 = SkeletonQueue(evaluations, store)
    queue.new_skeleton(stream_plan, opt_action_plan, opt_cost)
    queue.greedily_process(sampling_time)
示例#6
0
def solve_focused(problem,
                  stream_info={},
                  action_info={},
                  synthesizers=[],
                  max_time=INF,
                  max_cost=INF,
                  unit_costs=False,
                  unit_efforts=False,
                  effort_weight=None,
                  eager_layers=1,
                  search_sampling_ratio=1,
                  use_skeleton=True,
                  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 synthesizers: a list of StreamSynthesizer objects
    :param max_time: the maximum amount of time to apply streams
    :param max_cost: a strict upper bound on plan cost
    :param unit_costs: use unit costs rather than numeric costs
    :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 search_sampling_ratio: the desired ratio of search time / sample time
    :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 postprocess: postprocess the stream plan to find a better solution
    :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
    # TODO: select whether to search or sample based on expected success rates
    solve_stream_plan_fn = relaxed_stream_plan
    #solve_stream_plan_fn = relaxed_stream_plan if effort_weight is None else simultaneous_stream_plan
    #solve_stream_plan_fn = sequential_stream_plan # simultaneous_stream_plan | sequential_stream_plan
    #solve_stream_plan_fn = incremental_stream_plan # incremental_stream_plan | exhaustive_stream_plan
    # TODO: warning check if using simultaneous_stream_plan or sequential_stream_plan with non-eager functions
    # TODO: no optimizers during search with relaxed_stream_plan
    num_iterations = 0
    search_time = sample_time = 0
    store = SolutionStore(max_time, max_cost,
                          verbose)  # TODO: include other info here?
    evaluations, goal_expression, domain, externals = parse_problem(
        problem, stream_info)
    unit_costs |= not has_costs(domain)
    full_action_info = get_action_info(action_info)
    load_stream_statistics(externals + synthesizers)
    if visualize and not has_pygraphviz():
        visualize = False
        print(
            'Warning, visualize=True requires pygraphviz. Setting visualize=False'
        )
    if visualize:
        reset_visualizations()
    eager_externals = list(filter(lambda e: e.info.eager, externals))
    streams, functions, negative = partition_externals(externals)
    if verbose:
        print('Streams: {}\nFunctions: {}\nNegated: {}'.format(
            streams, functions, negative))
    queue = SkeletonQueue(store, evaluations, goal_expression, domain)
    disabled = set()
    while not store.is_terminated():
        start_time = time.time()
        num_iterations += 1
        print(
            '\nIteration: {} | Queue: {} | Evaluations: {} | Cost: {} '
            '| Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'.
            format(num_iterations, len(queue), len(evaluations),
                   store.best_cost, search_time, sample_time,
                   store.elapsed_time()))

        layered_process_stream_queue(
            Instantiator(evaluations, eager_externals), evaluations, store,
            eager_layers)
        solve_stream_plan = lambda sr: solve_stream_plan_fn(
            evaluations,
            goal_expression,
            domain,
            sr,
            negative,
            max_cost=store.
            best_cost,  #max_cost=min(store.best_cost, max_cost),
            unit_costs=unit_costs,
            unit_efforts=unit_efforts,
            effort_weight=effort_weight,
            **search_kwargs)
        #combined_plan, cost = solve_stream_plan(optimistic_process_streams(evaluations, streams + functions))
        combined_plan, cost = iterative_solve_stream_plan(
            evaluations, streams, functions, solve_stream_plan)
        if action_info:
            combined_plan = reorder_combined_plan(evaluations, combined_plan,
                                                  full_action_info, domain)
            print('Combined plan: {}'.format(combined_plan))
        stream_plan, action_plan = separate_plan(combined_plan,
                                                 full_action_info)
        #stream_plan = replan_with_optimizers(evaluations, stream_plan, domain, externals)
        stream_plan = combine_optimizers(evaluations, stream_plan)
        #stream_plan = get_synthetic_stream_plan(stream_plan, # evaluations
        #                                        [s for s in synthesizers if not s.post_only])
        stream_plan = reorder_stream_plan(
            stream_plan)  # TODO: is this redundant when combined_plan?
        dump_plans(stream_plan, action_plan, cost)
        if (stream_plan is not None) and visualize:
            log_plans(stream_plan, action_plan, num_iterations)
            create_visualizations(evaluations, stream_plan, num_iterations)
        search_time += elapsed_time(start_time)

        # TODO: more generally just add the original plan skeleton to the plan
        # TODO: cutoff search exploration time at a certain point
        start_time = time.time()
        allocated_sample_time = search_sampling_ratio * search_time - sample_time
        if use_skeleton:
            terminate = not process_skeleton_queue(store, queue, stream_plan,
                                                   action_plan, cost,
                                                   allocated_sample_time)
        else:
            terminate = not process_disabled(
                store, evaluations, domain, disabled, stream_plan, action_plan,
                cost, allocated_sample_time, effort_weight is not None)
        sample_time += elapsed_time(start_time)
        if terminate:
            break

    if postprocess and (not unit_costs):  # and synthesizers
        locally_optimize(evaluations, store, goal_expression, domain,
                         functions, negative, synthesizers, visualize)
    write_stream_statistics(externals + synthesizers, verbose)
    return revert_solution(store.best_plan, store.best_cost, evaluations)
示例#7
0
def solve_focused(problem,
                  stream_info={},
                  action_info={},
                  synthesizers=[],
                  max_time=INF,
                  max_cost=INF,
                  unit_costs=None,
                  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 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
    search_sampling_ratio = 1
    solve_stream_plan_fn = relaxed_stream_plan if effort_weight is None else simultaneous_stream_plan
    # TODO: warning check if using simultaneous_stream_plan or sequential_stream_plan with non-eager functions
    num_iterations = 0
    search_time = sample_time = 0
    store = SolutionStore(max_time, max_cost,
                          verbose)  # TODO: include other info here?
    evaluations, goal_expression, domain, stream_name, externals = parse_problem(
        problem, stream_info)
    compile_to_exogenous(evaluations, domain, externals)
    if unit_costs is None:
        unit_costs = not has_costs(domain)
    full_action_info = get_action_info(action_info)
    load_stream_statistics(stream_name, externals + synthesizers)
    if visualize:
        clear_visualizations()
    # TODO: somehow Functions became no longer eager?
    eager_externals = list(
        filter(lambda e: e.info.eager or type(e) == Function, externals))
    streams, functions, negative = partition_externals(externals)
    queue = SkeletonQueue(store, evaluations)
    # TODO: decide max_sampling_time based on total search_time or likelihood estimates
    # TODO: switch to searching if believe chance of search better than sampling
    while not store.is_terminated():
        num_iterations += 1
        print(
            '\nIteration: {} | Queue: {} | Evaluations: {} | Cost: {} '
            '| Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'.
            format(num_iterations, len(queue), len(evaluations),
                   store.best_cost, search_time, sample_time,
                   store.elapsed_time()))

        start_time = time.time()
        layered_process_stream_queue(
            Instantiator(evaluations, eager_externals), evaluations, store,
            eager_layers)
        solve_stream_plan = lambda sr: solve_stream_plan_fn(
            evaluations,
            goal_expression,
            domain,
            sr,
            negative,
            max_cost=store.best_cost,
            #max_cost=min(store.best_cost, max_cost),
            unit_costs=unit_costs,
            **search_kwargs)
        #combined_plan, cost = solve_stream_plan(populate_results(evaluations, streams + functions))
        combined_plan, cost = iterative_solve_stream_plan(
            evaluations, streams, functions, solve_stream_plan)
        if action_info:
            combined_plan = reorder_combined_plan(evaluations, combined_plan,
                                                  full_action_info, domain)
            print('Combined plan: {}'.format(combined_plan))
        stream_plan, action_plan = separate_plan(combined_plan,
                                                 full_action_info)
        stream_plan = reorder_stream_plan(
            stream_plan)  # TODO: is this strictly redundant?
        stream_plan = get_synthetic_stream_plan(stream_plan, synthesizers)
        print('Stream plan: {}\n'
              'Action plan: {}'.format(stream_plan, action_plan))
        search_time += elapsed_time(start_time)

        start_time = time.time()
        if stream_plan is None:
            if not queue:
                break
            queue.process_until_success()
            #queue.fairly_process()
        else:
            if visualize:
                create_visualizations(evaluations, stream_plan, num_iterations)
            queue.new_skeleton(stream_plan, action_plan, cost)
            queue.greedily_process()
        sample_time += elapsed_time(start_time)

        start_time = time.time()
        queue.timed_process(search_sampling_ratio * search_time - sample_time)
        sample_time += elapsed_time(start_time)

    if postprocess and (not unit_costs):
        locally_optimize(evaluations, store, goal_expression, domain,
                         functions, negative, synthesizers)
    write_stream_statistics(stream_name, externals + synthesizers, verbose)
    return revert_solution(store.best_plan, store.best_cost, evaluations)
示例#8
0
def solve_focused(problem, constraints=PlanConstraints(),
                  stream_info={}, action_info={}, synthesizers=[],
                  max_time=INF, max_iterations=INF, max_skeletons=INF,
                  unit_costs=False, success_cost=INF,
                  complexity_step=1,
                  unit_efforts=False, max_effort=INF, effort_weight=None,
                  reorder=True, search_sample_ratio=0,
                  visualize=False, verbose=True, **search_kwargs):
    """
    Solves a PDDLStream problem by first hypothesizing stream outputs and then determining whether they exist
    :param problem: a PDDLStream problem
    :param constraints: PlanConstraints on the set of legal solutions
    :param stream_info: a dictionary from stream name to StreamInfo altering how individual streams are handled
    :param action_info: a dictionary from stream name to ActionInfo for planning and execution
    :param synthesizers: a list of StreamSynthesizer objects
    :param max_time: the maximum amount of time to apply streams
    :param max_iterations: the maximum number of search iterations
    :param max_iterations: the maximum number of plan skeletons to consider
    :param unit_costs: use unit action costs rather than numeric costs
    :param success_cost: an exclusive (strict) upper bound on plan cost to terminate
    :param unit_efforts: use unit stream efforts rather than estimated numeric efforts
    :param complexity_step: the increase in the effort limit after each failure
    :param max_effort: the maximum amount of effort to consider for streams
    :param effort_weight: a multiplier for stream effort compared to action costs
    :param reorder: if True, stream plans are reordered to minimize the expected sampling overhead
    :param search_sample_ratio: the desired ratio of search time / sample time
    :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: select whether to search or sample based on expected success rates
    # TODO: no optimizers during search with relaxed_stream_plan
    num_iterations = search_time = sample_time = eager_calls = 0
    complexity_limit = float(INITIAL_COMPLEXITY)
    eager_disabled = effort_weight is None  # No point if no stream effort biasing
    evaluations, goal_exp, domain, externals = parse_problem(
        problem, stream_info=stream_info, constraints=constraints,
        unit_costs=unit_costs, unit_efforts=unit_efforts)
    store = SolutionStore(evaluations, max_time, success_cost, verbose)
    full_action_info = get_action_info(action_info)
    load_stream_statistics(externals + synthesizers)
    if visualize and not has_pygraphviz():
        visualize = False
        print('Warning, visualize=True requires pygraphviz. Setting visualize=False')
    if visualize:
        reset_visualizations()
    streams, functions, negative = partition_externals(externals, verbose=verbose)
    eager_externals = list(filter(lambda e: e.info.eager, externals))
    skeleton_queue = SkeletonQueue(store, goal_exp, domain)
    disabled = set()
    while (not store.is_terminated()) and (num_iterations < max_iterations):
        start_time = time.time()
        num_iterations += 1
        eager_instantiator = Instantiator(eager_externals, evaluations) # Only update after an increase?
        if eager_disabled:
            push_disabled(eager_instantiator, disabled)
        eager_calls += process_stream_queue(eager_instantiator, store, complexity_limit=complexity_limit, verbose=verbose)

        print('\nIteration: {} | Complexity: {} | Skeletons: {} | Skeleton Queue: {} | Disabled: {} | Evaluations: {} | '
              'Eager Calls: {} | Cost: {:.3f} | Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'.format(
            num_iterations, complexity_limit, len(skeleton_queue.skeletons), len(skeleton_queue), len(disabled),
            len(evaluations), eager_calls, store.best_cost, search_time, sample_time, store.elapsed_time()))
        optimistic_solve_fn = get_optimistic_solve_fn(goal_exp, domain, negative,
                                                      max_cost=min(store.best_cost, constraints.max_cost),
                                                      unit_efforts=unit_efforts, max_effort=max_effort,
                                                      effort_weight=effort_weight, **search_kwargs)
        if (max_skeletons is not None) and (len(skeleton_queue.skeletons) < max_skeletons):
            combined_plan, cost = iterative_plan_streams(evaluations, externals, optimistic_solve_fn, complexity_limit,
                                                         unit_efforts=unit_efforts, max_effort=max_effort)
        else:
            combined_plan, cost = INFEASIBLE, INF
        if action_info:
            combined_plan = reorder_combined_plan(evaluations, combined_plan, full_action_info, domain)
            print('Combined plan: {}'.format(combined_plan))
        stream_plan, action_plan = separate_plan(combined_plan, full_action_info)
        #stream_plan = replan_with_optimizers(evaluations, stream_plan, domain, externals)
        stream_plan = combine_optimizers(evaluations, stream_plan)
        #stream_plan = get_synthetic_stream_plan(stream_plan, # evaluations
        #                                       [s for s in synthesizers if not s.post_only])
        if reorder:
            stream_plan = reorder_stream_plan(stream_plan) # This may be redundant when using reorder_combined_plan
        print('Stream plan ({}, {:.3f}): {}\nAction plan ({}, {:.3f}): {}'.format(
            get_length(stream_plan), compute_plan_effort(stream_plan), stream_plan,
            get_length(action_plan), cost, str_from_plan(action_plan)))
        if is_plan(stream_plan) and visualize:
            log_plans(stream_plan, action_plan, num_iterations)
            create_visualizations(evaluations, stream_plan, num_iterations)
        search_time += elapsed_time(start_time)

        if (stream_plan is INFEASIBLE) and (not eager_instantiator) and (not skeleton_queue) and (not disabled):
            break
        start_time = time.time()
        if not is_plan(stream_plan):
            complexity_limit += complexity_step
            if not eager_disabled:
                reenable_disabled(evaluations, domain, disabled)
        elif not stream_plan:
            store.add_plan(action_plan, cost)

        if max_skeletons is None:
            process_stream_plan(store, domain, disabled, stream_plan)
        else:
            allocated_sample_time = (search_sample_ratio * search_time) - sample_time
            skeleton_queue.process(stream_plan, action_plan, cost, complexity_limit, allocated_sample_time)
        sample_time += elapsed_time(start_time)

    write_stream_statistics(externals + synthesizers, verbose)
    return store.extract_solution()
示例#9
0
def solve_focused(problem,
                  constraints=PlanConstraints(),
                  stream_info={},
                  replan_actions=set(),
                  max_time=INF,
                  max_iterations=INF,
                  initial_complexity=0,
                  complexity_step=1,
                  max_skeletons=INF,
                  bind=True,
                  max_failures=0,
                  unit_costs=False,
                  success_cost=INF,
                  unit_efforts=False,
                  max_effort=INF,
                  effort_weight=None,
                  reorder=True,
                  search_sample_ratio=0,
                  visualize=False,
                  verbose=True,
                  **search_kwargs):
    """
    Solves a PDDLStream problem by first hypothesizing stream outputs and then determining whether they exist
    :param problem: a PDDLStream problem
    :param constraints: PlanConstraints on the set of legal solutions
    :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_iterations: the maximum number of search iterations
    :param max_skeletons: the maximum number of plan skeletons to consider
    :param unit_costs: use unit action costs rather than numeric costs
    :param success_cost: an exclusive (strict) upper bound on plan cost to terminate
    :param unit_efforts: use unit stream efforts rather than estimated numeric efforts
    :param initial_complexity: the initial effort limit
    :param complexity_step: the increase in the effort limit after each failure
    :param max_effort: the maximum amount of effort to consider for streams
    :param effort_weight: a multiplier for stream effort compared to action costs
    :param reorder: if True, stream plans are reordered to minimize the expected sampling overhead
    :param search_sample_ratio: the desired ratio of search time / sample time
    :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: select whether to search or sample based on expected success rates
    # TODO: no optimizers during search with relaxed_stream_plan
    # TODO: locally optimize only after a solution is identified
    # TODO: replan with a better search algorithm after feasible
    num_iterations = search_time = sample_time = eager_calls = 0
    complexity_limit = initial_complexity
    # TODO: make effort_weight be a function of the current cost
    # TODO: change the search algorithm and unit costs based on the best cost
    eager_disabled = effort_weight is None  # No point if no stream effort biasing
    evaluations, goal_exp, domain, externals = parse_problem(
        problem,
        stream_info=stream_info,
        constraints=constraints,
        unit_costs=unit_costs,
        unit_efforts=unit_efforts)
    store = SolutionStore(evaluations, max_time, success_cost, verbose)
    load_stream_statistics(externals)
    if visualize and not has_pygraphviz():
        visualize = False
        print(
            'Warning, visualize=True requires pygraphviz. Setting visualize=False'
        )
    if visualize:
        reset_visualizations()
    streams, functions, negative, optimizers = partition_externals(
        externals, verbose=verbose)
    eager_externals = list(filter(lambda e: e.info.eager, externals))
    use_skeletons = max_skeletons is not None
    has_optimizers = bool(optimizers)
    assert implies(has_optimizers, use_skeletons)
    skeleton_queue = SkeletonQueue(store, domain, disable=not has_optimizers)
    disabled = set()  # Max skeletons after a solution
    while (not store.is_terminated()) and (num_iterations < max_iterations):
        start_time = time.time()
        num_iterations += 1
        eager_instantiator = Instantiator(
            eager_externals, evaluations)  # Only update after an increase?
        if eager_disabled:
            push_disabled(eager_instantiator, disabled)
        eager_calls += process_stream_queue(eager_instantiator,
                                            store,
                                            complexity_limit=complexity_limit,
                                            verbose=verbose)

        print(
            '\nIteration: {} | Complexity: {} | Skeletons: {} | Skeleton Queue: {} | Disabled: {} | Evaluations: {} | '
            'Eager Calls: {} | Cost: {:.3f} | Search Time: {:.3f} | Sample Time: {:.3f} | Total Time: {:.3f}'
            .format(num_iterations, complexity_limit,
                    len(skeleton_queue.skeletons), len(skeleton_queue),
                    len(disabled), len(evaluations), eager_calls,
                    store.best_cost, search_time, sample_time,
                    store.elapsed_time()))
        optimistic_solve_fn = get_optimistic_solve_fn(
            goal_exp,
            domain,
            negative,
            replan_actions=replan_actions,
            reachieve=use_skeletons,
            max_cost=min(store.best_cost, constraints.max_cost),
            max_effort=max_effort,
            effort_weight=effort_weight,
            **search_kwargs)
        # TODO: just set unit effort for each stream beforehand
        if (max_skeletons is None) or (len(skeleton_queue.skeletons) <
                                       max_skeletons):
            disabled_axioms = create_disabled_axioms(
                skeleton_queue) if has_optimizers else []
            if disabled_axioms:
                domain.axioms.extend(disabled_axioms)
            stream_plan, action_plan, cost = iterative_plan_streams(
                evaluations, (streams + functions + optimizers),
                optimistic_solve_fn,
                complexity_limit,
                max_effort=max_effort)
            for axiom in disabled_axioms:
                domain.axioms.remove(axiom)
        else:
            stream_plan, action_plan, cost = INFEASIBLE, INFEASIBLE, INF
        #stream_plan = replan_with_optimizers(evaluations, stream_plan, domain, externals) or stream_plan
        stream_plan = combine_optimizers(evaluations, stream_plan)
        #stream_plan = get_synthetic_stream_plan(stream_plan, # evaluations
        #                                       [s for s in synthesizers if not s.post_only])
        if reorder:
            stream_plan = reorder_stream_plan(
                stream_plan
            )  # This may be redundant when using reorder_combined_plan

        num_optimistic = sum(r.optimistic
                             for r in stream_plan) if stream_plan else 0
        print('Stream plan ({}, {}, {:.3f}): {}\nAction plan ({}, {:.3f}): {}'.
              format(get_length(stream_plan), num_optimistic,
                     compute_plan_effort(stream_plan), stream_plan,
                     get_length(action_plan), cost,
                     str_from_plan(action_plan)))
        if is_plan(stream_plan) and visualize:
            log_plans(stream_plan, action_plan, num_iterations)
            create_visualizations(evaluations, stream_plan, num_iterations)
        search_time += elapsed_time(start_time)

        if (stream_plan is INFEASIBLE) and (not eager_instantiator) and (
                not skeleton_queue) and (not disabled):
            break
        start_time = time.time()
        if not is_plan(stream_plan):
            complexity_limit += complexity_step
            if not eager_disabled:
                reenable_disabled(evaluations, disabled)

        #print(stream_plan_complexity(evaluations, stream_plan))
        if use_skeletons:
            #optimizer_plan = replan_with_optimizers(evaluations, stream_plan, domain, optimizers)
            optimizer_plan = None
            if optimizer_plan is not None:
                # TODO: post process a bound plan
                print('Optimizer plan ({}, {:.3f}): {}'.format(
                    get_length(optimizer_plan),
                    compute_plan_effort(optimizer_plan), optimizer_plan))
                skeleton_queue.new_skeleton(optimizer_plan, action_plan, cost)
            allocated_sample_time = (search_sample_ratio * search_time) - sample_time \
                if len(skeleton_queue.skeletons) <= max_skeletons else INF
            skeleton_queue.process(stream_plan, action_plan, cost,
                                   complexity_limit, allocated_sample_time)
        else:
            process_stream_plan(store,
                                domain,
                                disabled,
                                stream_plan,
                                action_plan,
                                cost,
                                bind=bind,
                                max_failures=max_failures)
        sample_time += elapsed_time(start_time)

    write_stream_statistics(externals, verbose)
    return store.extract_solution()