1 :- module(synthesis_util, [get_distinguishing_state_or_trans/8,
2 get_valid_transitions_for_operation/5,
3 get_invariant_violating_transition/6,
4 get_valid_and_invalid_equality_predicates_for_operation/6,
5 get_distinct_states/5,
6 get_valid_and_invalid_equality_predicates_for_invariants/4,
7 get_violated_and_valid_machine_invariants/4,
8 get_invariant_violating_example/4,
9 get_involved_variables/4,
10 get_invariant_violating_vars_from_examples/3,
11 get_single_constant_or_set_operator_id/3,
12 get_input_output_nodes_from_bindings/3,
13 get_output_nodes_from_bindings/2,
14 get_location_var_node_by_info_term/3,
15 get_location_var_node_by_name/3,
16 get_var_node_by_info_term/3,
17 get_operation_params_from_ids/2,
18 set_operation_params_domain/2,
19 get_guard_list_from_operation/2,
20 get_current_vars_from_example/2,
21 get_input_nodes_from_bindings/2,
22 get_varname_from_node_info/2,
23 get_varname_from_id_node/2,
24 get_valid_states/3,
25 get_machinevars_by_name/2,
26 get_precondition_from_operation_body/2,
27 get_binding_for_name_or_value/3,
28 get_valid_inputs_for_operation/3,
29 b_get_typing_predicate_for_vars/2,
30 b_get_typed_invariant_from_machine/1,
31 b_compute_expression_nowf_no_bindings/2,
32 expand_state_cache_if_guard_and_solution/6,
33 add_distinguishing_states_from_cache/6,
34 conjunct_previous_invariant_or_guard_if_necessary/4,
35 check_transitions_against_machine_operations/4,
36 check_transition_against_machine_operations/5,
37 check_negative_inputs_against_operation_precondition/2,
38 replace_preds_by_subst_if_neccessary/3,
39 replace_precondition_of_operation/3,
40 contains_equivalent_state/3,
41 find_typed_identifier_uses_with_info/2,
42 delete_numbers_from_atom/2,
43 create_equality_nodes_from_example/2,
44 adapt_machine_code_for_operations/2,
45 % b_synthesis
46 b_get_machinevars_with_operation_params/1,
47 remove_prime/2,
48 parallel_to_conjunction/2,
49 prime_or_unprime_variables_in_ast/4,
50 parse_and_typecheck_value/2,
51 keep_asserted_initial_examples/6,
52 prepare_solution/6,
53 finalize_synthesized_action/3,
54 split_input_output_tuples/3,
55 prepare_synthesized_guards_for_action/2,
56 %
57 mark_examples_as_initial/4,
58 reduce_input_to_violating_vars/3,
59 is_ast/1,
60 zip/3]).
61
62 :- use_module(synthesis(logging)).
63
64 :- use_module(probsrc(bsyntaxtree)).
65 :- use_module(probsrc(error_manager), [add_error/3]).
66 :- use_module(probsrc(b_interpreter), [b_test_boolean_expression_wf/3,b_compute_expression_nowf/4]).
67 :- use_module(probsrc(solver_interface), [solve_predicate/3]).
68 :- use_module(smt_solvers_interface(smt_solvers_interface), [smt_solve_predicate/4]).
69 :- use_module(probsrc(bmachine_eventb), [prime_variable/2,is_primed_id/1]).
70 :- use_module(probsrc(bmachine)).
71 :- use_module(probsrc(before_after_predicates), [before_after_predicate_with_equalities/3]).
72 :- use_module(probsrc(btypechecker), [btype/7]).
73 :- use_module(probsrc(parsercall), [parse/3]).
74 :- use_module(probsrc(translate), [translate_bexpression/2,
75 translate_bexpression_to_codes/2,
76 translate_machine/3,
77 generate_typing_predicates/2]).
78
79 :- use_module(library(lists)).
80 :- use_module(library(sets), [subtract/3,intersection/3]).
81
82 :- use_module(extension('plspec/plspec/plspec_core')).
83
84 b_get_machinevars_with_operation_params(MachineVarsWithParams) :-
85 b_get_machine_variables(MachineVars),
86 b_get_machinevars_with_operation_params_aux(MachineVars, MachineVarsWithParams).
87 b_get_machinevars_with_operation_params_aux(MachineVars, MachineVarsWithParams) :-
88 % TODO: fix this spider warning, do not access dynamic additional_machinevars/1 in this module
89 on_exception(error(existence_error(_,_),_), b_synthesis:additional_machinevars(AdditionalMachineVars), fail),
90 !,
91 append(MachineVars, AdditionalMachineVars, MachineVarsWithParams).
92 b_get_machinevars_with_operation_params_aux(MachineVars, MachineVars).
93
94 parse_and_typecheck_value(Value, ValueAst) :-
95 atom_codes(Value, L),
96 parse(expression, L, Parsed),
97 btype(bsynthesis, Parsed, openenv(_,env_empty), _, TempAst, [], _),
98 set_type_if_necessary(TempAst, ValueAst).
99
100 get_machinevars_by_name(VarNames, CurrentVars) :-
101 b_get_machinevars_with_operation_params(MachineVarsWithParams),
102 get_machinevars_by_name_aux(VarNames, MachineVarsWithParams, [], CurrentVars).
103 get_machinevars_by_name_aux([], _, Acc, Acc).
104 get_machinevars_by_name_aux([VarName|T], MachineVars, Acc, CurrentVars) :-
105 member(b(identifier(VarName),Type,Info), MachineVars),
106 !,
107 get_machinevars_by_name_aux(T, MachineVars, [b(identifier(VarName),Type,Info)|Acc], CurrentVars).
108 get_machinevars_by_name_aux([VarName|_], _, _, _) :-
109 add_error(get_machinevars_by_name, 'This is not a machine variable: ',[VarName]),
110 !,
111 fail.
112
113 % True if the given set of states contains an equivalent state.
114 contains_equivalent_state(State, States, EquivalentState) :-
115 length(State, VarAmount),
116 contains_equivalent_state(VarAmount, State, States, EquivalentState).
117 contains_equivalent_state(_, _, [], _) :-
118 !,
119 fail.
120 contains_equivalent_state(VarAmount, State, [ExampleState|_], EquivalentState) :-
121 length(ExampleState, ExampleVarAmount),
122 VarAmount = ExampleVarAmount,
123 create_equality_nodes_from_example(State, StateEqualityNodes),
124 create_equality_nodes_from_example(ExampleState, ExampleStateEqualityNodes),
125 get_distinct_independent_types_constraint_for_enums(DistinctEnumSetsConstraint),
126 ( DistinctEnumSetsConstraint == b(truth,pred,[])
127 ->
128 append([StateEqualityNodes,ExampleStateEqualityNodes], EqualityNodes)
129 ; append([DistinctEnumSetsConstraint,StateEqualityNodes,ExampleStateEqualityNodes], EqualityNodes)
130 ),
131 conjunct_predicates(EqualityNodes, Equality),
132 solver_interface:solve_predicate(Equality, _, Solution),
133 Solution = solution(_),
134 !,
135 EquivalentState = ExampleState.
136 contains_equivalent_state(VarAmount, State, [_|T], EquivalentState) :-
137 contains_equivalent_state(VarAmount, State, T, EquivalentState).
138
139 get_distinct_independent_types_constraint_for_enums(Constraint) :-
140 findall(MachineSetName, b_get_machine_set(MachineSetName), MachineSetNames),
141 get_distinct_independent_types_constraint_for_enums(MachineSetNames, [], ConstraintList),
142 conjunct_predicates(ConstraintList, Constraint).
143
144 get_distinct_independent_types_constraint_for_enums([], Acc, Acc).
145 get_distinct_independent_types_constraint_for_enums([MachineSetName|T], Acc, ConstraintList) :-
146 b_get_named_machine_set(MachineSetName, SetValues),
147 findall(SetValueNode, ( member(SetValue, SetValues),
148 SetValueNode = b(identifier(SetValue),global(MachineSetName),[])
149 ), SetValueNodes),
150 findall(Inequality, ( member(Node1, SetValueNodes),
151 member(Node2, SetValueNodes),
152 Node1 \= Node2,
153 Inequality = b(not_equal(Node1,Node2),pred,[])
154 ), Inequalities),
155 get_distinct_independent_types_constraint_for_enums(T, [Inequalities|Acc], ConstraintList).
156
157 % seq(_), string_set, integer_set, bool_set,..
158 % Also needed in location_vars_to_program.
159 get_single_constant_or_set_operator_id(seq-Type, Out, b(seq(Set),set(seq(NodeType)),[])) :-
160 get_single_constant_or_set_operator_id(Type, _, Set),
161 Set = b(_,TInnerType,_),
162 TInnerType =.. [_|InnerType],
163 NodeType =.. InnerType,
164 unique_typed_id("o", set(seq(NodeType)), TempOut),
165 % we add the internal type of infinite set constants here
166 % so we are able to call this predicate when converting location variables to ASTs later on
167 add_texpr_infos(TempOut, [synthesis(type,seq-Type)], Out).
168 get_single_constant_or_set_operator_id(constant-Type, Out, ConstantNode) :-
169 get_constant_node_or_id(constant-Type, ConstantNode),
170 unique_typed_id("o", Type, TempOut),
171 add_texpr_infos(TempOut, [synthesis(type,Type)], Out).
172
173 get_constant_node_or_id(string_set, b(string_set,set(string),[])).
174 get_constant_node_or_id(bool_set, b(bool_set,set(boolean),[])).
175 get_constant_node_or_id(integer_set, b(integer_set('INTEGER'),set(integer),[])).
176 get_constant_node_or_id(integer_set_min_max, b(integer_set('INT'),set(integer),[])).
177 get_constant_node_or_id(natural1, b(integer_set('NATURAL1'),set(integer),[])).
178 get_constant_node_or_id(natural, b(integer_set('NATURAL'),set(integer),[])).
179 get_constant_node_or_id(implementable_natural1, b(integer_set('NAT1'),set(integer),[])).
180 get_constant_node_or_id(implementable_natural, b(integer_set('NAT'),set(integer),[])).
181 get_constant_node_or_id(constant-Type, Constant) :-
182 unique_typed_id("constant", Type, TempConstant),
183 add_texpr_infos(TempConstant, [synthesis(enumerated_constant),synthesis(type,Type)], Constant).
184
185 add_distinguishing_states_from_cache(action, _, PosInput, NegInput, PosInput, NegInput) :-
186 !.
187 add_distinguishing_states_from_cache(_, (DistIn,DistOut), PosInput, NegInput, NewPosInput, NewNegInput) :-
188 append(DistIn, PosInput, TempPosInput),
189 append(DistOut, NegInput, TempNegInput),
190 remove_dups(TempPosInput, NewPosInput),
191 remove_dups(TempNegInput, NewNegInput).
192
193 b_test_boolean_expression_wf_no_bindings(BooleanExpr, Result) :-
194 find_identifier_uses(BooleanExpr, [], UsedIdNames),
195 findall(bind(UsedIdName,_), member(UsedIdName, UsedIdNames), Bindings),
196 b_test_boolean_expression_wf(BooleanExpr, Bindings, Result).
197
198 b_compute_expression_nowf_no_bindings(Expression, Result) :-
199 find_identifier_uses(Expression, [], UsedIdNames),
200 findall(bind(UsedIdName,_), member(UsedIdName, UsedIdNames), Bindings),
201 b_compute_expression_nowf(Expression, [], Bindings, Result).
202
203 % If the domain is enumerated from 1 to n we suppose set(couple(integer,_)) is a sequence.
204 is_seq(b(Node,Type,Info)) :-
205 ( Type = set(couple(integer,_))
206 ; Type = seq(_)
207 ),
208 b_test_boolean_expression_wf_no_bindings(b(equal(b(domain(b(Node,Type,Info)),set(integer),[]),
209 b(interval(b(integer(1),integer,[]),
210 b(size(b(Node,Type,Info)),integer,[])),set(integer),[])),pred,[]), []).
211
212 get_distinguishing_state_or_trans(DistTransitionCache, CurrentVars, Type, ValidInvariantsOrGuards, AST1,
213 AST2, NewDistTransitionCache, Distinguishing) :-
214 % add typing of machine variables to the invariant for consistency with AtelierB and to find a solution referring to
215 % all machine variables
216 b_get_typed_invariant_from_machine(TypedInvariant),
217 % add WD-constraints for sequences
218 find_typed_identifier_uses(AST1, AST1Nodes),
219 find_typed_identifier_uses(AST2, AST2Nodes),
220 findall(Seq, ( member(Seq, AST1Nodes),
221 is_seq(Seq)
222 ), Seq1),
223 findall(Seq, ( member(Seq, AST2Nodes),
224 is_seq(Seq)
225 ), Seq2),
226 append(Seq1, Seq2, TSequences),
227 remove_dups(TSequences, Sequences),
228 maplist(sequence_well_definedness_constraint, Sequences, SeqConstraintList),
229 conjunct_predicates(SeqConstraintList, SeqConstraints),
230 get_distinct_independent_types_constraint_for_enums(DistinctEnumSetsConstraint),
231 preferences:set_preference(randomise_enumeration_order, true),
232 get_distinguishing_state_or_trans_aux(DistinctEnumSetsConstraint, DistTransitionCache, Type, ValidInvariantsOrGuards,
233 b(conjunct(SeqConstraints,b(conjunct(b(negation(
234 b(equivalence(AST1,AST2),pred,[])),pred,[]),TypedInvariant),pred,[])),pred,[]), Distinguishing),
235 expand_transition_cache_if_solution(Type, DistTransitionCache, CurrentVars, Distinguishing, NewDistTransitionCache),
236 synthesis_log(distinguishing_transition_cache_changed(DistTransitionCache,NewDistTransitionCache)).
237 % When synthesizing an action only search for a distinguishing transition that doesn't violate the
238 % so far synthesized guard (in case there is one).
239 % Furthermore, we exclude already visited distinguishing transitions using the cache in order to
240 % prevent cycles when a distinguishing transition's output is changed by the user
241 % (otherwise we would find the same transition over and over again because the one with an adapted
242 % output is added to the examples).
243 get_distinguishing_state_or_trans_aux(DistinctEnumSetsConstraint, DistTransitionCache, action, ValidInvariantsOrGuards, Constraint, Distinguishing) :-
244 ValidInvariantsOrGuards \= any,
245 ValidInvariantsOrGuards \= none,
246 !,
247 DistConstraint = b(conjunct(DistinctEnumSetsConstraint,b(conjunct(b(conjunct(Constraint,ValidInvariantsOrGuards),pred,[]),DistTransitionCache),pred,[])),pred,[]),
248 synthesis_log(distinguishing_constraint(action,DistConstraint)),
249 solve_distinguishing_constraint_with_fallback(DistConstraint, TDistinguishing),
250 get_solution_or_none(TDistinguishing, Distinguishing).
251 get_distinguishing_state_or_trans_aux(DistinctEnumSetsConstraint, DistTransitionCache, action, _, Constraint, Distinguishing) :-
252 !,
253 DistConstraint = b(conjunct(DistinctEnumSetsConstraint,b(conjunct(Constraint,DistTransitionCache),pred,[])),pred,[]),
254 synthesis_log(distinguishing_constraint(action,Constraint)),
255 solve_distinguishing_constraint_with_fallback(DistConstraint, TDistinguishing),
256 get_solution_or_none(TDistinguishing, Distinguishing).
257 % DistTransitionCache is empty when synthesizing guard/invariant
258 get_distinguishing_state_or_trans_aux(DistinctEnumSetsConstraint, _, Type, _, Constraint, Distinguishing) :-
259 synthesis_log(distinguishing_constraint(Type,Constraint)),
260 solve_distinguishing_constraint_with_fallback(b(conjunct(DistinctEnumSetsConstraint,Constraint),pred,[]), TDistinguishing),
261 get_solution_or_none(TDistinguishing, Distinguishing).
262
263 % Solving the distinguishing constraint maybe causes an integer overflow due to infinite domains which
264 % possibly ends in not finding any solution, i.e., neither true nor false.
265 % Therefore, we try different solvers if no solution can be found.
266 % Of course, we do not want to enumerate infinite domains, but there is no reasonable domain restriction
267 % if for instance the invariant defines a variable to be an element of INTEGER without an upper bound.
268 % The distinguishing constraint is of the form "not(P1 <=> P2) & I", whereat P1,P2 are two synthesized
269 % programs and I is the current machine invariant. When synthesizing a substitution with already known
270 % guards G the constraint results to "not(P1 <=> P2) & I & G".
271 solve_distinguishing_constraint_with_fallback(DistConstraint, Solution) :-
272 solve_predicate(DistConstraint, _, ProBSolution),
273 % ProB either found a solution or a contradiction
274 synthesis_log(solve_distinguishing_constraint(DistConstraint,'ProB')),
275 ProBSolution \= no_solution_found(_),
276 !,
277 Solution = ProBSolution.
278 solve_distinguishing_constraint_with_fallback(DistConstraint, Z3Solution) :-
279 % ProB could not make a decision and answered no_solution_found/1, then we ask z3
280 synthesis_log(solve_distinguishing_constraint(DistConstraint,'Z3')),
281 smt_solve_predicate(z3, DistConstraint, _, Z3Solution).
282 % Solution \= no_solution_found(_) , ! , Solution = Z3Solution.
283 %%%%% Maybe too much overhead to ask a third solver for the distinguishing constraint since two solvers were already not able to find a solution.
284 % solve_distinguishing_constraint_with_fallback(DistConstraint,ProBZ3Solution) :-
285 % synthesis_log(solve_distinguishing_constraint(DistConstraint,'Combined ProB and Z3')) ,
286 % preferences:set_preference(smt_supported_interpreter,true) ,
287 % Z3 also did not find a solution, then we ask ProB/Z3 combined as a last try
288 % solve_predicate(DistConstraint,_,ProBZ3Solution) ,
289 % preferences:set_preference(smt_supported_interpreter,false).
290 get_solution_or_none(solution(Solution), solution(Solution)).
291 get_solution_or_none(Solution, none) :-
292 Solution \= solution(_).
293
294 b_get_typed_invariant_from_machine(TypedInvariant) :-
295 b_get_typing_predicate(TypingPredicate),
296 b_get_invariant_from_machine(Invariant),
297 conjunct_predicates([TypingPredicate,Invariant], TypedInvariant).
298
299 % Return typing predicate for the machine variables.
300 b_get_typing_predicate(TypingPredicate) :-
301 b_get_machinevars_with_operation_params(MachineVars),
302 findall(NonSeq, ( member(NonSeq, MachineVars),
303 NonSeq \= b(_,seq(_),_)
304 ), NonSeqMachineVars),
305 b_get_typing_predicate_for_vars(NonSeqMachineVars, TypingPredicate).
306
307 % Return typing predicate for specific machine variables.
308 b_get_typing_predicate_for_vars(CurrentVars, TypingPredicate) :-
309 generate_typing_predicates(CurrentVars, TypingPredicatesList),
310 conjunct_predicates(TypingPredicatesList, TypingPredicate).
311
312 :- spec_pre(expand_transition_cache_if_solution/5, [atom,ast,list(ast),one_of([atom,solution_compound]),var]).
313 :- spec_invariant(expand_transition_cache_if_solution/5, [atom,ast,list(ast),one_of([atom,solution_compound]),ast]).
314 :- spec_post(expand_transition_cache_if_solution/5, [atom,ast,list(ast),one_of([atom,solution_compound]),var],
315 [atom,ast,list(ast),one_of([atom,solution_compound]),ast]).
316 expand_transition_cache_if_solution(action, DistTransitionCache, CurrentVars, solution(Solution), NewDistTransitionCache) :-
317 !,
318 get_input_output_nodes_from_bindings(Solution, Input, Output),
319 exclude_transition_constraint(Input, Output, CurrentVars, Exclusion),
320 NewDistTransitionCache = b(conjunct(DistTransitionCache,Exclusion),pred,[]).
321 expand_transition_cache_if_solution(action, DistTransitionCache, _, _, DistTransitionCache).
322 expand_transition_cache_if_solution(Type, DistTransitionCache, _, _, DistTransitionCache) :-
323 Type \= action.
324
325 :- spec_pre(expand_state_cache_if_guard_and_solution/6, [atom,solution_compound,pair(ast_examples,ast_examples),
326 ast_examples,ast_examples,var]).
327 :- spec_invariant(expand_state_cache_if_guard_and_solution/6, [atom,solution_compound,pair(ast_examples,ast_examples),
328 ast_examples,ast_examples,pair(ast_examples,ast_examples)]).
329 :- spec_post(expand_state_cache_if_guard_and_solution/6, [atom,solution_compound,pair(ast_examples,ast_examples),
330 ast_examples,ast_examples,var],
331 [atom,solution_compound,pair(ast_examples,ast_examples),
332 ast_examples,ast_examples,pair(ast_examples,ast_examples)]).
333 expand_state_cache_if_guard_and_solution(guard, solution(_), (UsedPositives,UsedNegatives), PosInput,
334 NegInput, (PositiveStates,NegativeStates)) :-
335 append(UsedPositives, PosInput, TPositiveStates),
336 append(UsedNegatives, NegInput, TNegativeStates),
337 remove_dups(TPositiveStates, PositiveStates),
338 remove_dups(TNegativeStates, NegativeStates).
339 expand_state_cache_if_guard_and_solution(_, _, DistStateCache, _, _, DistStateCache).
340
341 :- spec_pre(exclude_transition_constraint/4, [list(ast),list(ast),list(ast),var]).
342 :- spec_invariant(exclude_transition_constraint/4, [list(ast),list(ast),list(ast),ast]).
343 :- spec_post(exclude_transition_constraint/4, [list(ast),list(ast),list(ast),var],
344 [list(ast),list(ast),list(ast),ast]).
345 exclude_transition_constraint(Input, Output, CurrentVars, b(negation(EqualityConjunction),pred,[])) :-
346 b_get_machinevars_with_operation_params(MachineVars),
347 maplist(get_varname_from_id_node, CurrentVars, CurrentIDs),
348 create_equality_nodes_from_examples(CurrentIDs, Input, Output, MachineVars, EqualityNodes),
349 conjunct_predicates(EqualityNodes, EqualityConjunction).
350
351 sequence_well_definedness_constraint(SeqIDNode, WDConstraint) :-
352 % well-defined sequence: domain enumerated from 1..n
353 WDConstraint = b(equal(b(domain(SeqIDNode),set(integer),[]),
354 b(interval(b(integer(1),integer,[]),b(size(SeqIDNode),integer,[])),set(integer),[])),pred,[]).
355
356 is_ast(b(_,_,_)).
357
358 delete_numbers_from_atom(NumberAtom, Atom) :-
359 atom_codes(NumberAtom, Codes),
360 delete_numbers_from_codelist(Codes, NewCodes),
361 atom_codes(Atom, NewCodes).
362 delete_numbers_from_codelist([], []).
363 delete_numbers_from_codelist([Code|R], [Code|NR]) :-
364 ( Code > 57
365 ; Code < 48
366 ),
367 !,
368 delete_numbers_from_codelist(R, NR).
369 delete_numbers_from_codelist([_|R], NR) :-
370 delete_numbers_from_codelist(R, NR).
371
372 % Returns a list of all guards or 'any' if none is given.
373 :- spec_pre(get_guard_list_from_operation/2, [atom,var]).
374 :- spec_invariant(get_guard_list_from_operation/2, [atom,one_of([ast,atom])]).
375 :- spec_post(get_guard_list_from_operation/2, [atom,var], [atom,one_of([ast,atom])]).
376 get_guard_list_from_operation(Operation, ListOfGuards) :-
377 b_get_machine_operation(Operation, _, OperationParameters, OpBody),
378 get_guard_list_from_operation_aux(Operation, OpBody, GuardList),
379 recreate_guards_for_operation_parameters(OperationParameters, OperationParameterGuards),
380 append(GuardList, OperationParameterGuards, ListOfGuards).
381 % No given guards.
382 get_guard_list_from_operation(_, any).
383
384 get_guard_list_from_operation_aux(Operation, OpBody, GuardList) :-
385 get_guard_list_from_operation_aux2(Operation, OpBody, Guard),
386 conjunction_to_list(Guard, GuardList).
387 get_guard_list_from_operation_aux(_, _, []).
388
389 get_guard_list_from_operation_aux2(_, b(precondition(Guard,_),_,_), Guard).
390 get_guard_list_from_operation_aux2(Operation, b(rlevent(Operation,_,_,_,Guard,_,_,_,_,_,_),_,_), Guard).
391 get_guard_list_from_operation_aux2(_, b(any(_,Guard,_),subst,_), Guard).
392
393 % ProB removes typing guards for operations parameters which we need for synthesis to create constants for operation parameters
394 recreate_guards_for_operation_parameters(OperationParameters, OperationParameterGuards) :-
395 findall(SetAst, b_get_machine_set(_, SetAst), IndependentTypes),
396 recreate_guards_for_operation_parameters(OperationParameters, IndependentTypes, [], OperationParameterGuards).
397 recreate_guards_for_operation_parameters([], _, Acc, Acc).
398 recreate_guards_for_operation_parameters([OperationParameter|T], IndependentTypes, Acc, OperationParameterGuards) :-
399 get_texpr_type(OperationParameter, Type),
400 member(b(SetName,set(Type),Info), IndependentTypes),
401 Membership = b(member(OperationParameter,b(SetName,set(Type),Info)),pred,[]),
402 recreate_guards_for_operation_parameters(T, IndependentTypes, [Membership|Acc], OperationParameterGuards).
403
404 :- spec_pre(conjunct_previous_invariant_or_guard_if_necessary/4, [atom,one_of([atom,ast,list(ast)]),ast,var]).
405 :- spec_invariant(conjunct_previous_invariant_or_guard_if_necessary/4, [atom,one_of([atom,ast,list(ast)]),ast,ast]).
406 :- spec_post(conjunct_previous_invariant_or_guard_if_necessary/4, [atom,one_of([atom,ast,list(ast)]),ast,var],
407 [atom,one_of([atom,ast,list(ast)]),ast,ast]).
408 conjunct_previous_invariant_or_guard_if_necessary(invariant, ValidInvariants, ProgramAST, SolutionAST) :-
409 !,
410 % mark synthesized invariants in the info to be able to split synthesized invariants from those that have already been valid beforehand
411 % we want to avoid redundancy when generating typing invariants later on
412 conjunction_to_list(ProgramAST, ProgramASTList),
413 findall(MarkedConjunct, ( member(Conjunct, ProgramASTList),
414 add_texpr_infos(Conjunct, [synthesized_code], MarkedConjunct)
415 ), MarkedConjunctList),
416 conjunct_predicates(MarkedConjunctList, MarkedProgramAst),
417 append(ValidInvariants, [MarkedProgramAst], InvariantsList), % ValidInvariants prior to synthesized ones since they may contain typing invariants
418 conjunct_predicates(InvariantsList, SolutionAST).
419 conjunct_previous_invariant_or_guard_if_necessary(guard, Guards, ProgramAST, SolutionAST) :-
420 Guards \= any,
421 !,
422 % search for valid guards that are already given by the machine ( NewPreCond => OldPreCond )
423 find_typed_identifier_uses(ProgramAST, [], ProgIDs),
424 findall(Pre, ( member(Pre, Guards),
425 find_typed_identifier_uses(Pre, PreIDs),
426 append(ProgIDs, PreIDs, TIDs),
427 remove_dups(TIDs, IDs),
428 b_test_boolean_expression_wf_no_bindings(b(forall(IDs,ProgramAST,Pre),pred,[used_ids([])]), [])
429 ), InvalidPreConds),
430 sets:subtract(Guards, InvalidPreConds, ValidPreConds),
431 append(ValidPreConds, [ProgramAST], PreCondsList), % ValidPreConds prior to synthesized ones since they may contain predicates setting the type of operation parameters
432 conjunct_predicates(PreCondsList, SolutionAST).
433 conjunct_previous_invariant_or_guard_if_necessary(action, Guard, ProgramAST, SolutionAST) :-
434 \+ member(Guard, [any,none]),
435 !,
436 SolutionAST = b(precondition(Guard,ProgramAST),subst,[]).
437 conjunct_previous_invariant_or_guard_if_necessary(_, _, ProgramAST, ProgramAST).
438
439 % Replace equal by assign_single_id and conjunctions by parallel substitution.
440 :- spec_pre(replace_preds_by_subst_if_neccessary/3, [atom,ast,var]).
441 :- spec_invariant(replace_preds_by_subst_if_neccessary/3, [atom,ast,ast]).
442 :- spec_post(replace_preds_by_subst_if_neccessary/3, [atom,ast,var], [atom,ast,ast]).
443 replace_preds_by_subst_if_neccessary(action, TSolutionAST, SolutionAST) :-
444 conjunction_to_list(TSolutionAST, EqualityList),
445 maplist(equality_to_assignment, EqualityList, AssignmentList),
446 SolutionAST = b(parallel(AssignmentList),subst,[]).
447 replace_preds_by_subst_if_neccessary(_, SolutionAST, SolutionAST).
448
449 equality_to_assignment(b(equal(Primed,Assignment),pred,Info), b(assign_single_id(Primed,Assignment),subst,Info)).
450
451 % Replace parallel substitution by conjunction predicates and assignments by equalities.
452 :- spec_pre(parallel_to_conjunction/2, [ast,var]).
453 :- spec_invariant(parallel_to_conjunction/2, [ast,ast]).
454 :- spec_post(parallel_to_conjunction/2, [ast,var], [ast,ast]).
455 parallel_to_conjunction(b(Node,Type,Info), b(Node,Type,Info)) :-
456 ground(Node),
457 Type \= subst.
458 parallel_to_conjunction(b(Node,subst,_), Conjunction) :-
459 ground(Node),
460 Node =.. [parallel,Assignments],
461 findall(Equality, ( member(Assignment, Assignments),
462 equality_to_assignment(Equality, Assignment)
463 ), EqualityNodes),
464 conjunct_predicates(EqualityNodes, Conjunction).
465 %%
466 % Get the variables involved in an invariant violation if currently all machine variables are considered,
467 % i.e., they have not been reduced by now.
468 get_involved_variables(_, PosInput, _, VarNames) :-
469 examples_already_reduced(PosInput),
470 !,
471 PosInput = [Example|_],
472 % the examples already have been reduced by the user
473 maplist(get_varname_from_node_info, Example, VarNames).
474 get_involved_variables(Guards, PosInput, NegInput, VarNames) :-
475 get_involved_variables_aux(Guards, PosInput, NegInput, TempVarNames),
476 remove_dups(TempVarNames, VarNames),
477 % only consider machine variables
478 % b_get_machinevars_with_operation_params(MachineVars) ,
479 % maplist(get_varname_from_id_node,MachineVars,MachineVarNames) ,
480 % sets:intersection(VarNamesNoDups,MachineVarNames,VarNames) ,
481 synthesis_log(involved_variables(VarNames)).
482 % check the invariants first
483 get_involved_variables_aux(_, _, NegInput, VarNames) :-
484 get_violated_and_valid_machine_invariants(NegInput, _, ViolatingVars, _),
485 ViolatingVars \= [],
486 !,
487 findall(Name, member(b(identifier(Name),_,_), ViolatingVars), VarNames).
488 % if no invariant violating vars, check the guards
489 get_involved_variables_aux(Guards, PosInput, NegInput, VarNames) :-
490 Guards \= [],
491 append(PosInput, NegInput, Input),
492 check_states_on_guards(Input, Guards, ViolatedGuards),
493 findall(UsedIDs, ( member(Guard, ViolatedGuards),
494 find_identifier_uses(Guard, [], UsedIDs)
495 ), NestedList),
496 append(NestedList, UsedIDs),
497 UsedIDs \= [],
498 remove_dups(UsedIDs, VarNames).
499 % otherwise, consider all variables used in the examples
500 get_involved_variables_aux(_, PosInput, _, VarNames) :-
501 PosInput = [Example|_],
502 maplist(get_varname_from_node_info, Example, VarNames).
503
504 check_states_on_guards(State, Guards, ViolatedGuards) :-
505 maplist(create_equality_nodes_from_example, State, StateEqualities),
506 findall(Guard, ( member(Guard, Guards),
507 check_states_on_guard(StateEqualities, Guard)
508 ), ValidGuards),
509 subtract(Guards, ValidGuards, ViolatedGuards).
510 check_states_on_guard([], _).
511 check_states_on_guard([StateEquality|T], Guard) :-
512 conjunct_predicates([Guard|StateEquality], CheckGuard),
513 b_test_boolean_expression_wf_no_bindings(CheckGuard, []),
514 !,
515 check_states_on_guard(T, Guard).
516
517 :- spec_pre(get_violated_and_valid_machine_invariants/4, [list(ast),var,var,var]).
518 :- spec_invariant(get_violated_and_valid_machine_invariants/4, [list(ast),list(ast),list(ast),list(ast)]).
519 :- spec_post(get_violated_and_valid_machine_invariants/4, [list(ast),var,var,var],
520 [list(ast),list(ast),list(ast),list(ast)]).
521 get_violated_and_valid_machine_invariants(Input, ViolatedInvariants, ViolatingVars, ValidInvariants) :-
522 % according to specific operation
523 get_invariants_for_current_vars(Input, _, InvariantList),
524 % consider the machine properties in case an invariant refers to machine constants
525 b_get_properties_from_machine(MachineProperties),
526 maplist(get_violated_and_valid_machine_invariants_aux(MachineProperties, InvariantList), Input, TempViolatedInvariants),
527 tools:flatten(TempViolatedInvariants, TempViolatedInvariants2),
528 remove_dups(TempViolatedInvariants2, ViolatedInvariants),
529 conjunct_predicates(ViolatedInvariants, TempPred),
530 find_typed_identifier_uses_with_info(TempPred, TempViolatingVars),
531 b_get_machinevars_with_operation_params(MachineVars),
532 % filter only machine variables from TempViolatingVars and do not consider machine constants that may occur within an invariant
533 % but do not define the machine state which only refers to machine variables
534 findall(MachineVar, ( member(MachineVar, TempViolatingVars),
535 get_varname_from_id_node(MachineVar, MachineVarName),
536 member(b(identifier(MachineVarName),_,_), MachineVars)
537 ), ViolatingVars),
538 % all other machine variables are valid considering the current machine variables
539 b_get_invariant_from_machine(MachineInvariant),
540 conjunction_to_list(MachineInvariant, MachineInvariantList),
541 subtract(MachineInvariantList, ViolatedInvariants, ValidInvariants).
542
543 get_violated_and_valid_machine_invariants_aux(MachineProperties, InvariantList, Input, ViolatedInvariants) :-
544 create_equality_nodes_from_example(Input, EqualityNodes),
545 conjunct_predicates([MachineProperties|EqualityNodes], EqualityPredWithMachineProperties),
546 get_violated_and_valid_machine_invariants_aux2(EqualityPredWithMachineProperties, InvariantList, ViolatedInvariants).
547
548 get_violated_and_valid_machine_invariants_aux2(_, [], []).
549 get_violated_and_valid_machine_invariants_aux2(EqualityNodes, [SingleInv|T], [SingleInv|NT]) :-
550 conjunct_predicates([EqualityNodes,SingleInv], InvPred),
551 \+ b_test_boolean_expression_wf_no_bindings(InvPred, []),
552 !,
553 get_violated_and_valid_machine_invariants_aux2(EqualityNodes, T, NT).
554 get_violated_and_valid_machine_invariants_aux2(EqualityNodes, [_|T], NT) :-
555 get_violated_and_valid_machine_invariants_aux2(EqualityNodes, T, NT).
556
557 % Get the machine invariants considering at least one of the current variables derived from the examples.
558 get_invariants_for_current_vars(Examples, TypedIDs, InvariantList) :-
559 Examples = [Example|_],
560 maplist(get_varname_from_node_info, Example, VarNames),
561 get_machinevars_by_name(VarNames, TypedIDs),
562 b_get_invariant_from_machine(MachineInvariant),
563 conjunction_to_list(MachineInvariant, CompleteInvariantList),
564 findall(Invariant, ( member(Invariant, CompleteInvariantList),
565 find_identifier_uses(Invariant, [], UsedIDs),
566 intersection(UsedIDs, VarNames, Intersection),
567 Intersection \= []
568 ), InvariantList).
569
570 % Check if the given examples are already reduced by the user, i.e., they refer to less variables than
571 % there are machine variables.
572 examples_already_reduced(Examples) :-
573 Examples = [Example|_],
574 length(Example, VarAmount),
575 b_get_machinevars_with_operation_params(MachineVars),
576 length(MachineVars, MachineVarAmount),
577 VarAmount < MachineVarAmount.
578
579 % The examples are tuples of variable name and pretty value from the java ui.
580 get_invariant_violating_vars_from_examples([], [], []) :-
581 !.
582 get_invariant_violating_vars_from_examples(Positive, Negative, ViolatingVarNames) :-
583 % split examples that are tuples of input and output state
584 split_input_output_tuples(Positive, PosInput, PosOutput),
585 split_input_output_tuples(Negative, NegInput, NegOutput),
586 append([PosInput,PosOutput,NegInput,NegOutput], Input),
587 get_violated_and_valid_machine_invariants(Input, _, ViolatingVars, _),
588 !,
589 maplist(get_varname_from_id_node, ViolatingVars, ViolatingVarNames).
590
591 % Get another transition that violates the invariant, exclude given input/output example.
592 :- spec_pre(get_invariant_violating_transition/6, [atom,list(ast),list(ast),list(ast),list(ast),var]).
593 :- spec_invariant(get_invariant_violating_transition/6, [atom,list(ast),list(ast),list(ast),list(ast),pair(ast,ast)]).
594 :- spec_post(get_invariant_violating_transition/6, [atom,list(ast),list(ast),list(ast),list(ast),var],
595 [atom,list(ast),list(ast),list(ast),list(ast),pair(ast,ast)]).
596 get_invariant_violating_transition(Operation, UsedVars, ViolatedInvariants, Input, Output, Counter) :-
597 b_get_machine_operation(Operation, _, _, TOpBody),
598 % don't create contradiction in case the guard is equivalent
599 % to an invariant which we will negate in the following
600 remove_pre_condition_from_body(TOpBody, OpBody),
601 before_after_predicate_with_equalities(OpBody, UsedVars, BABody),
602 % find_identifier_uses(OpBody,[],BodyIDs) ,
603 findall(V, ( member(b(identifier(V),_,_), UsedVars)
604 ), BodyIDs),
605 b_get_machinevars_with_operation_params(MachineVars),
606 create_equality_nodes_from_examples(BodyIDs, Input, Output, MachineVars, TNodeList),
607 % negate equalities to exclude this transition
608 findall(Inequality, ( create_texpr(negation(Equality), pred, [], Inequality),
609 member(Equality, TNodeList)
610 ), NodeList),
611 conjunct_predicates(ViolatedInvariants, Invariant),
612 maplist(get_varname_from_id_node, MachineVars, MachineVarNames),
613 prime_or_unprime_variables_in_ast(prime, MachineVarNames, Invariant, PrimedInvariant),
614 create_texpr(negation(Invariant), pred, [], NInvariant),
615 create_texpr(negation(PrimedInvariant), pred, [], NPrimedInvariant),
616 conjunct_predicates([BABody,NInvariant,NPrimedInvariant|NodeList], BAExclusion),
617 solve_predicate(BAExclusion, _, Solution),
618 get_invariant_violating_transition_aux(Solution, Counter).
619
620 get_invariant_violating_transition_aux(Solution, none) :-
621 Solution \= solution(_).
622 get_invariant_violating_transition_aux(solution(Solution), (CounterInput,CounterOutput)) :-
623 % split by input and output state
624 get_input_output_nodes_from_bindings(Solution, CounterInput, CounterOutput).
625
626 get_invariant_violating_example(_, [], [], _) :-
627 fail.
628 get_invariant_violating_example(ViolatedInvariants, [PosInput|TIn], [PosOutput|TOut], Example) :-
629 maplist(check_invariant_on_state(PosInput, PosOutput), ViolatedInvariants),
630 !,
631 % transition doesn't violate an invariant
632 get_invariant_violating_example(ViolatedInvariants, TIn, TOut, Example).
633 % invariant violating transition found
634 get_invariant_violating_example(_, [PosInput|_], [PosOutput|_], (PosInput,PosOutput)).
635
636 % Is true if the given invariant is true for the pair of input/output states.
637 check_invariant_on_state(Input, Output, InvariantAst) :-
638 create_equality_nodes_from_examples(Input, Output, EqualityNodes),
639 conjunct_predicates([InvariantAst|EqualityNodes], InvariantTransitionPred),
640 b_test_boolean_expression_wf_no_bindings(InvariantTransitionPred, _).
641
642 %% Get the input and/or output nodes from a solution of the distinguishing constraint.
643 :- spec_pre(get_input_output_nodes_from_bindings/3, [solution_bindings,var,var]).
644 :- spec_invariant(get_input_output_nodes_from_bindings/3, [solution_bindings,list(ast),list(ast)]).
645 :- spec_post(get_input_output_nodes_from_bindings/3, [solution_bindings,var,var], [solution_bindings,list(ast),list(ast)]).
646 get_input_output_nodes_from_bindings(Solution, Input, Output) :-
647 get_input_nodes_from_bindings(Solution, Input),
648 get_output_nodes_from_bindings(Solution, Output).
649
650 :- spec_pre(get_input_nodes_from_bindings/2, [solution_bindings,var]).
651 :- spec_invariant(get_input_nodes_from_bindings/2, [solution_bindings,list(ast)]).
652 :- spec_post(get_input_nodes_from_bindings/2, [solution_bindings,var], [solution_bindings,list(ast)]).
653 get_input_nodes_from_bindings(Solution, Input) :-
654 findall(Binding, ( member(Binding, Solution),
655 get_varname_from_binding(Binding, VarName),
656 \+ is_primed_id(VarName)
657 ), Bindings),
658 example_bindings_to_ast_nodes(Bindings, Input).
659
660 :- spec_pre(get_output_nodes_from_bindings/2, [solution_bindings,var]).
661 :- spec_invariant(get_output_nodes_from_bindings/2, [solution_bindings,list(ast)]).
662 :- spec_post(get_output_nodes_from_bindings/2, [solution_bindings,var], [solution_bindings,list(ast)]).
663 get_output_nodes_from_bindings(Solution, Output) :-
664 get_output_nodes_from_bindings_aux(Solution, NewSolution),
665 example_bindings_to_ast_nodes(NewSolution, Output).
666 get_output_nodes_from_bindings_aux([], []).
667 get_output_nodes_from_bindings_aux([Binding|T], [Binding|NT]) :-
668 get_varname_from_binding(Binding, VarName),
669 is_primed_id(VarName),
670 !,
671 get_output_nodes_from_bindings_aux(T, NT).
672 get_output_nodes_from_bindings_aux([_|T], NT) :-
673 get_output_nodes_from_bindings_aux(T, NT).
674
675 get_varname_from_binding(binding(VarName,_,_), VarName).
676 get_varname_from_binding(bind(VarName,_), VarName).
677
678 % rlevent/11
679 remove_pre_condition_from_body(b(Node,_,_), Body) :-
680 Node =.. [_,_,_,_,_,_,_,Actions|_],
681 !,
682 create_texpr(parallel(Actions), subst, [], OpBody),
683 remove_pre_condition_from_body(OpBody, Body).
684 remove_pre_condition_from_body(b(any(_,_,TActions),subst,_), Body) :-
685 ( is_list(TActions) ->
686 Actions = TActions
687 ; Actions = [TActions]
688 ),
689 !,
690 create_texpr(parallel(Actions), subst, [], OpBody),
691 remove_pre_condition_from_body(OpBody, Body).
692 remove_pre_condition_from_body(PreBody, Body) :-
693 PreBody = b(precondition(_,Body),_,_),
694 !.
695 remove_pre_condition_from_body(Body, Body).
696
697 % prime/unprime all identifiers in VarsToConsider within an ast, if VarsToConsider is an empty list prime/unprime all variables
698 :- spec_pre(prime_or_unprime_variables_in_ast/4, [atom,list(ast),ast,var]).
699 :- spec_invariant(prime_or_unprime_variables_in_ast/4, [atom,list(ast),ast,ast]).
700 :- spec_post(prime_or_unprime_variables_in_ast/4, [atom,list(ast),ast,var], [atom,list(ast),ast,ast]).
701 prime_or_unprime_variables_in_ast(prime, VarsToConsider, b(identifier(ID),Type,Info), PrimedID) :-
702 ( member(ID, VarsToConsider)
703 ; VarsToConsider = []
704 ),
705 !,
706 prime_variable(b(identifier(ID),Type,Info), PrimedID).
707 prime_or_unprime_variables_in_ast(prime, VarsToConsider, b(identifier(ID),Type,Info), Ast) :-
708 !,
709 \+ member(ID, VarsToConsider),
710 Ast = b(identifier(ID),Type,Info).
711 prime_or_unprime_variables_in_ast(unprime, VarsToConsider, b(identifier(ID),Type,Info), UnprimedID) :-
712 ( member(ID, VarsToConsider)
713 ; VarsToConsider = []
714 ),
715 !,
716 ( is_primed_id(ID)
717 ->
718 remove_prime(b(identifier(ID),Type,Info), UnprimedID)
719 ; UnprimedID = b(identifier(ID),Type,Info)
720 ).
721 prime_or_unprime_variables_in_ast(unprime, VarsToConsider, b(identifier(ID),Type,Info), Ast) :-
722 !,
723 \+ member(ID, VarsToConsider),
724 Ast = b(identifier(ID),Type,Info).
725 prime_or_unprime_variables_in_ast(_, _, b(Node,Type,Info), Ast) :-
726 ( Node = integer(_)
727 ; Node = value(_)
728 ; Node = integer_set(_)
729 ; Node = string(_)
730 ; Node =.. [_]
731 ),
732 !,
733 Ast = b(Node,Type,Info).
734 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(Node,Type,Info), b(NewNode,Type,Info)) :-
735 Node =.. [parallel,Assignments],
736 maplist(prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider), Assignments, NewAssignments),
737 NewNode =.. [parallel,NewAssignments].
738 % skip nodes like comprehension_set, set_extension or sequence_extension
739 prime_or_unprime_variables_in_ast(_, _, b(Node,Type,Info), b(Node,Type,Info)) :-
740 Node =.. [OpType|_],
741 ( OpType = comprehension_set
742 ; OpType = set_extension
743 ; OpType = sequence_extension
744 ),
745 !.
746 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(Node,Type,Info), b(NewNode,Type,Info)) :-
747 Node =.. [Op,In],
748 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In, NewIn),
749 NewNode =.. [Op,NewIn].
750 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(exists(Ids,Pred),Type,Info), b(exists(NewIds,NewPred),Type,Info)) :-
751 maplist(prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider), Ids, NewIds),
752 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, Pred, NewPred).
753 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(Node,Type,Info), b(NewNode,Type,Info)) :-
754 Node =.. [Op,In1,In2],
755 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In1, NewIn1),
756 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In2, NewIn2),
757 NewNode =.. [Op,NewIn1,NewIn2].
758 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(forall(Ids,Left,Right),Type,Info), b(forall(NewIds,NewLeft,NewRight),Type,Info)) :-
759 maplist(prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider), Ids, NewIds),
760 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, Left, NewLeft),
761 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, Right, NewRight).
762 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, b(Node,Type,Info), b(NewNode,Type,Info)) :-
763 % e.g. if_then_else
764 Node =.. [Op,In1,In2,In3],
765 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In1, NewIn1),
766 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In2, NewIn2),
767 prime_or_unprime_variables_in_ast(PrimeType, VarsToConsider, In3, NewIn3),
768 NewNode =.. [Op,NewIn1,NewIn2,NewIn3].
769
770 % Check that all negative inputs are invalid for the operation's precondition.
771 check_negative_inputs_against_operation_precondition(_, []). % no negative input states are present
772 check_negative_inputs_against_operation_precondition(Operation, NegInput) :-
773 NegInput \= [],
774 b_get_machine_operation(Operation, _, _, OpBody),
775 OpBody = b(precondition(PreCondition,_),_,_),
776 check_negative_inputs_against_operation_precondition_aux(PreCondition, NegInput).
777
778 % fails if any negative input state is valid on the current precondition, that means, the precondition needs to be strengthened
779 check_negative_inputs_against_operation_precondition_aux(_, []).
780 check_negative_inputs_against_operation_precondition_aux(PreCondition, [NegState|T]) :-
781 create_equality_nodes_from_example(NegState, EqualityNodes),
782 conjunct_predicates([PreCondition|EqualityNodes], EqualityPred),
783 \+ b_test_boolean_expression_wf_no_bindings(EqualityPred, _),
784 check_negative_inputs_against_operation_precondition_aux(PreCondition, T).
785
786 %% User adds a missing state transition.
787 % Search for a machine operation that completely supports the missing state
788 % or one where we just have to synthesize a relaxed guard.
789 % VarNames refers to the variables used in the added states.
790 check_transitions_against_machine_operations(VarNodes, InputExamples, OutputExamples, Result) :-
791 % check each example againt the existing machine operations
792 maplist(check_transition_against_machine_operations(VarNodes), InputExamples, OutputExamples, SingleResults),
793 check_transitions_against_machine_operations_aux(SingleResults, Result),
794 !.
795 check_transitions_against_machine_operations_aux(SingleResults, Result) :-
796 % an operation satisifies the transition but its guard needs to be relaxed
797 member((OpName,guard), SingleResults),
798 % and all other example transitions are also satisfied by this operation,
799 maplist(operation_match(OpName), SingleResults),
800 % therefore we synthesize a relaxed guard
801 Result = (OpName,guard).
802 check_transitions_against_machine_operations_aux(SingleResults, Result) :-
803 % an operation satisifies all transitions, and thus, we don't have to synthesize anything
804 member((OpName,done), SingleResults),
805 maplist('='((OpName,done)), SingleResults),
806 Result = (OpName,done).
807 check_transitions_against_machine_operations_aux(_, no_match).
808
809 operation_match(OpName, (OpName,_)).
810
811 :- spec_pre(check_transition_against_machine_operations/4, [list(ast),list(ast),list(ast),var]).
812 :- spec_invariant(check_transition_against_machine_operations/4, [list(ast),list(ast),list(ast),
813 one_of([atom,pair(atom,atom)])]).
814 :- spec_post(check_transition_against_machine_operations/4, [list(ast),list(ast),list(ast),var],
815 [list(ast),list(ast),list(ast),
816 one_of([atom,pair(atom,atom)])]).
817 % Check a single transition against the existing machine operations.
818 check_transition_against_machine_operations(VarNodes, Input, Output, Result) :-
819 findall((Op,Res,Par,Body), b_get_machine_operation(Op, Res, Par, Body), Operations),
820 check_transition_against_machine_operations(Operations, Input, Output, VarNodes, Result).
821 check_transition_against_machine_operations([], _, _, _, no_match).
822 check_transition_against_machine_operations([(_,_,_,b(skip,subst,_))|T], Input, Output, VarNodes, Result) :-
823 check_transition_against_machine_operations(T, Input, Output, VarNodes, Result).
824 % Skip if the desired action's and the given ones' variables doesn't match.
825 check_transition_against_machine_operations([(_,_,_,OpBody)|T], Input, Output, VarNodes, Result) :-
826 find_identifier_uses(OpBody, [], BodyIDs),
827 findall(Name, member(b(identifier(Name),_,_), VarNodes), VarNames),
828 % find distinguishing variables
829 findall(DistName, ( member(DistName, BodyIDs),
830 \+ member(DistName, VarNames)
831 ), DistNames),
832 DistNames \= [],
833 !,
834 check_transition_against_machine_operations(T, Input, Output, VarNodes, Result).
835 check_transition_against_machine_operations([(OpName,_,_,OpBody)|T], Input, Output, VarNodes, Result) :-
836 b_get_machinevars_with_operation_params(MachineVars),
837 before_after_predicate_with_equalities(OpBody, MachineVars, BABody),
838 find_identifier_uses(OpBody, [], BodyIDs),
839 create_equality_nodes_from_examples(BodyIDs, Input, Output, VarNodes, NodeList),
840 b_get_typed_invariant_from_machine(Invariant),
841 conjunct_predicates([BABody,Invariant|NodeList], BABodyPred),
842 check_transition_against_machine_operations_aux(BABodyPred, NodeList, [(OpName,_,_,OpBody)|T], Input, Output, VarNodes, Result).
843
844 % Found operation that already executes the transition.
845 check_transition_against_machine_operations_aux(BABodyPred, _, [(OpName,_,_,_)|_], _, _, _, (OpName,done)) :-
846 solve_predicate(BABodyPred, _, solution(_)),
847 !.
848 % Only the guard of an operation does not fit.
849 check_transition_against_machine_operations_aux(_, NodeList, [(OpName,_,_,OpBody)|_], _, _, _, (OpName,guard)) :-
850 b_get_machinevars_with_operation_params(MachineVars),
851 % remove guard and try if action itself supports the missing state
852 OpBody = b(precondition(_PreCondition,Action),_,_),
853 before_after_predicate_with_equalities(Action, MachineVars, BAAction),
854 conjunct_predicates([BAAction|NodeList], BAActionPred),
855 solve_predicate(BAActionPred, _, solution(_)),
856 !.
857 % The action also does not match so that we search for another operation.
858 check_transition_against_machine_operations_aux(_, _, [_|T], Input, Output, VarNodes, Result) :-
859 check_transition_against_machine_operations(T, Input, Output, VarNodes, Result).
860 %%
861 % Get valid transitions for an operation and return tuples holding pretty printed equality predicates of before/after states.
862 % Furthermore, get invalid states if a precondition is given and return pretty printed equality predicates for this states.
863 % We can directly use these pretty printed predicates to compute the states in ProB2 using FindStateCommand.
864 get_valid_and_invalid_equality_predicates_for_operation(OperationName, ValidAmount, InvalidAmount, ValidPrettyEqualityTuples, InvalidPrettyEqualities, IgnoredIDs) :-
865 preferences:set_preference(randomise_enumeration_order, true),
866 b_get_machine_operation(OperationName, _, _, Substitution),
867 find_identifier_uses(Substitution, [], TempUsedIDs),
868 % filter only machine variables, an operation may access machine constants that we need to discard here
869 b_get_machinevars_with_operation_params(MachineVars),
870 findall(UsedID, ( member(UsedID, TempUsedIDs),
871 member(b(identifier(UsedID),_,_), MachineVars)
872 ), UsedIDs),
873 findall(IgnoredID, ( member(b(identifier(IgnoredID),_,_), MachineVars),
874 \+ member(IgnoredID, UsedIDs)
875 ), IgnoredIDs),
876 get_machinevars_by_name(UsedIDs, UsedMachineVars),
877 get_valid_transitions_for_operation(UsedMachineVars, ValidAmount, OperationName, BeforeStates, AfterStates),
878 maplist(create_equality_predicate_from_example, BeforeStates, BeforeEqualities),
879 maplist(create_equality_predicate_from_example, AfterStates, AfterEqualities),
880 maplist(translate_bexpression, BeforeEqualities, PrettyBeforeEqualities),
881 maplist(translate_bexpression, AfterEqualities, PrettyAfterEqualities),
882 zip(PrettyBeforeEqualities, PrettyAfterEqualities, ValidPrettyEqualityTuples),
883 get_invalid_state_equalities_for_operation(OperationName, UsedMachineVars, InvalidAmount, Substitution, InvalidEqualities),
884 maplist(translate_bexpression, InvalidEqualities, InvalidPrettyEqualities),
885 !.
886
887 get_invalid_state_equalities_for_operation(OperationName, MachineVars, Amount, b(precondition(Precondition,_),subst,_), InvalidEqualities) :-
888 !,
889 % additionally consider the machine properties since a precondition may access machine constants
890 b_get_properties_from_machine(MachineProperties),
891 % filter predicates that set the types of operation parameters from the actual preconditions, since we do not want to negate the typing of operation parameters in the following
892 b_get_machine_operation(OperationName, _, OperationParams, _),
893 split_typing_predicates_from_precondition(OperationParams, Precondition, TypingPredicates, PreconditionPredicate),
894 conjunct_predicates([MachineProperties,TypingPredicates,b(negation(PreconditionPredicate),pred,[])], NegatedPrecondition),
895 get_invalid_state_equalities_for_operation_aux(MachineVars, Amount, NegatedPrecondition, [], InvalidStates),
896 maplist(create_equality_predicate_from_example, InvalidStates, InvalidEqualities).
897 % no precondition is given
898 get_invalid_state_equalities_for_operation(_, _, _, _, []).
899
900 get_invalid_state_equalities_for_operation_aux(_, 0, _, Acc, Acc).
901 get_invalid_state_equalities_for_operation_aux(MachineVars, Amount, PreconditionWithProperties, Acc, InvalidStates) :-
902 exclude_accumulated_states(MachineVars, Acc, [], TExclusion),
903 ( TExclusion = [] ->
904 Exclusion = b(truth,pred,[])
905 ; Exclusion = TExclusion
906 ),
907 create_texpr(conjunct(Exclusion,PreconditionWithProperties), pred, [], Predicate),
908 solve_predicate(Predicate, _, Solution),
909 Solution = solution(SolutionBindings),
910 !,
911 % solutions may also refer to machine constants that we do not want to consider here since we search for machine states
912 findall(Binding, ( member(Binding, SolutionBindings),
913 Binding = binding(Name,_,_),
914 member(b(identifier(Name),_,_), MachineVars)
915 ), MachineVarBindings),
916 example_bindings_to_ast_nodes(MachineVarBindings, InvalidState),
917 NAmount is Amount-1,
918 get_invalid_state_equalities_for_operation_aux(MachineVars, NAmount, PreconditionWithProperties, [InvalidState|Acc], InvalidStates).
919 get_invalid_state_equalities_for_operation_aux(_, _, _, Acc, Acc).
920
921 get_valid_transitions_for_operation(CurrentVars, Amount, OperationName, BeforeStates, AfterStates) :-
922 Amount \= 0,
923 get_valid_inputs_for_operation(OperationName, Amount, ValidInputStates),
924 maplist(create_equality_nodes_from_example, ValidInputStates, ValidInputStateEqualities),
925 before_after_predicates:before_after_predicate_for_operation(OperationName, BeforeAfterPredicate),
926 get_valid_transitions_for_operation_aux(CurrentVars, ValidInputStateEqualities, BeforeAfterPredicate, [], [], BeforeStates, AfterStates).
927 get_valid_transitions_for_operation(_, _, _, [], []).
928
929 get_valid_transitions_for_operation_aux(_, [], _, BeforeAcc, AfterAcc, BeforeAcc, AfterAcc).
930 get_valid_transitions_for_operation_aux(CurrentVars, [ValidInputStateEquality|T], BeforeAfterPredicate, BeforeAcc, AfterAcc, BeforeStates, AfterStates) :-
931 conjunct_predicates(ValidInputStateEquality, InputEquality),
932 solve_predicate(b(conjunct(InputEquality,BeforeAfterPredicate),pred,[]), _, Solution),
933 Solution = solution(SolutionBindings),
934 !,
935 % solutions may also refer to machine constants that we do not want to consider here since we search for machine states
936 findall(Primed, ( member(Primed, SolutionBindings),
937 Primed = binding(Name,_,_),
938 bmachine_eventb:is_primed_id(Name),
939 remove_prime(b(identifier(Name),_,_), UnprimedAst),
940 member(UnprimedAst, CurrentVars)
941 ), AfterBindings),
942 sets:subtract(SolutionBindings, AfterBindings, TempBeforeBindings),
943 findall(Unprimed, ( member(Unprimed, TempBeforeBindings),
944 Unprimed = binding(Name,_,_),
945 \+ bmachine_eventb:is_primed_id(Name),
946 member(b(identifier(Name),_,_), CurrentVars)
947 ), BeforeBindings),
948 example_bindings_to_ast_nodes(BeforeBindings, Before),
949 example_bindings_to_ast_nodes(AfterBindings, After),
950 get_valid_transitions_for_operation_aux(CurrentVars, T, BeforeAfterPredicate, [Before|BeforeAcc], [After|AfterAcc], BeforeStates, AfterStates).
951 get_valid_transitions_for_operation_aux(CurrentVars, [_|T], BeforeAfterPredicate, BeforeAcc, AfterAcc, BeforeStates, AfterStates) :-
952 get_valid_transitions_for_operation_aux(CurrentVars, T, BeforeAfterPredicate, BeforeAcc, AfterAcc, BeforeStates, AfterStates).
953
954 exclude_accumulated_states(_, [], Acc, Exclusion) :-
955 conjunct_predicates(Acc, Exclusion).
956 exclude_accumulated_states(CurrentVars, [BeforeState|T], Acc, Exclusion) :-
957 maplist(exclude_variable_state(CurrentVars), BeforeState, ExclusionList),
958 conjunct_predicates(ExclusionList, Inequalities),
959 exclude_accumulated_states(CurrentVars, T, [Inequalities|Acc], Exclusion).
960
961 exclude_variable_state(MachineVars, b(Node,Type,Info), Inequality) :-
962 member(synthesis(machinevar,VarName), Info),
963 member(b(identifier(VarName),MachineVarType,MachineVarInfo), MachineVars),
964 create_texpr(not_equal(b(Node,Type,Info),b(identifier(VarName),MachineVarType,MachineVarInfo)), pred, [], Inequality).
965
966 % Filter predicates that set the types of operation parameters from the actual preconditions.
967 split_typing_predicates_from_precondition(OperationParams, Precondition, TypingPredicate, PreconditionPredicate) :-
968 maplist(get_texpr_id, OperationParams, OperationParamNames),
969 conjunction_to_list(Precondition, PreconditionList),
970 findall(TypingPred, ( member(TypingPred, PreconditionList),
971 find_identifier_uses(TypingPred, [], UsedIDs),
972 sets:intersection(UsedIDs, OperationParamNames, Intersection),
973 Intersection \= []
974 ), TypingPredicatesList),
975 sets:subtract(PreconditionList, TypingPredicatesList, ActualPreconditionList),
976 conjunct_predicates(TypingPredicatesList, TypingPredicate),
977 conjunct_predicates(ActualPreconditionList, PreconditionPredicate).
978
979 % Can be used in both directions: Either VarName or Value has to be ground.
980 :- spec_pre(get_binding_for_name_or_value/3, [solution_bindings,one_of([var,atom]),one_of([var,atom,compound])]).
981 :- spec_invariant(get_binding_for_name_or_value/3, [solution_bindings,one_of([var,atom]),one_of([var,atom,compound])]).
982 :- spec_post(get_binding_for_name_or_value/3, [solution_bindings,one_of([var,atom]),one_of([var,atom,compound])],
983 [solution_bindings,one_of([var,atom]),one_of([var,atom,compound])]).
984 get_binding_for_name_or_value(SolutionBindings, VarName, Value) :-
985 ( member(binding(VarName,Value,_), SolutionBindings)
986 ;
987 member(bind(VarName,Value), SolutionBindings)
988 ).
989
990 % search identifier nodes within an ast and keep each nodes information
991 find_typed_identifier_uses_with_info(AST, UsedIDs) :-
992 find_typed_identifier_uses_with_info_aux(AST, TempUsedIDs),
993 remove_dups(TempUsedIDs, UsedIDs),
994 !.
995
996 find_typed_identifier_uses_with_info_aux(List, IDs) :-
997 is_list(List),
998 findall(ID, ( member(ID, List),
999 ID = b(identifier(_),_,_)
1000 ), IDs).
1001 find_typed_identifier_uses_with_info_aux(b(identifier(IDName),Type,Info), [b(identifier(IDName),Type,Info)]).
1002 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1003 Node =.. [Name,List],
1004 ( Name = set_extension
1005 ; Name = parallel
1006 ),
1007 maplist(find_typed_identifier_uses_with_info_aux, List, UsedIDsNested),
1008 tools:flatten(UsedIDsNested, UsedIDs).
1009 find_typed_identifier_uses_with_info_aux(b(assign_single_id(_ID,Ast),_,_), UsedIDs) :-
1010 find_typed_identifier_uses_with_info_aux(Ast, UsedIDs).
1011 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1012 Node =.. [if_then_else,Condition,TrueOut,FalseOut],
1013 find_typed_identifier_uses_with_info_aux(Condition, ConditionIDs),
1014 find_typed_identifier_uses_with_info_aux(TrueOut, TrueOutIDs),
1015 find_typed_identifier_uses_with_info_aux(FalseOut, FalseOutIDs),
1016 append([ConditionIDs,TrueOutIDs,FalseOutIDs], UsedIDs).
1017 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1018 Node =.. [forall,_,Left,Right],
1019 find_typed_identifier_uses_with_info_aux(Left, LeftIDs),
1020 find_typed_identifier_uses_with_info_aux(Right, RightIDs),
1021 append([LeftIDs,RightIDs], UsedIDs).
1022 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1023 Node =.. [_,Arg],
1024 find_typed_identifier_uses_with_info_aux(Arg, UsedIDs).
1025 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1026 Node =.. [_,Arg1,Arg2],
1027 find_typed_identifier_uses_with_info_aux(Arg1, UsedIDs1),
1028 find_typed_identifier_uses_with_info_aux(Arg2, UsedIDs2),
1029 append(UsedIDs1, UsedIDs2, UsedIDs).
1030 % rlevent
1031 find_typed_identifier_uses_with_info_aux(b(Node,_,_), UsedIDs) :-
1032 Node =.. [_,_,_,_,_,Body|_],
1033 find_typed_identifier_uses_with_info_aux(Body, UsedIDs).
1034 find_typed_identifier_uses_with_info_aux(_, []).
1035
1036 % Get current identifier names from an example before creating equality nodes to the example.
1037 :- spec_pre(create_equality_nodes_from_examples/3, [ast_example,ast_example,var]).
1038 :- spec_invariant(create_equality_nodes_from_examples/3, [ast_example,ast_example,ast_example]).
1039 :- spec_post(create_equality_nodes_from_examples/3, [ast_example,ast_example,var],
1040 [ast_example,ast_example,ast_example]).
1041 create_equality_nodes_from_examples(Input, Output, EqualityNodes) :-
1042 b_get_machinevars_with_operation_params(MachineVars),
1043 maplist(get_varname_from_node_info, Input, CurrentIDs),
1044 create_equality_nodes_from_examples(CurrentIDs, Input, Output, MachineVars, EqualityNodes).
1045 % We need to set variables to values from example by creating equality nodes
1046 % that we can add to the before after predicate.
1047 create_equality_nodes_from_examples([], _, _, _, []).
1048 create_equality_nodes_from_examples([VarName|T], Input, Output, VarNodes, [Node1,Node2|NodeList]) :-
1049 member(VarNode, VarNodes),
1050 VarNode = b(identifier(VarName),_,_),
1051 member(InputNode, Input),
1052 get_varname_from_node_info(InputNode, VarName),
1053 member(OutputNode, Output),
1054 get_varname_from_node_info(OutputNode, VarName),
1055 Node1 = b(equal(VarNode,InputNode),pred,[]),
1056 prime_variable(VarNode, PrimedVarNode),
1057 Node2 = b(equal(PrimedVarNode,OutputNode),pred,[]),
1058 create_equality_nodes_from_examples(T, Input, Output, VarNodes, NodeList).
1059
1060 create_equality_nodes_from_example(ExampleState, EqualityNodes) :-
1061 create_equality_nodes_from_example(ExampleState, [], EqualityNodes).
1062 create_equality_nodes_from_example([], Acc, Acc).
1063 create_equality_nodes_from_example([ValueAst|T], Acc, EqualityNodes) :-
1064 get_varname_from_node_info(ValueAst, VarName),
1065 get_machinevars_by_name([VarName], [MachineVar]),
1066 Equality = b(equal(MachineVar,ValueAst),pred,[]),
1067 create_equality_nodes_from_example(T, [Equality|Acc], EqualityNodes).
1068
1069 create_equality_predicate_from_example(ExampleState, EqualityPredicate) :-
1070 create_equality_nodes_from_example(ExampleState, EqualityNodes),
1071 conjunct_predicates(EqualityNodes, EqualityPredicate).
1072
1073 get_location_var_node_by_info_term(LocationVars, SynthesisTerm, LocationVar) :-
1074 member(LocationVar, LocationVars),
1075 LocationVar = b(identifier(_),integer,Info),
1076 member(SynthesisTerm, Info).
1077
1078 get_var_node_by_info_term(LocationVars, SynthesisTerm, LocationVar) :-
1079 member(LocationVar, LocationVars),
1080 get_texpr_info(LocationVar, Info),
1081 member(SynthesisTerm, Info).
1082
1083 get_location_var_node_by_name(LocationVarName, LocationVars, LocationVarNode) :-
1084 member(LocationVarNode, LocationVars),
1085 LocationVarNode = b(identifier(LocationVarName),integer,_).
1086
1087 % Compute some valid input states for a given operation by considering the invariant as well as the operation's precondition.
1088 get_valid_inputs_for_operation(OperationName, C, ValidStates) :-
1089 preferences:get_preference(randomise_enumeration_order, RandEnumOrder),
1090 preferences:set_preference(randomise_enumeration_order, true),
1091 b_get_machine_operation(OperationName, _, _, Substitution),
1092 get_precondition_from_operation_body(Substitution, Precondition),
1093 b_get_typed_invariant_from_machine(Invariant),
1094 % consider the machine properties since the guard may access machine constants
1095 b_get_properties_from_machine(MachineProperties),
1096 conjunct_predicates([Invariant,Precondition,MachineProperties], PreconditionInvariant),
1097 solve_predicate(PreconditionInvariant, _, SolutionTerm),
1098 SolutionTerm = solution(Solution),
1099 !,
1100 find_identifier_uses(Substitution, [], TempUsedIDs),
1101 % filter only machine variables, an operation may access machine constants that we need to discard here
1102 b_get_machinevars_with_operation_params(MachineVars),
1103 findall(UsedID, ( member(UsedID, TempUsedIDs),
1104 member(b(identifier(UsedID),_,_), MachineVars)
1105 ), UsedIDs),
1106 get_machinevars_by_name(UsedIDs, UsedMachineVars),
1107 get_states_aux(UsedMachineVars, C, Solution, PreconditionInvariant, b(truth,pred,[]), ValidStates),
1108 !,
1109 % restore previous enumeration order
1110 ( RandEnumOrder == false ->
1111 preferences:set_preference(randomise_enumeration_order, false)
1112 ; true
1113 ).
1114
1115 get_precondition_from_operation_body(b(select([b(select_when(Condition,_),_,_)]),_,_), Condition).
1116 get_precondition_from_operation_body(b(precondition(Precondition,_),_,_), Precondition).
1117 get_precondition_from_operation_body(_, b(truth,pred,[])).
1118
1119 get_valid_and_invalid_equality_predicates_for_invariants(ValidAmount, InvalidAmount, ValidPrettyEqualities, InvalidPrettyEqualities) :-
1120 b_get_machinevars_with_operation_params(MachineVars),
1121 maplist(get_texpr_id, MachineVars, MachineVarNames),
1122 get_valid_states(MachineVarNames, ValidAmount, ValidStates),
1123 maplist(create_equality_predicate_from_example, ValidStates, ValidEqualities),
1124 maplist(translate_bexpression, ValidEqualities, ValidPrettyEqualities),
1125 get_invalid_states(MachineVarNames, InvalidAmount, InvalidStates),
1126 maplist(create_equality_predicate_from_example, InvalidStates, InvalidEqualities),
1127 maplist(translate_bexpression, InvalidEqualities, InvalidPrettyEqualities).
1128
1129 % Get invalid states for visualizing the invariants.
1130 :- spec_pre(get_invalid_states/3, [list(atom),int,var]).
1131 :- spec_invariant(get_invalid_states/3, [list(atom),int,list(ast)]).
1132 :- spec_post(get_invalid_states/3, [list(atom),int,var], [list(atom),int,list(ast)]).
1133 get_invalid_states(CurrentVarNames, C, ValidStates) :-
1134 preferences:set_preference(randomise_enumeration_order, true),
1135 b_get_invariant_from_machine(Invariant),
1136 Invariant \= b(truth,pred,_), % only typing invariants are given, we then do not provide any invalid states
1137 NegInvariant = b(negation(Invariant),pred,[]),
1138 solve_predicate(NegInvariant, _, SolutionTerm),
1139 SolutionTerm = solution(Solution),
1140 !,
1141 get_machinevars_by_name(CurrentVarNames, CurrentVarNodes),
1142 get_states_aux(CurrentVarNodes, C, Solution, NegInvariant, b(truth,pred,[]), ValidStates).
1143 get_invalid_states(_, _, []).
1144
1145 % Get valid states for synthesis of invariants.
1146 :- spec_pre(get_valid_states/3, [list(atom),int,var]).
1147 :- spec_invariant(get_valid_states/3, [list(atom),int,list(ast)]).
1148 :- spec_post(get_valid_states/3, [list(atom),int,var], [list(atom),int,list(ast)]).
1149 get_valid_states(CurrentVarNames, C, ValidStates) :-
1150 preferences:set_preference(randomise_enumeration_order, true),
1151 b_get_typed_invariant_from_machine(Invariant),
1152 solve_predicate(Invariant, _, SolutionTerm),
1153 SolutionTerm = solution(Solution),
1154 !,
1155 get_machinevars_by_name(CurrentVarNames, CurrentVarNodes),
1156 get_states_aux(CurrentVarNodes, C, Solution, Invariant, b(truth,pred,[]), ValidStates).
1157
1158 :- spec_pre(get_states_aux/6, [list(atom),int,solution_bindings,ast,ast,var]).
1159 :- spec_invariant(get_states_aux/6, [list(atom),int,solution_bindings,ast,ast,list(ast)]).
1160 :- spec_post(get_states_aux/6, [list(atom),int,solution_bindings,ast,ast,var], [list(atom),int,solution_bindings,ast,ast,list(ast)]).
1161 get_states_aux(CurrentVarNodes, C, Solution, Invariant, PriorExclusion, [ValidState|NT]) :-
1162 C \= 1,
1163 C1 is C-1,
1164 findall(Exclusion, ( member(Var, CurrentVarNodes),
1165 Var = b(identifier(VarName),Type,_),
1166 member(binding(VarName,Value,_), Solution),
1167 create_texpr(not_equal(Var,b(value(Value),Type,[])), pred, [], Exclusion)
1168 ), ExclusionList),
1169 conjunct_predicates(ExclusionList, Exclusion),
1170 create_texpr(conjunct(PriorExclusion,Exclusion), pred, [], TExclusion),
1171 create_texpr(conjunct(Invariant,TExclusion), pred, [], NewPred),
1172 solve_predicate(NewPred, _, SolutionTerm),
1173 SolutionTerm = solution(NewSolution),
1174 !,
1175 example_bindings_to_ast_nodes(Solution, TempValidState),
1176 reduce_state_to_current_vars(CurrentVarNodes, TempValidState, ValidState),
1177 get_states_aux(CurrentVarNodes, C1, NewSolution, NewPred, TExclusion, NT).
1178 get_states_aux(CurrentVarNodes, _, Solution, _, _, [ValidState]) :-
1179 is_list(Solution),
1180 example_bindings_to_ast_nodes(Solution, TempValidState),
1181 reduce_state_to_current_vars(CurrentVarNodes, TempValidState, ValidState).
1182 get_states_aux(_, _, _, _, _, []).
1183
1184 % A state is a list of ast value nodes each having the term synthesis/2 with the corresponding machine var name in its info.
1185 reduce_state_to_current_vars(CurrentVarNodes, State, ReducedState) :-
1186 findall(ValueNode, ( member(ValueNode, State),
1187 get_texpr_info(ValueNode, ValueNodeInfo),
1188 member(synthesis(machinevar,MachineVar), ValueNodeInfo),
1189 member(b(identifier(MachineVar),_,_), CurrentVarNodes)
1190 ), ReducedState).
1191
1192 %% Only for synthesis of guards or invariants:
1193 % In case we synthesize guard/invariant it is possible that a state is graduated as positive and negative
1194 % because we replace output states with TRUE/FALSE. Thus, the constraint would have a contradiction.
1195 % E.g. synthesizing an invariant: If we graduate [0]-->[-1] as valid and [-1]-->[-2] as invalid,
1196 % we don't want to assume [-1] to be a negative state from the second example.
1197 % Synthesizing a guard it is the opposite, i.e., we don't want to assume [-1] to be a positive state.
1198 get_distinct_states(invariant, Positive, TempNegative, Positive, Negative) :-
1199 get_distinct_states(Positive, TempNegative, Negative).
1200 get_distinct_states(guard, TempPositive, Negative, Positive, Negative) :-
1201 get_distinct_states(Negative, TempPositive, Positive).
1202
1203 % Duplicates are subtracted from the examples given in the second argument.
1204 :- spec_pre(get_distinct_states/3, [ast_examples,ast_examples,var]).
1205 :- spec_invariant(get_distinct_states/3, [ast_examples,ast_examples,ast_examples]).
1206 :- spec_post(get_distinct_states/3, [ast_examples,ast_examples,var], [ast_examples,ast_examples,ast_examples]).
1207 get_distinct_states(Examples1, TempExamples2, Examples2) :-
1208 findall(E, ( member(E, TempExamples2),
1209 \+ contains_equivalent_state(E, Examples1, _)
1210 ), Examples2).
1211
1212 % Mark initial examples to be able to restrict constant domains when defining the synthesis
1213 % constraint. Otherwise we would expand the constant domains for each new example derived from
1214 % distinguishing interactions.
1215 mark_examples_as_initial(TempPositive, TempNegative, Positive, Negative) :-
1216 maplist(mark_examples_as_initial_aux, TempPositive, Positive),
1217 maplist(mark_examples_as_initial_aux, TempNegative, Negative).
1218 mark_examples_as_initial_aux([], []).
1219 mark_examples_as_initial_aux([ValueNode|T], [b(Node,Type,NewInfo)|NT]) :-
1220 ValueNode = b(Node,Type,Info),
1221 mark_examples_as_initial_aux2(Info, NewInfo),
1222 mark_examples_as_initial_aux(T, NT).
1223 mark_examples_as_initial_aux2(Info, Info) :-
1224 member(synthesis(initial_example), Info).
1225 mark_examples_as_initial_aux2(Info, [synthesis(initial_example)|Info]) :-
1226 \+ member(synthesis(initial_example), Info).
1227
1228 % InputList contains all machine variables, but for synthesizing an invariant we only need to
1229 % observe variables from violated invariants.
1230 % Furthermore we accept hints from the user on variables that are probably involved in an action's
1231 % guard so we also need to reduce examples there.
1232 reduce_input_to_violating_vars(ViolatingVars, InputExample, ReducedExample) :-
1233 % find values of matching variable names located in ast nodes info term synthesis/2
1234 findall(Value, ( member(Value, InputExample),
1235 get_varname_from_node_info(Value, VarName),
1236 member(VarName, ViolatingVars)
1237 ), ReducedExample).
1238
1239 % Get the current variables from an example (info contains synthesis/2 with var name).
1240 get_current_vars_from_example(Example, CurrentVars) :-
1241 b_get_machinevars_with_operation_params(MachineVars),
1242 findall(VarName, ( member(Node, Example),
1243 get_varname_from_node_info(Node, VarName)
1244 ), CurrentVarNames),
1245 findall(VarNode, ( member(VarNode, MachineVars),
1246 VarNode = b(identifier(VarName),_,_),
1247 member(VarName, CurrentVarNames)
1248 ), CurrentVars).
1249
1250 value_to_ast(Value, b(value(Value),Type,[])) :-
1251 kernel_objects:infer_value_type(Value, Type).
1252
1253 get_varname_from_node_info(b(_,_,Info), VarName) :-
1254 member(synthesis(machinevar,VarName), Info).
1255
1256 get_varname_from_id_node(b(identifier(VarName),_,_), VarName).
1257
1258 % translate prob values to asts node and add the machine variable name to each node's info
1259 example_bindings_to_ast_nodes([], []).
1260 example_bindings_to_ast_nodes([Binding|T], [Ast|NT]) :-
1261 ( Binding = binding(TVarName,In,_)
1262 ; Binding = bind(TVarName,In)
1263 ),
1264 value_to_ast(In, TAst),
1265 remove_prime(TVarName, VarName),
1266 add_texpr_infos(TAst, [synthesis(machinevar,VarName)], TTAst),
1267 set_type_if_necessary(TTAst, Ast),
1268 !,
1269 example_bindings_to_ast_nodes(T, NT).
1270
1271 remove_prime(b(identifier(VarName),Type,Info), b(identifier(UnPrimed),Type,Info)) :-
1272 !,
1273 remove_prime(VarName, UnPrimed).
1274 remove_prime(VarName, UnPrimed) :-
1275 atom_concat(UnPrimed, '\'', VarName),
1276 !.
1277 remove_prime(VarName, VarName).
1278
1279 % we have to set the types of untyped ast nodes like empty sets
1280 set_type_if_necessary(b(Node,Type,Info), b(TypedNode,GroundType,Info)) :-
1281 Node \= identifier(_),
1282 Node \= couple(_,_),
1283 untyped(Type),
1284 b_get_machinevars_with_operation_params(MachineVars),
1285 member(synthesis(machinevar,VarName), Info),
1286 member(b(identifier(VarName),GroundType,_), MachineVars),
1287 set_nested_types_if_necessary(Node, GroundType, TypedNode).
1288 % or couples refering to enumerated machine sets
1289 set_type_if_necessary(b(couple(Key,Value),Type,Info), b(couple(TypedKey,TypedValue),couple(KeyType,ValueType),Info)) :-
1290 untyped(Type),
1291 !,
1292 set_type_if_necessary(Key, TypedKey),
1293 set_type_if_necessary(Value, TypedValue),
1294 get_texpr_type(TypedKey, KeyType),
1295 get_texpr_type(TypedValue, ValueType).
1296 % or elements of enumerated machine sets
1297 set_type_if_necessary(b(identifier(IdName),Type,Info), b(identifier(IdName),GroundType,Info)) :-
1298 untyped(Type),
1299 !,
1300 b_get_machine_enumerated_sets_with_names(SetNamesTuples),
1301 % get the ast node of the enumerated set the identifier belongs to
1302 findall(SetNode, ( member((SetNode,ElmNames), SetNamesTuples),
1303 member(IdName, ElmNames)
1304 ), [SetNode]),
1305 SetNode = b(_,set(GroundType),_).
1306 set_type_if_necessary(b(Node,Type,Info), b(Node,Type,Info)).
1307
1308 % set the type of the elements of sets or sequences
1309 set_nested_types_if_necessary(Node, set(InnerType), TypedNode) :-
1310 Node =.. [SetOrSeq,Elements],
1311 ( SetOrSeq = set_extension
1312 ; SetOrSeq = sequence_extension
1313 ),
1314 maplist(set_explicit_type_if_necessary(InnerType), Elements, TypedElements),
1315 TypedNode =.. [SetOrSeq,TypedElements].
1316 set_nested_types_if_necessary(Node, _, Node).
1317
1318 set_explicit_type_if_necessary(InnerType, b(Node,Type,Info), TypedNode) :-
1319 untyped(Type),
1320 !,
1321 TypedNode = b(Node,InnerType,Info).
1322 set_explicit_type_if_necessary(_, Ast, Ast).
1323
1324 b_get_machine_enumerated_sets_with_names(SetNamesTuples) :-
1325 findall((SetName,SetNode), b_get_machine_set(SetName, SetNode), NameNodeTuples),
1326 findall((SetName,ElmNames), bmachine:b_get_named_machine_set(SetName, ElmNames), NameElmsTuples),
1327 findall((SetNode,ElmNames), ( member((SetName,SetNode), NameNodeTuples),
1328 member((SetName,ElmNames), NameElmsTuples)
1329 ), SetNamesTuples).
1330
1331 untyped(Type) :-
1332 var(Type).
1333 untyped(set(Type)) :-
1334 untyped(Type).
1335 untyped(set(couple(Key,Value))) :-
1336 ( untyped(Key)
1337 ; untyped(Value)
1338 ).
1339 untyped(seq(Type)) :-
1340 untyped(Type).
1341 untyped(seq(couple(Key,Value))) :-
1342 ( untyped(Key)
1343 ; untyped(Value)
1344 ).
1345 % ProB sometimes sets the type of empty sets to set(any)
1346 untyped(any).
1347
1348 % Zip two lists of the same size, i.e., create tuples of elements having the same index respectively.
1349 zip(L1, L2, Zipped) :-
1350 zip_aux(L1, L2, [], Zipped).
1351 zip_aux([], [], Acc, Acc).
1352 zip_aux([Elm1|T1], [Elm2|T2], Acc, Zipped) :-
1353 zip_aux(T1, T2, [(Elm1,Elm2)|Acc], Zipped).
1354
1355 % Used in b_synthesis
1356 % An operation satisfies the provided behavior, and thus, we do not have to synthesize anything.
1357 prepare_solution(_AdaptMachineCode, _, _, operation_satisfied(OperationName), operation_satisfied(OperationName), none).
1358 % Synthesis returned a distinguishing state or transition. The machine code is not changed.
1359 prepare_solution(_AdaptMachineCode, _, _, state(State), none, state(TranslatedState)) :-
1360 !,
1361 maplist(translate_example_ast, State, TranslatedState).
1362 prepare_solution(_AdaptMachineCode, _, _, transition(Input,Output), none, transition(TranslatedInput,TranslatedOutput)) :-
1363 !,
1364 maplist(translate_example_ast, Input, TranslatedInput),
1365 maplist(translate_example_ast, Output, TranslatedOutput).
1366 % Succeeded synthesizing a program fitting the desired behavior. Apply the solution to the machine code.
1367 prepare_solution(yes, Operation, SynthesisType, Synthesized, NewMachineAtom, distinguishing(none)) :-
1368 full_b_machine(Machine),
1369 apply_solution_to_machine_and_type_invariant(Machine, Operation, SynthesisType, Synthesized, NewMachineAst),
1370 translate_machine(NewMachineAst, Codes, _),
1371 atom_codes(NewMachineAtom, Codes).
1372 prepare_solution(no, _, _, Synthesized, Solution, Distinguishing) :-
1373 !,
1374 translate_bexpression_to_codes(Synthesized, SynthesizedAsCodes),
1375 Solution = (Synthesized,SynthesizedAsCodes),
1376 Distinguishing = distinguishing(none).
1377
1378 % Return a tuple of machine variable name and value for a given state's value ast.
1379 translate_example_ast(ExampleAst, (MachineVarName,TranslatedValue)) :-
1380 translate_bexpression(ExampleAst, TranslatedValue),
1381 get_varname_from_node_info(ExampleAst, MachineVarName).
1382
1383 % We derive several operations when implicitly synthesizing if-statements which we here apply to the machine code.
1384 adapt_machine_code_for_operations(Operations, NewMachineAtom) :-
1385 full_b_machine(Machine),
1386 adapt_machine_code_for_operations_aux(Operations, Machine, TempNewMachine),
1387 % type invariants which may have been optimized by ProB
1388 b_get_invariant_from_machine(Invariant),
1389 apply_solution_to_machine_and_type_invariant(TempNewMachine, _, invariant, Invariant, NewMachineAst),
1390 translate_machine(NewMachineAst, Codes, _),
1391 atom_codes(NewMachineAtom, Codes).
1392
1393 adapt_machine_code_for_operations_aux([], MachineCode, MachineCode).
1394 adapt_machine_code_for_operations_aux([Operation|T], MachineCode, NewMachineCode) :-
1395 apply_solution_to_machine(MachineCode, _, action, Operation, TempNewMachine),
1396 adapt_machine_code_for_operations_aux(T, TempNewMachine, NewMachineCode).
1397
1398 apply_solution_to_machine_and_type_invariant(Machine, Operation, Type, Synthesized, NewMachine) :-
1399 Type \= invariant,
1400 apply_solution_to_machine(Machine, Operation, Type, Synthesized, TempNewMachine),
1401 % the invariant has not been changed but typing predicates may be removed by the solver optimization,
1402 % therefore, we add typing predicates for each machine variable at the beginning of the invariant
1403 b_get_invariant_from_machine(Invariant),
1404 apply_solution_to_machine(TempNewMachine, _, invariant, Invariant, NewMachine).
1405 apply_solution_to_machine_and_type_invariant(Machine, Operation, invariant, SynthesizedInvariant, NewMachine) :-
1406 apply_solution_to_machine(Machine, Operation, invariant, SynthesizedInvariant, NewMachine).
1407
1408 apply_solution_to_machine(Machine, _, _, none, Machine).
1409 apply_solution_to_machine(machine(MachineName,Content), _, action, Synthesized, NewMachine) :-
1410 member(operation_bodies/OperationBodies, Content),
1411 subtract(Content, [operation_bodies/_], TempContent),
1412 apply_solution_to_machine_aux(action, OperationBodies, Synthesized, NewOperationBodies),
1413 append(TempContent, [operation_bodies/NewOperationBodies], NewContent),
1414 NewMachine = machine(MachineName,NewContent).
1415 apply_solution_to_machine(machine(MachineName,Content), Operation, guard, Synthesized, NewMachine) :-
1416 member(operation_bodies/OperationBodies, Content),
1417 subtract(Content, [operation_bodies/_], TempContent),
1418 apply_solution_to_machine_aux(guard, Operation, Synthesized, OperationBodies, NewOperationBodies),
1419 append(TempContent, [operation_bodies/NewOperationBodies], NewContent),
1420 NewMachine = machine(MachineName,NewContent).
1421 apply_solution_to_machine(machine(MachineName,Content), _, invariant, Synthesized, NewMachine) :-
1422 subtract(Content, [invariant/_], TempContent),
1423 conjunction_to_list(Synthesized, SynthesizedList),
1424 % split synthesized code from previous invariants that have been valid beforehand
1425 findall(SynthesizedCode, ( member(SynthesizedCode, SynthesizedList),
1426 get_texpr_info(SynthesizedCode, Info),
1427 member(synthesized_code, Info)
1428 ), SynthesizedCodeList),
1429 conjunct_predicates(SynthesizedCodeList, TempSynthesizedCode),
1430 find_typed_identifier_uses(TempSynthesizedCode, UsedVars),
1431 % create typing invariants only for variables that are involved in the synthesized code, the other typing invariants have already been conjuncted in ValidInvariants
1432 % we hereby want to avoid redundancy and conflicts in typing invariants, like the valid invariant has been i : NATURAL but generate_typing_predicates creates i : INTEGER afterwards
1433 % whilst i has not even been affected by the invariant violation
1434 b_get_typing_predicate_for_vars(UsedVars, TypingPredicate),
1435 conjunct_predicates([TypingPredicate,Synthesized], TypedSynthesizedInvariant),
1436 add_invariant_to_machine_content(TempContent, TypedSynthesizedInvariant, NewContent),
1437 NewMachine = machine(MachineName,NewContent).
1438
1439 % Existing operations are replaced by the synthesized ones.
1440 apply_solution_to_machine_aux(action, OperationBodies, Synthesized, NewOperationBodies) :-
1441 is_list(Synthesized),
1442 maplist(get_name_from_operation_ast, Synthesized, OperationNames),
1443 remove_operations_from_list(OperationBodies, OperationNames, [], UninvoledOperations),
1444 append(Synthesized, UninvoledOperations, NewOperationBodies).
1445 apply_solution_to_machine_aux(action, OperationBodies, Synthesized, [Synthesized|UninvoledOperations]) :-
1446 \+ is_list(Synthesized),
1447 get_name_from_operation_ast(Synthesized, OperationName),
1448 remove_operations_from_list(OperationBodies, [OperationName], [], UninvoledOperations).
1449
1450 % Given a list of operation bodies, i.e. operation/4 ASTs, remove those whose name is in OperationNames.
1451 remove_operations_from_list([], _, Acc, Acc).
1452 remove_operations_from_list([OperationBody|T], OperationNames, Acc, NewOperationBodies) :-
1453 get_name_from_operation_ast(OperationBody, OperationName),
1454 \+ member(OperationName, OperationNames),
1455 remove_operations_from_list(T, OperationNames, [OperationBody|Acc], NewOperationBodies).
1456 remove_operations_from_list([_|T], OperationNames, Acc, NewOperationBodies) :-
1457 remove_operations_from_list(T, OperationNames, Acc, NewOperationBodies).
1458
1459 apply_solution_to_machine_aux(guard, OperationName, Synthesized, [Operation|T], [NewOperation|T]) :-
1460 replace_precondition_if_operation_fits(OperationName, Operation, Synthesized, NewOperation),
1461 !.
1462 apply_solution_to_machine_aux(guard, OperationName, Synthesized, [Operation|T], [Operation|NT]) :-
1463 apply_solution_to_machine_aux(guard, OperationName, Synthesized, T, NT).
1464
1465 get_name_from_operation_ast(b(operation(ID,_,_,_),_,_), OperationName) :-
1466 ID = b(identifier(op(OperationName)),_,_).
1467
1468 % insert the synthesized invariant prior to the linking_invariant
1469 add_invariant_to_machine_content([linking_invariant/OperationBodies|T], Invariant, [invariant/Invariant,linking_invariant/OperationBodies|T]).
1470 add_invariant_to_machine_content([ContentType/Content|T], Invariant, [ContentType/Content|NewContent]) :-
1471 ContentType \= operation_bodies,
1472 add_invariant_to_machine_content(T, Invariant, NewContent).
1473
1474 replace_precondition_if_operation_fits(OperationName, Operation, Synthesized, NewOperation) :-
1475 Operation = b(Node,Type,Info),
1476 Node = operation(OperationNameId,X,Y,Body),
1477 get_varname_from_id_node(OperationNameId, IdName),
1478 IdName = op(OperationName), % operation fits
1479 replace_precondition_if_operation_fits_aux(Body, Synthesized, NewBody),
1480 NewOperation = b(operation(OperationNameId,X,Y,NewBody),Type,Info).
1481 % Replace or create a new precondition if the given operation name is equal to the one of the operation.
1482 replace_precondition_if_operation_fits_aux(Body, Synthesized, NewBody) :-
1483 Body = b(precondition(_,Substitutions),subst,Info),
1484 !,
1485 NewBody = b(precondition(Synthesized,Substitutions),subst,Info).
1486 replace_precondition_if_operation_fits_aux(Body, Synthesized, NewBody) :-
1487 Body = b(Substitutions,subst,Info),
1488 NewBody = b(precondition(Synthesized,Substitutions),subst,Info).
1489
1490 replace_precondition_of_operation(Operation, none, FinalOperation) :-
1491 !,
1492 FinalOperation = Operation.
1493 replace_precondition_of_operation(Operation, Precondition, FinalOperation) :-
1494 Operation = b(operation(OperationName,Res,Par,Body),subst,_),
1495 Body = b(precondition(_,Subst),_,_),
1496 !,
1497 FinalOperation = b(operation(OperationName,Res,Par,b(precondition(Precondition,Subst),subst,[])),subst,[]).
1498 replace_precondition_of_operation(Operation, Precondition, FinalOperation) :-
1499 Operation = b(operation(OperationName,Res,Par,Subst),subst,_),
1500 FinalOperation = b(operation(OperationName,Res,Par,b(precondition(Precondition,Subst),subst,[])),subst,[]).
1501
1502 % The Java UI provides tuples of input and output examples.
1503 split_input_output_tuples(InputOutputTupleList, InputList, OutputList) :-
1504 split_input_output_tuples(InputOutputTupleList, [], [], InputList, OutputList).
1505 split_input_output_tuples([], InputListAcc, OutputListAcc, InputListAcc, OutputListAcc).
1506 split_input_output_tuples([(Input,Output)|T], InputListAcc, OutputListAcc, InputList, OutputList) :-
1507 maplist(variable_parsedvalue_tuple_to_ast, Input, InputAsts),
1508 maplist(variable_parsedvalue_tuple_to_ast, Output, OutputAsts),
1509 accumulate_input_output_if_non_empty(InputAsts, InputListAcc, NewInputListAcc),
1510 accumulate_input_output_if_non_empty(OutputAsts, OutputListAcc, NewOutputListAcc),
1511 split_input_output_tuples(T, NewInputListAcc, NewOutputListAcc, InputList, OutputList).
1512
1513 accumulate_input_output_if_non_empty([], Acc, Acc).
1514 accumulate_input_output_if_non_empty(Asts, Acc, [Asts|Acc]) :-
1515 Asts \= [].
1516
1517 % Given a tuple of variable name and parsed term. Create the ast using the typechecker and
1518 % add synthesis/2 term to the node's info describing the corresponding machine variable.
1519 variable_parsedvalue_tuple_to_ast((VarName,ParsedValue), TypedAst) :-
1520 btype(bsynthesis, ParsedValue, openenv(_,env_empty), _, TempAst, [], _),
1521 add_texpr_infos(TempAst, [synthesis(machinevar,VarName)], TempAst2),
1522 remove_set_of_couple_type(TempAst2, TempAst3),
1523 set_type_if_necessary(TempAst3, TempAst4),
1524 !,
1525 get_texpr_type(TempAst4, Type),
1526 add_texpr_infos(TempAst4, [synthesis(type,Type)], TypedAst).
1527
1528 % Remove set(couple(_,_)) type since a sequence with size < 3 may be interpreted as a set of couples although it should be a seq(_).
1529 % The type is added afterwards according to the corresponding machine variable.
1530 remove_set_of_couple_type(b(Node,Type,Info), b(Node,_,Info)) :-
1531 Type == set(couple(_,_)),
1532 !.
1533 remove_set_of_couple_type(AST, AST).
1534
1535
1536 keep_asserted_initial_examples(Input, Output, OldInput, OldOutput, NewInput, NewOutput) :-
1537 keep_asserted_initial_states(Input, OldInput, NewInput),
1538 keep_asserted_initial_states(Output, OldOutput, NewOutput).
1539 keep_asserted_initial_states([], _, []).
1540 keep_asserted_initial_states([State|T], OldStates, [NewState|NT]) :-
1541 contains_equivalent_state(State, OldStates, EquivalentState),
1542 !,
1543 NewState = EquivalentState,
1544 keep_asserted_initial_states(T, OldStates, NT).
1545 keep_asserted_initial_states([State|T], OldStates, [State|NT]) :-
1546 keep_asserted_initial_states(T, OldStates, NT).
1547
1548 get_operation_params_from_ids(TypedIdentifiers, Params) :-
1549 get_operation_params_from_ids(TypedIdentifiers, [], Params).
1550 get_operation_params_from_ids([], Acc, Acc).
1551 get_operation_params_from_ids([TypedIdentifier|T], Acc, Params) :-
1552 get_texpr_info(TypedIdentifier, Info),
1553 ( ( member(synthesis(ParamType,_), Info),
1554 ( ParamType = param_single
1555 ; ParamType = param_set
1556 )
1557 )
1558 ; member(introduced_by(operation), Info)
1559 ),
1560 TypedIdentifier = b(Node,Type,_),
1561 \+ member(b(Node,Type,_), Acc),
1562 !,
1563 get_operation_params_from_ids(T, [TypedIdentifier|Acc], Params).
1564 get_operation_params_from_ids([_|T], Acc, Params) :-
1565 get_operation_params_from_ids(T, Acc, Params).
1566
1567 set_operation_params_domain(Params, Membership) :-
1568 set_operation_params_domain(Params, [], MembershipList),
1569 conjunct_predicates(MembershipList, Membership).
1570
1571 set_operation_params_domain([], Acc, Acc).
1572 set_operation_params_domain([Param|T], Acc, MembershipList) :-
1573 get_texpr_info(Param, ParamInfo),
1574 ( member(synthesis(type,set(global(IndependentType))), ParamInfo)
1575 ; Param = b(_,global(IndependentType),_)
1576 ),
1577 bmachine:b_get_named_machine_set(IndependentType, SetAst, _),
1578 set_operation_params_domain(T, [b(member(Param,SetAst),pred,[])|Acc], MembershipList).
1579
1580 finalize_synthesized_action(_, none, none).
1581 finalize_synthesized_action(OperationName, b(precondition(PreCondition,Substitutions),subst,[]),
1582 b(operation(OpNameId,_,Params,b(precondition(NewPreCondition,UnprimedSubstitutions),subst,[])),subst,[])) :-
1583 OpNameId = b(identifier(op(OperationName)),op([],[]),[]),
1584 find_typed_identifier_uses_with_info(Substitutions, TypedIdentifiers),
1585 get_operation_params_from_ids(TypedIdentifiers, Params),
1586 Params \= [],
1587 !,
1588 set_operation_params_domain(Params, ParamTypeDefsPred),
1589 conjunct_predicates([ParamTypeDefsPred,PreCondition], NewPreCondition),
1590 prime_or_unprime_variables_in_ast(unprime, [], Substitutions, UnprimedSubstitutions).
1591 finalize_synthesized_action(OperationName, b(precondition(PreCondition,Substitutions),subst,[]),
1592 b(operation(OpNameId,_,_,b(precondition(PreCondition,UnprimedSubstitutions),subst,[])),subst,[])) :-
1593 OpNameId = b(identifier(op(OperationName)),op([],[]),[]),
1594 prime_or_unprime_variables_in_ast(unprime, [], Substitutions, UnprimedSubstitutions).
1595 finalize_synthesized_action(OperationName, Action, b(operation(OpNameId,_,Params,b(precondition(ParamTypeDefsPred,UnprimedAction),subst,[])),subst,[])) :-
1596 OpNameId = b(identifier(op(OperationName)),op([],[]),[]),
1597 find_typed_identifier_uses_with_info(Action, TypedIdentifiers),
1598 get_operation_params_from_ids(TypedIdentifiers, Params),
1599 Params \= [],
1600 !,
1601 set_operation_params_domain(Params, ParamTypeDefsPred),
1602 prime_or_unprime_variables_in_ast(unprime, [], Action, UnprimedAction).
1603 finalize_synthesized_action(OperationName, Action, b(operation(OpNameId,_,_,UnprimedAction),subst,[])) :-
1604 OpNameId = b(identifier(op(OperationName)),op([],[]),[]),
1605 prime_or_unprime_variables_in_ast(unprime, [], Action, UnprimedAction).
1606
1607 % Synthesizing a guard for an action simultaneously can fail. We memorize distinguishing transitions
1608 % so even without a guard we won't find a distinguishing transitions twice. However,
1609 % finding a new distingushing transition that leads to synthesizing a guard simultaneously may
1610 % succeed with the new example later on (previous distinguishing states are also memorized and will be reused).
1611 prepare_synthesized_guards_for_action(Guards, Guards) :-
1612 is_ast(Guards).
1613 prepare_synthesized_guards_for_action(_, any).
1614
1615
1616 % Get all the location vars from a list of operators. The result is a map with entries like
1617 % Operator:ListOfLocationVars. Just one iteration of the list of location variables for all operators.
1618 % get_all_location_vars_for_operators(Operators,LocationVars,OperatorLVarsMap) :-
1619 % findall(Op:[],member(Op,Operators),EmptyAcc) ,
1620 % get_all_location_vars_for_operators_aux(LocationVars,EmptyAcc,OperatorLVarsMap).
1621 % get_all_location_vars_for_operators_aux([],Acc,Acc).
1622 % get_all_location_vars_for_operators_aux([LocationVar|T],Acc,OperatorLVarsMap) :-
1623 % LocationVar = b(_,_,Info) ,
1624 % member(synthesis(ComponentName,LocationType),Info) ,
1625 % member(LocationType,[left_input,right_input,output]) ,
1626 % delete_numbers_from_atom(ComponentName,Operator) ,
1627 % accumulate_locationvar_for_operator(LocationVar,Operator,Acc,NewAcc) ,
1628 % get_all_location_vars_for_operators_aux(T,NewAcc,OperatorLVarsMap).
1629 % get_all_location_vars_for_operators_aux([_|T],Acc,OperatorLVarsMap) :-
1630 % get_all_location_vars_for_operators_aux(T,Acc,OperatorLVarsMap).
1631
1632 % If the operator the location variable refers to is one that we search for, we accumulate the variable respectively.
1633 % accumulate_locationvar_for_operator(LocationVar,Operator,Acc,NewAcc) :-
1634 % member(Operator:OperatorLocationVars,Acc) ,
1635 % delete(Acc,Operator:_,TempAcc) ,
1636 % NewAcc = [Operator:[LocationVar|OperatorLocationVars]|TempAcc].
1637 % Otherwise skip the location variable.
1638 % accumulate_locationvar_for_operator(_,Operator,Acc,Acc) :-
1639 % \+member(Operator:_,Acc).
1640
1641 % Adjust the distinguishing state to the current variables (synthesis type is guard or invariant).
1642 % :- spec_pre(adjust_distinguishing_state_binding/3,[list(ast),solution_bindings,var]).
1643 % :- spec_invariant(adjust_distinguishing_state_binding/3,[list(ast),solution_bindings,solution_bindings]).
1644 % :- spec_post(adjust_distinguishing_state_binding/3,[list(ast),solution_bindings,var],
1645 % [list(ast),solution_bindings,solution_bindings]).
1646 % adjust_distinguishing_state_binding(CurrentVars,Distinguishing,Distinguishing) :-
1647 % length(CurrentVars,VarAmount) ,
1648 % length(Distinguishing,VarAmount).
1649 % Shrink distinguishing state.
1650 % adjust_distinguishing_state_binding(CurrentVars,Distinguishing,ShrunkenInput) :-
1651 % length(CurrentVars,VarAmount) ,
1652 % length(Distinguishing,DistAmount) ,
1653 % VarAmount < DistAmount ,
1654 % findall(Binding,(member(Binding,Distinguishing) , Binding = binding(VarName,_,_) ,
1655 % member(b(identifier(VarName),_,_),CurrentVars)),ShrunkenInput).
1656 % Expand distinguishing state.
1657 % adjust_distinguishing_state_binding(CurrentVars,Distinguishing,ShrunkenInput) :-
1658 % length(CurrentVars,VarAmount) ,
1659 % length(Distinguishing,DistAmount) ,
1660 % VarAmount > DistAmount ,
1661 % findall(Binding,(member(b(identifier(VarName),_,_),CurrentVars) ,
1662 % \+member(Binding,Distinguishing) , Binding = binding(VarName,_,_)),ShrunkenInput).