def optimistic_stream_instantiation(instance, bindings, evaluations, opt_evaluations, only_immediate=False): # TODO: combination for domain predicates new_instances = [] for input_combo in product( *[bindings.get(i, [i]) for i in instance.input_objects]): mapping = get_mapping(instance.input_objects, input_combo) domain_evaluations = set( map(evaluation_from_fact, substitute_expression( instance.get_domain(), mapping))) # TODO: could just instantiate first if domain_evaluations <= opt_evaluations: new_instance = instance.external.get_instance(input_combo) if (new_instance.opt_index != 0) and implies( only_immediate, domain_evaluations <= evaluations): new_instance.opt_index -= 1 new_instances.append(new_instance) return new_instances
def __init__(self, queue, stream_plan, action_plan, cost): # TODO: estimate statistics per stream_instance online and use to reorder the skeleton self.queue = queue self.index = len(self.queue.skeletons) self.stream_plan = stream_plan self.action_plan = action_plan self.cost = cost self.best_binding = None self.improved = False self.root = Binding(self, self.cost, history=[], mapping={}, index=0, parent=None, parent_result=None) self.affected_indices = [compute_affected_downstream(self.stream_plan, index) for index in range(len(self.stream_plan))] stream_orders = get_partial_orders(self.stream_plan) # init_facts=self.queue.evaluations) index_from_result = get_mapping(stream_plan, range(len(stream_plan))) index_orders = {(index_from_result[r1], index_from_result[r2]) for r1, r2 in stream_orders} preimage = stream_plan_preimage(stream_plan) self.preimage_complexities = [[queue.evaluations[evaluation_from_fact(fact)].complexity for fact in stream.get_domain() if fact in preimage] for stream in stream_plan] self.incoming_indices = incoming_from_edges(index_orders) self.outgoing_indices = outgoing_from_edges(index_orders)
def apply_rules_to_streams(rules, streams): # TODO: can actually this with multiple condition if stream certified contains all # TODO: do also when no domain conditions processed_rules = deque(rules) while processed_rules: rule = processed_rules.popleft() if len(rule.domain) != 1: continue [rule_fact] = rule.domain rule.info.p_success = 0 # Need not be applied for stream in streams: if not isinstance(stream, Stream): continue for stream_fact in stream.certified: if get_prefix(rule_fact) == get_prefix(stream_fact): mapping = get_mapping(get_args(rule_fact), get_args(stream_fact)) new_facts = set( substitute_expression(rule.certified, mapping)) - set( stream.certified) stream.certified = stream.certified + tuple(new_facts) if new_facts and (stream in rules): processed_rules.append(stream)
def retrace_instantiation(fact, streams, evaluations, visited_facts, planned_results): if (evaluation_from_fact(fact) in evaluations) or (fact in visited_facts): return visited_facts.add(fact) for stream in streams: for cert in stream.certified: if get_prefix(fact) == get_prefix(cert): mapping = get_mapping(get_args(cert), get_args(fact)) # Should be same anyways if not all(p in mapping for p in (stream.inputs + stream.outputs)): # TODO: assumes another effect is sufficient for binding # Can lead to incorrect ordering continue input_objects = tuple(mapping[p] for p in stream.inputs) instance = stream.get_instance(input_objects) for new_fact in instance.get_domain(): retrace_instantiation(new_fact, streams, evaluations, visited_facts, planned_results) output_objects = tuple(mapping[p] for p in stream.outputs) result = instance.get_result(output_objects) planned_results.append(result)
def process_stream_plan_branch(store, domain, disabled, stream_plan, action_plan, cost): if not is_plan(stream_plan): return stream_plan = [result for result in stream_plan if result.optimistic] if not stream_plan: store.add_plan(action_plan, cost) return free_objects = get_free_objects(stream_plan) bindings = defaultdict(set) for opt_result in stream_plan: opt_inputs = [inp for inp in opt_result.instance.input_objects if inp in free_objects] inp_bindings = [bindings[inp] for inp in opt_inputs] for combo in product(*inp_bindings): bound_result = opt_result.remap_inputs(get_mapping(opt_inputs, combo)) bound_instance = bound_result.instance if bound_instance.enumerated or not is_instance_ready(store.evaluations, bound_instance): continue # Disabled new_results = process_instance(store, domain, bound_instance) if not bound_instance.enumerated: disabled.add(bound_instance) if isinstance(opt_result, StreamResult): for new_result in new_results: for out, obj in safe_zip(opt_result.output_objects, new_result.output_objects): bindings[out].add(obj)
def optimizer_conditional_effects(domain, externals): import pddl #from pddlstream.algorithms.scheduling.negative import get_negative_predicates # TODO: extend this to predicates negative_streams = list( filter(lambda e: isinstance(e, ConstraintStream) and e.is_negated(), externals)) negative_from_predicate = get_predicate_map(negative_streams) if not negative_from_predicate: return for action in domain.actions: universal_to_conditional(action) for effect in action.effects: if isinstance(effect, pddl.Effect) and (effect.literal.predicate == UNSATISFIABLE): condition = effect.condition new_parts = [] stream_fact = None for literal in get_conjuctive_parts(condition): if isinstance(literal, pddl.Literal) and ( literal.predicate in negative_from_predicate): if stream_fact is not None: raise NotImplementedError() stream = negative_from_predicate[literal.predicate] certified = find_unique( lambda f: get_prefix(f) == literal.predicate, stream.certified) mapping = get_mapping(get_args(certified), literal.args) stream_fact = substitute_expression( stream.stream_fact, mapping) else: new_parts.append(literal) if stream_fact is not None: effect.condition = pddl.Conjunction(new_parts) effect.literal = fd_from_fact(stream_fact)
def mapping(self): if self._mapping is None: self._mapping = get_mapping(self.external.outputs, self.output_objects) self._mapping.update(self.instance.get_mapping()) return self._mapping
def attempts_from_index(self): return get_mapping(self.stream_indices, self.stream_attempts)
def gen_fn(*input_values): mapping = get_mapping(inputs, input_values) targets = substitute_expression(certified, mapping) return procedure(outputs, targets)
def mapping(self): return get_mapping(self.inputs + self.outputs, self.input_objects + self.output_objects)
def select_inputs(instance, inputs): external = instance.external assert set(inputs) <= set(external.inputs) mapping = get_mapping(external.inputs, instance.input_objects) return tuple(mapping[inp] for inp in inputs)
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
def select_inputs(instance, inputs): external = instance.external assert set(inputs) <= set(external.inputs) mapping = get_mapping(external.inputs, instance.input_objects) return safe_apply_mapping(inputs, mapping)
def remap_certified(literal, stream): certified = find_unique(lambda f: get_prefix(f) == literal.predicate, stream.certified) mapping = get_mapping(get_args(certified), literal.args) if not all(arg in mapping for arg in stream.inputs): # Certified must contain all inputs return None return mapping
def mapping(self): if self._mapping is None: self._mapping = get_mapping(self.external.inputs, self.input_objects) for constant in self.external.constants: self._mapping[constant] = Object.from_name(constant) return self._mapping
def get_mapping(self, element): return get_mapping(self.heading, element)