def solve_incremental(problem, constraints=PlanConstraints(), unit_costs=False, success_cost=INF, max_iterations=INF, max_time=INF, start_complexity=0, complexity_step=1, max_complexity=INF, verbose=False, **search_args): """ Solves a PDDLStream problem by alternating between applying all possible streams and searching :param problem: a PDDLStream problem :param constraints: PlanConstraints on the set of legal solutions :param max_time: the maximum amount of time to apply streams :param max_iterations: the maximum amount of search iterations :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 start_complexity: the stream complexity on the first iteration :param complexity_step: the increase in the complexity limit after each iteration :param max_complexity: the maximum stream complexity :param verbose: if True, this prints the result of each stream application :param search_args: 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 """ # max_complexity = 0 => current # complexity_step = INF => exhaustive # success_cost = terminate_cost = decision_cost evaluations, goal_expression, domain, externals = parse_problem( problem, constraints=constraints, unit_costs=unit_costs) store = SolutionStore(evaluations, max_time, success_cost, verbose) # TODO: include other info here? ensure_no_fluent_streams(externals) if UPDATE_STATISTICS: load_stream_statistics(externals) num_iterations = num_calls = 0 complexity_limit = start_complexity instantiator = Instantiator(externals, evaluations) num_calls += process_stream_queue(instantiator, store, complexity_limit, verbose=verbose) while not store.is_terminated() and (num_iterations <= max_iterations) and (complexity_limit <= max_complexity): num_iterations += 1 print('Iteration: {} | Complexity: {} | Calls: {} | Evaluations: {} | Solved: {} | Cost: {} | Time: {:.3f}'.format( num_iterations, complexity_limit, num_calls, len(evaluations), store.has_solution(), store.best_cost, store.elapsed_time())) plan, cost = solve_finite(evaluations, goal_expression, domain, max_cost=min(store.best_cost, constraints.max_cost), **search_args) if is_plan(plan): store.add_plan(plan, cost) if not instantiator: break if complexity_step is None: # TODO: option to select the next k-smallest complexities complexity_limit = instantiator.min_complexity() else: complexity_limit += complexity_step num_calls += process_stream_queue(instantiator, store, complexity_limit, verbose=verbose) #retrace_stream_plan(store, domain, goal_expression) #print('Final queue size: {}'.format(len(instantiator))) if UPDATE_STATISTICS: write_stream_statistics(externals, verbose) return store.extract_solution()
def solve_incremental(problem, constraints=PlanConstraints(), unit_costs=False, success_cost=INF, max_iterations=INF, max_time=INF, max_memory=INF, initial_complexity=0, complexity_step=1, max_complexity=INF, verbose=False, **search_kwargs): """ Solves a PDDLStream problem by alternating between applying all possible streams and searching :param problem: a PDDLStream problem :param constraints: PlanConstraints on the set of legal solutions :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 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 """ # max_complexity = 0 => current # complexity_step = INF => exhaustive # success_cost = terminate_cost = decision_cost # TODO: warning if optimizers are present evaluations, goal_expression, domain, externals = parse_problem( problem, constraints=constraints, unit_costs=unit_costs) store = SolutionStore( evaluations, max_time, success_cost, verbose, max_memory=max_memory) # TODO: include other info here? if UPDATE_STATISTICS: load_stream_statistics(externals) static_externals = compile_fluents_as_attachments(domain, externals) num_iterations = num_calls = 0 complexity_limit = initial_complexity instantiator = Instantiator(static_externals, evaluations) num_calls += process_stream_queue(instantiator, store, complexity_limit, verbose=verbose) while not store.is_terminated() and (num_iterations < max_iterations) and ( complexity_limit <= max_complexity): num_iterations += 1 print( 'Iteration: {} | Complexity: {} | Calls: {} | Evaluations: {} | Solved: {} | Cost: {:.3f} | ' 'Search Time: {:.3f} | Sample Time: {:.3f} | Time: {:.3f}'.format( num_iterations, complexity_limit, num_calls, len(evaluations), store.has_solution(), store.best_cost, store.search_time, store.sample_time, store.elapsed_time())) plan, cost = solve_finite(evaluations, goal_expression, domain, max_cost=min(store.best_cost, constraints.max_cost), **search_kwargs) if is_plan(plan): store.add_plan(plan, cost) if not instantiator: break if complexity_step is None: # TODO: option to select the next k-smallest complexities complexity_limit = instantiator.min_complexity() else: complexity_limit += complexity_step num_calls += process_stream_queue(instantiator, store, complexity_limit, verbose=verbose) #retrace_stream_plan(store, domain, goal_expression) #print('Final queue size: {}'.format(len(instantiator))) summary = store.export_summary() summary.update({ 'iterations': num_iterations, 'complexity': complexity_limit, }) print('Summary: {}'.format(str_from_object( summary, ndigits=3))) # TODO: return the summary if UPDATE_STATISTICS: write_stream_statistics(externals, verbose) return store.extract_solution()