Esempio n. 1
0
def simplify1(fm):
    """Simplify formula for one step."""
    if fm.is_not():
        if fm.arg == false:
            return true
        elif fm.arg == true:
            return false
        elif fm.arg.is_not():
            return fm.arg.arg
        else:
            return fm
    elif fm.is_conj():
        if fm.arg1 == false or fm.arg == false:
            return false
        elif fm.arg1 == true:
            return fm.arg
        elif fm.arg == true:
            return fm.arg1
        else:
            return fm
    elif fm.is_disj():
        if fm.arg1 == true or fm.arg == true:
            return true
        elif fm.arg1 == false:
            return fm.arg
        elif fm.arg == false:
            return fm.arg1
        else:
            return fm
    elif fm.is_implies():
        if fm.arg1 == false or fm.arg == true:
            return true
        elif fm.arg1 == true:
            return fm.arg
        elif fm.arg == false:
            return Not(fm.arg1)
        else:
            return fm
    elif fm.is_equals():
        if fm.arg1 == true:
            return fm.arg
        elif fm.arg == true:
            return fm.arg1
        elif fm.arg1 == false:
            return Not(fm.arg)
        elif fm.arg == false:
            return Not(fm.arg1)
        else:
            return fm
    elif fm.is_forall() or fm.is_exists():
        if has_bound0(fm.arg.body):
            return fm
        else:
            return fm.arg.subst_bound(Var("_u", fm.arg.var_T))
    else:
        return fm
Esempio n. 2
0
    def get_proof_term(self, args, pts):

        # First, find the pair i, j such that B_j = ~A_i or A_i = ~B_j, the
        # variable side records the side of the positive literal.
        pt1, pt2 = pts
        disj1 = strip_num(pt1.prop, args[0])
        disj2 = strip_num(pt2.prop, args[1])
        side = None
        for i, t1 in enumerate(disj1):
            for j, t2 in enumerate(disj2):
                if t2 == Not(t1):
                    side = 'left'
                    break
                elif t1 == Not(t2):
                    side = 'right'
                    break
            if side is not None:
                break

        assert side is not None, "resolution: literal not found"

        # If side is wrong, just swap:
        if side == 'right':
            return self.get_proof_term([args[1], args[0]], [pt2, pt1])

        # Move items i and j to the front
        disj1 = [disj1[i]] + disj1[:i] + disj1[i + 1:]
        disj2 = [disj2[j]] + disj2[:j] + disj2[j + 1:]
        eq_pt1 = logic.imp_disj_iff(Eq(pt1.prop, Or(*disj1)))
        eq_pt2 = logic.imp_disj_iff(Eq(pt2.prop, Or(*disj2)))
        pt1 = eq_pt1.equal_elim(pt1)
        pt2 = eq_pt2.equal_elim(pt2)

        if len(disj1) > 1 and len(disj2) > 1:
            pt = logic.apply_theorem('resolution', pt1, pt2)
        elif len(disj1) > 1 and len(disj2) == 1:
            pt = logic.apply_theorem('resolution_left', pt1, pt2)
        elif len(disj1) == 1 and len(disj2) > 1:
            pt = logic.apply_theorem('resolution_right', pt1, pt2)
        else:
            pt = logic.apply_theorem('negE', pt2, pt1)

        # return pt.on_prop(disj_norm())
        disj_new = set(disj1[1:] + disj2[1:])
        # eq_pt_norm = logic.imp_disj_iff(Eq(pt.prop, Or(*disj_new)))
        implies_pt_norm = ProofTerm("imp_disj",
                                    Implies(pt.prop, Or(*disj_new)))
        pt_final = implies_pt_norm.implies_elim(pt)
        self.arity = len(disj_new)
        return pt_final.on_prop(conv.top_conv(conv.rewr_conv("double_neg")))
Esempio n. 3
0
    def get_proof_term(self, goal, *, args=None, prevs=None):
        assert isinstance(args, Term), "cases"

        As = goal.hyps
        C = goal.prop
        goal1 = ProofTerm.sorry(Thm(goal.hyps, Implies(args, C)))
        goal2 = ProofTerm.sorry(Thm(goal.hyps, Implies(Not(args), C)))
        return apply_theorem('classical_cases', goal1, goal2)
