def next_optimistic(self): # TODO: compute this just once and store if self.enumerated or self.disabled: return [] # TODO: (potentially infinite) sequence of optimistic objects # TODO: how do I distinguish between real and not real verifications of things? # TODO: reuse these? self.opt_results = [] output_set = set() for output_list in self.opt_gen_fn(*self.get_input_values()): self._check_output_values(output_list) for i, output_values in enumerate(output_list): output_objects = [] for output_index, value in enumerate(output_values): # TODO: maybe record history of values here? unique = UniqueOptValue(self, len(self.opt_results), output_index) # object() param = unique if self.use_unique() else value output_objects.append( OptimisticObject.from_opt(value, param)) output_objects = tuple(output_objects) if output_objects not in output_set: output_set.add( output_objects ) # No point returning the exact thing here... self.opt_results.append( self._Result(self, output_objects, opt_index=self.opt_index, call_index=len(self.opt_results), list_index=0)) return self.opt_results
def convert_fluent_streams(stream_plan, real_states, action_plan, step_from_fact, node_from_atom): #return stream_plan import pddl assert len(real_states) == len(action_plan) + 1 steps_from_stream = get_steps_from_stream(stream_plan, step_from_fact, node_from_atom) # TODO: ensure that derived facts aren't in fluents? # TODO: handle case where costs depend on the outputs _, outgoing_edges = neighbors_from_orders( get_partial_orders(stream_plan, init_facts=map( fact_from_fd, filter(lambda f: isinstance(f, pddl.Atom), real_states[0])))) static_plan = [] fluent_plan = [] for result in stream_plan: external = result.external if isinstance(result, FunctionResult) or (result.opt_index != 0) or ( not external.is_fluent): static_plan.append(result) continue if outgoing_edges[result]: # No way of taking into account the binding of fluent inputs when preventing cycles raise NotImplementedError( 'Fluent stream is required for another stream: {}'.format( result)) #if (len(steps_from_stream[result]) != 1) and result.output_objects: # raise NotImplementedError('Fluent stream required in multiple states: {}'.format(result)) for state_index in steps_from_stream[result]: new_output_objects = [ #OptimisticObject.from_opt(out.value, object()) OptimisticObject.from_opt( out.value, UniqueOptValue(result.instance, object(), name)) for name, out in safe_zip(result.external.outputs, result.output_objects) ] if new_output_objects and (state_index <= len(action_plan) - 1): # TODO: check that the objects aren't used in any effects instance = copy.copy(action_plan[state_index]) action_plan[state_index] = instance output_mapping = get_mapping( list(map(pddl_from_object, result.output_objects)), list(map(pddl_from_object, new_output_objects))) instance.var_mapping = { p: output_mapping.get(v, v) for p, v in instance.var_mapping.items() } new_instance = get_fluent_instance(external, result.instance.input_objects, real_states[state_index]) # TODO: handle optimistic here new_result = new_instance.get_result(new_output_objects, opt_index=result.opt_index) fluent_plan.append(new_result) return static_plan + fluent_plan
def wrap_optimistic(self, output_values, call_index): output_objects = [] for name, value in safe_zip(self.external.outputs, output_values): unique = UniqueOptValue(instance=self, sequence_index=call_index, output=name) # object() param = unique if ( self.opt_index == 0) else value # TODO: make a proper abstraction generator output_objects.append(OptimisticObject.from_opt(value, param)) return tuple(output_objects)
def convert_fluent_streams(stream_plan, real_states, action_plan, step_from_fact, node_from_atom): import pddl assert len(real_states) == len(action_plan) + 1 steps_from_stream = {} for result in reversed(stream_plan): steps_from_stream[result] = set() for fact in result.get_certified(): if (fact in step_from_fact) and (node_from_atom[fact].result == result): steps_from_stream[result].update(step_from_fact[fact]) for fact in result.instance.get_domain(): step_from_fact[fact] = step_from_fact.get( fact, set()) | steps_from_stream[result] # TODO: apply this recursively # TODO: ensure that derived facts aren't in fluents? # TODO: handle case where costs depend on the outputs _, outgoing_edges = neighbors_from_orders( get_partial_orders(stream_plan, init_facts=map( fact_from_fd, filter(lambda f: isinstance(f, pddl.Atom), real_states[0])))) static_plan = [] fluent_plan = [] for result in stream_plan: external = result.external if (result.opt_index != 0) or (not external.is_fluent()): static_plan.append(result) continue if outgoing_edges[result]: # No way of taking into account the binding of fluent inputs when preventing cycles raise NotImplementedError( 'Fluent stream is required for another stream: {}'.format( result)) #if (len(steps_from_stream[result]) != 1) and result.output_objects: # raise NotImplementedError('Fluent stream required in multiple states: {}'.format(result)) for state_index in steps_from_stream[result]: new_output_objects = [ # OptimisticObject.from_opt(out.value, object()) OptimisticObject.from_opt( out.value, UniqueOptValue(result.instance, object(), i)) for i, out in enumerate(result.output_objects) ] if new_output_objects and (state_index < len(action_plan)): # TODO: check that the objects aren't used in any effects instance = copy.copy(action_plan[state_index]) action_plan[state_index] = instance output_mapping = get_mapping( map(pddl_from_object, result.output_objects), map(pddl_from_object, new_output_objects)) instance.var_mapping = { p: output_mapping.get(v, v) for p, v in instance.var_mapping.items() } fluent_facts = list( map( fact_from_fd, filter( lambda f: isinstance(f, pddl.Atom) and (f.predicate in external.fluents), real_states[state_index]))) new_instance = external.get_instance(result.instance.input_objects, fluent_facts=fluent_facts) new_result = new_instance.get_result(new_output_objects, opt_index=result.opt_index) fluent_plan.append(new_result) return static_plan + fluent_plan