def negate(axioms): assert axioms result = [ pddl.PropositionalAxiom(axioms[0].name, [], axioms[0].effect.negate()) ] for axiom in axioms: condition = axiom.condition if len(condition) == 0: # The derived fact we want to negate is triggered with an # empty condition, so it is always true and its negation # is always false. return [] elif len(condition) == 1: # Handle easy special case quickly. new_literal = condition[0].negate() for result_axiom in result: result_axiom.condition.append(new_literal) else: new_result = [] for literal in condition: literal = literal.negate() for result_axiom in result: new_axiom = result_axiom.clone() new_axiom.condition.append(literal) new_result.append(new_axiom) result = new_result result = simplify(result) return result
def compute_negative_axioms(clusters): for cluster in clusters: if cluster.needed_negatively: if len(cluster.variables) > 1: # If the cluster contains multiple variables, they have a cyclic # positive dependency. In this case, the "obvious" way of # negating the formula defining the derived variable is # semantically wrong. For details, see issue453. # # Therefore, in this case we perform a naive overapproximation # instead, which assumes that derived variables occurring in # such clusters can be false unconditionally. This is good # enough for correctness of the code that uses these negated # axioms (within heuristics of the search component), but loses # accuracy. Negating the rules in an exact # (non-overapproximating) way is possible but more expensive. # Again, see issue453 for details. for variable in cluster.variables: axioms = cluster.axioms[variable] negated_axiom = pddl.PropositionalAxiom( axioms[0].name, [], variable.negate(), axioms[0].axiom, axioms[0].var_mapping) cluster.axioms[variable].append(negated_axiom) else: variable = next(iter(cluster.variables)) negated_axioms = negate(cluster.axioms[variable]) cluster.axioms[variable] += negated_axioms
def add_optimizer_axioms(results, instantiated): # Ends up being a little slower than version in optimizer.py when not blocking shared # TODO: add this to simultaneous import pddl results_from_instance = defaultdict(list) for result in results: results_from_instance[result.instance].append(result) optimizer_results = list(filter(is_optimizer_result, results)) optimizers = {result.external.optimizer for result in optimizer_results} for optimizer in optimizers: optimizer_facts = { substitute_expression(result.external.stream_fact, result.get_mapping()) for result in optimizer_results if result.external.optimizer is optimizer } facts_from_arg = defaultdict(list) for fact in optimizer_facts: for arg in get_args(fact): facts_from_arg[arg].append(fact) for stream in optimizer.streams: if not stream.instance.disabled: continue constraints = stream.instance.get_constraints() output_variables = [] for out in stream.output_objects: assert isinstance(out.param, UniqueOptValue) output_variables.append([ r.output_objects[out.param.output_index] for r in results_from_instance[out.param.instance] ]) for combo in product(*output_variables): mapping = get_mapping(stream.output_objects, combo) name = '({})'.join(UNSATISFIABLE) blocked = set(substitute_expression(constraints, mapping)) additional = { fact for arg in combo for fact in facts_from_arg[arg] } - blocked # TODO: like a partial disable, if something has no outputs, then adding things isn't going to help if stream.instance.enumerated and not stream.instance.successes: # Assumes the optimizer is submodular condition = list(map(fd_from_fact, blocked)) else: condition = list( map(fd_from_fact, blocked | set(map(Not, additional)))) effect = fd_from_fact((UNSATISFIABLE, )) instantiated.axioms.append( pddl.PropositionalAxiom(name, condition, effect)) instantiated.atoms.add(effect)
def negate(axioms): assert axioms result = [pddl.PropositionalAxiom(axioms[0].name, [], axioms[0].effect.negate())] for axiom in axioms: condition = axiom.condition length_cond = len(condition) assert length_cond > 0, "Negated axiom impossible; cannot deal with that" if length_cond == 1: # Handle easy special case quickly. new_literal = condition[0].negate() for result_axiom in result: result_axiom.condition.append(new_literal) elif length_cond == 2: new_literal1 = condition[0].negate() new_literal2 = condition[1].negate() new_result = [] for result_axiom in result: new_axiom = result_axiom.clone() new_axiom.condition.append(new_literal1) new_result.append(new_axiom) result_axiom.condition.append(new_literal2) result.extend(new_result) else: new_result = [] for i in range(1, len(condition)): literal = condition[i].negate() for result_axiom in result: new_axiom = result_axiom.clone() new_axiom.condition.append(literal) new_result.append(new_axiom) for result_axiom in result: result_axiom.append(literal) result.extend(new_result) #else: # new_result = [] # for literal in condition: # literal = literal.negate() # for result_axiom in result: # new_axiom = result_axiom.clone() # new_axiom.condition.append(literal) # new_result.append(new_axiom) # result = new_result result = simplify(result) return result
def negate(axioms): assert axioms result = [pddl.PropositionalAxiom(axioms[0].name, [], axioms[0].effect.negate())] for axiom in axioms: condition = axiom.condition assert len(condition) > 0, "Negated axiom impossible; cannot deal with that" if len(condition) == 1: # Handle easy special case quickly. new_literal = condition[0].negate() for result_axiom in result: result_axiom.condition.append(new_literal) else: new_result = [] for literal in condition: literal = literal.negate() for result_axiom in result: new_axiom = result_axiom.clone() new_axiom.condition.append(literal) new_result.append(new_axiom) result = new_result result = simplify(result) return result
def compute_groups(task, atoms, reachable_action_params,actions,axioms): print(options.invariant) if options.invariant == 'mip': groups = mip_invariant_finder.get_groups(task,reachable_action_params,atoms,actions) else: groups = invariant_finder.get_groups(task, reachable_action_params) with timers.timing("Instantiating groups"): groups = instantiate_groups(groups, task, atoms) # groups = [group for group in groups if is_group_useful(group,atoms)] # Sort here already to get deterministic mutex groups. groups = sort_groups(groups) # TODO: I think that collect_all_mutex_groups should do the same thing # as choose_groups with partial_encoding=False, so these two should # be unified. with timers.timing("Collecting mutex groups"): mutex_groups = collect_all_mutex_groups(groups, atoms) inessentials = defaultdict(list) if options.group_choice == 'exact': with timers.timing("Choosing groups", block=True): essentials = mip.choose_groups_exact(groups, atoms) elif options.group_choice == 'essential': with timers.timing("Computing exactly groups", block=True): exactly1 = exactly_groups.compute_groups(task,actions,mutex_groups) with timers.timing("Choosing groups", block=True): essentials,inessentials = mip.choose_groups_essential_exact(mutex_groups,exactly1,atoms) else: with timers.timing("Choosing groups", block=True): essentials = choose_groups(groups, atoms) groups = essentials + [[item] for item in inessentials.keys()] if options.group_choice == 'essential' and options.axiom: task.init = [item for item in task.init if not isinstance(item,pddl.Assign) and not item in inessentials ] actions = [action.filt(inessentials) for action in actions] for k,v in inessentials.items(): if len(v) <= 1: axiom = pddl.PropositionalAxiom(k,[],k) axioms.append(axiom) continue neg = pddl.Atom("neg-" + k.predicate,k.args) groups.append([neg]) atoms.add(neg) for atom in v: neg_axiom = pddl.PropositionalAxiom(neg,[atom],neg) axiom = pddl.PropositionalAxiom(k,[neg.negate()],k) axioms.append(neg_axiom) axioms.append(axiom) groups = sort_groups(groups) # for item in groups: # print(item) with timers.timing("Building translation key"): translation_key = build_translation_key(groups) if DEBUG: for group in groups: if len(group) >= 2: print("{%s}" % ", ".join(map(str, group))) return groups, mutex_groups, translation_key,(inessentials)