Esempio n. 4
0
    def get_proof_term(self, arg, pts):
        """Input proof terms are A_1 | ... | A_m and B_1 | ... | B_n, where
        there is some i, j such that B_j = ~A_i or A_i = ~B_j."""
        
        # First, find the pair i, j such that B_j = ~A_i or A_i = ~B_j, the
        # variable side records the side of the positive literal.
        pt1, pt2 = pts
        disj1 = strip_disj(pt1.prop)
        disj2 = strip_disj(pt2.prop)
        
        side = None
        for i, t1 in enumerate(disj1):
            for j, t2 in enumerate(disj2):
                if t2 == Not(t1):
                    side = 'left'
                    break
                elif t1 == Not(t2):
                    side = 'right'
                    break
            if side is not None:
                break
                
        assert side is not None, "resolution: literal not found"
        
        # If side is wrong, just swap:
        if side == 'right':
            return self.get_proof_term(arg, [pt2, pt1])
        
        # Move items i and j to the front
        disj1 = [disj1[i]] + disj1[:i] + disj1[i+1:]
        disj2 = [disj2[j]] + disj2[:j] + disj2[j+1:]
        eq_pt1 = imp_disj_iff(Eq(pt1.prop, Or(*disj1)))
        eq_pt2 = imp_disj_iff(Eq(pt2.prop, Or(*disj2)))
        pt1 = eq_pt1.equal_elim(pt1)
        pt2 = eq_pt2.equal_elim(pt2)
        
        if len(disj1) > 1 and len(disj2) > 1:
            pt = apply_theorem('resolution', pt1, pt2)
        elif len(disj1) > 1 and len(disj2) == 1:
            pt = apply_theorem('resolution_left', pt1, pt2)
        elif len(disj1) == 1 and len(disj2) > 1:
            pt = apply_theorem('resolution_right', pt1, pt2)
        else:
            pt = apply_theorem('negE', pt2, pt1)

        return pt.on_prop(disj_norm())
Esempio n. 5
0
File: nat.py Progetto: bzhan/holpy
 def get_proof_term(self, goal, pts):
     assert isinstance(goal, Term)
     assert len(pts) == 0, "nat_const_less_macro"
     m, n = goal.args
     assert m.dest_number() < n.dest_number()
     less_eq_pt = nat_const_less_eq_macro().get_proof_term(m <= n, [])
     ineq_pt = nat_const_ineq_macro().get_proof_term(Not(Eq(m, n)), [])
     return apply_theorem("less_lesseqI", less_eq_pt, ineq_pt)
Esempio n. 6
0
 def testEvalSem5(self):
     com = While(Lambda(s, Not(Eq(s(zero), Nat(3)))), assn_true, incr_one)
     st = mk_const_fun(NatType, zero)
     st2 = fun_upd_of_seq(0, 3)
     goal = Sem(com, st, st2)
     prf = imp.eval_Sem_macro().get_proof_term(goal, []).export()
     rpt = ProofReport()
     self.assertEqual(theory.check_proof(prf, rpt), Thm([], goal))
Esempio n. 7
0
    def testPelletier(self):
        with open('prover/tests/pelletier.json', 'r', encoding='utf-8') as f:
            f_data = json.load(f)

        for problem in f_data:
            context.set_context('sat', vars=problem['vars'])
            prop = parser.parse_term(problem['prop'])
            cnf = tseitin.convert_cnf(tseitin.encode(Not(prop)).prop)
            res, cert = sat.solve_cnf(cnf)
            self.assertEqual(res, 'unsatisfiable')
Esempio n. 8
0
    def get_proof_term(self, t):
        if not t.is_disj():
            return refl(t)

        nnf_pt = nnf_conv().get_proof_term(Not(t))
        norm_neg_disj_pt = sort_conj().get_proof_term(nnf_pt.rhs)
        nnf_pt_norm = nnf_pt.transitive(norm_neg_disj_pt)
        return nnf_pt_norm.on_prop(rewr_conv('neg_iff_both_sides'),
                                   arg1_conv(rewr_conv('double_neg')),
                                   arg_conv(nnf_conv()))
