def get_proof_term(self, t): assert t.is_equals() or t.is_less_eq() or t.is_less()\ or t.is_greater_eq() or t.is_greater(), "%s is not an equality term" % t pt1 = refl(t) # a = b <==> a = b if t.is_equals(): pt2 = pt1.on_rhs(rewr_conv('int_sub_move_0_r', sym=True)) # a = b <==> a - b = 0 eq_refl = ProofTerm.reflexive(equals(IntType)) elif t.is_less_eq(): pt2 = pt1.on_rhs(rewr_conv('int_leq')) eq_refl = ProofTerm.reflexive(less_eq(IntType)) elif t.is_less(): pt2 = pt1.on_rhs(rewr_conv('int_less')) eq_refl = ProofTerm.reflexive(less(IntType)) elif t.is_greater_eq(): pt2 = pt1.on_rhs(rewr_conv('int_geq')) eq_refl = ProofTerm.reflexive(greater_eq(IntType)) elif t.is_greater(): pt2 = pt1.on_rhs(rewr_conv('int_gt')) eq_refl = ProofTerm.reflexive(greater(IntType)) pt3 = simp_full().get_proof_term( pt2.prop.arg.arg1) # a - b = a + (-1) * b pt4 = ProofTerm.combination(eq_refl, pt3) pt5 = ProofTerm.combination(pt4, refl(Const( 'zero', IntType))) # a - b = 0 <==> a + (-1)*b = 0 return pt2.transitive(pt5) # a = b <==> a + (-1) * b = 0
def testExport2(self): """Repeated theorems.""" pt1 = ProofTerm.assume(Eq(x, y)) pt2 = ProofTerm.reflexive(f) pt3 = pt2.combination(pt1) # f x = f y pt4 = pt3.combination(pt1) # f x x = f y y prf = pt4.export() self.assertEqual(len(prf.items), 4) self.assertEqual(theory.check_proof(prf), pt4.th)
def get_proof_term(self, t): if not t.is_comb(): raise ConvException("combination_conv: not a combination") pt1 = self.cv1.get_proof_term(t.fun) pt2 = self.cv2.get_proof_term(t.arg) # Obtain some savings if one of pt1 and pt2 is reflexivity: if pt1.th.is_reflexive() and pt2.th.is_reflexive(): return ProofTerm.reflexive(t) else: return pt1.combination(pt2)
def get_proofterm(u, v): """Get proof term corresponding to u = v.""" path = explain[(u, v)] cur_pos = u pt = ProofTerm.reflexive(self.index[u]) for eq in path: # Form the proof term for eq, depending on the two cases. if eq[0] == EQ_CONST: _, a, b = eq if (a, b) in self.pts: eq_pt = self.pts[(a, b)] else: eq_pt = ProofTerm.sorry( Thm([], Eq(self.index[a], self.index[b]))) else: _, ((a1, a2), a), ((b1, b2), b) = eq # We already should have: # - a corresponds to Comb(a1, a2) # - b corresponds to Comb(b1, b2) eq_pt1 = get_proofterm( a1, b1) if a1 != b1 else ProofTerm.reflexive( self.index[a1]) eq_pt2 = get_proofterm( a2, b2) if a2 != b2 else ProofTerm.reflexive( self.index[a2]) eq_pt = eq_pt1.combination(eq_pt2) # Append the equality to the current chain. if a == cur_pos: pt = pt.transitive(eq_pt) cur_pos = b else: assert b == cur_pos pt = pt.transitive(pt, eq_pt.symmetric()) cur_pos = a return pt
def get_proof_term(self, goal, prevs=None): elems = goal.strip_disj() preds, concl = elems[:-1], elems[-1] args_pair = [(i, j) for i, j in zip(concl.lhs.strip_comb()[1], concl.rhs.strip_comb()[1])] preds_pair = [(i.arg.lhs, i.arg.rhs) for i in preds] fun = concl.lhs.head pt0 = ProofTerm.reflexive(fun) pt_args_assms = [] for pair in args_pair: r_pair = pair[::-1] if pair in args_pair: pt_args_assms.append(ProofTerm.assume(Eq(*pair))) elif r_pair in args_pair: pt_args_assms.append(ProofTerm.assume(Eq(*r_pair))) pt1 = functools.reduce(lambda x, y: x.combination(y), pt_args_assms, pt0) return ProofTerm("imp_to_or", elems[:-1] + [goal], prevs=[pt1])
def get_proof_term(self, goal, prevs=None): """{(not (= x_1 y_1)) ... (not (= x_n y_n)) (not (p x_1 ... x_n)) (p y_1 ... y_n)} Special case: (not (= x y)) (not (p x y)) (p y x) """ elems = goal.strip_disj() preds, pred_fun, concl = elems[:-2], elems[-2], elems[-1] if pred_fun.is_not(): args_pair = [(i, j) for i, j in zip(pred_fun.arg.strip_comb()[1], concl.strip_comb()[1])] else: args_pair = [(i, j) for i, j in zip(pred_fun.strip_comb()[1], concl.arg.strip_comb()[1])] if len(preds) > 1: preds_pair = [(i.arg.lhs, i.arg.rhs) for i in preds] else: preds_pair = [(preds[0].arg.lhs, preds[0].arg.rhs), (preds[0].arg.lhs, preds[0].arg.rhs)] if pred_fun.is_not(): fun = concl.head else: fun = pred_fun.head pt0 = ProofTerm.reflexive(fun) pt_args_assms = [] for arg, pred in zip(args_pair, preds_pair): if arg == pred: pt_args_assms.append(ProofTerm.assume(Eq(pred[0], pred[1]))) elif arg[0] == pred[1] and pred[0] == arg[1]: pt_args_assms.append( ProofTerm.assume(Eq(pred[0], pred[1])).symmetric()) else: raise NotImplementedError pt1 = functools.reduce(lambda x, y: x.combination(y), pt_args_assms, pt0) if pred_fun.is_not(): pt2 = logic.apply_theorem("eq_implies1", pt1).implies_elim( ProofTerm.assume(pred_fun.arg)) return ProofTerm("imp_to_or", elems[:-1] + [goal], prevs=[pt2]) else: pt2 = pt1.on_prop(conv.rewr_conv("neg_iff_both_sides")) pt3 = logic.apply_theorem("eq_implies1", pt2).implies_elim( ProofTerm.assume(Not(pred_fun))) return ProofTerm("imp_to_or", elems[:-1] + [goal], prevs=[pt3])
def solve(self): """ Call zChaff solver, return the proof term. """ # First write the cnf to a .cnf file. s = 'p cnf ' + str(self.var_num) + ' ' + str(self.clause_num) for clause in self.cnf_list: s += '\n' + ' '.join(str(l) for l in clause) + ' 0' with open('./sat/x.cnf', 'w') as f: f.write(s) # then call zChaff to get the proof trace p = subprocess.Popen('.\\sat\\binaries\\zchaff.exe .\\sat\\x.cnf', stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() result = stdout.decode('utf-8').split('\n')[-2] assert result == "RESULT:\tUNSAT\r" # proof reconstruct first = [] second = [] third = [] with open('.\\resolve_trace', 'r') as f: lines = f.readlines() for l in lines: if l.startswith('CL'): first.append(Resolvent(l)) elif l.startswith('VAR'): second.append(ImpliedVarValue(l)) else: third.append(Conflict(l)) for j, f in enumerate(first): res_cls = f.rsl pt = self.clause_pt[res_cls[0]] for i in range(len(res_cls) - 1): pt = resolution(pt, self.clause_pt[res_cls[i + 1]]) self.clause_pt[len(self.clause_pt)] = pt second = sorted(second, key=lambda x: x.level) # dictionary from var index to its true value var_pt = {} for s in second: cls_pt = self.clause_pt[s.act] pts = [] lits = [floor(l / 2) for l in s.lits if floor(l / 2) != s.var] if not lits: var_pt[s.var] = cls_pt continue exist_var_pt = [var_pt[l] for l in lits] exact_var = self.index_var[s.var] if s.value == 1 else Not( self.index_var[s.var]) prevs = [cls_pt] + exist_var_pt var_pt[s.var] = DisjForceMacro().get_proof_term(prevs, exact_var) conflict_cls = third[0] literal_pt = [var_pt[floor(i / 2)] for i in conflict_cls.lits] self.conflict_pt = DisjFalseMacro().get_proof_term( self.clause_pt[conflict_cls.cls], literal_pt) # return the theorem pt1, pt2 = self.encode_pt, self.conflict_pt while pt1.prop.is_conj(): pt_left = apply_theorem('conjD1', pt1) pt2 = pt2.implies_intr(pt_left.prop).implies_elim( pt_left) # remove one clause from assumption pt1 = apply_theorem('conjD2', pt1) pt2 = pt2.implies_intr(pt1.prop).implies_elim( pt1) # remove last clause from assumption # Clear definition of new variables from antecedent eqs = [t for t in pt2.hyps if t.is_equals()] eqs = list(reversed(sorted(eqs, key=lambda t: int(t.lhs().name[1:])))) for eq in eqs: pt2 = pt2.implies_intr(eq).forall_intr(eq.lhs).forall_elim(eq.rhs) \ .implies_elim(ProofTerm.reflexive(eq.rhs)) return apply_theorem('negI', pt2.implies_intr(pt2.hyps[0])).on_prop( rewr_conv('double_neg'))
def get_proof_term(self, args, prevs=None): """ Let x_i denotes greater comparison, x__i denotes less comparison, for the greater comparison, find the smallest number x_min = min(x_1, ..., x_n), since x_min is positive, x_min/2 > 0 ==> x_min >= x_min / 2 ==> x_1, ..., x_n >= x_min / 2 ==> ∃δ. δ > 0 ∧ x_1 >= δ ∧ ... ∧ x_n >= δ. for the less comparison, find the largest number x_max = max(x__1, ..., x__n), since x_max is negative, x_max < x_max/2 ==> x__1, ..., x__n <= x_max/2; let δ = min(x_min/2, -x_max/2), then all x_i >= δ as well as all x__i <= -δ. """ def need_convert(tm): return False if real_eval(tm.arg) != 0 else True original_ineq_pts = [ProofTerm.assume(ineq) for ineq in args] # record the ineq which rhs is not 0 need_convert_pt = {arg for arg in args if need_convert(arg)} # record the args order order_args = {args[i].arg1: i for i in range(len(args))} # convert all ineqs to x_i > 0 or x_i < 0 normal_ineq_pts = [ pt.on_prop(norm_real_ineq_conv()) if pt.prop.arg != Real(0) else pt for pt in original_ineq_pts ] # dividing less comparison and greater comparison greater_ineq_pts = [ pt for pt in normal_ineq_pts if pt.prop.is_greater() ] less_ineq_pts = [pt for pt in normal_ineq_pts if pt.prop.is_less()] # stage 1: get the max(min) pos bound # ⊢ min(...) ≥ δ_1, δ_1 > 0 # ⊢ max(...) ≤ δ_2, δ_2 < 0 pt_lower_bound, lower_bound_pos_pt, pt_assert_delta1 = self.handle_geq_stage1( greater_ineq_pts) pt_upper_bound, upper_bound_neg_pt, pt_assert_delta2 = self.handle_leq_stage1( less_ineq_pts) delta_1 = Var("δ_1", RealType) delta_2 = Var("δ_2", RealType) # generate the relaxed inequations if pt_lower_bound is None: # all comparisons are ≤ pts = self.handle_leq_stage2(pt_upper_bound, less_ineq_pts, delta_2) bound_pt = upper_bound_neg_pt delta = delta_2 pt_asserts = [pt_assert_delta2] elif pt_upper_bound is None: # all comparisons are ≥ pts = self.handle_geq_stage2(pt_lower_bound, greater_ineq_pts, delta_1) bound_pt = lower_bound_pos_pt delta = delta_1 pt_asserts = [pt_assert_delta1] else: # have both ≥ and ≤ # ⊢ δ_1 ≥ min(δ_1, δ_2) pt_min_lower_bound = logic.apply_theorem("real_greater_min", inst=matcher.Inst( x=delta_1, y=delta_2)) # ⊢ -δ_2 ≤ max(-δ_2, -δ_1) pt_max_upper_bound = logic.apply_theorem("real_less_max", inst=matcher.Inst( x=-delta_2, y=-delta_1)) # ⊢ max(-δ_2, -δ_1) = -min(δ_1, δ_2) pt_max_min = logic.apply_theorem("max_min", inst=matcher.Inst(x=delta_1, y=delta_2)) # ⊢ min(...) ≥ min(δ_1, δ_2) pt_new_lower_bound = logic.apply_theorem("real_geq_trans", pt_lower_bound, pt_min_lower_bound) # ⊢ -δ_2 ≤ -min(δ_1, δ_2) pt_max_upper_bound_1 = pt_max_upper_bound.on_prop( arg_conv(replace_conv(pt_max_min))) # ⊢ max(...) ≤ -min(δ_1, δ_2) pt_new_upper_bound = logic.apply_theorem("real_le_trans", pt_upper_bound, pt_max_upper_bound_1) # ⊢ min(δ_1, δ_2) > 0 pt_new_lower_bound_pos = logic.apply_theorem( "min_pos", lower_bound_pos_pt, upper_bound_neg_pt) # ⊢ min(δ_1, δ_2) = δ delta = Var("δ", RealType) pt_delta_eq = ProofTerm.assume( Eq(pt_min_lower_bound.prop.arg, delta)) pt_asserts = [pt_delta_eq, pt_assert_delta1, pt_assert_delta2] # ⊢ min(...) ≥ δ pt_new_lower_bound_delta = pt_new_lower_bound.on_prop( arg_conv(replace_conv(pt_delta_eq))) # ⊢ max(...) ≤ -δ pt_new_upper_bound_delta = pt_new_upper_bound.on_prop( top_conv(replace_conv(pt_delta_eq))) # use new bound pts_leq = self.handle_leq_stage2(pt_new_upper_bound_delta, less_ineq_pts, delta) pts_geq = self.handle_geq_stage2(pt_new_lower_bound_delta, greater_ineq_pts, delta) pts = pts_leq + pts_geq bound_pt = pt_new_lower_bound_pos.on_prop( arg1_conv(replace_conv(pt_delta_eq))) # sort_pts = sorted(pts, key=lambda pt: order_args[pt.prop.arg1]) pt_conj = functools.reduce( lambda x, y: logic.apply_theorem("conjI", y, x), reversed([bound_pt] + pts)) # get ⊢∃δ. δ > 0 ∧ x_1 >= δ ∧ ... ∧ x_n >= δ th = ProofTerm.theorem("exI") inst = matcher.first_order_match(th.prop.arg, Exists(delta, pt_conj.prop)) pt_conj_exists = logic.apply_theorem("exI", pt_conj, inst=inst) pt_final = pt_conj_exists for pt_subst in pt_asserts: lhs, rhs = pt_subst.prop.args if not rhs.is_uminus(): pt_final = pt_final.implies_intr(pt_subst.prop).forall_intr(rhs).\ forall_elim(lhs).implies_elim(ProofTerm.reflexive(lhs)) else: pt_final = pt_final.implies_intr(pt_subst.prop).forall_intr(rhs.arg).\ forall_elim(-lhs).on_prop(top_conv(rewr_conv("real_neg_neg"))).implies_elim(ProofTerm.reflexive(lhs)) return pt_final