def _add_sum_constraint(self, atom): if not isinstance(atom, ConstraintAtom): sum_con = ConstraintAtom.copy(atom) else: sum_con = atom for con in self._sum_constraints: if str(con) == str(sum_con): return con.literal if sum_con.literal is None: new_lit = self._add_atom() sum_con.literal = new_lit if self._appconfig.print_trans: print() print("% Adding sum constraint:", atom) print() self._sum_constraints.add(sum_con) defined = [] for element in sum_con.elements: for var in self.vars(element.terms[0]): def_lit = self._add_defined(var) defined.append(def_lit) self._add_rule([], [sum_con.literal, -def_lit]) for var in self.vars(sum_con.guard[1]): def_lit = self._add_defined(var) self._add_rule([], [sum_con.literal, -def_lit]) defined.append(def_lit) if match(sum_con.term.arguments[0], "head", 0): self._define_variables(sum_con) elif match(sum_con.term.arguments[0], "body", 0): new_lit = self._add_atom() self._add_rule([new_lit], [], True) defined.append(new_lit) self._add_rule([sum_con.literal], defined) sum_con.literal = new_lit return sum_con.literal
def _define_variables(self, atom): assert match(atom.term.arguments[0], "head", 0) and match( atom.term, "sum", 1) and not self.conditional(atom) for var in self.vars(atom.guard[1]): self._add_defined(var, [atom.literal]) for element in atom.elements: reason = [atom.literal] for var in self.vars(element.terms[0]): if element.condition: reason.append(element.condition_id) self._add_defined(var, reason)
def _translate_constraint(self, atom): if match(atom.term, "sum", 1) and not self.conditional(atom) and atom.guard[0] in ( "=", "<", ">", "<=", ">=", "!="): self._add_sum_constraint(atom) elif self.conditional(atom): self._translate_conditional(atom) elif atom.guard[0] == "=:": self._translate_assignment(atom) elif match(atom.term, "max", 1): self._translate_max(atom) elif match(atom.term, "min", 1): self._translate_min(atom) elif match(atom.term, "in", 1): self._translate_in(atom) else: self._aux_constraints.add(ConstraintAtom.copy(atom))
def _translate_min(self, atom): assert not self.conditional(atom) if self._appconfig.print_trans: print() print("% Translating min aggregate:", atom) print() min_var = self._add_auxvar() min_def = self._add_defined(min_var) def_fact = False beta_lit = self._add_atom() for element in atom.elements: body = [] for var in self.vars(element.terms[0]): body.append(self._add_defined(var)) if not def_fact: if len(body) == 0: def_fact = True self._add_defined(min_var, body) body.append(min_def) check_lit = self._add_atom() self._add_sum_constraint( ConstraintAtom([ConstraintElement([min_var], None, None)], ["<=", element.terms[0]], check_lit, SUM_TERM_BODY)) self._add_rule([], [-check_lit]) check_lit = self._add_atom() self._add_sum_constraint( ConstraintAtom([ConstraintElement([min_var], None, None)], ["=", element.terms[0]], check_lit, SUM_TERM_BODY)) self._add_rule([beta_lit], [check_lit]) self._add_rule([], [-beta_lit, min_def]) type_term = ConstraintTerm("sum", None, [atom.term.arguments[0]], clingo.TheoryTermType.Function) eq_lit = self._add_sum_constraint( ConstraintAtom([ConstraintElement([min_var], None, None)], atom.guard, None, type_term)) if match(atom.term.arguments[0], "head", 0): self._add_rule([eq_lit], [atom.literal]) self._add_rule([atom.literal], [eq_lit]) elif match(atom.term.arguments[0], "body", 0): self._add_rule([atom.literal], [eq_lit, min_def])
def _parse_dom_elem(term): if match(term, "..", 2): a = _evaluate_term(term.arguments[0]) if a.type != clingo.SymbolType.Number: raise RuntimeError("Invalid Syntax") b = _evaluate_term(term.arguments[1]) if b.type != clingo.SymbolType.Number: raise RuntimeError("Invalid Syntax") return (a.number, b.number + 1) a = _evaluate_term(term) if a.type != clingo.SymbolType.Number: raise RuntimeError("Invalid Syntax") return (a.number, a.number + 1)
def _parse_show_elem(builder, term): if match(term, "/", 2): a = _evaluate_term(term.arguments[0]) if a.type != clingo.SymbolType.Function or a.arguments: raise RuntimeError("Invalid Syntax") b = _evaluate_term(term.arguments[1]) if b.type != clingo.SymbolType.Number: raise RuntimeError("Invalid Syntax") builder.show_signature(a.name, b.number) else: a = _evaluate_term(term) if a.type == clingo.SymbolType.Number: raise RuntimeError("Invalid Syntax") builder.show_variable(a)
def parse_theory(builder, theory_atoms): """ Parse the atoms in the given theory and pass them to the builder. """ for atom in theory_atoms: is_sum = match(atom.term, "sum", 1) is_diff = match(atom.term, "diff", 1) if is_sum or is_diff: body = match(atom.term.arguments[0], "body", 0) _parse_constraint(builder, atom, is_sum, body) elif match(atom.term, "distinct", 0): _parse_distinct(builder, atom) elif match(atom.term, "show", 0): _parse_show(builder, atom) elif match(atom.term, "dom", 0): _parse_dom(builder, atom) elif match(atom.term, "minimize", 0): _parse_objective(builder, atom, 1) elif match(atom.term, "maximize", 0): _parse_objective(builder, atom, -1)
def vars(self, term): """ Return all variables in a term. """ if term.type == clingo.SymbolType.Number: return set() if match(term, "-", 2) or match(term, "+", 2) or match( term, "*", 2) or match(term, "..", 2): return self.vars(term.arguments[0]).union( self.vars(term.arguments[1])) if match(term, "-", 1) or match(term, "+", 1): return self.vars(term.arguments[0]) if term.type in (clingo.TheoryTermType.Symbol, clingo.TheoryTermType.Function, clingo.TheoryTermType.Tuple): return {term} return set()
def _translate_conditional(self, atom): if self._appconfig.print_trans: print() print("% Translating conditionals:", atom) print() elements = [] neutral = ZERO if match(atom.term, "sum", 1): neutral = ZERO elif match(atom.term, "min", 1): neutral = ConstraintTerm(None, self._propconfig.max_int, None, clingo.TheoryTermType.Number) elif match(atom.term, "max", 1): neutral = ConstraintTerm(None, self._propconfig.min_int, None, clingo.TheoryTermType.Number) for element in atom.elements: if element.condition_id: cond = element.condition_id aux_var = self._add_auxvar() terms = [aux_var] terms.extend(element.terms[1:]) elements.append(ConstraintElement(terms, None, None)) self._add_defined(aux_var) holds_def = [ self._add_defined(var) for var in self.vars(element.terms[0]) ] aux_var_elem = ConstraintElement([aux_var], None, None) holds_term = element.terms[0] holds = self._add_sum_constraint( ConstraintAtom([aux_var_elem], ["=", holds_term], None, SUM_TERM_HEAD)) nholds = self._add_sum_constraint( ConstraintAtom([aux_var_elem], ["=", neutral], None, SUM_TERM_HEAD)) body = [cond] body.extend(holds_def) self._add_rule([holds], body) body = [-cond] self._add_rule([nholds], body) body = [cond] body.append(self._defined[aux_var]) self._add_rule([holds], body) body = [-cond] body.append(self._defined[aux_var]) self._add_rule([nholds], body) self._add_rule([cond], [self._defined[aux_var]], True) else: elements.append(element) cond_free_lit = self._add_atom() type_term = ConstraintTerm(atom.term.name, None, [atom.term.arguments[0]], clingo.TheoryTermType.Function) self._add_rule([cond_free_lit], [atom.literal]) self._add_rule([atom.literal], [cond_free_lit]) self._translate_constraint( ConstraintAtom(elements, atom.guard, cond_free_lit, type_term))
def _parse_constraint_elem(builder, term, is_sum): assert term is not None if not is_sum: if match(term, "-", 2): a = _evaluate_term(term.arguments[0]) if a.type == clingo.SymbolType.Number: yield a.number, None else: yield 1, builder.add_variable(a) b = _evaluate_term(term.arguments[1]) if b.type == clingo.SymbolType.Number: yield -b.number, None else: yield -1, builder.add_variable(b) else: raise RuntimeError("Invalid Syntax for difference constraint") else: if match(term, "+", 2): for co, var in _parse_constraint_elem(builder, term.arguments[0], True): yield co, var for co, var in _parse_constraint_elem(builder, term.arguments[1], True): yield co, var elif match(term, "-", 2): for co, var in _parse_constraint_elem(builder, term.arguments[0], True): yield co, var for co, var in _parse_constraint_elem(builder, term.arguments[1], True): yield -co, var elif match(term, "*", 2): lhs = list(_parse_constraint_elem(builder, term.arguments[0], True)) for co_prime, var_prime in _parse_constraint_elem( builder, term.arguments[1], True): for co, var in lhs: if var is None: yield co * co_prime, var_prime elif var_prime is None: yield co * co_prime, var else: raise RuntimeError( "Invalid Syntax, only linear constraints allowed") elif match(term, "-", 1): for co, var in _parse_constraint_elem(builder, term.arguments[0], True): yield -co, var elif match(term, "+", 1): for co, var in _parse_constraint_elem(builder, term.arguments[0], True): yield co, var elif term.type == clingo.TheoryTermType.Number: yield term.number, None elif term.type in (clingo.TheoryTermType.Symbol, clingo.TheoryTermType.Function, clingo.TheoryTermType.Tuple): yield 1, builder.add_variable(_evaluate_term(term)) else: raise RuntimeError("Invalid Syntax for linear constraint")