Esempio n. 9
0
def encode(t):
    """Given a propositional formula t, compute its Tseitin encoding.

    The theorem is structured as follows:

    Each of the assumptions, except the last, is an equality, where
    the right side is either an atom or a logical operation between
    atoms. We call these assumptions As.

    The last assumption is the original formula. We call it F.

    The conclusion is in CNF. Each clause except the last is an
    expansion of one of As. The last clause is obtained by performing
    substitutions of As on F.

    """
    # Mapping from subterms to newly introduced variables
    subterm_dict = dict()
    for i, subt in enumerate(logic_subterms(t)):
        subterm_dict[subt] = Var('x' + str(i + 1), BoolType)

    # Collect list of equations
    eqs = []
    for subt in subterm_dict:
        r = subterm_dict[subt]
        if not is_logical(subt):
            eqs.append(Eq(r, subt))
        elif subt.is_not():
            r1 = subterm_dict[subt.arg]
            eqs.append(Eq(r, Not(r1)))
        else:
            r1 = subterm_dict[subt.arg1]
            r2 = subterm_dict[subt.arg]
            eqs.append(Eq(r, subt.head(r1, r2)))

    # Form the proof term
    eq_pts = [ProofTerm.assume(eq) for eq in eqs]
    encode_pt = ProofTerm.assume(t)
    for eq_pt in eq_pts:
        encode_pt = encode_pt.on_prop(top_conv(rewr_conv(eq_pt, sym=True)))
    for eq_pt in eq_pts:
        if is_logical(eq_pt.rhs):
            encode_pt = logic.apply_theorem('conjI', eq_pt, encode_pt)

    # Rewrite using Tseitin rules
    encode_thms = [
        'encode_conj', 'encode_disj', 'encode_imp', 'encode_eq', 'encode_not'
    ]

    for th in encode_thms:
        encode_pt = encode_pt.on_prop(top_conv(rewr_conv(th)))

    # Normalize the conjuncts
    return encode_pt.on_prop(logic.conj_norm())
Esempio n. 10
0
    def get_proof_term(self, prevs, goal_lit):
        disj, *lit_pts = prevs
        pt_conj = lit_pts[0]

        for i in range(len(lit_pts)):
            pt = lit_pts[i]
            if not pt.prop.is_not():
                lit_pts[i] = pt.on_prop(rewr_conv('double_neg', sym=True))

        def conj_right_assoc(pts):
            """
            Give a sequence of proof terms: ⊢ A, ⊢ B, ⊢ C,
            return ⊢ A ∧ (B ∧ C)
            """
            if len(pts) == 1:
                return pts[0]
            else:
                return apply_theorem('conjI', pts[0],
                                     conj_right_assoc(pts[1:]))

        # get a /\ b /\ c
        pt_conj = conj_right_assoc(lit_pts)

        other_lits = [
            l.prop.arg if l.prop.is_not() else Not(l.prop) for l in lit_pts
        ]

        # use de Morgan
        pt_conj1 = pt_conj.on_prop(
            bottom_conv(rewr_conv('de_morgan_thm2', sym=True)))

        # if len(other_lits) == 1 and other_lits[0].is_not():
        #     pt_conj1 = pt_conj.on_prop(rewr_conv('double_neg', sym=True))

        # Equality for two disjunctions which literals are the same, but order is different.
        eq_pt = imp_disj_iff(Eq(disj.prop, Or(goal_lit, *other_lits)))
        new_disj_pt = disj.on_prop(top_conv(replace_conv(eq_pt)))

        # A \/ B --> ~B --> A
        pt = ProofTerm.theorem('force_disj_true1')
        A, B = pt.prop.strip_implies()[0]
        C = pt.prop.strip_implies()[1]

        inst1 = matcher.first_order_match(C, goal_lit)
        inst2 = matcher.first_order_match(A,
                                          Or(goal_lit, *other_lits),
                                          inst=inst1)
        inst3 = matcher.first_order_match(B, pt_conj1.prop, inst=inst2)
        pt_implies = apply_theorem('force_disj_true1',
                                   new_disj_pt,
                                   pt_conj1,
                                   inst=inst3)

        return pt_implies.on_prop(try_conv(rewr_conv('double_neg')))
