def test_synthesize_for_model(debug=False): all_models1 = [{'x': False}, {'x': True}] all_models2 = [{'p': False, 'q': False}, {'p': False, 'q': True}, {'p': True, 'q': False}, {'p': True, 'q': True}] all_models3 = [{'r1': False, 'r12': False, 'p37': False}, {'r1': False, 'r12': False, 'p37': True}, {'r1': False, 'r12': True, 'p37': False}, {'r1': False, 'r12': True, 'p37': True}, {'r1': True, 'r12': False, 'p37': False}, {'r1': True, 'r12': False, 'p37': True}, {'r1': True, 'r12': True, 'p37': False}, {'r1': True, 'r12': True, 'p37': True}] for all_models in [all_models1, all_models2, all_models3]: for idx in range(len(all_models)): if debug: print('Testing synthesis of formula for model', all_models[idx]) f = synthesize_for_model(frozendict(all_models[idx])) assert type(f) is Formula, 'Expected a formula, got ' + str(f) assert is_clause(f), str(f) + ' should be a clause' all_values = [False] * len(all_models) all_values[idx] = True for model,value in zip(all_models, all_values): assert evaluate(f, frozendict(model)) == value
def test_evaluate_inference(debug=False): from propositions.proofs import InferenceRule # Test 1 rule1 = InferenceRule([Formula.parse('p'), Formula.parse('q')], Formula.parse('r')) for model in all_models(['p', 'q', 'r']): if debug: print('Testing evaluation of inference rule', rule1, 'in model', model) assert evaluate_inference(rule1, frozendict(model)) == \ (not model['p']) or (not model['q']) or model['r'] # Test 2 rule2 = InferenceRule([Formula.parse('(x|y)')], Formula.parse('x')) for model in all_models(['x', 'y']): if debug: print('Testing evaluation of inference rule', rule2, 'in model', model) assert evaluate_inference(rule2, frozendict(model)) == \ (not model['y']) or model['x'] # Test 3 rule3 = InferenceRule([Formula.parse(s) for s in ['(p->q)', '(q->r)']], Formula.parse('r')) for model in all_models(['p', 'q', 'r']): if debug: print('Testing evaluation of inference rule', rule3, 'in model', model) assert evaluate_inference(rule3, frozendict(model)) == \ (model['p'] and not model['q']) or \ (model['q'] and not model['r']) or model['r']
def test_merge_specialization_maps(debug=False): for d1, d2, d in [ ({}, {}, {}), ({}, None, None), (None, {}, None), (None, None, None), ({'p':'q'}, {'r':'s'}, {'p':'q', 'r':'s'}), ({'p':'q'}, {}, {'p':'q'}), ({}, {'p':'q'}, {'p':'q'}), ({'p':'q'}, {'p':'r'}, None), ({'p':'q'}, None, None), (None, {'p':'q'}, None), ({'x':'p1', 'y':'p2'}, {'x':'p1', 'z':'p3'}, {'x':'p1', 'y':'p2', 'z':'p3'}), ({'x':'p1', 'y':'p2'}, {'x':'p1', 'y':'p3'}, None), ({'x':'p1', 'y':'p2'}, {'x':'p1', 'y':'p2', 'z':'p3'}, {'x':'p1', 'y':'p2', 'z':'p3'}), ({'x':'p1', 'y':'p2', 'z':'p3'}, {'x':'p1', 'y':'p2'}, {'x':'p1', 'y':'p2', 'z':'p3'})]: if debug: print('Testing merging of dictionaries', d1, d2) dd = InferenceRule.merge_specialization_maps( frozendict({v: Formula.parse(d1[v]) for v in d1}) if d1 is not None else None, frozendict({v: Formula.parse(d2[v]) for v in d2}) if d2 is not None else None) assert dd == ({v: Formula.parse(d[v]) for v in d} if d is not None else None), "got " + dd
def __test_synthesize_clause(clause_synthesizer, for_model, debug): all_models1 = [{'x': False}, {'x': True}] all_models2 = [{'p': False, 'q': False}, {'p': False, 'q': True}, {'p': True, 'q': False}, {'p': True, 'q': True}] all_models3 = [{'r1': False, 'r12': False, 'p37': False}, {'r1': False, 'r12': False, 'p37': True}, {'r1': False, 'r12': True, 'p37': False}, {'r1': False, 'r12': True, 'p37': True}, {'r1': True, 'r12': False, 'p37': False}, {'r1': True, 'r12': False, 'p37': True}, {'r1': True, 'r12': True, 'p37': False}, {'r1': True, 'r12': True, 'p37': True}] for all_models in [all_models1, all_models2, all_models3]: for idx in range(len(all_models)): if debug: print('Testing', clause_synthesizer.__qualname__, 'for model', all_models[idx]) f = clause_synthesizer(frozendict(all_models[idx])) assert type(f) is Formula, 'Expected a formula, got ' + str(f) if for_model: assert is_conjunctive_clause(f), \ str(f) + ' should be a conjunctive clause' all_values = [False] * len(all_models) all_values[idx] = True else: assert is_disjunctive_clause(f), \ str(f) + ' should be a disjunctive clause' all_values = [True] * len(all_models) all_values[idx] = False for model, value in zip(all_models, all_values): assert evaluate(f, frozendict(model)) == value
def evaluate_formula( self, formula: Formula, assignment: Mapping[str, T] = frozendict()) -> bool: """Calculates the truth value of the given formula in the current model, for the given assignment of values to free occurrences of variables names. Parameters: formula: formula to calculate the truth value of, for the constants, functions, and relations of which the current model has meanings. assignment: mapping from each variable name that has a free occurrence in the given formula to a universe element to which it is to be evaluated. Returns: The truth value of the given formula in the current model, for the given assignment of values to free occurrences of variable names. """ assert formula.constants().issubset(self.constant_meanings.keys()) assert formula.free_variables().issubset(assignment.keys()) for function, arity in formula.functions(): assert function in self.function_meanings and \ self.function_arities[function] == arity for relation, arity in formula.relations(): assert relation in self.relation_meanings and \ self.relation_arities[relation] in {-1, arity} # Task 7.8 return self.evaluate_helper(assignment, formula)
def evaluate_term( self, term: Term, assignment: Mapping[str, T] = frozendict()) -> T: """Calculates the value of the given term in the current model, for the given assignment of values to variables names. Parameters: term: term to calculate the value of, for the constants and functions of which the current model has meanings. assignment: mapping from each variable name in the given term to a universe element to which it is to be evaluated. Returns: The value (in the universe of the current model) of the given term in the current model, for the given assignment of values to variable names. """ assert term.constants().issubset(self.constant_meanings.keys()) assert term.variables().issubset(assignment.keys()) for function, arity in term.functions(): assert function in self.function_meanings and \ self.function_arities[function] == arity # Decide based on the term type term_type = term.get_type() if term_type == Term.TermType.T_CONST: return self.constant_meanings[term.root] elif term_type == Term.TermType.T_VARIABLE: return assignment[term.root] elif term_type == Term.TermType.T_FUNCTION: # Evaluate the arguments args = [self.evaluate_term(t, assignment) for t in term.arguments] return self.function_meanings[term.root][tuple(args)]
def test_evaluate_all_operators(debug=False): infix1 = '(p+q7)' models_values1 = [ ({'p': True, 'q7': False}, True), ({'p': False, 'q7': False}, False), ({'p': True, 'q7': True}, False) ] infix2 = '~(p<->q7)' models_values2 = [ ({'p': True, 'q7': False}, True), ({'p': False, 'q7': False}, False), ({'p': True, 'q7': True}, False) ] infix3 = '~((x-&x)-|(y-&y))' models_values3 = [ ({'x': True, 'y': False}, True), ({'x': False, 'y': False}, True), ({'x': True, 'y': True}, False) ] for infix,models_values in [[infix1, models_values1], [infix2, models_values2], [infix3, models_values3]]: formula = Formula.parse(infix) for model,value in models_values: if debug: print('Testing evaluation of formula', formula, 'in model', model) assert evaluate(formula, frozendict(model)) == value
def test_reduce_assumption(debug=False): for f, m, v in [ ('(y->x)', {'x':True}, 'y'), ('(p->p)', {}, 'p'), ('(p->(r->q))', {'p':True, 'q':True}, 'r')]: f = Formula.parse(f) m[v]=True pt = prove_in_model(f, frozendict(m)) m[v]=False pf = prove_in_model(f, frozendict(m)) if debug: print("testing reduce assumption on", pt.statement, "and", pf.statement) p = reduce_assumption(pt,pf) assert p.statement.conclusion == pf.statement.conclusion assert p.statement.assumptions[:] == pt.statement.assumptions[:-1] assert p.rules == AXIOMATIC_SYSTEM assert p.is_valid(), offending_line(p)
def test_formulas_capturing_model(debug=False): for q,a in [({'p':True},['p']), ({'q7':False}, ['~q7']), ({'x1':True, 'x2':False, 'x3':True}, ['x1', '~x2', 'x3']), ({'q3':False, 'p13':False, 'r':True}, ['~p13', '~q3', 'r'])]: if debug: print("Testing formulas_capturing_model on", q) aa = [Formula.parse(f) for f in a] assert formulas_capturing_model(frozendict(q)) == aa
def test_prove_in_model_full(debug=False): for (f, m, a, cp) in [ ('x', {'x':True}, ['x'], ''), ('x',{'x':False}, ['~x'], '~'), ('~x', {'x':False}, ['~x'], ''), ('~x', {'x':True}, ['x'], '~'), ('x', {'x':True, 'z5':False}, ['x', '~z5'], ''), ('(p->~p)', {'p':True}, ['p'], '~'), ('(p->~p)', {'p':False}, ['~p'], ''), ('(p->q)', {'p':True, 'q':True}, ['p','q'], ''), ('(p->q)', {'p':True, 'q':False}, ['p','~q'], '~'), ('(p->q)', {'p':False, 'q':True}, ['~p','q'], ''), ('(p->q)', {'p':False, 'q':False}, ['~p', '~q'], ''), ('~~~~y7', {'y7':True}, ['y7'], ''), ('~~~~y7', {'y7':False}, ['~y7'], '~'), ('~(~p->~q)', {'p':True, 'q':True}, ['p','q'], '~'), ('~(~p->~q)', {'p':False, 'q':True}, ['~p','q'], ''), ('((p1->p2)->(p3->p4))', {'p1':True, 'p2':True, 'p3':True, 'p4':True}, ['p1','p2','p3','p4'], ''), ('((p1->p2)->(p3->p4))', {'p1':True, 'p2':True, 'p3':True, 'p4':False}, ['p1','p2','p3','~p4'], '~'), ('((p1->p2)->(p3->p4))', {'p1':True, 'p2':False, 'p3':True, 'p4':False}, ['p1','~p2','p3','~p4'], ''), ('(~(~x->~~y)->(z->(~x->~~~z)))', {'z':True, 'x':False, 'y':False}, ['~x','~y','z'], '~'), ('T', {}, [], ''), ('F', {}, [], '~'), ('(p|q)', {'p': True, 'q': True}, ['p', 'q'], ''), ('(p|q)', {'p': True, 'q': False}, ['p', '~q'], ''), ('(p|q)', {'p': False, 'q': True}, ['~p', 'q'], ''), ('(p|q)', {'p': False, 'q': False}, ['~p', '~q'], '~'), ('(p&q)', {'p': True, 'q': True}, ['p', 'q'], ''), ('(p&q)', {'p': True, 'q': False}, ['p', '~q'], '~'), ('(p&q)', {'p': False, 'q': True}, ['~p', 'q'], '~'), ('(p&q)', {'p': False, 'q': False}, ['~p', '~q'], '~'), ('~(~(q|p)&(r->~(s|q)))', {'p': False, 'q': False, 'r': False, 's': False}, ['~p', '~q', '~r', '~s'], '~'), ('~(~(q|p)&(r->~(s|q)))', {'p': False, 'q': False, 'r': True, 's': True}, ['~p', '~q', 'r', 's'], '') ]: c = Formula.parse(cp+f) f = Formula.parse(f) a = (Formula.parse(v) for v in a) if debug: print('Testing prove_in_model_full on formula',f, 'in model', m) p = prove_in_model_full(f, frozendict(m)) assert p.statement == InferenceRule(a, c) assert p.rules == AXIOMATIC_SYSTEM_FULL assert p.is_valid(), offending_line(p)
def prove_tautology(tautology: Formula, model: Model = frozendict()) -> Proof: """Proves the given tautology from the formulas that capture the given model. Parameters: tautology: tautology that contains no constants or operators beyond ``'->'`` and ``'~'``, to prove. model: model over a (possibly empty) prefix (with respect to the alphabetical order) of the variables of `tautology`, from whose formulas to prove. Returns: A valid proof of the given tautology from the formulas that capture the given model, in the order returned by `formulas_capturing_model`\ ``(``\ `model`\ ``)``, via `~propositions.axiomatic_systems.AXIOMATIC_SYSTEM`. Examples: >>> proof = prove_tautology(Formula.parse('(~(p->p)->q)'), ... {'p': True, 'q': False}) >>> proof.is_valid() True >>> proof.statement.conclusion (~(p->p)->q) >>> proof.statement.assumptions (p, ~q) >>> proof.rules == AXIOMATIC_SYSTEM True >>> proof = prove_tautology(Formula.parse('(~(p->p)->q)')) >>> proof.is_valid() True >>> proof.statement.conclusion (~(p->p)->q) >>> proof.statement.assumptions () >>> proof.rules == AXIOMATIC_SYSTEM True """ assert is_tautology(tautology) assert tautology.operators().issubset({'->', '~'}) assert is_model(model) assert sorted(tautology.variables())[:len(model)] == sorted(model.keys()) if len(model) == len(tautology.variables()): return prove_in_model(tautology, model) variables_not_in_model = sorted( [v for v in tautology.variables() if v not in model]) check_on_var = variables_not_in_model[0] variables_not_in_model.remove(check_on_var) new_model = {check_on_var: True} new_model.update(model) aff_proof = prove_tautology(tautology, new_model) new_model[check_on_var] = False neg_proof = prove_tautology(tautology, new_model) return reduce_assumption(aff_proof, neg_proof)
def __test_synthesize(synthesizer, dnf, debug): all_variables1 = ['p'] all_models1 = [{'p': False}, {'p': True}] value_lists1 = [(False, False), (False, True), (True, False), (True, True)] all_variables2 = ['p', 'q'] all_models2 = [{'p': False, 'q': False}, {'p': False, 'q': True}, {'p': True, 'q': False}, {'p': True, 'q': True}] value_lists2 = [(True, False, False, True), (True, True, True, True), (False, False, False, False)] all_variables3 = ['r1', 'r12', 'p37'] all_models3 = [{'r1': False, 'r12': False, 'p37': False}, {'r1': False, 'r12': False, 'p37': True}, {'r1': False, 'r12': True, 'p37': False}, {'r1': False, 'r12': True, 'p37': True}, {'r1': True, 'r12': False, 'p37': False}, {'r1': True, 'r12': False, 'p37': True}, {'r1': True, 'r12': True, 'p37': False}, {'r1': True, 'r12': True, 'p37': True}] value_lists3 = [(True, False, True, True, False, True, False, True), (True, True, True, True, True, True, True, True), (False, False, False, False, False, False, False, False)] for all_variables, all_models, value_lists in [ [all_variables1, all_models1, value_lists1], [all_variables2, all_models2, value_lists2], [all_variables3, all_models3, value_lists3]]: for all_values in value_lists: if debug: print('Testing', synthesizer.__qualname__, 'for variables', all_variables, 'and model-values', all_values) formula = synthesizer(tuple(all_variables), all_values) assert type(formula) is Formula, \ 'Expected a formula, got ' + str(formula) if dnf: assert is_dnf(formula), str(formula) + ' should be a DNF' else: assert is_cnf(formula), str(formula) + ' should be a CNF' assert formula.variables().issubset(set(all_variables)) for model, value in zip(all_models, all_values): assert evaluate(formula, frozendict(model)) == value, \ str(formula) + ' does not evaluate to ' + str(value) + \ ' on ' + str(model)
def prove_tautology(tautology: Formula, model: Model = frozendict()) -> Proof: """Proves the given tautology from the formulae that capture the given model. Parameters: tautology: tautology that contains no constants or operators beyond ``'->'`` and ``'~'``, to prove. model: model over a (possibly empty) prefix (with respect to the alphabetical order) of the variables of `tautology`, from whose formulae to prove. Returns: A valid proof of the given tautology from the formulae that capture the given model, in the order returned by `formulae_capturing_model`\ ``(``\ `model`\ ``)``, via `~propositions.axiomatic_systems.AXIOMATIC_SYSTEM`. Examples: If the given model is the empty dictionary, then the returned proof is of the given tautology from no assumptions. """ assert is_tautology(tautology) assert tautology.operators().issubset({'->', '~'}) assert is_model(model) assert sorted(tautology.variables())[:len(model)] == sorted(model.keys()) # Task 6.3a statement = InferenceRule(formulae_capturing_model(model), tautology) # rules are AXIOMATIC_SYSTEM list_of_var_in_formula = list(tautology.variables()) list_of_var_in_formula.sort() for var in list_of_var_in_formula: if var not in model: new_model = dict(model) new_model[var] = True # proof 1 is with that var with value True proof1 = prove_tautology(tautology, new_model) new_model[var] = False # proof 2 is with that var with value False proof2 = prove_tautology(tautology, new_model) # proof without that var return reduce_assumption(proof1, proof2) # if the model contains all the var in the tautology formula return prove_in_model(tautology, model)
def prove_tautology(tautology: Formula, model: Model = frozendict()) -> Proof: """Proves the given tautology from the formulae that capture the given model. Parameters: tautology: tautology that contains no constants or operators beyond ``'->'`` and ``'~'``, to prove. model: model over a (possibly empty) prefix (with respect to the alphabetical order) of the variables of `tautology`, from whose formulae to prove. Returns: A valid proof of the given tautology from the formulae that capture the given model, in the order returned by `formulae_capturing_model`\ ``(``\ `model`\ ``)``, via `~propositions.axiomatic_systems.AXIOMATIC_SYSTEM`. Examples: If the given model is the empty dictionary, then the returned proof is of the given tautology from no assumptions. """ assert is_tautology(tautology) assert tautology.operators().issubset({'->', '~'}) assert is_model(model) assert sorted(tautology.variables())[:len(model)] == sorted(model.keys()) # Task 6.3a if model is not None and len(tautology.variables()) == len(model): return prove_in_model(tautology, model) else: variables = sorted(tautology.variables()) new_model_1 = dict() if model is not None: for var in model.keys(): new_model_1[var] = model[var] new_model_2 = deepcopy(new_model_1) for var in variables: if var not in model.keys(): new_model_1[var] = True new_model_2[var] = False antecedent_proof_1 = prove_tautology(tautology, new_model_1) antecedent_proof_2 = prove_tautology(tautology, new_model_2) return reduce_assumption(antecedent_proof_1, antecedent_proof_2)
def test_specialize(debug=False): for t in substitutions: d = t[0] if debug: print('Testing substitition dictionary', d) d = frozendict({k: Formula.parse(d[k]) for k in d}) cases = [ [Formula.parse(c[0]), Formula.parse(c[1])] for c in t[1:]] for case in cases: if debug: print('...checking that', case[0], 'specializes to', case[1]) general = InferenceRule([],case[0]) special = InferenceRule([],case[1]) assert general.specialize(d) == special, \ "got " + str(general.specialize(d).conclusion) if debug: print('...now checking all together in a single rule') general = InferenceRule([case[0] for case in cases[1:]],cases[0][0]) special = InferenceRule([case[1] for case in cases[1:]],cases[0][1]) assert general.specialize(d) == special, \ "got " + str(general.specialize(d))
def test_substitute_variables(debug=False): # f d result tests = [('v', {}, 'v'), ('v', {'v': 'p'}, 'p'), ('(F->v12)', {'v12': 'v11'}, '(F->v11)'), ('v', {'q': 'r', 'z': 'w'}, 'v'), ('p', {'p': '(q|q)'}, '(q|q)'), ('~v', {'v': '(q|q)'}, '~(q|q)'), ('(~v|v)', {'v': '(q|q)'}, '(~(q|q)|(q|q))'), ('(q12->w)', {'q12': 'T', 'w': 'x'}, '(T->x)'), ('(v->w)', {'v': 'T', 'w': 'v'}, '(T->v)'), ('((~v&w)|(v->u))', {'v': '(~p->q)', 'u': '~~F'}, '((~(~p->q)&w)|((~p->q)->~~F))'), ('v2', {'v': 'p'}, 'v2')] for f, d, r in tests: if debug: print("Testing substituting variables according to", d, "in formula", f) f = Formula.parse(f) d = {k: Formula.parse(d[k]) for k in d} a = str(f.substitute_variables(frozendict(d))) assert a == r, "Incorrect answer:" + a
def prove_tautology(tautology: Formula, model: Model = frozendict()) -> Proof: """Proves the given tautology from the formulae that capture the given model. Parameters: tautology: tautology that contains no constants or operators beyond ``'->'`` and ``'~'``, to prove. model: model over a (possibly empty) prefix (with respect to the alphabetical order) of the variables of `tautology`, from whose formulae to prove. Returns: A valid proof of the given tautology from the formulae that capture the given model, in the order returned by `formulae_capturing_model`\ ``(``\ `model`\ ``)``, via `~propositions.axiomatic_systems.AXIOMATIC_SYSTEM`. Examples: If the given model is the empty dictionary, then the returned proof is of the given tautology from no assumptions. """ assert is_tautology(tautology) assert tautology.operators().issubset({'->', '~'}) assert is_model(model) assert sorted(tautology.variables())[:len(model)] == sorted(model.keys()) tautology_variables = list(sorted(tautology.variables())) if len(model) == len(tautology_variables): return prove_in_model(tautology, model) else: #craete a model with added assumption, assigned to be True, and another model #with the same added assumption assigned to be False model_with_negation = dict(model) model_with_negation[tautology_variables[len(model)]] = False model_with_affirmation = dict(model) model_with_affirmation[tautology_variables[len(model)]] = True proof_from_affirmation = prove_tautology(tautology, model_with_affirmation) proof_from_negation = prove_tautology(tautology, model_with_negation) return reduce_assumption(proof_from_affirmation, proof_from_negation)