def negate(self): """ Pushes the negation through self.formula to remove the not. """ if isinstance(self.formula, terms.TermComparison): return terms.TermComparison(self.formula.term1, terms.comp_negate(self.formula.comp), self.formula.term2) elif isinstance(self.formula, And): return Or(*[Not(a) for a in self.formula.conjuncts]) elif isinstance(self.formula, Or): return And(*[Not(a) for a in self.formula.disjuncts]) elif isinstance(self.formula, Not): return self.formula.formula elif isinstance(self.formula, Implies): return And(self.formula.hyp, Not(self.formula.con)) elif isinstance(self.formula, Univ): return Exist(self.formula.vars, Not(self.formula.formula)) elif isinstance(self.formula, Exist): return Univ(self.formula.vars, Not(self.formula.formula))
def assert_comparison(self, c): """ Take an instance of terms.TermComparison, and adds the comparison to the blackboard. If the comparison terms are not both IVars, finds or creates indices for the terms. """ c = c.canonize() # c is now of the form "term comp sterm" term1, comp, coeff, term2 = c.term1, c.comp, c.term2.coeff, c.term2.term if coeff == 0: term2 = terms.IVar(0) if not isinstance(term1, terms.IVar) or not isinstance( term2, terms.IVar): ivar1 = term1 if isinstance(term1, terms.IVar) else self.term_name(term1) ivar2 = term2 if isinstance(term2, terms.IVar) else self.term_name(term2) c = terms.TermComparison(ivar1, comp, coeff * ivar2).canonize() term1, comp, coeff, term2 = c.term1, c.comp, c.term2.coeff, c.term2.term if coeff == 0: term2 = terms.IVar(0) if self.implies(term1.index, comp, coeff, term2.index): return elif self.implies(term1.index, terms.comp_negate(comp), coeff, term2.index): self.raise_contradiction(term1.index, comp, coeff, term2.index) if comp in (terms.GE, terms.GT, terms.LE, terms.LT): if coeff == 0: self.assert_zero_inequality(term1.index, comp) else: self.assert_inequality(term1.index, comp, coeff, term2.index) elif comp == terms.EQ: if coeff == 0: self.assert_zero_equality(term1.index) else: self.assert_equality(term1.index, coeff, term2.index) elif comp == terms.NE: if coeff == 0: self.assert_zero_disequality(term1.index) else: self.assert_disequality(term1.index, coeff, term2.index) else: raise Error('Unrecognized comparison: {0!s}'.format())
def prove(self, claim): """ Tries to establish the truth of TermComparison claim from what is already known. Returns true if claim follows from the current blackboard, false otherwise. Argument: -- claim: a TermComparison, ie 3*x > 2*y**2 """ if self.contradiction: return True a = terms.TermComparison(claim.term1, terms.comp_negate(claim.comp), claim.term2) try: B = run_util.copy_and_add(self.B, a) except terms.Contradiction as e: messages.announce(e.msg+'\n', messages.ASSERTION) self.contradiction = True return True else: return run_util.run_modules(B, self.modules, self.split_depth, self.split_breadth)
def negate(self): """ Pushes the negation through self.formula to remove the not. """ if isinstance(self.formula, terms.TermComparison): return terms.TermComparison(self.formula.term1, terms.comp_negate(self.formula.comp), self.formula.term2) elif isinstance(self.formula, And): return Or(*[Not(a) for a in self.formula.conjuncts]) elif isinstance(self.formula, Or): return And(*[Not(a) for a in self.formula.disjuncts]) elif isinstance(self.formula, Not): return self.formula elif isinstance(self.formula, Implies): return And(self.formula.hyp, Not(self.formula.con))
def prove(self, claim): """ Tries to establish the truth of TermComparison claim from what is already known. Returns true if claim follows from the current blackboard, false otherwise. Argument: -- claim: a TermComparison, ie 3*x > 2*y**2 """ if self.contradiction: return True a = terms.TermComparison(claim.term1, terms.comp_negate(claim.comp), claim.term2) try: B = run_util.copy_and_add(self.B, a) except terms.Contradiction as e: messages.announce(e.msg + '\n', messages.ASSERTION) self.contradiction = True return True else: return run_util.run_modules(B, self.modules, self.split_depth, self.split_breadth)
def assert_comparison(self, c): """ Take an instance of terms.TermComparison, and adds the comparison to the blackboard. If the comparison terms are not both IVars, finds or creates indices for the terms. """ c = c.canonize() # c is now of the form "term comp sterm" term1, comp, coeff, term2 = c.term1, c.comp, c.term2.coeff, c.term2.term if coeff == 0: term2 = terms.IVar(0) if not isinstance(term1, terms.IVar) or not isinstance(term2, terms.IVar): ivar1 = term1 if isinstance(term1, terms.IVar) else self.term_name(term1) ivar2 = term2 if isinstance(term2, terms.IVar) else self.term_name(term2) c = terms.TermComparison(ivar1, comp, coeff * ivar2).canonize() term1, comp, coeff, term2 = c.term1, c.comp, c.term2.coeff, c.term2.term if coeff == 0: term2 = terms.IVar(0) if self.implies(term1.index, comp, coeff, term2.index): return elif self.implies(term1.index, terms.comp_negate(comp), coeff, term2.index): self.raise_contradiction(term1.index, comp, coeff, term2.index) if comp in (terms.GE, terms.GT, terms.LE, terms.LT): if coeff == 0: self.assert_zero_inequality(term1.index, comp) else: self.assert_inequality(term1.index, comp, coeff, term2.index) elif comp == terms.EQ: if coeff == 0: self.assert_zero_equality(term1.index) else: self.assert_equality(term1.index, coeff, term2.index) elif comp == terms.NE: if coeff == 0: self.assert_zero_disequality(term1.index) else: self.assert_disequality(term1.index, coeff, term2.index) else: raise Error('Unrecognized comparison: {0!s}'.format())
def knows_split(B, i, j, comp, c): """ Returns True if B knows either t_i comp c*t_j or its negation. """ return B.implies(i, comp, c, j) or B.implies(i, terms.comp_negate(comp), c, j)
def split_modules(B, modules, depth, breadth, saturate=True): """ B is a blackboard. modules is a list of modules. depth restricts how many subsequent splits will be performed: ie, if depth=2, will assume x>0 and y>0, but won't assume z>0 on top of that. breadth restricts how many splits will be considered at each depth. ie, if depth=1, breadth=3, will try the three most promising splits separately. If depth=2, breadth=3, will try the three most promising splits determined after each of the three most promising preliminary splits. """ if saturate: saturate_modules(B, modules) if depth <= 0: return B else: backup_bbds = {} backup_modules = {} if breadth <= 0: candidates = get_splits(B, modules) else: candidates = get_splits(B, modules)[:breadth] for i in range(len(candidates)): can = candidates[i] ti, tj = terms.IVar(can[0]), can[3] * terms.IVar(can[1]) comp = can[2] backup_bbds[i, comp] = copy.deepcopy(B) backup_modules[i, comp] = copy.deepcopy(modules) gtsplit = False try: newcomp = terms.comp_eval[comp](ti, tj) messages.announce( "Case split: assuming {0} at depth {1}".format( newcomp, depth), messages.ASSERTION) backup_bbds[i, comp].assert_comparison(newcomp) gtsplit = run_modules(backup_bbds[i, comp], backup_modules[i, comp], 0, 0) except terms.Contradiction: gtsplit = True if gtsplit: #print 'DETERMINED {0} <= {1}'.format(ti, tj) messages.announce( "Split led to contradiction at depth {0}. Learned:".format( depth), messages.ASSERTION) B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)]( ti, tj)) return split_modules(B, modules, depth, breadth) # at this point, none of the depth-1 splits have returned any useful information. for (i, c) in backup_bbds.keys(): messages.announce( "Working under depth {4} assumption: t{0} {1} {2} t{3}".format( candidates[i][0], terms.comp_str[candidates[i][2]], candidates[i][3], candidates[i][1], depth), messages.ASSERTION) try: split_modules(backup_bbds[i, c], backup_modules[i, c], depth - 1, breadth, saturate=False) except terms.Contradiction: messages.announce( "Split led to contradiction at depth {0}. Learned:".format( depth), messages.ASSERTION) can = candidates[i] ti, tj = terms.IVar(can[0]), can[3] * terms.IVar(can[1]) comp = can[2] B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)]( ti, tj)) return split_modules(B, modules, depth, breadth) messages.announce( "Ending depth {4} assumption: t{0} {1} {2} t{3}".format( candidates[i][0], terms.comp_str[candidates[i][2]], candidates[i][3], candidates[i][1], depth), messages.ASSERTION)
def split_modules(B, modules, depth, breadth, saturate=True): """ B is a blackboard. modules is a list of modules. depth restricts how many subsequent splits will be performed: ie, if depth=2, will assume x>0 and y>0, but won't assume z>0 on top of that. breadth restricts how many splits will be considered at each depth. ie, if depth=1, breadth=3, will try the three most promising splits separately. If depth=2, breadth=3, will try the three most promising splits determined after each of the three most promising preliminary splits. """ if saturate: saturate_modules(B, modules) if depth <= 0: return B else: backup_bbds = {} backup_modules = {} if breadth <= 0: candidates = get_splits(B, modules) else: candidates = get_splits(B, modules)[:breadth] for i in range(len(candidates)): can = candidates[i] ti, tj = terms.IVar(can[0]), can[3]*terms.IVar(can[1]) comp = can[2] backup_bbds[i, comp] = copy.deepcopy(B) backup_modules[i, comp] = copy.deepcopy(modules) gtsplit = False try: newcomp = terms.comp_eval[comp](ti, tj) messages.announce("Case split: assuming {0} at depth {1}".format(newcomp, depth), messages.ASSERTION) backup_bbds[i, comp].assert_comparison(newcomp) gtsplit = run_modules(backup_bbds[i, comp], backup_modules[i, comp], 0, 0) except terms.Contradiction: gtsplit = True if gtsplit: #print 'DETERMINED {0} <= {1}'.format(ti, tj) messages.announce("Split led to contradiction at depth {0}. Learned:".format(depth), messages.ASSERTION) B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](ti, tj)) return split_modules(B, modules, depth, breadth) # at this point, none of the depth-1 splits have returned any useful information. for (i, c) in backup_bbds.keys(): messages.announce("Working under depth {4} assumption: t{0} {1} {2} t{3}".format( candidates[i][0], terms.comp_str[candidates[i][2]], candidates[i][3], candidates[i][1], depth), messages.ASSERTION) try: split_modules(backup_bbds[i, c], backup_modules[i, c], depth-1, breadth, saturate=False) except terms.Contradiction: messages.announce("Split led to contradiction at depth {0}. Learned:".format(depth), messages.ASSERTION) can = candidates[i] ti, tj = terms.IVar(can[0]), can[3]*terms.IVar(can[1]) comp = can[2] B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](ti, tj)) return split_modules(B, modules, depth, breadth) messages.announce("Ending depth {4} assumption: t{0} {1} {2} t{3}".format( candidates[i][0], terms.comp_str[candidates[i][2]], candidates[i][3], candidates[i][1], depth), messages.ASSERTION)