def recursive_solve_stream_plan(evaluations, streams, functions, stream_results, solve_stream_plan, depth): # TODO: check empty plan first? combined_plan, cost = solve_stream_plan(stream_results) stream_plan, action_plan = separate_plan(combined_plan, action_info=None, terminate=False, stream_only=False) #dump_plans(stream_plan, action_plan, cost) #create_visualizations(evaluations, stream_plan, depth) if stream_plan is None: return stream_plan, cost, depth plan_index = get_stream_plan_index(stream_plan) if plan_index == 0: return combined_plan, cost, depth if not RECURSIVE: # TODO: not quite right return None, cost, depth # TODO: should I just plan using all original plus expanded # TODO: might need new actions here (such as a move) stream_results, bindings = optimistic_process_stream_plan( evaluations, stream_plan) # TODO: plan up to first action that only has one # Only use actions in the states between the two # planned_instances = [] # for name, args in action_plan: # input_objects = [bindings.get(i, [i]) for i in args] # instances = [] # for combo in product(*input_objects): # # TODO: prune actions that aren't feasible # instances.append((name, combo)) # planned_instances.append(instances) # print(action_plan) # print(planned_instances) if not ONLY_LOCAL: # I don't think the double bound thing really makes entire sense here double_bindings = { v: k for k, values in bindings.items() if 2 <= len(values) for v in values } stream_results.extend( optimistic_process_streams(evaluations_from_stream_plan( evaluations, stream_results), streams, double_bindings=double_bindings)) stream_results += optimistic_process_streams( evaluations_from_stream_plan(evaluations, stream_results), functions) return recursive_solve_stream_plan(evaluations, streams, functions, stream_results, solve_stream_plan, depth + 1)
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)
def recover_stream_plan(evaluations, current_plan, opt_evaluations, goal_expression, domain, node_from_atom, action_plan, axiom_plans, negative): # Universally quantified conditions are converted into negative axioms # Existentially quantified conditions are made additional preconditions # Universally quantified effects are instantiated by doing the cartesian produce of types (slow) # Added effects cancel out removed effects # TODO: node_from_atom is a subset of opt_evaluations (only missing functions) real_task = task_from_domain_problem( domain, get_problem(evaluations, goal_expression, domain)) opt_task = task_from_domain_problem( domain, get_problem(opt_evaluations, goal_expression, domain)) negative_from_name = get_negative_predicates(negative) real_states, combined_plan = recover_negative_axioms( real_task, opt_task, axiom_plans, action_plan, negative_from_name) function_plan = compute_function_plan(opt_evaluations, action_plan) full_preimage = plan_preimage(combined_plan, []) stream_preimage = set(full_preimage) - real_states[0] negative_preimage = set( filter(lambda a: a.predicate in negative_from_name, stream_preimage)) function_plan.update( convert_negative(negative_preimage, negative_from_name, full_preimage, real_states)) positive_preimage = stream_preimage - negative_preimage step_from_fact = { fact_from_fd(l): full_preimage[l] for l in positive_preimage if not l.negated } target_facts = { fact for fact in step_from_fact.keys() if get_prefix(fact) != EQ } #stream_plan = reschedule_stream_plan(evaluations, target_facts, domain, stream_results) # visualize_constraints(map(fact_from_fd, target_facts)) stream_plan = [] for result in current_plan: if isinstance(result.external, Function) or (result.external in negative): function_plan.add( result) # Prevents these results from being pruned else: stream_plan.append(result) curr_evaluations = evaluations_from_stream_plan(evaluations, stream_plan, max_effort=None) extraction_facts = target_facts - set( map(fact_from_evaluation, curr_evaluations)) extract_stream_plan(node_from_atom, extraction_facts, stream_plan) stream_plan = postprocess_stream_plan(evaluations, domain, stream_plan, target_facts) stream_plan = convert_fluent_streams(stream_plan, real_states, action_plan, step_from_fact, node_from_atom) return stream_plan + list(function_plan)
def compute_stream_results(evaluations, opt_results, externals, complexity_limit, **effort_args): # TODO: start from the original evaluations or use the stream plan preimage # TODO: only use streams in the states between the two actions # TODO: apply hierarchical planning to restrict the set of streams that considered on each subproblem # TODO: plan up to first action that only has one # TODO: revisit considering double bound streams functions = list(filter(lambda s: type(s) is Function, externals)) opt_evaluations = evaluations_from_stream_plan(evaluations, opt_results) new_results, _ = optimistic_process_streams(opt_evaluations, functions, complexity_limit, **effort_args) return opt_results + new_results
def get_combined_orders(evaluations, stream_plan, action_plan, domain): if action_plan is None: return None # TODO: could just do this within relaxed # TODO: do I want to strip the fluents and just do the partial ordering? stream_instances = get_stream_instances(stream_plan) negative_results = filter( lambda r: isinstance(r, PredicateResult) and (r.value == False), stream_plan) negative_init = set( fd_from_evaluation(evaluation_from_fact(f)) for r in negative_results for f in r.get_certified()) #negated_from_name = {r.instance.external.name for r in negative_results} opt_evaluations = evaluations_from_stream_plan(evaluations, stream_plan) goal_expression = And() task = task_from_domain_problem( domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs=True)) action_instances = get_action_instances(task, action_plan) replace_derived(task, negative_init, action_instances) #combined_instances = stream_instances + action_instances orders = set() for i, a1 in enumerate(action_plan): for a2 in action_plan[i + 1:]: orders.add((a1, a2)) # TODO: just store first achiever here for i, instance1 in enumerate(stream_instances): for j in range(i + 1, len(stream_instances)): effects = {e for _, e in instance1.add_effects} if effects & set(stream_instances[j].precondition): orders.add((stream_plan[i], stream_plan[j])) for i, instance1 in enumerate(stream_instances): for j, instance2 in enumerate(action_instances): effects = {e for _, e in instance1.add_effects} | \ {e.negate() for _, e in instance1.del_effects} if effects & set(instance2.precondition): orders.add((stream_plan[i], action_plan[j])) return orders
def sequential_stream_plan(evaluations, goal_expression, domain, stream_results, negated, effort_weight, unit_costs=True, debug=False, **kwargs): # Intuitively, actions have infinitely more weight than streams if negated: raise NotImplementedError(negated) for result in stream_results: if isinstance(result.external, Stream) and result.external.is_fluent(): raise NotImplementedError('Fluents are not supported') # TODO: compute preimage and make that the goal instead opt_evaluations = evaluations_from_stream_plan(evaluations, stream_results) opt_task = task_from_domain_problem(domain, get_problem(opt_evaluations, goal_expression, domain, unit_costs)) action_plan, action_cost = abstrips_solve_from_task(sas_from_pddl(opt_task, debug=debug), debug=debug, **kwargs) if action_plan is None: return None, action_cost actions = domain.actions[:] domain.actions[:] = [] stream_domain, stream_result_from_name = add_stream_actions(domain, stream_results) # TODO: effort_weight domain.actions.extend(actions) stream_task = task_from_domain_problem(stream_domain, get_problem(evaluations, goal_expression, stream_domain, unit_costs)) action_from_name, function_plan = simplify_actions(opt_evaluations, action_plan, stream_task, actions, unit_costs) # TODO: lmcut? combined_plan, _ = solve_from_task(sas_from_pddl(opt_task, debug=debug), planner=kwargs.get('planner', 'ff-astar'), debug=debug, **kwargs) if combined_plan is None: return None, INF stream_plan, action_plan = [], [] for name, args in combined_plan: if name in stream_result_from_name: stream_plan.append(stream_result_from_name[name]) else: action_plan.append(action_from_name[name]) combined_plan = stream_plan + function_plan + action_plan return combined_plan, action_cost