Esempio n. 11
0
    def testEvalSem4(self):
        com = Cond(Lambda(s, Not(Eq(s(zero), one))), incr_one, Skip)
        st = mk_const_fun(NatType, zero)
        st2 = fun_upd_of_seq(0, 1)
        goal = Sem(com, st, st2)
        prf = imp.eval_Sem_macro().get_proof_term(goal, []).export()
        self.assertEqual(theory.check_proof(prf), Thm([], goal))

        goal = Sem(com, st2, st2)
        prf = imp.eval_Sem_macro().get_proof_term(goal, []).export()
        self.assertEqual(theory.check_proof(prf), Thm([], goal))
Esempio n. 12
0
    def get_proof_term(self, t):
        pt = refl(t)
        if t.arg1 == true:
            return pt.on_rhs(rewr_conv('conj_true_left'))
        elif t.arg == true:
            return pt.on_rhs(rewr_conv('conj_true_right'))
        elif t.arg1 == false:
            return pt.on_rhs(rewr_conv('conj_false_right'))
        elif t.arg == false:
            return pt.on_rhs(rewr_conv('conj_false_left'))
        elif t.arg.is_conj():
            if t.arg1 == Not(t.arg.arg1):  # A /\ (A_1 /\ ... /\ A_n)
                return pt.on_rhs(rewr_conv('conj_assoc'),
                                 arg1_conv(rewr_conv('conj_neg_pos')),
                                 rewr_conv('conj_false_right'))
            elif Not(t.arg1) == t.arg.arg1:
                return pt.on_rhs(rewr_conv('conj_assoc'),
                                 arg1_conv(rewr_conv('conj_pos_neg')),
                                 rewr_conv('conj_false_right'))

            cp = term_ord.fast_compare(t.arg1, t.arg.arg1)
            if cp > 0:
                return pt.on_rhs(swap_conj_r(), arg_conv(self), try_conv(self))
            elif cp == 0:
                return pt.on_rhs(rewr_conv('conj_assoc'),
                                 arg1_conv(rewr_conv('conj_same_atom')))
            else:
                return pt
        else:
            if t.arg == Not(t.arg1):
                return pt.on_rhs(rewr_conv('conj_pos_neg'))
            elif t.arg1 == Not(t.arg):
                return pt.on_rhs(rewr_conv('conj_neg_pos'))
            cp = term_ord.fast_compare(t.arg1, t.arg)
            if cp > 0:
                return pt.on_rhs(swap_conj_r())
            elif cp == 0:
                return pt.on_rhs(rewr_conv('conj_same_atom'))
            else:
                return pt
Esempio n. 13
0
def convert_cnf_to_HOL(cnf_file):
    disjs = read_cnf_file(cnf_file)
    tms = []
    for disj in disjs:
        lits = []
        for var, stat in disj:
            if stat:
                lits.append(Var(var, BoolType))
            else:
                lits.append(Not(Var(var, BoolType)))
        tms.append(Or(*lits))

    return And(*tms)
Esempio n. 14
0
    def eval(self, goal, prevs):
        assert len(prevs) == 0, "int_const_ineq: no conditions expected"

        if goal.is_not():
            goal = goal.arg

        assert (goal.is_compares() or goal.is_equals()) and goal.arg1.is_constant() and goal.arg.is_constant()\
            and goal.arg1.get_type() == IntType, repr(goal)
        lhs, rhs = int_eval(goal.arg1), int_eval(goal.arg)
        if goal.is_less():
            if lhs < rhs:
                return Thm([], goal)
            else:
                return Thm([], Not(goal))
        elif goal.is_less_eq():
            if lhs <= rhs:
                return Thm([], goal)
            else:
                return Thm([], Not(goal))
        elif goal.is_greater():
            if lhs > rhs:
                return Thm([], goal)
            else:
                return Thm([], Not(goal))
        elif goal.is_greater_eq():
            if lhs >= rhs:
                return Thm([], goal)
            else:
                return Thm([], Not(goal))
        elif goal.is_equals():
            if lhs == rhs:
                return Thm([], goal)
            else:
                return Thm([], Not(goal))
        else:
            raise NotImplementedError
