示例#1
0
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)
示例#2
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)
示例#3
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)
示例#4
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()