| 1 | % (c) 2015-2022 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(kinduction,[kinduction_symbolic_model_check/1, | |
| 6 | tinduction_symbolic_model_check/1]). | |
| 7 | ||
| 8 | :- use_module(probsrc(module_information)). | |
| 9 | :- module_info(group,symbolic_model_checker). | |
| 10 | :- module_info(description,'A finite-state symbolic model checker based on k-Induction.'). | |
| 11 | ||
| 12 | :- use_module(library(lists), [append/2, | |
| 13 | maplist/3, | |
| 14 | include/3]). | |
| 15 | ||
| 16 | :- use_module(extension('counter/counter'),[counter_init/0, | |
| 17 | new_counter/1]). | |
| 18 | ||
| 19 | :- use_module(extrasrc(before_after_predicates), [before_after_predicate_for_operation/2]). | |
| 20 | :- use_module(probsrc(translate), [translate_bexpression/2]). | |
| 21 | :- use_module(probsrc(bmachine),[b_get_invariant_from_machine/1, | |
| 22 | b_get_machine_constants/1, | |
| 23 | b_get_machine_variables/1, | |
| 24 | b_specialized_invariant_for_op/2]). | |
| 25 | :- use_module(probsrc(btypechecker), [prime_identifiers/2]). | |
| 26 | :- use_module(probsrc(bsyntaxtree), [conjunct_predicates/2, | |
| 27 | disjunct_predicates/2, | |
| 28 | safe_create_texpr/3, | |
| 29 | create_negation/2]). | |
| 30 | :- use_module(probsrc(preferences), [get_preference/2]). | |
| 31 | :- use_module(symbolic_model_checker(predicate_handling), [prime_predicate/2, | |
| 32 | deprime_state/2, | |
| 33 | prime_n_times/3, | |
| 34 | unprimed/1]). | |
| 35 | :- use_module(symbolic_model_checker(solver_handling), [solve/2]). | |
| 36 | :- use_module(symbolic_model_checker(bmc), [get_constraint/2, | |
| 37 | constraint_transitions/2]). | |
| 38 | :- use_module(symbolic_model_checker(ce_replay), [replay_counter_example/1]). | |
| 39 | ||
| 40 | kinduction_symbolic_model_check(Res) :- | |
| 41 | counter_init, new_counter(ic3solvercalls), | |
| 42 | ? | induction_symbolic_model_check(kinduction,0,Res). |
| 43 | tinduction_symbolic_model_check(Res) :- | |
| 44 | counter_init, new_counter(ic3solvercalls), | |
| 45 | induction_symbolic_model_check(tinduction,0,Res). | |
| 46 | ||
| 47 | mysolve(Pred,Res) :- | |
| 48 | catch(solve(Pred,Res),solver_and_provers_too_weak,Res=solver_and_provers_too_weak). | |
| 49 | ||
| 50 | % base case: search for counter-example of length K | |
| 51 | induction_symbolic_model_check(_,K,Res) :- % base case is the same for kinduction and tinduction | |
| 52 | format('K = ~w~n', [K]), | |
| 53 | get_constraint(K,Base), | |
| 54 | (debug:debug_mode(off) -> true | |
| 55 | ; translate_bexpression(Base,PPBase), | |
| 56 | format('Base Constraint (~w): ~w~n',[K,PPBase]) | |
| 57 | ), | |
| 58 | mysolve(Base,Result), | |
| 59 | Result = solution(Sol), !, | |
| 60 | Res = counterexample_found, | |
| 61 | replay_counter_example(Sol). | |
| 62 | % kinduction statically adds no_loop_constraint | |
| 63 | induction_symbolic_model_check(kinduction,K,Res) :- | |
| 64 | get_step_constraint(K,Step), | |
| 65 | ? | no_loop_constraint(K,NoLoop), |
| 66 | conjunct_predicates([Step,NoLoop],FullStep), | |
| 67 | (debug:debug_mode(off) -> true | |
| 68 | ; translate_bexpression(FullStep,PPStep), | |
| 69 | format('k-Induction Step Constraint (~w): ~w~n',[K,PPStep]) | |
| 70 | ), | |
| 71 | mysolve(FullStep,Result), | |
| 72 | (Result = contradiction_found(_) -> Res = property_holds ; | |
| 73 | ? | Result = solution(_) -> K2 is K + 1, induction_symbolic_model_check(kinduction,K2,Res) ; |
| 74 | Res = solver_and_provers_too_weak). | |
| 75 | % tinduction dynamically adds no_loop_constraint where two equal states have been computed | |
| 76 | induction_symbolic_model_check(tinduction,K,Res) :- | |
| 77 | get_step_constraint(K,Step), | |
| 78 | t_induction_step(K,Step,Res). | |
| 79 | ||
| 80 | t_induction_step(K,CurrentStep,Res) :- | |
| 81 | (debug:debug_mode(off) -> true | |
| 82 | ; translate_bexpression(CurrentStep,PPStep), | |
| 83 | format('t-Induction Current Step Constraint (~w): ~w~n',[K,PPStep]) | |
| 84 | ), | |
| 85 | mysolve(CurrentStep,Result), | |
| 86 | t_induction_step_aux(Result,K,CurrentStep,Res). | |
| 87 | t_induction_step_aux(contradiction_found(_),_,_,property_holds) :- !. | |
| 88 | t_induction_step_aux(solution(Sol),K,CurrentStep,Res) :- | |
| 89 | % if there are duplicated states, add no loop Constraint | |
| 90 | add_no_loop_constraint(Sol,CurrentStep,NewStep), !, | |
| 91 | t_induction_step(K,NewStep,Res). | |
| 92 | t_induction_step_aux(solution(_),K,_,Res) :- !, | |
| 93 | % otherwise increase K | |
| 94 | K2 is K + 1, | |
| 95 | (induction_symbolic_model_check(tinduction,K2,Res) ; | |
| 96 | t_induction_step_aux(_,_,_,solver_and_provers_too_weak)). | |
| 97 | ||
| 98 | add_no_loop_constraint(Solution,CurrentStep,NewStep) :- | |
| 99 | add_no_loop_constraint(Solution,0,CurrentStep,NewStep). | |
| 100 | % no variables left, i.e. no constraint needed | |
| 101 | add_no_loop_constraint([],_,_,_) :- !, fail. | |
| 102 | add_no_loop_constraint(Solution,NoOfPrimes,CurrentStep,NewStep) :- | |
| 103 | include(unprimed,Solution,UnprimedVars), | |
| 104 | deprime_state(Solution,DePrimedSolution), | |
| 105 | DePrimedSolution \= [], | |
| 106 | % if there is a variable that is not the same in the states, | |
| 107 | % we do not need to add anything | |
| 108 | (states_have_diff_var(UnprimedVars,DePrimedSolution) | |
| 109 | -> NewNo is NoOfPrimes + 1, | |
| 110 | add_no_loop_constraint(DePrimedSolution,NewNo,CurrentStep,NewStep) | |
| 111 | ; no_loop_constraint(1,NL), | |
| 112 | prime_n_times(NoOfPrimes,NL,PrimedNL), | |
| 113 | conjunct_predicates([CurrentStep,PrimedNL],NewStep)). | |
| 114 | ||
| 115 | states_have_diff_var(Unprimed,DePrimed) :- | |
| 116 | member(binding(Name,Val,_),Unprimed), | |
| 117 | member(binding(Name,Val2,_),DePrimed), | |
| 118 | Val \= Val2. | |
| 119 | ||
| 120 | get_step_constraint(K,Step) :- | |
| 121 | get_preference(use_po,false), !, | |
| 122 | b_get_invariant_from_machine(P), | |
| 123 | constraint_transitions(K,Transitions), | |
| 124 | step_constraint_property(K,P,Property), | |
| 125 | K2 is K + 1, | |
| 126 | prime_n_times(K2,P,PPrimed), | |
| 127 | create_negation(PPrimed,NegPPrimed), | |
| 128 | conjunct_predicates([Transitions,Property,NegPPrimed],Step). | |
| 129 | get_step_constraint(K,Step) :- | |
| 130 | get_preference(use_po,true), !, | |
| 131 | b_get_invariant_from_machine(P), | |
| 132 | K2 is K - 1, K3 is K + 1, | |
| 133 | constraint_transitions(K2,Transitions), | |
| 134 | step_constraint_property(K,P,Property), | |
| 135 | proof_supported_step_constraint(K3,StepConstraint), | |
| 136 | % translate_bexpression(NL,PPNL), | |
| 137 | % format('No Loop Constraint: ~w~n',[PPNL]), | |
| 138 | conjunct_predicates([Transitions,Property,StepConstraint],Step). | |
| 139 | ||
| 140 | proof_supported_step_constraint(K,b(truth,pred,[])) :- | |
| 141 | K < 0, !. | |
| 142 | proof_supported_step_constraint(N,TPred) :- | |
| 143 | findall(op(OpName,Pred),(before_after_predicate_for_operation(OpName,Pred)),Ops), | |
| 144 | maplist(op_to_step_constraint,Ops,SingleSteps), | |
| 145 | disjunct_predicates(SingleSteps,Step), | |
| 146 | N2 is N - 1, | |
| 147 | prime_n_times(N2,Step,TPred). | |
| 148 | ||
| 149 | op_to_step_constraint(op(OpName,BaPred),StepConstraint) :- | |
| 150 | (b_specialized_invariant_for_op(OpName,UncheckedInvariant) | |
| 151 | -> true ; b_get_invariant_from_machine(UncheckedInvariant)), | |
| 152 | create_negation(UncheckedInvariant,NegUncheckedInvariant), | |
| 153 | prime_predicate(NegUncheckedInvariant,PrimedNegUncheckedInvariant), | |
| 154 | conjunct_predicates([BaPred,PrimedNegUncheckedInvariant],StepConstraint). | |
| 155 | ||
| 156 | step_constraint_property(K,P,FullProperty) :- | |
| 157 | step_constraint_property_aux(K,P,Conjuncts), | |
| 158 | conjunct_predicates(Conjuncts,FullProperty). | |
| 159 | step_constraint_property_aux(0,P,[P]) :- !. | |
| 160 | step_constraint_property_aux(N,P,[P|Rest]) :- | |
| 161 | prime_predicate(P,PP), | |
| 162 | N2 is N - 1, | |
| 163 | step_constraint_property_aux(N2,PP,Rest). | |
| 164 | ||
| 165 | no_loop_constraint(K,NL) :- | |
| 166 | b_get_machine_variables(Variables), | |
| 167 | b_get_machine_constants(Constants), | |
| 168 | append(Variables,Constants,VarsAndConsts), | |
| 169 | ? | no_loop_constraint_add_primes(K,VarsAndConsts,ListOfPrimedStates), |
| 170 | ? | no_loop_constraint_aux(ListOfPrimedStates,Conjuncts), |
| 171 | conjunct_predicates(Conjuncts,NL). | |
| 172 | ||
| 173 | no_loop_constraint_aux([],[]). | |
| 174 | no_loop_constraint_aux([PState|PStates],Conjuncts) :- | |
| 175 | ? | no_loop_constraint_aux(PState,PStates,Conj1), |
| 176 | ? | no_loop_constraint_aux(PStates,Conj2), |
| 177 | append([Conj1,Conj2],Conjuncts). | |
| 178 | no_loop_constraint_aux(_State,[],[]). | |
| 179 | no_loop_constraint_aux(PState1,[PState2|States],[NotEqualDisjunct|NotEquals]) :- | |
| 180 | states_not_equal(PState1,PState2,NotEqual), | |
| 181 | disjunct_predicates(NotEqual,NotEqualDisjunct), | |
| 182 | ? | no_loop_constraint_aux(PState1,States,NotEquals). |
| 183 | ||
| 184 | states_not_equal(P,P,[]) :- !. | |
| 185 | states_not_equal([V1|V1s],[V2|V2s],[NotEqual|T]) :- | |
| 186 | safe_create_texpr(not_equal(V1,V2),pred,NotEqual), | |
| 187 | states_not_equal(V1s,V2s,T). | |
| 188 | ||
| 189 | no_loop_constraint_add_primes(0,V,[V]). | |
| 190 | no_loop_constraint_add_primes(1,VarsAndConsts,[PVarsAndConsts,VarsAndConsts]) :- | |
| 191 | prime_identifiers(VarsAndConsts,PVarsAndConsts). | |
| 192 | no_loop_constraint_add_primes(N,VAC,[VAC|VACS]) :- | |
| 193 | prime_identifiers(VAC,PVAC), | |
| 194 | N2 is N - 1, | |
| 195 | no_loop_constraint_add_primes(N2,PVAC,VACS). |