Esempio n. 15
0
def simplify(fm):
    """Simplify formula.
    
    Remove true, false, and vacuous forall/exists quantification.

    """
    if fm.is_not():
        return simplify1(Not(simplify(fm.arg)))
    elif fm.is_conj() or fm.is_disj() or fm.is_implies() or fm.is_equals():
        return simplify1(fm.head(simplify(fm.arg1), simplify(fm.arg)))
    elif fm.is_forall() or fm.is_exists():
        assert fm.arg.is_abs()
        return simplify1(
            fm.fun(Abs(fm.arg.var_name, fm.arg.var_T, simplify(fm.arg.body))))
    else:
        return fm
Esempio n. 16
0
    def testPrintUnicode(self):
        test_data = [
            (And(A, B), "A ∧ B"),
            (Or(A, B), "A ∨ B"),
            (Implies(A, B), "A ⟶ B"),
            (Lambda(a, P(a)), "λa. P a"),
            (Forall(a, P(a)), "∀a. P a"),
            (Exists(a, P(a)), "∃a. P a"),
            (Not(A), "¬A"),
            (Lambda(m, m + 2), "λm::nat. m + 2"),
            (Lambda(m, m + n), "λm. m + n"),
        ]

        with global_setting(unicode=True):
            for t, s in test_data:
                self.assertEqual(printer.print_term(t), s)
Esempio n. 17
0
 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])
Esempio n. 18
0
    def get_extension(self):
        assert self.error is None, "get_extension"
        res = []

        # Add to type and term signature.
        res.append(extension.TConst(self.name, len(self.args)))
        for constr in self.constrs:
            res.append(
                extension.Constant(constr['name'],
                                   constr['type'],
                                   ref_name=constr['cname']))

        # Add non-equality theorems.
        for constr1, constr2 in itertools.combinations(self.constrs, 2):
            # For each A x_1 ... x_m and B y_1 ... y_n, get the theorem
            # ~ A x_1 ... x_m = B y_1 ... y_n.
            argT1, _ = constr1['type'].strip_type()
            argT2, _ = constr2['type'].strip_type()
            lhs_vars = [Var(nm, T) for nm, T in zip(constr1['args'], argT1)]
            rhs_vars = [Var(nm, T) for nm, T in zip(constr2['args'], argT2)]
            A = Const(constr1['name'], constr1['type'])
            B = Const(constr2['name'], constr2['type'])
            lhs = A(*lhs_vars)
            rhs = B(*rhs_vars)
            neq = Not(Eq(lhs, rhs))
            th_name = "%s_%s_%s_neq" % (self.name, constr1['name'],
                                        constr2['name'])
            res.append(extension.Theorem(th_name, Thm([], neq)))

        # Add injectivity theorems.
        for constr in self.constrs:
            # For each A x_1 ... x_m with m > 0, get the theorem
            # A x_1 ... x_m = A x_1' ... x_m' --> x_1 = x_1' & ... & x_m = x_m'
            if constr['args']:
                argT, _ = constr['type'].strip_type()
                lhs_vars = [Var(nm, T) for nm, T in zip(constr['args'], argT)]
                rhs_vars = [
                    Var(nm + "1", T) for nm, T in zip(constr['args'], argT)
                ]
                A = Const(constr['name'], constr['type'])
                assum = Eq(A(*lhs_vars), A(*rhs_vars))
                concls = [
                    Eq(var1, var2) for var1, var2 in zip(lhs_vars, rhs_vars)
                ]
                concl = And(*concls)
                th_name = "%s_%s_inject" % (self.name, constr['name'])
                res.append(
                    extension.Theorem(th_name, Thm([], Implies(assum, concl))))

        # Add the inductive theorem.
        tvars = [TVar(targ) for targ in self.args]
        T = TConst(self.name, *tvars)
        var_P = Var("P", TFun(T, BoolType))
        ind_assums = []
        for constr in self.constrs:
            A = Const(constr['name'], constr['type'])
            argT, _ = constr['type'].strip_type()
            args = [Var(nm, T2) for nm, T2 in zip(constr['args'], argT)]
            C = var_P(A(*args))
            As = [
                var_P(Var(nm, T2)) for nm, T2 in zip(constr['args'], argT)
                if T2 == T
            ]
            ind_assum = Implies(*(As + [C]))
            for arg in reversed(args):
                ind_assum = Forall(arg, ind_assum)
            ind_assums.append(ind_assum)
        ind_concl = var_P(Var("x", T))
        th_name = self.name + "_induct"
        res.append(
            extension.Theorem(th_name,
                              Thm([], Implies(*(ind_assums + [ind_concl])))))
        res.append(extension.Attribute(th_name, "var_induct"))

        return res
