Пример #1
0
def parse_problem(problem, stream_info={}, constraints=None, unit_costs=False, unit_efforts=False):
    # TODO: just return the problem if already written programmatically
    #reset_globals() # Prevents use of satisfaction.py
    domain_pddl, constant_map, stream_pddl, stream_map, init, goal = problem
    domain = parse_domain(domain_pddl)
    #domain = domain_pddl
    if not isinstance(domain, Domain):
        #assert isinstance(domain, str) # raw PDDL is returned
        obj_from_constant = {name: Object(value, name=name)
                             for name, value in constant_map.items()}
        streams = parse_stream_pddl(stream_pddl, stream_map, stream_info=stream_info,
                                    unit_costs=unit_costs, unit_efforts=unit_efforts)
        evaluations = evaluations_from_init(init)
        goal_exp = obj_from_value_expression(goal)
        return evaluations, goal_exp, domain, streams
    if len(domain.types) != 1:
        raise NotImplementedError('Types are not currently supported')
    if unit_costs:
        set_unit_costs(domain)
    obj_from_constant = parse_constants(domain, constant_map)
    streams = parse_stream_pddl(stream_pddl, stream_map, stream_info=stream_info,
                                unit_costs=unit_costs, unit_efforts=unit_efforts)
    check_problem(domain, streams, obj_from_constant)

    evaluations = evaluations_from_init(init)
    goal_exp = obj_from_value_expression(goal)
    #normalize_domain_goal(domain, goal_expression)
    goal_exp = add_plan_constraints(constraints, domain, evaluations, goal_exp)
    parse_goal(goal_exp, domain) # Just to check that it parses

    # TODO: refactor the following?
    compile_to_exogenous(evaluations, domain, streams)
    enforce_simultaneous(domain, streams)
    compile_fluent_streams(domain, streams)
    return evaluations, goal_exp, domain, streams
Пример #2
0
def parse_problem(problem, stream_info={}, constraints=None, unit_costs=False, unit_efforts=False):
    # TODO: just return the problem if already written programmatically
    domain_pddl, constant_map, stream_pddl, stream_map, init, goal = problem
    domain = parse_domain(domain_pddl)
    if len(domain.types) != 1:
        raise NotImplementedError('Types are not currently supported')
    set_unit_costs(domain, unit_costs)
    obj_from_constant = parse_constants(domain, constant_map)
    streams = parse_stream_pddl(stream_pddl, stream_map, stream_info=stream_info, unit_efforts=unit_efforts)
    check_problem(domain, streams, obj_from_constant)

    evaluations = evaluations_from_init(init)
    goal_exp = obj_from_value_expression(goal)
    #normalize_domain_goal(domain, goal_expression)
    goal_exp = add_plan_constraints(constraints, domain, evaluations, goal_exp)
    parse_goal(goal_exp, domain) # Just to check that it parses

    # TODO: refactor the following?
    compile_to_exogenous(evaluations, domain, streams)
    compile_fluent_streams(domain, streams)
    enforce_simultaneous(domain, streams)
    return evaluations, goal_exp, domain, streams
Пример #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()