| 1 | :- module(b_synthesis, [start_synthesis_from_ui/11, | |
| 2 | start_synthesis_from_ui/13, | |
| 3 | start_synthesis_single_operation_from_ui/11, | |
| 4 | reset_synthesis_context/0]). | |
| 5 | ||
| 6 | :- use_module(synthesis(logging)). | |
| 7 | :- use_module(synthesis(constraints)). | |
| 8 | :- use_module(synthesis(library_setup)). | |
| 9 | :- use_module(synthesis(location_vars_to_program)). | |
| 10 | :- use_module(synthesis(synthesis_util)). | |
| 11 | ||
| 12 | :- use_module(probsrc(bsyntaxtree)). | |
| 13 | :- use_module(probsrc(bmachine), [b_get_machine_set/1,b_get_machine_set/2,b_get_machine_operation/4]). | |
| 14 | :- use_module(probsrc(preferences), [set_preference/2]). | |
| 15 | :- use_module(probsrc(module_information), [module_info/2]). | |
| 16 | :- use_module(probsrc(solver_interface), [solve_predicate/3]). | |
| 17 | :- use_module(smt_solvers_interface(smt_solvers_interface), [smt_solve_predicate/4]). | |
| 18 | ||
| 19 | :- use_module(library(lists)). | |
| 20 | :- use_module(library(sets), [intersection/3]). | |
| 21 | :- use_module(library(terms), [term_size/2]). | |
| 22 | ||
| 23 | :- use_module(extension('plspec/plspec/plspec_core')). | |
| 24 | ||
| 25 | :- defspec(solution_bindings, one_of([list(compound(binding(any,any,any))),list(compound(bind(any,any)))])). | |
| 26 | :- defspec(solution_compound, compound(solution(solution_bindings))). | |
| 27 | :- defspec(ast_example, list(ast)). | |
| 28 | :- defspec(ast_examples, list(ast_example)). | |
| 29 | :- defspec(ast, compound(b(any,any,list(any)))). | |
| 30 | :- defspec(pair(X,Y), compound(','(X,Y))). | |
| 31 | % :- enable_all_spec_checks. | |
| 32 | :- module_info(group, synthesis). | |
| 33 | :- module_info(description, 'This module contains the synthesis workflow following the approach by Gulwani et.al. using SMT solving'). | |
| 34 | ||
| 35 | % The synthesis context storing the current state of synthesis when the workflow has been interrupted to interact with the user. | |
| 36 | :- dynamic synthesis_context/9. | |
| 37 | :- volatile synthesis_context/9. | |
| 38 | ||
| 39 | % The solver to be used for synthesis which is either ProB (default) or Z3. | |
| 40 | :- dynamic solver/1. | |
| 41 | :- volatile solver/1. | |
| 42 | solver(proB). | |
| 43 | ||
| 44 | % Library components selected by the user or a specific default configuration like 'default:1' to parallelize library expansions | |
| 45 | % from the Java UI. Default configuration is used if the predicate does not exist. If is 'default' the library is expanded successively | |
| 46 | % in prolog using synthesis_callback/16 on a single instance. | |
| 47 | :- dynamic library_from_ui/1. | |
| 48 | :- volatile library_from_ui/1. | |
| 49 | ||
| 50 | % The names of machine variables that we want to consider if-statements for. | |
| 51 | :- dynamic consider_if_var_names/1. | |
| 52 | :- volatile consider_if_var_names/1. | |
| 53 | ||
| 54 | % Determines whether to use constants during synthesis that are assigned by the solver. | |
| 55 | :- dynamic not_consider_constants/1. | |
| 56 | :- volatile not_consider_constants/1. | |
| 57 | ||
| 58 | % Additional machinevars for operation parameters when synthesizing a precondition. | |
| 59 | :- dynamic additional_machinevars/1. | |
| 60 | :- volatile additional_machinevars/1. | |
| 61 | additional_machinevars([]). | |
| 62 | ||
| 63 | % Synthesis mode is either first_solution or interactive. | |
| 64 | :- dynamic synthesis_mode/1. | |
| 65 | :- volatile synthesis_mode/1. | |
| 66 | synthesis_mode(interactive). | |
| 67 | ||
| 68 | % Expand library in case a solution has been found using the default library configuration. | |
| 69 | % :- dynamic current_library_lookahead/1. | |
| 70 | % :- volatile current_library_lookahead/1. | |
| 71 | % max_library_lookahead(3). | |
| 72 | max_library_expansion(30). | |
| 73 | ||
| 74 | % TO DO: - use sets instead of lists | |
| 75 | % - improve detection of variables taking part in an invariant violation | |
| 76 | % -> keep the current analysis and filter those vars that have changed in the transition leading to the invariant violation | |
| 77 | % - equal_object | |
| 78 | % Start synthesis from the UI based on the ProB2 Java API. Returns the adapted machine code with | |
| 79 | % the generated changes if synthesis succeeded. Otherwise, the unchanged machine code is returned or a distinguishing example in case two | |
| 80 | % non equivalent programs have been synthesized. | |
| 81 | start_synthesis_from_ui(SolverTimeOut, Library, DoNotUseConstants, Solver, ConsiderIfVarNames, Operation, SynthesisType, Positive, Negative, NewMachineAtom, Distinguishing) :- | |
| 82 | synthesis_mode(SynthesisMode), | |
| 83 | start_synthesis_from_ui(SynthesisMode, yes, SolverTimeOut, Library, DoNotUseConstants, Solver, ConsiderIfVarNames, Operation, SynthesisType, Positive, Negative, NewMachineAtom, Distinguishing). | |
| 84 | start_synthesis_from_ui(SynthesisMode, AdaptMachineCode, SolverTimeOut, Library, DoNotUseConstants, Solver, ConsiderIfVarNames, Operation, SynthesisType, Positive, Negative, NewMachineAtom, Distinguishing) :- | |
| 85 | set_preference(time_out, SolverTimeOut), | |
| 86 | logging:enable_logging, | |
| 87 | set_synthesis_mode(SynthesisMode), | |
| 88 | prepare_synthesis(Library, DoNotUseConstants, Solver, ConsiderIfVarNames, Positive, Negative, PosInput, PosOutput, NegInput, NegOutput), | |
| 89 | start_synthesis_from_ui_aux(Operation, SynthesisType, (PosInput,PosOutput), (NegInput,NegOutput), (_,Synthesized)), | |
| 90 | !, | |
| 91 | prepare_solution(AdaptMachineCode, Operation, SynthesisType, Synthesized, NewMachineAtom, Distinguishing), | |
| 92 | retract_context_if_solution(Distinguishing). | |
| 93 | ||
| 94 | set_synthesis_mode(SynthesisMode) :- | |
| 95 | retractall(synthesis_mode(_)), | |
| 96 | assert(synthesis_mode(SynthesisMode)). | |
| 97 | ||
| 98 | % Implicitly consider if-statements, i.e., synthesize several operations describing the different semantics of the examples. | |
| 99 | % Here, we start synthesize for a single example but consider more examples if synthesis has been suspended because of finding a distinguishing example. | |
| 100 | start_synthesis_single_operation_from_ui(SolverTimeOut, Operations, Library, DoNotUseConstants, Solver, Operation, action, Positive, Negative, CacheOperationTuple, Distinguishing) :- | |
| 101 | set_preference(time_out, SolverTimeOut), | |
| 102 | % TODO: consider the other examples to check against distinguishing examples, this is not essential though and works as is | |
| 103 | prepare_synthesis(Library, DoNotUseConstants, Solver, [], Positive, Negative, PosInput, PosOutput, NegInput, NegOutput), | |
| 104 | ( Operations = [] | |
| 105 | -> | |
| 106 | Result = no_match | |
| 107 | ; maplist(cache_operation_tuple_to_quadruple, Operations, OperationQuadruples), | |
| 108 | PosInput = [Input], | |
| 109 | PosOutput = [Output], | |
| 110 | findall(UsedID, ( member(Value, Input), | |
| 111 | get_texpr_info(Value, Info), | |
| 112 | member(synthesis(machinevar,UsedID), Info) | |
| 113 | ), UsedIDs), | |
| 114 | get_machinevars_by_name(UsedIDs, UsedIDNodes), | |
| 115 | check_transition_against_machine_operations(OperationQuadruples, Input, Output, UsedIDNodes, Result) | |
| 116 | ), | |
| 117 | start_synthesis_single_operation_from_ui_aux(Result, Operations, Operation, PosInput, PosOutput, NegInput, NegOutput, CacheOperationTuple, Distinguishing), | |
| 118 | retract_context_if_solution(Distinguishing). | |
| 119 | ||
| 120 | start_synthesis_single_operation_from_ui_aux((OperationName,done), _, _, _, _, _, _, done(OperationName,done), none). | |
| 121 | start_synthesis_single_operation_from_ui_aux((OperationName,guard), Operations, _, PosInput, _, NegInput, _, FinalOperation, Distinguishing) :- | |
| 122 | get_distinguishing_state_cache_from_operation_tuples(Operations, OperationName, (CachePos,CacheNeg), Operation), | |
| 123 | append(PosInput, CachePos, Positive), | |
| 124 | append(NegInput, CacheNeg, Negative), | |
| 125 | start_synthesis_from_ui_aux(OperationName, guard, (Positive,_), (Negative,_), (_,SynthesizedGuard)), | |
| 126 | !, | |
| 127 | prepare_solution(yes, Operation, guard, SynthesizedGuard, _, Distinguishing), | |
| 128 | ( is_distinguishing(SynthesizedGuard) -> | |
| 129 | FinalOperation = none | |
| 130 | ; replace_precondition_of_operation(Operation, SynthesizedGuard, FinalOperation) | |
| 131 | ). | |
| 132 | start_synthesis_single_operation_from_ui_aux(no_match, _, Operation, PosInput, PosOutput, NegInput, NegOutput, CacheOperationTuple, Distinguishing) :- | |
| 133 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), (DistStateCache,Synthesized)), | |
| 134 | !, | |
| 135 | prepare_solution(yes, Operation, action, Synthesized, _, Distinguishing), | |
| 136 | ( is_distinguishing(Synthesized) -> | |
| 137 | CacheOperationTuple = none | |
| 138 | ; CacheOperationTuple = (DistStateCache,Synthesized) | |
| 139 | ). | |
| 140 | ||
| 141 | prepare_synthesis(Library, DoNotUseConstants, Solver, ConsiderIfVarNames, Positive, Negative, PosInput, PosOutput, NegInput, NegOutput) :- | |
| 142 | % retractall(current_library_lookahead(_)) , | |
| 143 | % asserta(current_library_lookahead(0)) , | |
| 144 | retractall(solver(_)), | |
| 145 | asserta(solver(Solver)), | |
| 146 | retractall(not_consider_constants(_)), | |
| 147 | asserta(not_consider_constants(DoNotUseConstants)), | |
| 148 | assert_library_configuration_from_ui(Library), | |
| 149 | assert_if_statement_var_names(ConsiderIfVarNames), | |
| 150 | % split examples that are tuples of input and output state | |
| 151 | split_input_output_tuples(Positive, PosInput, PosOutput), | |
| 152 | split_input_output_tuples(Negative, NegInput, NegOutput), | |
| 153 | !. | |
| 154 | ||
| 155 | /* filter_new_examples(Input,Output,OldInput,NewInput,NewOutput) :- | |
| 156 | filter_new_examples(Input,Output,OldInput,[],[],NewInput,NewOutput). | |
| 157 | ||
| 158 | filter_new_examples([],[],_,AccInput,AccOutput,AccInput,AccOutput). | |
| 159 | filter_new_examples([Input|TI],[Output|TO],OldInput,AccInput,AccOutput,NewInput,NewOutput) :- | |
| 160 | \+ contains_equivalent_state(Input,OldInput,_) , ! , | |
| 161 | filter_new_examples(TI,TO,OldInput,[Input|AccInput],[Output|AccOutput],NewInput,NewOutput). | |
| 162 | filter_new_examples([_|TI],[_|TO],OldInput,AccInput,AccOutput,NewInput,NewOutput) :- | |
| 163 | filter_new_examples(TI,TO,OldInput,AccInput,AccOutput,NewInput,NewOutput). */ | |
| 164 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), (DistStateCache,FinalAction)) :- | |
| 165 | % synthesizing the action already succeeded but synthesizing an appropriate guard afterwards has been suspended by | |
| 166 | % finding a distingushing state, the synthesized action is asserted and we just synthesize the guard here | |
| 167 | on_exception(error(existence_error(_,_),_), synthesis_context(_, DistStateCache, _, PreCondVars, _, guard, OldPosInput, OldNegInput, Action), fail), | |
| 168 | \+ on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, action, _, _, _), fail), | |
| 169 | Action \== temp(_), | |
| 170 | !, | |
| 171 | ( add_operation_parameter_values_to_examples(PosInput, PosOutput, NegInput, NegOutput, [Action], ExtendedPosInput, ExtendedNegInput) | |
| 172 | ; PosInput = ExtendedPosInput, | |
| 173 | NegInput = ExtendedNegInput | |
| 174 | ), | |
| 175 | keep_asserted_initial_examples(ExtendedPosInput, ExtendedNegInput, OldPosInput, OldNegInput, NewPosInput, NewNegInput), | |
| 176 | post_synthesize_action(Operation, PreCondVars, NewPosInput, PosOutput, NewNegInput, NegOutput, [], Action, FinalAction). | |
| 177 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), (NewDistStateCache,FinalAction)) :- | |
| 178 | % synthesis type is action but the simultaneous generation of a guard has been suspended by finding a distinguishing state, | |
| 179 | % synthesizing the action has not succeeded yet | |
| 180 | on_exception(error(existence_error(_,_),_), synthesis_context(_, PreDistStateCache, _, PreCondVars, ValidInvariantsOrGuards, guard, OldPosInput, OldNegInput, temp(Actions)), fail), | |
| 181 | retractall(synthesis_context(_, _, _, _, ValidGuards, guard, _, _, _)), | |
| 182 | ( add_operation_parameter_values_to_examples(PosInput, PosOutput, NegInput, NegOutput, Actions, ExtendedPosInput, ExtendedNegInput) | |
| 183 | ; PosInput = ExtendedPosInput, | |
| 184 | NegInput = ExtendedNegInput | |
| 185 | ), | |
| 186 | keep_asserted_initial_examples(ExtendedPosInput, ExtendedNegInput, OldPosInput, OldNegInput, NewPosInput, NewNegInput), | |
| 187 | maplist(get_varname_from_id_node, PreCondVars, PreVarNames), | |
| 188 | % therefore we start/restart synthesis of a guard | |
| 189 | synthesized_operation_uses_parameters(Actions, OperationUsesParameters), | |
| 190 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, PreVarNames, (ValidGuards,Operation), NewPosInput, NewNegInput, PrePositive, PreNegative, PreLibrary, | |
| 191 | PreParameterAmount, PreM1, PreCurrentVars, PreBehavioralConstraint, PreLocationVars, PreSolution), | |
| 192 | synthesis_from_examples(Operation, b(truth,pred,[]), PreDistStateCache, PreLibrary, 1, PreCurrentVars, PreCurrentVars, ValidInvariantsOrGuards, guard, PrePositive, PreNegative, | |
| 193 | PreBehavioralConstraint, PreLocationVars, PreM1, PreParameterAmount, PreSolution, PreCondition, NewDistStateCache), | |
| 194 | distinguishing_state_or_synthesize_action(Operation, PreCondition, NewDistStateCache, (PosInput,PosOutput), (NegInput,NegOutput), FinalAction). | |
| 195 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), (NewDistStateCache,FinalAction)) :- | |
| 196 | % synthesizing an action has been suspended by a distinguishing transition, but the user validated the distinguishing example to be negative | |
| 197 | \+ on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, guard, _, _, _), fail), | |
| 198 | on_exception(error(existence_error(_,_),_), synthesis_context(_, DistStateCache, _, _, ValidInvariantsOrGuards, action, OldPosInput, OldNegInput, temp(Action)), fail), | |
| 199 | length(OldPosInput, PLen), | |
| 200 | length(PosInput, PLen), | |
| 201 | length(OldNegInput, NLen), | |
| 202 | length(NegInput, NLen), | |
| 203 | NegInput \= [], | |
| 204 | !, | |
| 205 | ( add_operation_parameter_values_to_examples(PosInput, PosOutput, NegInput, NegOutput, [Action], ExtendedPosInput, ExtendedNegInput) | |
| 206 | ; PosInput = ExtendedPosInput, | |
| 207 | NegInput = ExtendedNegInput | |
| 208 | ), | |
| 209 | keep_asserted_initial_examples(ExtendedPosInput, ExtendedNegInput, OldPosInput, OldNegInput, NewPosInput, NewNegInput), | |
| 210 | ExtendedPosInput = [Example|_], | |
| 211 | maplist(get_varname_from_node_info, Example, PreVarNames), | |
| 212 | % therefore we start/restart synthesis of a guard | |
| 213 | synthesized_operation_uses_parameters([Action], OperationUsesParameters), | |
| 214 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, PreVarNames, (ValidInvariantsOrGuards,Operation), NewPosInput, NewNegInput, PrePositive, PreNegative, PreLibrary, | |
| 215 | PreParameterAmount, PreM1, PreCurrentVars, PreBehavioralConstraint, PreLocationVars, PreSolution), | |
| 216 | synthesis_from_examples(Operation, b(truth,pred,[]), DistStateCache, PreLibrary, 1, PreCurrentVars, PreCurrentVars, ValidInvariantsOrGuards, guard, PrePositive, PreNegative, | |
| 217 | PreBehavioralConstraint, PreLocationVars, PreM1, PreParameterAmount, PreSolution, PreCondition, NewDistStateCache), | |
| 218 | distinguishing_state_or_synthesize_action(Operation, PreCondition, NewDistStateCache, (PosInput,PosOutput), (NegInput,NegOutput), FinalAction). | |
| 219 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), ((PosDistInput,NegDistInput),FinalAction)) :- | |
| 220 | % synthesizing an action has been suspended by a distinguishing transition, no guard | |
| 221 | \+ on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, guard, _, _, _), fail), | |
| 222 | on_exception(error(existence_error(_,_),_), synthesis_context(DistTransitionCache, DistStateCache, _, PreCondVars, ValidGuards, action, OldPosInput, OldPosOutput, _), fail), | |
| 223 | retractall(synthesis_context(_, _, _, _, _, action, _, _, _)), | |
| 224 | keep_asserted_initial_examples(PosInput, PosOutput, OldPosInput, OldPosOutput, NewPosInput, NewPosOutput), | |
| 225 | prepare_synthesis_of_action_by_examples(Operation, NewPosInput, NewPosOutput, Library, ParameterAmount, M1, CurrentVars, BehavioralConstraint, LocationVars, Solution), | |
| 226 | DistStateCache = (PosDist,NegDist), | |
| 227 | append(NegInput, NegDist, NewNegDist), | |
| 228 | synthesis_from_examples(Operation, DistTransitionCache, (PosDist,NewNegDist), Library, 1, CurrentVars, PreCondVars, ValidGuards, action, | |
| 229 | NewPosInput, NewPosOutput, BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, Synthesized, (PosDistInput,NegDistInput)), | |
| 230 | !, | |
| 231 | Synthesized \= none, | |
| 232 | post_synthesize_action(Operation, CurrentVars, NewPosInput, NewPosOutput, NegInput, NegOutput, NegDistInput, Synthesized, FinalAction). | |
| 233 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), (DistStateCache,Synthesized)) :- | |
| 234 | % no context asserted, start new synthesis instance for type action, | |
| 235 | % check if the machine already satisfies the behavior and relax a guard or synthesize a new operation | |
| 236 | !, | |
| 237 | behavior_satisfied_or_extend_machine(Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized), | |
| 238 | ( on_exception(error(existence_error(_,_),_), synthesis_context(_, DistStateCache, _, _, _, _, _, _, _), fail) | |
| 239 | -> | |
| 240 | true | |
| 241 | ; DistStateCache = ([],[]) | |
| 242 | ). | |
| 243 | start_synthesis_from_ui_aux(Operation, SynthesisType, (PosInput,_), (NegInput,_), (DistStateCache,Synthesized)) :- | |
| 244 | SynthesisType \= action, | |
| 245 | % go on synthesizing the guard/invariant using the validated distinguishing state | |
| 246 | on_exception(error(existence_error(_,_),_), synthesis_context(_, PreDistStateCache, _, PreCondVars, ValidInvariantsOrGuards, SynthesisType, OldPosInput, OldNegInput, _), fail), | |
| 247 | retractall(synthesis_context(_, _, _, _, _, SynthesisType, _, _, _)), | |
| 248 | keep_asserted_initial_examples(PosInput, NegInput, OldPosInput, OldNegInput, NewPosInput, NewNegInput), | |
| 249 | maplist(get_varname_from_id_node, PreCondVars, PreVarNames), | |
| 250 | machine_operation_uses_parameters(Operation, OperationUsesParameters), | |
| 251 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, PreVarNames, (ValidInvariantsOrGuards,Operation), NewPosInput, NewNegInput, PrePositive, PreNegative, PreLibrary, PreParameterAmount, PreM1, PreCurrentVars, | |
| 252 | PreBehavioralConstraint, PreLocationVars, PreSolution), | |
| 253 | synthesis_from_examples(Operation, b(truth,pred,[]), PreDistStateCache, PreLibrary, 1, PreCurrentVars, PreCurrentVars, ValidInvariantsOrGuards, SynthesisType, PrePositive, | |
| 254 | PreNegative, PreBehavioralConstraint, PreLocationVars, PreM1, PreParameterAmount, PreSolution, TSynthesized, DistStateCache), | |
| 255 | TSynthesized \= none, | |
| 256 | post_synthesize_predicate(SynthesisType, TSynthesized, Synthesized). | |
| 257 | start_synthesis_from_ui_aux(Operation, SynthesisType, (PosInput,PosOutput), (NegInput,NegOutput), (DistStateCache,Synthesized)) :- | |
| 258 | % no context asserted, we start a new synthesis instance | |
| 259 | \+ on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, _, _, _, _), fail), | |
| 260 | start_specific_synthesis(Operation, SynthesisType, PosInput, NegInput, PosOutput, NegOutput, TSynthesized), | |
| 261 | !, | |
| 262 | ( on_exception(error(existence_error(_,_),_), synthesis_context(_, DistStateCache, _, _, _, _, _, _, _), fail) | |
| 263 | -> | |
| 264 | true | |
| 265 | ; DistStateCache = ([],[]) | |
| 266 | ), | |
| 267 | TSynthesized \= none, | |
| 268 | post_synthesize_predicate(SynthesisType, TSynthesized, Synthesized). | |
| 269 | ||
| 270 | % Check if an operation already satisfies the provided behavior or if a precondition just has to be relaxed. | |
| 271 | % Otherwise, synthesize a new operation. | |
| 272 | behavior_satisfied_or_extend_machine(Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 273 | PosInput = [Example|_], | |
| 274 | get_current_vars_from_example(Example, CurrentVars), | |
| 275 | check_transitions_against_machine_operations(CurrentVars, PosInput, PosOutput, Result), | |
| 276 | behavior_satisfied_or_extend_machine_aux(Result, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized). | |
| 277 | % An operation satisfies the provided behavior and no negative input states conflict with the current precondition. | |
| 278 | % We pass the term operation_satisfied/1 to the UI and no distinguishing example. | |
| 279 | behavior_satisfied_or_extend_machine_aux((Operation,done), _, _, NegInput, _, _, operation_satisfied(Operation)) :- | |
| 280 | check_negative_inputs_against_operation_precondition(Operation, NegInput), | |
| 281 | !. | |
| 282 | % An operation satisfies the provided behavior but there are negative input states that are valid for the current precondition. | |
| 283 | % We thus need to synthesize a new precondition. | |
| 284 | behavior_satisfied_or_extend_machine_aux((Operation,done), _, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 285 | behavior_satisfied_or_extend_machine_aux2(guard, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized). | |
| 286 | % A precondition needs to be relaxed. | |
| 287 | behavior_satisfied_or_extend_machine_aux((Operation,guard), _, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 288 | behavior_satisfied_or_extend_machine_aux2(guard, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized). | |
| 289 | % No matching operation, we thus synthesize a new one. | |
| 290 | behavior_satisfied_or_extend_machine_aux(no_match, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 291 | behavior_satisfied_or_extend_machine_aux2(action, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized). | |
| 292 | % Synthesize guard or action. | |
| 293 | behavior_satisfied_or_extend_machine_aux2(SynthesisType, Operation, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 294 | start_specific_synthesis(Operation, SynthesisType, PosInput, NegInput, PosOutput, NegOutput, Synthesized), | |
| 295 | !, | |
| 296 | Synthesized \= none. | |
| 297 | ||
| 298 | % Synthesizing the action has been suspended and we synthesized a guard. | |
| 299 | % We derived a distinguishing state. | |
| 300 | distinguishing_state_or_synthesize_action(_, PreCondition, _, _, _, PreCondition) :- | |
| 301 | is_distinguishing(PreCondition). | |
| 302 | % Synthesizing the guard either succeded or failed. The latter means, we can't pass a guard. Thus, we use the old one. | |
| 303 | % We cached the distinguishing transitions so we try to go on synthesizing the action and maybe | |
| 304 | % find a guard later depending on the distinguishing interaction with the user. | |
| 305 | distinguishing_state_or_synthesize_action(Operation, PreCondition, NewDistStateCache, (PosInput,PosOutput), (NegInput,NegOutput), Action) :- | |
| 306 | % assert the synthesized precondition to the currently suspended synthesis context of the action and restart it | |
| 307 | synthesis_context(DistTransitionCache, _, CurrentVars, PreCondVars, OldPreCond, action, Input, Output, _), | |
| 308 | new_or_old_precondition(OldPreCond, PreCondition, NewPreCond), | |
| 309 | retractall(synthesis_context(_, _, _, _, _, action, _, _, _)), | |
| 310 | asserta(synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, NewPreCond, action, Input, Output, _)), | |
| 311 | start_synthesis_from_ui_aux(Operation, action, (PosInput,PosOutput), (NegInput,NegOutput), Action). | |
| 312 | ||
| 313 | new_or_old_precondition(OldPreCond, none, OldPreCond). | |
| 314 | new_or_old_precondition(_, PreCond, PreCond) :- | |
| 315 | PreCond \= none. | |
| 316 | ||
| 317 | % When synthesizing a guard, we may need to consider operation parameters. | |
| 318 | % Compute the values of operation parameters for each example and add the parameters to the examples like the other machine variables. | |
| 319 | add_operation_parameter_values_to_examples([], [], [], [], _, [], []). | |
| 320 | add_operation_parameter_values_to_examples(PosInput, PosOutput, [], [], Actions, NewPosInput, []) :- | |
| 321 | add_operation_parameter_values_to_examples(PosInput, PosOutput, Actions, NewPosInput). | |
| 322 | add_operation_parameter_values_to_examples([], [], NegInput, NegOutput, Actions, [], NewNegInput) :- | |
| 323 | add_operation_parameter_values_to_examples(NegInput, NegOutput, Actions, NewNegInput). | |
| 324 | add_operation_parameter_values_to_examples(PosInput, PosOutput, NegInput, NegOutput, Actions, NewPosInput, NewNegInput) :- | |
| 325 | add_operation_parameter_values_to_examples(PosInput, PosOutput, Actions, NewPosInput), | |
| 326 | add_operation_parameter_values_to_examples(NegInput, NegOutput, Actions, NewNegInput). | |
| 327 | ||
| 328 | add_operation_parameter_values_to_examples(Input, Output, Actions, NewInput) :- | |
| 329 | Input = [Example|_], | |
| 330 | maplist(get_varname_from_node_info, Example, CurrentVarNames), | |
| 331 | maplist(parallel_to_conjunction, Actions, ActionPreds), | |
| 332 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, Input, Output, ParamValues), | |
| 333 | maplist(append, Input, ParamValues, NewInput). | |
| 334 | ||
| 335 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, Input, Output, ParamValuesList) :- | |
| 336 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, Input, Output, [], ParamValuesList). | |
| 337 | ||
| 338 | add_operation_parameter_values_to_examples_aux(_, _, [], [], Acc, Acc). | |
| 339 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, [Input|IT], [Output|OT], Acc, ParamValuesList) :- | |
| 340 | create_before_after_equalities(Input, Output, BAEquality), | |
| 341 | member(ActionPred, ActionPreds), | |
| 342 | create_texpr(conjunct(ActionPred,BAEquality), pred, [], BeforeAfterWithEqualities), | |
| 343 | solve_predicate(BeforeAfterWithEqualities, _, Solution), | |
| 344 | Solution = solution(SolutionBindings), | |
| 345 | !, | |
| 346 | get_operation_parameter_values_from_before_after(CurrentVarNames, SolutionBindings, ParamValues), | |
| 347 | append(Acc, [ParamValues], NewAcc), | |
| 348 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, IT, OT, NewAcc, ParamValuesList). | |
| 349 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, [Input|IT], [_|OT], Acc, ParamValuesList) :- | |
| 350 | % we may not find a solution for the operation parameters for negative examples | |
| 351 | create_equality_nodes_from_example(Input, BeforeEqualityList), | |
| 352 | conjunct_predicates(BeforeEqualityList, BeforeEquality), | |
| 353 | member(ActionPred, ActionPreds), | |
| 354 | create_texpr(conjunct(ActionPred,BeforeEquality), pred, [], BeforeAfterWithEqualities), | |
| 355 | solve_predicate(BeforeAfterWithEqualities, _, Solution), | |
| 356 | Solution = solution(SolutionBindings), | |
| 357 | !, | |
| 358 | get_operation_parameter_values_from_before_after(CurrentVarNames, SolutionBindings, ParamValues), | |
| 359 | append(Acc, [ParamValues], NewAcc), | |
| 360 | add_operation_parameter_values_to_examples_aux(CurrentVarNames, ActionPreds, IT, OT, NewAcc, ParamValuesList). | |
| 361 | ||
| 362 | get_operation_parameter_values_from_before_after(CurrentVarNames, SolutionBindings, ParamValues) :- | |
| 363 | % only for those operation parameter that are not part of the current examples | |
| 364 | findall(ParamBinding, ( member(ParamBinding, SolutionBindings), | |
| 365 | ParamBinding = binding(TempIdName,_,_), | |
| 366 | remove_prime(TempIdName, IdName), | |
| 367 | \+ member(IdName, CurrentVarNames) | |
| 368 | ), ParamBindings), | |
| 369 | get_operation_parameter_values_from_before_after_aux(ParamBindings, [], ParamValues). | |
| 370 | ||
| 371 | get_operation_parameter_values_from_before_after_aux([], Acc, Acc). | |
| 372 | get_operation_parameter_values_from_before_after_aux([binding(ParamName,_,Value)|T], Acc, ParamValues) :- | |
| 373 | parse_and_typecheck_value(Value, TempValueAst), | |
| 374 | add_texpr_infos(TempValueAst, [synthesis(initial_example),synthesis(machinevar,ParamName)], ValueAst), | |
| 375 | create_machinevar(ValueAst), | |
| 376 | get_operation_parameter_values_from_before_after_aux(T, [ValueAst|Acc], ParamValues). | |
| 377 | ||
| 378 | % Create machinevars for operation parameters when synthesizing a precondition for an operation using parameters. | |
| 379 | create_machinevar(b(identifier(IdName),Type,Info)) :- | |
| 380 | member(synthesis(machinevar,IdName), Info), | |
| 381 | !, | |
| 382 | ( on_exception(error(existence_error(_,_),_), additional_machinevars(AdditionalMachineVars), fail) -> | |
| 383 | true | |
| 384 | ; AdditionalMachineVars = [] | |
| 385 | ), | |
| 386 | ( \+ member(b(identifier(IdName),Type,Info), AdditionalMachineVars) | |
| 387 | -> | |
| 388 | create_machinevar_aux(b(identifier(IdName),Type,Info), AdditionalMachineVars) | |
| 389 | ; true | |
| 390 | ). | |
| 391 | create_machinevar(b(_,Type,Info)) :- | |
| 392 | member(synthesis(machinevar,IdName), Info), | |
| 393 | create_machinevar(b(identifier(IdName),Type,Info)). | |
| 394 | ||
| 395 | create_machinevar_aux(IdNode, AdditionalMachineVars) :- | |
| 396 | retractall(additional_machinevars(_)), | |
| 397 | asserta(additional_machinevars([IdNode|AdditionalMachineVars])). | |
| 398 | ||
| 399 | create_before_after_equalities(In, Out, Equality) :- | |
| 400 | create_equality_nodes_from_example(In, EqIn), | |
| 401 | create_equality_nodes_from_example(Out, EqOut), | |
| 402 | maplist(prime_or_unprime_variables_in_ast(prime, []), EqOut, EqOutPrimed), | |
| 403 | append(EqIn, EqOutPrimed, Eqs), | |
| 404 | conjunct_predicates(Eqs, Equality), | |
| 405 | !. | |
| 406 | ||
| 407 | post_synthesize_predicate(guard, Synthesized, NewPreCondition) :- | |
| 408 | find_typed_identifier_uses_with_info(Synthesized, TypedIdentifiers), | |
| 409 | get_operation_params_from_ids(TypedIdentifiers, Params), | |
| 410 | Params \= [], | |
| 411 | !, | |
| 412 | synthesis_util:set_operation_params_domain(Params, ParamTypeDefsPred), | |
| 413 | conjunct_predicates([ParamTypeDefsPred,Synthesized], NewPreCondition). | |
| 414 | post_synthesize_predicate(_, Synthesized, Synthesized). | |
| 415 | ||
| 416 | % Synthesis returned a distinguishing transition. | |
| 417 | post_synthesize_action(_, _, _, _, _, _, _, Synthesized, Synthesized) :- | |
| 418 | is_distinguishing(Synthesized), | |
| 419 | synthesis_log(solution(_,Synthesized)). | |
| 420 | % example is given we generate an appropriate guard afterwards. | |
| 421 | post_synthesize_action(Operation, _Vars, PosInput, PosOutput, NegInput, NegOutput, _NegDistInput, Synthesized, FinalAction) :- | |
| 422 | \+ is_distinguishing(Synthesized), | |
| 423 | Synthesized \= none, | |
| 424 | ( add_operation_parameter_values_to_examples(PosInput, PosOutput, NegInput, NegOutput, [Synthesized], NewPosInput, NewNegInput) | |
| 425 | ; PosInput = NewPosInput, | |
| 426 | NegInput = NewNegInput | |
| 427 | ), | |
| 428 | NewPosInput = [Example|_], | |
| 429 | maplist(get_varname_from_node_info, Example, VarNames), | |
| 430 | synthesize_guard_if_necessary(VarNames, NewPosInput, NewNegInput, Synthesized, Action), | |
| 431 | post_synthesize_action_aux(Operation, Action, FinalAction). | |
| 432 | post_synthesize_action_aux(_, Distinguishing, Distinguishing) :- | |
| 433 | % synthesizing a guard afterwards returned a distinguishing state | |
| 434 | % the synthesized action is asserted in synthesis_context/9 and will be reused | |
| 435 | is_distinguishing(Distinguishing). | |
| 436 | post_synthesize_action_aux(Operation, Action, FinalAction) :- | |
| 437 | % synthesizing a guard afterwards succeeded or has already been sufficient beforehand, i.e., | |
| 438 | % a guard has been synthesized simultaneously when synthesizing the action | |
| 439 | \+ is_distinguishing(Action), | |
| 440 | finalize_synthesized_action(Operation, Action, FinalAction), | |
| 441 | synthesis_log(solution(action,FinalAction)). | |
| 442 | ||
| 443 | %% synthesize actions, invariants or guards | |
| 444 | start_specific_synthesis(Operation, action, PosInput, NegInput, PosOutput, NegOutput, Action) :- | |
| 445 | set_preference(randomise_enumeration_order, true), | |
| 446 | % no context asserted | |
| 447 | \+ on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, _, _, _, _), fail), | |
| 448 | mark_examples_as_initial(PosInput, PosOutput, InitialInput, InitialOutput), | |
| 449 | prepare_synthesis_of_action_by_examples(Operation, InitialInput, InitialOutput, Library, ParameterAmount, M1, CurrentVars, BehavioralConstraint, LocationVars, Solution), | |
| 450 | % use the negative input states for the distinguishing state cache | |
| 451 | synthesis_from_examples(Operation, b(truth,pred,[]), ([],NegInput), Library, 1, CurrentVars, CurrentVars, any, action, InitialInput, | |
| 452 | InitialOutput, BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, Synthesized, (_,NegDistInput)), | |
| 453 | !, | |
| 454 | post_synthesize_action(Operation, CurrentVars, InitialInput, InitialOutput, NegInput, NegOutput, NegDistInput, Synthesized, Action). | |
| 455 | start_specific_synthesis(Operation, action, PosInput, NegInput, PosOutput, _, Action) :- | |
| 456 | set_preference(randomise_enumeration_order, true), | |
| 457 | % context asserted, synthesis has been suspended | |
| 458 | on_exception(error(existence_error(_,_),_), synthesis_context(DistTransitionCache, DistStateCache, CurrentVars, PreCondVars, | |
| 459 | ValidInvariantsOrGuards, action, OldInput, OldOutput, _), fail), | |
| 460 | keep_asserted_initial_examples(PosInput, PosOutput, OldInput, OldOutput, NewPosInput, NewPosOutput), | |
| 461 | start_specific_synthesis_aux(Operation, action, NewPosInput, NegInput, NewPosOutput, _, DistTransitionCache, DistStateCache, | |
| 462 | CurrentVars, PreCondVars, ValidInvariantsOrGuards, Action). | |
| 463 | ||
| 464 | % the invariants are explicitly modified by the user, no operation is involved since no invariant violation has been found | |
| 465 | start_specific_synthesis(null, invariant, PosInput, NegInput, PosOutput, NegOutput, SynthesizedInvariant) :- | |
| 466 | set_preference(randomise_enumeration_order, true), | |
| 467 | get_violated_and_valid_machine_invariants(PosOutput, _, _, ValidInvariants), | |
| 468 | get_positive_and_negative_examples_for_invariant_synthesis(PosInput, PosOutput, NegInput, NegOutput, Positive, Negative), | |
| 469 | Positive = [Example|_], | |
| 470 | maplist(get_varname_from_node_info, Example, VarNames), | |
| 471 | synthesis_log(involved_variables(VarNames)), | |
| 472 | pre_library_setup(no, invariant, 1, Example, Library), | |
| 473 | mark_examples_as_initial(Positive, Negative, InitialPositive, InitialNegative), | |
| 474 | get_behavioral_constraint_from_input(Library, ([],_), InitialPositive, InitialNegative, BehavioralConstraint, LocationVars), | |
| 475 | % open('synthesis_constraint_invariant.eval',write,Stream) , tell(Stream) , | |
| 476 | % translate:nested_print_bexpr_as_classicalb(BehavioralConstraint) , nl , nl, close(Stream) , | |
| 477 | solve_using_selected_solver(BehavioralConstraint, Solution), | |
| 478 | get_line_amount(_, Library, Example, M), | |
| 479 | M1 is M-1, | |
| 480 | length(Example, ParameterAmount), | |
| 481 | b_get_machinevars_with_operation_params(MachineVars), | |
| 482 | synthesis_from_examples(null, b(truth,pred,[]), ([],[]), Library, 1, MachineVars, MachineVars, ValidInvariants, invariant, InitialPositive, | |
| 483 | InitialNegative, BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, SynthesizedInvariant, _). | |
| 484 | % if we synthesize an invariant after finding an invariant violation, we reduce the examples to violating vars only | |
| 485 | start_specific_synthesis(Operation, invariant, PosInput, NegInput, PosOutput, NegOutput, Synthesized) :- | |
| 486 | set_preference(randomise_enumeration_order, true), | |
| 487 | % use PosInput because at least one invariant violating state has been graduated as valid by the user | |
| 488 | get_violated_and_valid_machine_invariants(PosOutput, ViolatedInvariants, ViolatingVars, ValidInvariants), | |
| 489 | findall(Name, ( member(IDNode, ViolatingVars), | |
| 490 | IDNode = b(identifier(Name),_,_) | |
| 491 | ), VarNames), | |
| 492 | synthesis_log(involved_variables(VarNames)), | |
| 493 | get_positive_and_negative_examples_for_invariant_synthesis(PosInput, PosOutput, NegInput, NegOutput, Pos, Neg), | |
| 494 | maplist(reduce_input_to_violating_vars(VarNames), Pos, TRPositive), | |
| 495 | maplist(reduce_input_to_violating_vars(VarNames), Neg, RNegative), | |
| 496 | TRPositive = [Example|_], | |
| 497 | pre_library_setup(no, invariant, 1, Example, Library), | |
| 498 | get_valid_states(VarNames, 5, TValidStates), | |
| 499 | maplist(reduce_input_to_violating_vars(VarNames), TValidStates, ValidStates), | |
| 500 | append(TRPositive, ValidStates, RPositive), | |
| 501 | remove_dups(RPositive, NRPositive), | |
| 502 | % TODO: what about several invariant violating examples that are graduated to be valid? | |
| 503 | % get the example that violates an invariant but has been graduated to be valid by the user | |
| 504 | get_invariant_violating_example(ViolatedInvariants, PosInput, PosOutput, (In,Out)), | |
| 505 | % get counter example | |
| 506 | get_invariant_violating_transition(Operation, ViolatingVars, ViolatedInvariants, In, Out, Counter), | |
| 507 | start_specific_synthesis_aux(Operation, invariant, ValidInvariants, VarNames, NRPositive, RNegative, ViolatingVars, Library, Counter, Synthesized). | |
| 508 | ||
| 509 | start_specific_synthesis(Operation, guard, PosInput, NegInput, _, NegOutput, SynthesizedGuard) :- | |
| 510 | set_preference(randomise_enumeration_order, true), | |
| 511 | get_guard_list_from_operation(Operation, Guards), | |
| 512 | get_involved_variables(Guards, PosInput, NegOutput, InvolvedVarNames), | |
| 513 | % filter partial guards that are valid for the examples, and thus, do not need to be relaxed, | |
| 514 | % these are conjuncted to the synthesized guard later on | |
| 515 | findall(ValidGuard, ( member(ValidGuard, Guards), | |
| 516 | find_identifier_uses(ValidGuard, [], UsedIDs), | |
| 517 | intersection(UsedIDs, InvolvedVarNames, []) | |
| 518 | ), ValidGuards), | |
| 519 | mark_examples_as_initial(PosInput, NegInput, InitialPosInput, InitialNegInput), | |
| 520 | % TODO: handle operation parameters | |
| 521 | % get_machinevars_by_name(InvolvedVarNames,InvolvedVarNodes) , | |
| 522 | % get_valid_transitions_for_operation(InvolvedVarNodes,3,Operation,ValidInput,_) , | |
| 523 | % append(InitialPosInput,ValidInput,ExtendedPosInput) , | |
| 524 | machine_operation_uses_parameters(Operation, OperationUsesParameters), | |
| 525 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, InvolvedVarNames, (ValidGuards,Operation), InitialPosInput, InitialNegInput, Positive, Negative, Library, | |
| 526 | ParameterAmount, M1, CurrentVars, BehavioralConstraint, LocationVars, Solution), | |
| 527 | synthesis_from_examples(Operation, b(truth,pred,[]), ([],[]), Library, 1, CurrentVars, CurrentVars, ValidGuards, guard, Positive, Negative, | |
| 528 | BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, SynthesizedGuard, _), | |
| 529 | synthesis_log(solution(guard,SynthesizedGuard)). | |
| 530 | ||
| 531 | start_specific_synthesis_aux(Operation, action, NewPosInput, NegInput, NewPosOutput, NegOutput, DistTransitionCache, DistStateCache, | |
| 532 | CurrentVars, PreCondVars, _, Action) :- | |
| 533 | % synthesize guard if negative input states are given and synthesis has been suspended | |
| 534 | NegInput \= [], | |
| 535 | maplist(get_varname_from_id_node, PreCondVars, PreCondVarNames), | |
| 536 | DistStateCache = (PosDist,NegDist), | |
| 537 | append(NewPosInput, PosDist, GuardPositive), | |
| 538 | append(NegInput, NegDist, GuardNegative), | |
| 539 | % if neginput empty | |
| 540 | use_operation_parameters_for_current_synthesis_type(Operation, guard, OperationUsesParameters), | |
| 541 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, PreCondVarNames, ([],_), GuardPositive, GuardNegative, PrePositive, PreNegative, | |
| 542 | PreLibrary, PreParameterAmount, PreM1, _, PreBehavioralConstraint, PreLocationVars, Solution), | |
| 543 | synthesis_from_examples(Operation, b(truth,pred,[]), (PrePositive,PreNegative), PreLibrary, 1, PreCondVars, PreCondVars, | |
| 544 | any, guard, PrePositive, PreNegative, PreBehavioralConstraint, PreLocationVars, PreM1, | |
| 545 | PreParameterAmount, Solution, Guards, PreDistStateCache), | |
| 546 | ( is_distinguishing(Guards) | |
| 547 | -> | |
| 548 | Action = Guards | |
| 549 | ; prepare_synthesis_of_action_by_examples(Operation, NewPosInput, NewPosOutput, Library, ParameterAmount, M1, CurrentVars, BehavioralConstraint, | |
| 550 | LocationVars, Solution), | |
| 551 | prepare_synthesized_guards_for_action(Guards, GuardsForAction), | |
| 552 | synthesis_from_examples(Operation, DistTransitionCache, PreDistStateCache, Library, 1, CurrentVars, PreCondVars, | |
| 553 | GuardsForAction, action, NewPosInput, NewPosOutput, BehavioralConstraint, LocationVars, | |
| 554 | M1, ParameterAmount, Solution, Synthesized, (_,NegDistInput)), | |
| 555 | !, | |
| 556 | post_synthesize_action(Operation, CurrentVars, NewPosInput, NewPosOutput, NegInput, NegOutput, NegDistInput, Synthesized, Action) | |
| 557 | ). | |
| 558 | start_specific_synthesis_aux(Operation, action, NewPosInput, [], NewPosOutput, _, DistTransitionCache, DistStateCache, | |
| 559 | CurrentVars, PreCondVars, ValidInvariantsOrGuards, Action) :- | |
| 560 | prepare_synthesis_of_action_by_examples(Operation, NewPosInput, NewPosOutput, Library, ParameterAmount, M1, CurrentVars, BehavioralConstraint, | |
| 561 | LocationVars, Solution), | |
| 562 | synthesis_from_examples(Operation, DistTransitionCache, DistStateCache, Library, 1, CurrentVars, PreCondVars, | |
| 563 | ValidInvariantsOrGuards, action, NewPosInput, NewPosOutput, BehavioralConstraint, LocationVars, | |
| 564 | M1, ParameterAmount, Solution, Synthesized, (_,NegDistInput)), | |
| 565 | !, | |
| 566 | post_synthesize_action(Operation, CurrentVars, NewPosInput, NewPosOutput, [], [], NegDistInput, Synthesized, Action). | |
| 567 | ||
| 568 | % Auxiliary predicate for synthesis of invariants to check if we can find a counter example. | |
| 569 | start_specific_synthesis_aux(Operation, invariant, ValidInvariants, VarNames, Positive, TNegative, ViolatingVars, Library, (TCounterIn,TCounterOut), SynthesizedInvariant) :- | |
| 570 | maplist(reduce_input_to_violating_vars(VarNames), [TCounterIn,TCounterOut], [CounterIn,CounterOut]), | |
| 571 | % don't create contradiction by using the same example as positive and negative | |
| 572 | findall(Counter, ( member(Counter, [CounterIn,CounterOut]), | |
| 573 | \+ contains_equivalent_state(Counter, Positive, _) | |
| 574 | ), CounterStates), | |
| 575 | append(CounterStates, TNegative, Negative), | |
| 576 | mark_examples_as_initial(Positive, Negative, InitialPositive, InitialNegative), | |
| 577 | get_behavioral_constraint_from_input(Library, ([],_), InitialPositive, InitialNegative, BehavioralConstraint, LocationVars), | |
| 578 | solve_using_selected_solver(BehavioralConstraint, Solution), | |
| 579 | get_line_amount(Operation, Library, CounterIn, M), | |
| 580 | M1 is M-1, | |
| 581 | length(CounterIn, ParameterAmount), | |
| 582 | synthesis_from_examples(Operation, b(truth,pred,[]), ([],[]), Library, 1, ViolatingVars, ViolatingVars, ValidInvariants, invariant, InitialPositive, | |
| 583 | InitialNegative, BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, SynthesizedInvariant, _), | |
| 584 | synthesis_log(solution(invariant,SynthesizedInvariant)). | |
| 585 | % We can't find any invariant violating transition (counter example), therefore we just remove the violating invariants. | |
| 586 | % no invariant given | |
| 587 | start_specific_synthesis_aux(_, invariant, [], _, _, _, _, _, _, b(truth,pred,[])) :- | |
| 588 | synthesis_log(solution(invariant,b(truth,pred,[]))). | |
| 589 | % print valid invariants | |
| 590 | start_specific_synthesis_aux(_, invariant, ValidInvariants, _, _, _, _, _, _, Invariant) :- | |
| 591 | conjunct_predicates(ValidInvariants, Invariant), | |
| 592 | synthesis_log(solution(invariant,Invariant)). | |
| 593 | ||
| 594 | get_positive_and_negative_examples_for_invariant_synthesis(PosInput, PosOutput, NegInput, NegOutput, Pos, Neg) :- | |
| 595 | % for synthesizing invariants we also need output states | |
| 596 | append(PosInput, PosOutput, TempPositive), | |
| 597 | append(NegInput, NegOutput, TempNegative), | |
| 598 | get_distinct_states(invariant, TempPositive, TempNegative, Positive, Negative), | |
| 599 | % don't use an example more than one time, only possible for invariant synthesis | |
| 600 | % because we split every transition in two examples (input,output) | |
| 601 | remove_dups(Positive, Pos), | |
| 602 | remove_dups(Negative, Neg). | |
| 603 | ||
| 604 | prepare_synthesis_of_action_by_examples(Operation, Input, Output, Library, ParameterAmount, M1, CurrentVars, BehavioralConstraint, LocationVars, Solution) :- | |
| 605 | !, | |
| 606 | Input = [Example|_], | |
| 607 | length(Example, ParameterAmount), | |
| 608 | pre_library_setup(yes, action, 1, Example, Library), | |
| 609 | get_current_vars_from_example(Example, CurrentVars), | |
| 610 | get_behavioral_constraint(Library, ([],_), Input, Output, BehavioralConstraint, LocationVars), | |
| 611 | % open('synthesis_constraint.eval',write,Stream) , tell(Stream) , | |
| 612 | % translate:nested_print_bexpr_as_classicalb(BehavioralConstraint) , nl , nl, close(Stream) , | |
| 613 | get_line_amount(Operation, Library, Example, M), | |
| 614 | M1 is M-1, | |
| 615 | solve_using_selected_solver(BehavioralConstraint, Solution). | |
| 616 | ||
| 617 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, VarNames, (ValidGuards,Operation), TPositive, TNegative, Positive, Negative, Library, ParameterAmount, M1, | |
| 618 | CurrentVars, BehavioralConstraint, LocationVars, Solution) :- | |
| 619 | !, | |
| 620 | remove_dups(TPositive, TTPositive), | |
| 621 | remove_dups(TNegative, TTNegative), | |
| 622 | maplist(reduce_input_to_violating_vars(VarNames), TTPositive, TempPositive), | |
| 623 | maplist(reduce_input_to_violating_vars(VarNames), TTNegative, TempNegative), | |
| 624 | get_distinct_states(guard, TempPositive, TempNegative, Positive, Negative), | |
| 625 | % at least one negative example is given since an invariant is violated | |
| 626 | Negative = [Example|_], | |
| 627 | length(Example, ParameterAmount), | |
| 628 | pre_library_setup(OperationUsesParameters, guard, 1, Example, Library), | |
| 629 | get_current_vars_from_example(Example, CurrentVars), | |
| 630 | get_behavioral_constraint_from_input(Library, (ValidGuards,Operation), Positive, Negative, BehavioralConstraint, LocationVars), | |
| 631 | % open('synthesis_constraint.eval',write,Stream) , tell(Stream) , | |
| 632 | % unsat_cores:unsat_core(BehavioralConstraint,UC) , | |
| 633 | % translate:nested_print_bexpr_as_classicalb(BehavioralConstraint) , nl , nl, close(Stream) , | |
| 634 | solve_using_selected_solver(BehavioralConstraint, Solution), | |
| 635 | get_line_amount(Operation, Library, Example, M), | |
| 636 | M1 is M-1. | |
| 637 | ||
| 638 | synthesize_guard_if_necessary(_, _, NegativeInputStates, Synthesized, Synthesized) :- | |
| 639 | ( Synthesized = b(precondition(_,_),subst,_) | |
| 640 | ; NegativeInputStates = [] | |
| 641 | ). | |
| 642 | synthesize_guard_if_necessary(VarNames, PositiveInputStates, NegativeInputStates, SynthesizedBody, Synthesized) :- | |
| 643 | synthesized_operation_uses_parameters([SynthesizedBody], OperationUsesParameters), | |
| 644 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, VarNames, ([],_), PositiveInputStates, NegativeInputStates, Positive, Negative, Library, | |
| 645 | ParameterAmount, M1, CurrentVars, BehavioralConstraint, LocationVars, Solution), | |
| 646 | synthesis_from_examples(_, b(truth,pred,[]), ([],[]), Library, 1, CurrentVars, CurrentVars, any, guard, Positive, Negative, | |
| 647 | BehavioralConstraint, LocationVars, M1, ParameterAmount, Solution, SynthesizedGuard, _), | |
| 648 | synthesize_guard_if_necessary_aux(PositiveInputStates, NegativeInputStates, CurrentVars, SynthesizedGuard, SynthesizedBody, Synthesized). | |
| 649 | synthesize_guard_if_necessary_aux(PositiveInputStates, NegativeInputStates, CurrentVars, SynthesizedGuard, SynthesizedBody, SynthesizedGuard) :- | |
| 650 | % return the distinguishing state derived from synthesizing a guard after synthesizing the action succeeded | |
| 651 | is_distinguishing(SynthesizedGuard), | |
| 652 | assert_synthesis_context(b(truth,pred,[]), ([],[]), CurrentVars, CurrentVars, any, guard, PositiveInputStates, NegativeInputStates, SynthesizedBody). | |
| 653 | synthesize_guard_if_necessary_aux(_, _, _, SynthesizedGuard, SynthesizedBody, Synthesized) :- | |
| 654 | % synthesizing the guard succeeded | |
| 655 | \+ is_distinguishing(SynthesizedGuard), | |
| 656 | SynthesizedGuard \= none, | |
| 657 | Synthesized = b(precondition(SynthesizedGuard,SynthesizedBody),subst,[]). | |
| 658 | % synthesizing the guard failed and we only return the synthesized action. | |
| 659 | synthesize_guard_if_necessary_aux(_, _, _, none, SynthesizedBody, SynthesizedBody). | |
| 660 | ||
| 661 | %% SYNTHESIS LOOP | |
| 662 | %% Cache a predicate excluding already visited distinguishing transitions for each new run (see | |
| 663 | %% get_distinguishing_state_or_trans/8). | |
| 664 | %% Only for synthesis of an action (ignored otherwise): | |
| 665 | %% When simultaneously synthesizing a guard to an action we synthesize a new guard each time so that | |
| 666 | %% we also store each session's distinguishing states. | |
| 667 | %% The sixth argument PreCondVars defines the variables that should be considered for the simultaneous | |
| 668 | %% generation of a guard if known. Otherwise, 'PreCondVars = CurrentVars' holds. | |
| 669 | % search for further solution | |
| 670 | synthesis_from_examples(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 671 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, | |
| 672 | M1, ParameterAmount, Solution, Synthesized, NewDistStateCache) :- | |
| 673 | synthesis_log(start_synthesis_loop(DistTransitionCache,DistStateCache,Library,LibExpansion,CurrentVars,PreCondVars, | |
| 674 | ValidInvariantsOrGuards,Type,PosInput,NegInput,LocationVars,M1,ParameterAmount,Solution)), | |
| 675 | Solution = solution(SolutionBindings), | |
| 676 | set_preference(randomise_enumeration_order, true), | |
| 677 | location_vars_to_program(Library, Type, CurrentVars, LocationVars, M1, ParameterAmount, Solution, UsedLVars1, ProgramAST), | |
| 678 | % extend the BehavioralConstraint by a constraint excluding specific location mappings that | |
| 679 | % lead to just swapping equivalent components without changing the semantics | |
| 680 | get_prevent_component_swap_constraint(UsedLVars1, SolutionBindings, LocationVars, ComponentSwapExclusion), | |
| 681 | ExtendedBehavioralConstraint = b(conjunct(BehavioralConstraint,ComponentSwapExclusion),pred,[]), | |
| 682 | % In UsedLVars we have the used location variables from the synthesized solution, so we are able | |
| 683 | % to exclude those specific bindings when searching for a further solution (otherwise it would | |
| 684 | % be enough to just change some deadcode). | |
| 685 | find_further_solution(ProgramAST, LocationVars, UsedLVars1, Solution, ExtendedBehavioralConstraint, FurtherSolution, NewBehavioralConstraint), | |
| 686 | synthesis_log(defective_further_solution_and_fail(Type,NewBehavioralConstraint,FurtherSolution,Library,CurrentVars, | |
| 687 | PosInput,NegInput,LocationVars,M1,ParameterAmount)), | |
| 688 | !, | |
| 689 | add_distinguishing_states_from_cache(Type, DistStateCache, PosInput, NegInput, NewPosInput, NewPosOutput), | |
| 690 | synthesis_from_examples_aux1(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 691 | ValidInvariantsOrGuards, Type, NewPosInput, NewPosOutput, ExtendedBehavioralConstraint, LocationVars, | |
| 692 | M1, ParameterAmount, Solution, FurtherSolution, NewBehavioralConstraint, Synthesized, NewDistStateCache). | |
| 693 | % expand the library if no solution can be found | |
| 694 | synthesis_from_examples(Operation, DistTransitionCache, DistStateCache, OldLibrary, LibExpansion, CurrentVars, PreCondVars, | |
| 695 | ValidInvariantsOrGuards, Type, PosInput, NegInput, _, _, M1, ParameterAmount, Solution, | |
| 696 | Synthesized, NewDistStateCache) :- | |
| 697 | Solution \= solution(_), | |
| 698 | NewLibExpansion is LibExpansion+1, | |
| 699 | PosInput = [Example|_], | |
| 700 | use_operation_parameters_for_current_synthesis_type(Operation, Type, OperationUsesParameters), | |
| 701 | pre_library_setup(OperationUsesParameters, Type, NewLibExpansion, Example, NewLibrary), | |
| 702 | !, | |
| 703 | % library has changed | |
| 704 | synthesis_callback(Operation, DistTransitionCache, DistStateCache, OldLibrary, NewLibrary, NewLibExpansion, | |
| 705 | CurrentVars, PreCondVars, ValidInvariantsOrGuards, M1, ParameterAmount, Type, NewLibrary, PosInput, | |
| 706 | NegInput, Synthesized, NewDistStateCache). | |
| 707 | ||
| 708 | % Synthesis failed if library has not changed, i.e., there is no library expansion step left. | |
| 709 | synthesis_callback(_, _, DistStateCache, _, _, NewLibExpansion, _, _, _, _, _, _, _, _, _, Synthesized, NewDistStateCache) :- | |
| 710 | % (subtract(NewLibrary,OldLibrary,[]) ; | |
| 711 | max_library_expansion(MaxLibExpansion), | |
| 712 | NewLibExpansion > MaxLibExpansion, | |
| 713 | !, | |
| 714 | Synthesized = none, | |
| 715 | NewDistStateCache = DistStateCache. | |
| 716 | % If an explicit library is asserted in library_from_ui/1 we do not expand the library. If 'default:_' is asserted | |
| 717 | % we do not expand the library in prolog but use parallelization in Java. | |
| 718 | synthesis_callback(_, _, DistStateCache, _, _, _, _, _, _, _, _, _, _, _, _, Synthesized, NewDistStateCache) :- | |
| 719 | on_exception(error(existence_error(_,_),_), library_from_ui(Library), fail), | |
| 720 | Library \= default, | |
| 721 | !, | |
| 722 | Synthesized = none, | |
| 723 | NewDistStateCache = DistStateCache. | |
| 724 | % Otherwise, restart synthesis with the expanded library. Either no library is asserted in library_from_ui/1 or | |
| 725 | % 'default' is asserted and the library gets expanded successively in prolog using a single instance. | |
| 726 | synthesis_callback(Operation, DistTransitionCache, DistStateCache, _, NewLibrary, NewLibExpansion, CurrentVars, PreCondVars, | |
| 727 | ValidInvariantsOrGuards, _, ParameterAmount, Type, NewLibrary, PosInput, NegInput, Synthesized, NewDistStateCache) :- | |
| 728 | synthesis_log(expand_library), | |
| 729 | get_behavioral_constraint_aux((ValidInvariantsOrGuards,Operation), Type, NewLibrary, PosInput, NegInput, NewBehavioralConstraint, NewLocationVars), | |
| 730 | solve_using_selected_solver(NewBehavioralConstraint, NewSolution), | |
| 731 | !, | |
| 732 | % compute the new amount of lines of the synthesized program using the expanded library | |
| 733 | PosInput = [Input|_], | |
| 734 | get_line_amount(Operation, NewLibrary, Input, M), | |
| 735 | NewM1 is M-1, | |
| 736 | synthesis_from_examples(Operation, DistTransitionCache, DistStateCache, NewLibrary, NewLibExpansion, CurrentVars, PreCondVars, | |
| 737 | ValidInvariantsOrGuards, Type, PosInput, NegInput, NewBehavioralConstraint, NewLocationVars, | |
| 738 | NewM1, ParameterAmount, NewSolution, Synthesized, NewDistStateCache). | |
| 739 | ||
| 740 | % TODO: search programs for a few further default library configurations --> obsolete if we use neural guided search | |
| 741 | % done | |
| 742 | % copy distinguishing state cache | |
| 743 | synthesis_from_examples_aux1(_, _, DistStateCache, Library, _, CurrentVars, _, ValidInvariantsOrGuards, Type, PosInput, NegInput, | |
| 744 | _, LocationVars, M1, ParameterAmount, Solution, none, _, Synthesized, NewDistStateCache) :- | |
| 745 | location_vars_to_program(Library, Type, CurrentVars, LocationVars, M1, ParameterAmount, Solution, _, ProgramAST), | |
| 746 | replace_preds_by_subst_if_neccessary(Type, ProgramAST, TSolutionAST), | |
| 747 | % prime_or_unprime_variables_in_ast(unprime,[],TSolutionAST,SolutionAST) , | |
| 748 | synthesis_util:expand_state_cache_if_guard_and_solution(Type, Solution, DistStateCache, PosInput, NegInput, NewDistStateCache), | |
| 749 | conjunct_previous_invariant_or_guard_if_necessary(Type, ValidInvariantsOrGuards, TSolutionAST, Synthesized). | |
| 750 | % try to find a distinguishing input | |
| 751 | synthesis_from_examples_aux1(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 752 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, | |
| 753 | M1, ParameterAmount, Solution, FurtherSolution, NewBehavioralConstraint, Synthesized, NewDistStateCache) :- | |
| 754 | FurtherSolution \= none, | |
| 755 | location_vars_to_program(Library, Type, CurrentVars, LocationVars, M1, ParameterAmount, Solution, _, ProgramAST), | |
| 756 | location_vars_to_program(Library, Type, CurrentVars, LocationVars, M1, ParameterAmount, FurtherSolution, _, ProgramAST2), | |
| 757 | synthesis_log(solution_tuple(ProgramAST,ProgramAST2)), | |
| 758 | get_distinguishing_state_or_trans(DistTransitionCache, CurrentVars, Type, ValidInvariantsOrGuards, | |
| 759 | ProgramAST, ProgramAST2, NewDistTransitionCache, Distinguishing), | |
| 760 | synthesis_from_examples_aux2(Operation, NewDistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 761 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, | |
| 762 | M1, ParameterAmount, Solution, FurtherSolution, NewBehavioralConstraint, Distinguishing, ProgramAST, ProgramAST2, | |
| 763 | Synthesized, NewDistStateCache). | |
| 764 | ||
| 765 | % two non equivalent programs | |
| 766 | synthesis_from_examples_aux2(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 767 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, M1, ParameterAmount, | |
| 768 | Solution, FurtherSolution, NewBehavioralConstraint, solution(Dist), ProgramAST, ProgramAST2, Synthesized, NewDistStateCache) :- | |
| 769 | synthesis_log(two_non_equivalent_solutions(Type,Solution,FurtherSolution)), | |
| 770 | synthesis_from_examples_aux3(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 771 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, M1, | |
| 772 | ParameterAmount, Solution, FurtherSolution, NewBehavioralConstraint, Dist, ProgramAST, ProgramAST2, | |
| 773 | Synthesized, NewDistStateCache). | |
| 774 | % or we choose the one with a lower term size since we know that both ASTs are equivalent | |
| 775 | synthesis_from_examples_aux2(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 776 | ValidInvariantsOrGuards, Type, PosInput, NegInput, BehavioralConstraint, LocationVars, M1, | |
| 777 | ParameterAmount, Solution, FurtherSolution, FurtherBehavioralConstraint, Distinguishing, ProgramAST, ProgramAST2, | |
| 778 | Synthesized, NewDistStateCache) :- | |
| 779 | Distinguishing \= solution(_), | |
| 780 | % No distinguishing input, no possible conclusion about examples. | |
| 781 | % Therefore we pass the "new" behavioral constraint and start synthesis again, we keep the | |
| 782 | % solution with the smaller term size. | |
| 783 | synthesis_log(distinguishing_error(Distinguishing,ProgramAST,ProgramAST2)), | |
| 784 | term_size(ProgramAST, TS1), | |
| 785 | term_size(ProgramAST2, TS2), | |
| 786 | ( TS1 < TS2 | |
| 787 | -> | |
| 788 | get_new_behavioral_constraint(ProgramAST2, LocationVars, FurtherSolution, BehavioralConstraint, NewBehavioralConstraint), | |
| 789 | Sol = Solution | |
| 790 | ; NewBehavioralConstraint = FurtherBehavioralConstraint, | |
| 791 | Sol = FurtherSolution | |
| 792 | ), | |
| 793 | synthesis_from_examples(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 794 | ValidInvariantsOrGuards, Type, PosInput, NegInput, NewBehavioralConstraint, LocationVars, M1, | |
| 795 | ParameterAmount, Sol, Synthesized, NewDistStateCache). | |
| 796 | ||
| 797 | % distinguishing transition (actions) | |
| 798 | synthesis_from_examples_aux3(Operation, DistTransitionCache, DistStateCache, Library, LibExpansion, CurrentVars, PreCondVars, | |
| 799 | ValidInvariantsOrGuards, action, Input, Output, _, LocationVars, M1, ParameterAmount, Solution, FurtherSolution, | |
| 800 | _, Distinguishing, ProgramAST, ProgramAST2, Synthesized, NewDistStateCache) :- | |
| 801 | get_input_output_nodes_from_bindings(Distinguishing, TempDistIn, TempDistOut), | |
| 802 | DistStateCache = (_,NegativeInputStates), | |
| 803 | maplist(get_varname_from_id_node, CurrentVars, CurrentVarNames), | |
| 804 | reduce_input_to_violating_vars(CurrentVarNames, TempDistIn, DistIn), | |
| 805 | reduce_input_to_violating_vars(CurrentVarNames, TempDistOut, DistOut), | |
| 806 | ( contains_equivalent_state(DistIn, NegativeInputStates, _) | |
| 807 | -> | |
| 808 | % synthesize guard for the action, the synthesis of the action is suspended for this time, | |
| 809 | % the distinguishing transition's input is already part of the negative input states provided by the user | |
| 810 | maplist(get_varname_from_id_node, PreCondVars, PreCondVarNames), | |
| 811 | DistStateCache = (PosDist,NegDist), | |
| 812 | append(PosDist, Input, PreInput), | |
| 813 | append(NegDist, [DistIn], PreOutput), | |
| 814 | synthesized_operation_uses_parameters([ProgramAST,ProgramAST2], OperationUsesParameters), | |
| 815 | % TODO: assert context? to decide whether guard needs op params | |
| 816 | prepare_synthesis_of_guard_by_examples(OperationUsesParameters, PreCondVarNames, (ValidInvariantsOrGuards,Operation), PreInput, PreOutput, PrePositive, PreNegative, | |
| 817 | PreLibrary, PreParameterAmount, PreM1, _, PreBehavioralConstraint, PreLocationVars, PreSolution), | |
| 818 | synthesis_from_examples(Operation, b(truth,pred,[]), (PrePositive,PreNegative), PreLibrary, 1, PreCondVars, PreCondVars, | |
| 819 | any, guard, PrePositive, PreNegative, PreBehavioralConstraint, PreLocationVars, PreM1, | |
| 820 | PreParameterAmount, PreSolution, Guards, PreDistStateCache), | |
| 821 | ( is_distinguishing(Guards) | |
| 822 | -> | |
| 823 | Synthesized = Guards, | |
| 824 | NewDistStateCache = PreDistStateCache, | |
| 825 | assert_synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, action, | |
| 826 | Input, Output, _), | |
| 827 | assert_synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, guard, | |
| 828 | PrePositive, PreNegative, _) | |
| 829 | ; NewInput = Input, | |
| 830 | NewOutput = Output, | |
| 831 | NewLibrary = Library, | |
| 832 | NewLibExpansion = LibExpansion, | |
| 833 | get_behavioral_constraint(NewLibrary, (Guards,Operation), NewInput, NewOutput, DistBehavioralConstraint, DistLocationVars), | |
| 834 | solve_using_selected_solver(DistBehavioralConstraint, DistSolution), | |
| 835 | synthesis_from_examples(Operation, DistTransitionCache, PreDistStateCache, Library, NewLibExpansion, CurrentVars, PreCondVars, | |
| 836 | Guards, action, NewInput, NewOutput, DistBehavioralConstraint, DistLocationVars, M1, ParameterAmount, | |
| 837 | DistSolution, Synthesized, NewDistStateCache) | |
| 838 | ) | |
| 839 | ; % the distinguishing transition's input state is not part of the examples, and thus, we ask the user to validate the transition | |
| 840 | Synthesized = transition(DistIn,DistOut), | |
| 841 | NewDistStateCache = DistStateCache, | |
| 842 | % we assert both temporary solutions, in case of synthesizing a guard afterwards we may need to compute operation parameters | |
| 843 | location_vars_to_program(Library, action, CurrentVars, LocationVars, M1, ParameterAmount, Solution, _, ProgramAST), | |
| 844 | location_vars_to_program(Library, action, CurrentVars, LocationVars, M1, ParameterAmount, FurtherSolution, _, ProgramAST2), | |
| 845 | assert_synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, action, | |
| 846 | Input, Output, temp([ProgramAST,ProgramAST2])) | |
| 847 | ). | |
| 848 | % distinguishing state (guards, invariants) | |
| 849 | synthesis_from_examples_aux3(_, DistTransitionCache, DistStateCache, _, _, CurrentVars, PreCondVars, ValidInvariantsOrGuards, Type, | |
| 850 | Input, Output, _, _, _, _, _, _, _, Distinguishing, _, _, state(DistIn), DistStateCache) :- | |
| 851 | Type \= action, | |
| 852 | % adjust_distinguishing_state_binding(CurrentVars,Distinguishing,CompleteDist) , | |
| 853 | get_input_nodes_from_bindings(Distinguishing, TempDistIn), | |
| 854 | b_get_machinevars_with_operation_params(MachineVars), | |
| 855 | maplist(get_varname_from_id_node, MachineVars, MachineVarNames), | |
| 856 | % filter machine vars from a distinguishing state which may refers to machine constants that we are not interested in | |
| 857 | findall(MachineVarValue, ( member(MachineVarValue, TempDistIn), | |
| 858 | get_varname_from_node_info(MachineVarValue, MachineVarName), | |
| 859 | member(MachineVarName, MachineVarNames) | |
| 860 | ), DistIn), | |
| 861 | assert_synthesis_context(DistTransitionCache, DistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, Type, | |
| 862 | Input, Output, _). | |
| 863 | %% | |
| 864 | use_operation_parameters_for_current_synthesis_type(_, action, yes) :- | |
| 865 | b_get_machine_set(_), | |
| 866 | !. % at least one machine set is given | |
| 867 | use_operation_parameters_for_current_synthesis_type(_, action, no). | |
| 868 | use_operation_parameters_for_current_synthesis_type(_, invariant, no) :- | |
| 869 | !. | |
| 870 | use_operation_parameters_for_current_synthesis_type(OperationName, guard, OperationUsesParameters) :- | |
| 871 | machine_operation_uses_parameters(OperationName, OperationUsesParameters). | |
| 872 | use_operation_parameters_for_current_synthesis_type(_, guard, OperationUsesParameters) :- | |
| 873 | on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, guard, _, _, temp(Actions)), fail), | |
| 874 | synthesized_operation_uses_parameters(Actions, OperationUsesParameters). | |
| 875 | use_operation_parameters_for_current_synthesis_type(_, guard, OperationUsesParameters) :- | |
| 876 | on_exception(error(existence_error(_,_),_), synthesis_context(_, _, _, _, _, guard, _, _, Action), fail), | |
| 877 | synthesized_operation_uses_parameters([Action], OperationUsesParameters). | |
| 878 | use_operation_parameters_for_current_synthesis_type(_, guard, no). | |
| 879 | ||
| 880 | % fail if the machine operation does not exist | |
| 881 | machine_operation_uses_parameters(OperationName, yes) :- | |
| 882 | b_get_machine_operation(OperationName, _, Params, _), | |
| 883 | Params \= [], | |
| 884 | !. | |
| 885 | machine_operation_uses_parameters(_, no). | |
| 886 | ||
| 887 | synthesized_operation_uses_parameters([], no). | |
| 888 | synthesized_operation_uses_parameters([ProgramAST|_], yes) :- | |
| 889 | find_typed_identifier_uses_with_info(ProgramAST, TypedIdentifiers), | |
| 890 | member(TypedIdentifier, TypedIdentifiers), | |
| 891 | get_texpr_info(TypedIdentifier, Info), | |
| 892 | ( member(synthesis(param_single,_), Info) | |
| 893 | ; member(synthesis(param_set,_), Info) | |
| 894 | ), | |
| 895 | !. | |
| 896 | synthesized_operation_uses_parameters([_|T], OperationUsesParameters) :- | |
| 897 | synthesized_operation_uses_parameters(T, OperationUsesParameters). | |
| 898 | ||
| 899 | assert_synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, Type, | |
| 900 | Input, Output, Action) :- | |
| 901 | retractall(synthesis_context(_, _, _, _, _, Type, _, _, _)), | |
| 902 | asserta(synthesis_context(DistTransitionCache, NewDistStateCache, CurrentVars, PreCondVars, ValidInvariantsOrGuards, Type, | |
| 903 | Input, Output, Action)). | |
| 904 | ||
| 905 | is_distinguishing(transition(_,_)). | |
| 906 | is_distinguishing(state(_)). | |
| 907 | ||
| 908 | find_further_solution(_, _, _, _, BehavioralConstraint, FurtherSolution, NewBehavioralConstraint) :- | |
| 909 | synthesis_mode(SynthesisMode), | |
| 910 | SynthesisMode == first_solution, | |
| 911 | !, | |
| 912 | FurtherSolution = none, | |
| 913 | NewBehavioralConstraint = BehavioralConstraint. | |
| 914 | find_further_solution(ProgramAST, LocationVars, _, solution(SolutionBindings), BehavioralConstraint, FurtherSolution, NewBehavioralConstraint) :- | |
| 915 | get_new_behavioral_constraint(ProgramAST, LocationVars, solution(SolutionBindings), BehavioralConstraint, NewBehavioralConstraint), | |
| 916 | solve_using_selected_solver(NewBehavioralConstraint, TempSolution), | |
| 917 | find_further_solution_aux(TempSolution, FurtherSolution). | |
| 918 | find_further_solution_aux(solution(S), Solution) :- | |
| 919 | !, | |
| 920 | Solution = solution(S). | |
| 921 | find_further_solution_aux(_, none). | |
| 922 | ||
| 923 | % Solve a constraint using the selected solver provided by solver/1. | |
| 924 | solve_using_selected_solver(Constraint, Solution) :- | |
| 925 | solver(z3), | |
| 926 | smt_solve_predicate(z3, Constraint, _, Solution). | |
| 927 | solve_using_selected_solver(Constraint, Solution) :- | |
| 928 | \+ solver(z3), | |
| 929 | solver_interface:solve_predicate(Constraint, _, Solution). | |
| 930 | ||
| 931 | % no distinguishing example | |
| 932 | retract_context_if_solution(Distinguishing) :- | |
| 933 | ( Distinguishing = distinguishing(none) | |
| 934 | ; Distinguishing = none | |
| 935 | ), | |
| 936 | !, | |
| 937 | retractall(synthesis_context(_, _, _, _, _, _, _, _, _)), | |
| 938 | retractall(additional_machinevars(_)), | |
| 939 | asserta(additional_machinevars([])). | |
| 940 | retract_context_if_solution(_). | |
| 941 | ||
| 942 | assert_library_configuration_from_ui(Library) :- | |
| 943 | % either a list of manually selected components from the user or a term default:LibExpansion | |
| 944 | ( is_list(Library) | |
| 945 | ; Library = default:_LibExpansion | |
| 946 | ), | |
| 947 | retractall(library_from_ui(_)), | |
| 948 | asserta(library_from_ui(Library)). | |
| 949 | % default with library expansion in prolog | |
| 950 | assert_library_configuration_from_ui(_). | |
| 951 | ||
| 952 | % Empty list of var names means we do not consider if-statements at all. | |
| 953 | assert_if_statement_var_names([]). | |
| 954 | assert_if_statement_var_names(ConsiderIfVarNames) :- | |
| 955 | asserta(consider_if_var_names(ConsiderIfVarNames)). | |
| 956 | ||
| 957 | pre_library_setup(UseOperationParameters, Type, _, Example, Library) :- | |
| 958 | % either a specific default library is asserted (like default:1) or an explicit set of library | |
| 959 | % components selected by the user | |
| 960 | library_from_ui(LibraryFromUi), | |
| 961 | !, | |
| 962 | get_asserted_if_statement_vars(ConsiderIfVarNames), | |
| 963 | get_asserted_constant_configuration(NotConsiderConstants), | |
| 964 | get_all_machine_sets(MachineSets), | |
| 965 | library_setup(UseOperationParameters, MachineSets, ConsiderIfVarNames, NotConsiderConstants, LibraryFromUi, Type, Example, Library). | |
| 966 | pre_library_setup(UseOperationParameters, Type, LibExpansion, Example, Library) :- | |
| 967 | get_asserted_if_statement_vars(ConsiderIfVarNames), | |
| 968 | get_asserted_constant_configuration(NotConsiderConstants), | |
| 969 | get_all_machine_sets(MachineSets), | |
| 970 | % default if no library is asserted, gets expanded in prolog using synthesis_callback/16 | |
| 971 | library_setup(UseOperationParameters, MachineSets, ConsiderIfVarNames, NotConsiderConstants, default:LibExpansion, Type, Example, Library). | |
| 972 | ||
| 973 | get_all_machine_sets(MachineSets) :- | |
| 974 | findall(MachineSet, b_get_machine_set(_, MachineSet), MachineSets). | |
| 975 | ||
| 976 | get_asserted_constant_configuration(NotConsiderConstants) :- | |
| 977 | not_consider_constants(NotConsiderConstants), | |
| 978 | !. | |
| 979 | get_asserted_constant_configuration(no). | |
| 980 | ||
| 981 | get_asserted_if_statement_vars(ConsiderIfVarNames) :- | |
| 982 | consider_if_var_names(ConsiderIfVarNames), | |
| 983 | !. | |
| 984 | get_asserted_if_statement_vars([]). | |
| 985 | ||
| 986 | reset_synthesis_context :- | |
| 987 | retractall(synthesis_context(_, _, _, _, _, _, _, _, _)), | |
| 988 | retractall(additional_machinevars(_)), | |
| 989 | asserta(additional_machinevars([])). | |
| 990 | ||
| 991 | cache_operation_tuple_to_quadruple((_,b(operation(b(identifier(op(OperationName)),_,_),Res,Par,Body),_,_)), (OperationName,Res,Par,Body)). | |
| 992 | ||
| 993 | get_distinguishing_state_cache_from_operation_tuples(Operations, OperationName, (CachePos,CacheNeg), Operation) :- | |
| 994 | member(((CachePos,CacheNeg),Operation), Operations), | |
| 995 | Operation = b(operation(b(identifier(op(OperationName)),_,_),_,_,_),_,_). |