Esempio n. 19
0
def nnf(fm):
    """Negation normal form of a formula."""
    if fm.is_conj():
        return And(nnf(fm.arg1), nnf(fm.arg))
    elif fm.is_disj():
        return Or(nnf(fm.arg1), nnf(fm.arg))
    elif fm.is_implies():
        return Or(nnf(Not(fm.arg1)), nnf(fm.arg))
    elif fm.is_equals():
        return Or(And(nnf(fm.arg1), nnf(fm.arg)),
                  And(nnf(Not(fm.arg1)), nnf(Not(fm.arg))))
    elif fm.is_not():
        p = fm.arg
        if p.is_not():
            return nnf(p.arg)
        elif p.is_conj():
            return Or(nnf(Not(p.arg1)), nnf(Not(p.arg)))
        elif p.is_disj():
            return And(nnf(Not(p.arg1)), nnf(Not(p.arg)))
        elif p.is_implies():
            return And(nnf(p.arg1), nnf(Not(p.arg)))
        elif p.is_equals():
            return Or(And(nnf(p.arg1), nnf(Not(p.arg))),
                      And(nnf(Not(p.arg1)), nnf(p.arg)))
        elif p.is_forall():
            assert p.arg.is_abs()
            return term.exists(p.arg.var_T)(Abs(p.arg.var_name, p.arg.var_T,
                                                nnf(Not(p.arg.body))))
        elif p.is_exists():
            assert p.arg.is_abs()
            return term.forall(p.arg.var_T)(Abs(p.arg.var_name, p.arg.var_T,
                                                nnf(Not(p.arg.body))))
        else:
            return fm
    elif fm.is_forall() or fm.is_exists():
        assert fm.arg.is_abs()
        return fm.fun(Abs(fm.arg.var_name, fm.arg.var_T, nnf(fm.arg.body)))
    else:
        return fm
Esempio n. 20
0
 def ineq_cond(self, e1, e2):
     return Not(Eq(e1, e2))
Esempio n. 21
0
 def neg(self, t):
     return Not(t)
Esempio n. 22
0
    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'))
Esempio n. 23
0
File: nat.py Progetto: bzhan/holpy
def nat_const_ineq(a, b):
    return ProofTerm("nat_const_ineq", Not(Eq(a, b)), [])
Esempio n. 24
0
def init_proof(prop):
    """Initialize proof for proposition."""
    vars = prop.get_vars()
    assms, concl = prop.strip_implies()
    assms.append(concl.arg if concl.is_not() else Not(concl))
    return ProofState(vars, assms)
Esempio n. 25
0
    def testPrintLogical(self):
        test_data = [
            # Variables
            (SVar("P", BoolType), "?P"),
            (a, "a"),

            # Equality and implies
            (Eq(a, b), "a = b"),
            (Implies(A, B), "A --> B"),
            (Implies(A, B, C), "A --> B --> C"),
            (Implies(Implies(A, B), C), "(A --> B) --> C"),
            (Implies(A, Eq(a, b)), "A --> a = b"),
            (Eq(Implies(A, B), Implies(B, C)), "(A --> B) <--> (B --> C)"),
            (Eq(A, Eq(B, C)), "A <--> B <--> C"),
            (Eq(Eq(A, B), C), "(A <--> B) <--> C"),

            # Conjunction and disjunction
            (And(A, B), "A & B"),
            (Or(A, B), "A | B"),
            (And(A, And(B, C)), "A & B & C"),
            (And(And(A, B), C), "(A & B) & C"),
            (Or(A, Or(B, C)), "A | B | C"),
            (Or(Or(A, B), C), "(A | B) | C"),
            (Or(And(A, B), C), "A & B | C"),
            (And(Or(A, B), C), "(A | B) & C"),
            (Or(A, And(B, C)), "A | B & C"),
            (And(A, Or(B, C)), "A & (B | C)"),
            (Or(And(A, B), And(B, C)), "A & B | B & C"),
            (And(Or(A, B), Or(B, C)), "(A | B) & (B | C)"),

            # Negation
            (Not(A), "~A"),
            (Not(Not(A)), "~~A"),

            # Constants
            (true, "true"),
            (false, "false"),

            # Mixed
            (Implies(And(A, B), C), "A & B --> C"),
            (Implies(A, Or(B, C)), "A --> B | C"),
            (And(A, Implies(B, C)), "A & (B --> C)"),
            (Or(Implies(A, B), C), "(A --> B) | C"),
            (Not(And(A, B)), "~(A & B)"),
            (Not(Implies(A, B)), "~(A --> B)"),
            (Not(Eq(A, B)), "~(A <--> B)"),
            (Eq(Not(A), B), "~A <--> B"),
            (Eq(Not(A), Not(B)), "~A <--> ~B"),
            (Implies(A, Eq(B, C)), "A --> B <--> C"),
            (Eq(Implies(A, B), C), "(A --> B) <--> C"),

            # Abstraction
            (Lambda(a, And(P(a), Q(a))), "%a. P a & Q a"),

            # Quantifiers
            (Forall(a, P(a)), "!a. P a"),
            (Forall(a, Forall(b, And(P(a), P(b)))), "!a. !b. P a & P b"),
            (Forall(a, And(P(a), Q(a))), "!a. P a & Q a"),
            (And(Forall(a, P(a)), Q(a)), "(!a1. P a1) & Q a"),
            (Forall(a, Implies(P(a), Q(a))), "!a. P a --> Q a"),
            (Implies(Forall(a, P(a)), Q(a)), "(!a1. P a1) --> Q a"),
            (Implies(Forall(a, P(a)),
                     Forall(a, Q(a))), "(!a. P a) --> (!a. Q a)"),
            (Implies(Exists(a, P(a)),
                     Exists(a, Q(a))), "(?a. P a) --> (?a. Q a)"),
            (Eq(A, Forall(a, P(a))), "A <--> (!a. P a)"),
            (Exists(a, P(a)), "?a. P a"),
            (Exists(a, Forall(b, R(a, b))), "?a. !b. R a b"),
            (logic.mk_exists1(a, P(a)), "?!a. P a"),
            (logic.mk_the(a, P(a)), "THE a. P a"),
            (logic.mk_some(a, P(a)), "SOME a. P a"),
            (Forall(a, Exists(b, R(a, b))), "!a. ?b. R a b"),

            # If
            (mk_if(A, a, b), "if A then a else b"),
            (Eq(mk_if(A, a, b), a), "(if A then a else b) = a"),
            (mk_if(A, P, Q), "if A then P else Q"),
        ]

        with global_setting(unicode=False):
            for t, s in test_data:
                self.assertEqual(printer.print_term(t), s)
Esempio n. 26
0
    def get_proof_term(self, t):

        if not t.is_conj():
            return refl(t)

        d_pos = dict()
        d_neg = dict()
        qu = deque([ProofTerm.assume(t)])
        # collect each conjunct's proof term in conjuntion
        while qu:
            pt = qu.popleft()
            if pt.prop.is_conj():
                conj1, conj2 = pt.prop.arg1, pt.prop.arg
                pt_conj1, pt_conj2 = apply_theorem('conjD1',
                                                   pt), apply_theorem(
                                                       'conjD2', pt)
                if conj1 == false:
                    th = ProofTerm.theorem("falseE")
                    inst = matcher.first_order_match(th.prop.arg, t)
                    pt_false_implies_conj = th.substitution(inst)
                    return ProofTerm.equal_intr(pt_conj1.implies_intr(t),
                                                pt_false_implies_conj)
                elif conj2 == false:
                    th = ProofTerm.theorem("falseE")
                    inst = matcher.first_order_match(th.prop.arg, t)
                    pt_false_implies_conj = th.substitution(inst)
                    return ProofTerm.equal_intr(pt_conj2.implies_intr(t),
                                                pt_false_implies_conj)
                if conj1.is_conj():
                    qu.appendleft(pt_conj1)
                else:
                    if conj1.is_not():
                        d_neg[conj1] = pt_conj1
                    else:
                        d_pos[conj1] = pt_conj1
                if conj2.is_conj():
                    qu.appendleft(pt_conj2)
                else:
                    if conj2.is_not():
                        d_neg[conj2] = pt_conj2
                    else:
                        d_pos[conj2] = pt_conj2
            else:
                if pt.prop.is_not():
                    d_neg[pt.prop] = pt
                else:
                    d_pos[pt.prop] = pt

        # first check if there are opposite terms in conjunctions, if there exists, return a false proof term
        for key in d_pos:
            if Not(key) in d_neg:
                pos_pt, neg_pt = d_pos[key], d_neg[Not(key)]
                pt_conj_pos_neg = apply_theorem("conjI", pos_pt, neg_pt)
                pt_conj_implies_false = pt_conj_pos_neg.on_prop(
                    rewr_conv("conj_pos_neg")).implies_intr(t)
                th = ProofTerm.theorem("falseE")
                inst = matcher.first_order_match(th.prop.arg, t)
                pt_false_implies_conj = th.substitution(inst)
                return ProofTerm.equal_intr(pt_conj_implies_false,
                                            pt_false_implies_conj)

        d_pos.update(d_neg)
        d = d_pos

        def right_assoc(ts):
            l = len(ts)
            if l == 1:
                return d[ts[0]]
            elif l == 2:
                return apply_theorem('conjI', d[ts[0]], d[ts[1]])
            else:
                return apply_theorem('conjI', d[ts[0]], right_assoc(ts[1:]))

        # pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', x, d[y]), sorted(d.keys()), d[sorted(d.keys())[0]])
        if true not in d:
            sorted_keys = term_ord.sorted_terms(d.keys())
        else:
            d_keys_without_true = term_ord.sorted_terms(
                [k for k in d if k != true])
            sorted_keys = [true] + d_keys_without_true
        sorted_keys_num = len(sorted_keys)
        pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', d[sorted_keys[sorted_keys_num - y - 2]], x), \
                        range(sorted_keys_num - 1), d[sorted_keys[-1]])
        # pt_right = right_assoc(sorted_keys)
        # order implies original
        dd = dict()
        norm_conj = And(*sorted_keys)
        norm_conj_pt = ProofTerm.assume(norm_conj)
        for k in sorted_keys:
            if k != sorted_keys[-1]:
                dd[k] = apply_theorem('conjD1', norm_conj_pt)
                norm_conj_pt = apply_theorem('conjD2', norm_conj_pt)
            else:
                dd[k] = norm_conj_pt

        def traverse(t):
            if not t.is_conj():
                return dd[t]
            else:
                return apply_theorem('conjI', traverse(t.arg1),
                                     traverse(t.arg))

        pt_left = traverse(t)

        pt_final = ProofTerm.equal_intr(pt_right.implies_intr(t),
                                        pt_left.implies_intr(norm_conj))
        if true in d:
            return pt_final.on_rhs(rewr_conv("conj_true_left"),
                                   top_sweep_conv(sort_disj()))
        else:
            return pt_final.on_rhs(top_sweep_conv(sort_disj()))