1 % (c) 2017-2022 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(constraints,[get_behavioral_constraint_from_input/6,
6 get_behavioral_constraint/6,
7 get_behavioral_constraint_aux/7,
8 get_new_behavioral_constraint/5,
9 get_prevent_component_swap_constraint/4,
10 get_line_amount/4]).
11
12 :- use_module(synthesis(synthesis_util)).
13 :- use_module(synthesis(symmetry_reduction)).
14
15 :- use_module(probsrc(bsyntaxtree)).
16 :- use_module(probsrc(bmachine_structure),[get_section/3]).
17 :- use_module(probsrc(tools),[flatten/2]).
18 :- use_module(probsrc(module_information),[module_info/2]).
19 :- use_module(probsrc(bmachine),[full_b_machine/1,
20 b_get_machine_constants/1,
21 b_get_properties_from_machine/1,
22 b_get_machine_operation/4,
23 b_get_machine_variables/1,
24 b_get_machine_set/1]).
25
26 :- use_module(library(lists)).
27
28 :- use_module(extension('plspec/plspec/plspec_core')).
29
30 :- module_info(group,synthesis).
31 :- module_info(description,'This module defines the constraint for synthesizing invariants, preconditions or complete operations using simple I/O examples.').
32
33 :- set_prolog_flag(double_quotes, codes).
34
35 unfold_existential_quantification(true).
36
37 split_input_output_location_vars(LocationVars,LocationVarsIn,LocationVarsOut) :-
38 split_input_output_location_vars(LocationVars,[],[],LocationVarsIn,LocationVarsOut).
39
40 split_input_output_location_vars([],InAcc,OutAcc,InAcc,OutAcc).
41 split_input_output_location_vars([LocationVar|T],InAcc,OutAcc,LocationVarsIn,LocationVarsOut) :-
42 accumulate_location_var(LocationVar,InAcc,OutAcc,NewInAcc,NewOutAcc) ,
43 split_input_output_location_vars(T,NewInAcc,NewOutAcc,LocationVarsIn,LocationVarsOut).
44
45 accumulate_location_var(b(identifier(LocationVarName),integer,Info),InAcc,OutAcc,[b(identifier(LocationVarName),integer,Info)|InAcc],OutAcc) :-
46 atom_concat(li,_,LocationVarName).
47 accumulate_location_var(b(identifier(LocationVarName),integer,Info),InAcc,OutAcc,InAcc,[b(identifier(LocationVarName),integer,Info)|OutAcc]) :-
48 atom_concat(lo,_,LocationVarName).
49 accumulate_location_var(_,InAcc,OutAcc,InAcc,OutAcc).
50
51 % Exclude a solution and add this node to the behavioral constraint. We exclude only the solution given
52 % by the program ast without involving generated deadcode.
53 get_new_behavioral_constraint(ProgramAST,LocationVars,solution(SolutionBindings),BehavioralConstraint,NewBehavioralConstraint) :-
54 % get the used operators output location variables to exclude from the further solution
55 get_used_location_vars_and_op_names(ProgramAST,LocationVars,[],[],_,UsedOperatorNames) ,
56 exclude_solution_for_further_search(UsedOperatorNames,LocationVars,SolutionBindings,Exclusion) ,
57 split_input_output_location_vars(LocationVars,LocationVarsIn,LocationVarsOut) ,
58 used_library(Components) ,
59 %findall(Component,(member(Component,AllComponents) , Component = (_,Name) , member(Name,UsedOperatorNames)),UsedComponents) ,
60 get_post_symmetry_reduction_constraint(Components,SolutionBindings,LocationVarsIn,LocationVarsOut,SymmetryReduction) ,
61 conjunct_predicates([BehavioralConstraint,Exclusion,SymmetryReduction],NewBehavioralConstraint).
62
63 get_behavioral_constraint_aux((ValidGuards,Operation),action,Library,PosInput,PosOutput,BehavioralConstraint,LocationVars) :-
64 get_behavioral_constraint(Library,(ValidGuards,Operation),PosInput,PosOutput,BehavioralConstraint,LocationVars).
65 get_behavioral_constraint_aux((ValidInvariantsOrGuards,Operation),_,Library,PosInput,PosOutput,BehavioralConstraint,LocationVars) :-
66 get_behavioral_constraint_from_input(Library,(ValidInvariantsOrGuards,Operation),PosInput,PosOutput,BehavioralConstraint,LocationVars).
67
68 % create outputs and get behavioral constraint
69 get_behavioral_constraint_from_input(Library,(ValidGuards,Operation),PosInput,NegInput,BehavioralConstraint,LocationVars) :-
70 % get output values
71 length(PosInput,PosLength) , length(NegInput,NegLength) ,
72 % create empty lists
73 length(TempPosOutput,PosLength) , length(TempNegOutput,NegLength) ,
74 % for our task to repair invariant violations output is either "true" or "false" (interpreted as pred_true/pred_false (synthesis(type,pred))
75 % but implemented as boolean_true/boolean_false, we set options each node's info representing the type which can differ from the ast node's type)
76 findall(In,(member(In,TempPosOutput) , In = [b(boolean_true,boolean,[synthesis(type,pred)])]),PosOutput) ,
77 findall(In,(member(In,TempNegOutput) , In = [b(boolean_false,boolean,[synthesis(type,pred)])]),NegOutput) ,
78 append(PosInput,NegInput,Input) ,
79 append(PosOutput,NegOutput,Output) ,
80 get_behavioral_constraint(Library,(ValidGuards,Operation),Input,Output,BehavioralConstraint,LocationVars).
81
82 :- dynamic used_library/1.
83 :- volatile used_library/1.
84
85 % Get the functional constraint for each Input-Output Example
86 % It is sufficient to create one well-definedness constraint surrounding the behavioral constraint
87 % but the library constraint needs to be defined for every examples functional constraint.
88 get_behavioral_constraint(Library,(ValidGuards,Operation),InputExamples,OutputExamples,BehavioralConstraint,LocationVars) :-
89 % lists of currently used components, necessary if a library is used several times
90 retractall(used_library(_)) ,
91 asserta(used_library([])) ,
92 InputExamples = [InputValues|_] ,
93 % create library constraint separated from the funtional constraint
94 % to make sure to just obtain one set of location variables
95 get_library_constraint(InputValues,Library,(ValidGuards,Operation),LibConstraint,InputVars,OutputVars,EnumeratedConstants) ,
96 % set the temporary location variables with prefix "l"
97 maplist(get_location_var_from_ast_node,InputVars,LocationVarsIn) ,
98 maplist(get_location_var_from_ast_node,OutputVars,LocationVarsOut) ,
99 % tuples of raw component name and internal component name like (add,add1)
100 used_library(Components) ,
101 get_preliminary_symmetry_reduction_constraint(Components,LocationVarsIn,LocationVarsOut,SymmetryReductionPred) ,
102 conjunct_predicates([LibConstraint,SymmetryReductionPred],ExtendedLibConstraint) ,
103
104 % get some information needed for well-definedness constraint
105 get_line_amount(Operation,Library,InputValues,M) ,
106 length(InputValues,VarAmount) ,
107 % create well-definedness constraint separated from function constraints
108 get_well_definedness_constraint(VarAmount,LocationVarsIn,LocationVarsOut,M,WellDefinednessConstraint) ,
109 get_max_cardinality_from_examples(InputExamples,MaxCard) ,
110 get_range_of_integer_nodes_from_examples(MaxCard,InputExamples,InMin,InMax) ,
111 % create upper and lower bound for input values (kodkod warning) and constants
112 create_texpr(integer(InMin),integer,[],IntLowerBound) ,
113 create_texpr(integer(InMax),integer,[],IntUpperBound) ,
114 create_texpr(integer(MaxCard),integer,[],CardUpperBound) , ! ,
115 map_get_function_constraint(Operation,0,Library,ExtendedLibConstraint,InputVars,OutputVars,InputExamples,OutputExamples,FunctionConstraints,ProgramInLocationVars) ,
116 enumerated_sets_constraint(EnumeratedSetsConstraint) ,
117 append(OutputVars,EnumeratedConstants,ConstantsAndOutputs) ,
118 % restrict domains outside of the existential quantifiers
119 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,ConstantsAndOutputs,ConstantRestrictionList) ,
120 % and create typing predicates for constants and input output values of components
121 create_typing_predicates_from_info(ConstantsAndOutputs,TypingPredicatesConj) ,
122 conjunct_predicates(ConstantRestrictionList,ConstantRestrictions) ,
123 findall(InputRestriction,(member(In,InputVars) , get_bounds_for_node(In,IntLowerBound,IntUpperBound,CardUpperBound,InputRestriction)),TempInputRestrictions) ,
124 conjunct_predicates(TempInputRestrictions,InputRestrictions) ,
125 conjunct_predicates([EnumeratedSetsConstraint,WellDefinednessConstraint,TypingPredicatesConj,ConstantRestrictions,InputRestrictions|FunctionConstraints],BehavioralConstraint) ,
126 append([LocationVarsIn,LocationVarsOut,ProgramInLocationVars],LocationVars).
127
128 enumerated_sets_constraint(EnumeratedSetsConstraint) :-
129 findall(SetName,b_get_machine_set(SetName),EnumeratedSets) ,
130 full_b_machine(BMachine) ,
131 get_section(enumerated_elements,BMachine,Elems),
132 enumerated_sets_constraint_aux(Elems,EnumeratedSets,TEnumeratedSetsConstraint) ,
133 conjunct_predicates(TEnumeratedSetsConstraint,EnumeratedSetsConstraint).
134
135 enumerated_sets_constraint_aux(_,[],[]).
136 enumerated_sets_constraint_aux(Elems,[SetName|T],[b(conjunct(Equality,DistinctConstraint),pred,[])|NT]) :-
137 findall(b(identifier(N),global(SetName),[]),member(b(identifier(N),global(SetName),_),Elems),EElems) ,
138 EElems \== [] , ! ,
139 Equality = b(equal(b(identifier(SetName),set(global(SetName)),[]),b(set_extension(EElems),set(global(SetName)),[])),pred,[]) ,
140 get_consistency_constraint(EElems,DistinctConstraint) ,
141 enumerated_sets_constraint_aux(Elems,T,NT).
142 enumerated_sets_constraint_aux(Elems,[_|T],NT) :-
143 enumerated_sets_constraint_aux(Elems,T,NT).
144
145 map_get_function_constraint(_,_,_,_,_,_,[],[],[],[]).
146 map_get_function_constraint(Operation,ExampleCount,Library,LibConstraint,InputVars,OutputVars,[Input|TIn],[Output|TOut],[FunctionConstraint|NTFunction],LocationVars) :-
147 get_function_constraint(Operation,ExampleCount,Library,LibConstraint,InputVars,OutputVars,Input,Output,FunctionConstraint,NewLocationVars) ,
148 NewExampleCount is ExampleCount + 1 ,
149 map_get_function_constraint(Operation,NewExampleCount,Library,LibConstraint,InputVars,OutputVars,TIn,TOut,NTFunction,NTLVars) ,
150 append(NewLocationVars,NTLVars,LocationVars).
151
152 get_function_constraint(Operation,ExampleCount,Library,LibConstraint,InputVars,OutputVars,InputValues,OutputValues,FunctionConstraint,LocationVars) :-
153 % add a predicate setting equalities to the machine variables for the current example, since we possibly consider additional set constants like c = {i}, where i is a machine variable
154 synthesis_util:create_equality_nodes_from_example(InputValues,InputEqualityList) ,
155 % in this context, we have to add the invariants setting the types of the machine variables
156 conjunct_predicates(InputEqualityList,InputEquality) ,
157 b_get_machine_variables(MachineVars) ,
158 findall(MachineVar,(member(InputValue,InputValues) , get_texpr_info(InputValue,Info) , member(synthesis(machinevar,CurrentVarName),Info) ,
159 member(MachineVar,MachineVars) , get_texpr_id(MachineVar,CurrentVarName)),CurrentVars) ,
160 b_get_typing_predicate_for_vars(CurrentVars,TypingMachineVarsPredicate) ,
161 get_line_amount(Operation,Library,InputValues,M) ,
162 % enumerate input/output values
163 enumerate_inputs_and_outputs(ExampleCount,InputValues,input,InputValueNodes) ,
164 enumerate_inputs_and_outputs(ExampleCount,OutputValues,output,OutputValueNodes) ,
165 get_connectivity_constraint(InputValueNodes,OutputValueNodes,InputVars,OutputVars,ConnectivityConstraint) ,
166 set_input_location_vars(InputValueNodes,InputLocationConstraint) ,
167 set_output_location_vars(OutputValueNodes,M,OutputLocationConstraint,OutputLocationVars) ,
168 conjunct_predicates([TypingMachineVarsPredicate,InputEquality,OutputLocationConstraint,InputLocationConstraint,LibConstraint,ConnectivityConstraint],ExistsBody) ,
169 % get all used identifier as ast nodes
170 find_typed_identifier_uses_with_info(ExistsBody,TListOfIDNodes) ,
171 remove_dup_id_nodes(TListOfIDNodes,ListOfIDNodes) ,
172 get_temporary_ids(ListOfIDNodes,TempTemporaryIDs) ,
173 append(TempTemporaryIDs,CurrentVars,TemporaryIDs) , % the machine variables are local to the exists quantifier which are used within the equalities to the machine variables
174 findall(LocationVar,(member(LocationVar,ListOfIDNodes) , LocationVar = b(identifier(Name),integer,_) , atom_concat(l,_,Name)),TempListOfLVarNodes) ,
175 append(TempListOfLVarNodes,OutputLocationVars,LocationVars) ,
176 % and their corresponding identifier names
177 maplist(get_texpr_id,ListOfIDNodes,UsedIDs) ,
178 ( unfold_existential_quantification(true)
179 -> set_unique_temporary_id_names(ExampleCount,TemporaryIDs,ExistsBody,FunctionConstraint)
180 ; FunctionConstraint = b(exists(TemporaryIDs,ExistsBody),pred,[used_ids(UsedIDs)])
181 ).
182
183 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,b(identifier(Name),Type,Info),b(identifier(UniqueName),Type,Info)) :-
184 member(b(identifier(Name),Type,_),TemporaryIDs) , ! ,
185 atom_codes(Name,NameCodes) ,
186 number_codes(ExampleCount,SuffixNumber) ,
187 append(NameCodes,[95|SuffixNumber],UniqueNameCodes) ,
188 atom_codes(UniqueName,UniqueNameCodes).
189 set_unique_temporary_id_names(_,_,b(identifier(Name),Type,Info),b(identifier(Name),Type,Info)).
190 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,b(Node,Type,Info),b(NewNode,Type,Info)) :-
191 Node =.. [Functor,Arg1,Arg2] , ! ,
192 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,Arg1,NewArg1) ,
193 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,Arg2,NewArg2) ,
194 NewNode =.. [Functor,NewArg1,NewArg2].
195 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,b(Node,Type,Info),b(NewNode,Type,Info)) :-
196 Node =.. [Functor,Arg] , ! ,
197 set_unique_temporary_id_names(ExampleCount,TemporaryIDs,Arg,NewArg) ,
198 NewNode =.. [Functor,NewArg].
199 set_unique_temporary_id_names(_,_,Ast,Ast).
200
201 create_typing_predicates_from_info([],b(truth,pred,[])).
202 create_typing_predicates_from_info([Node|T],TypingPredicatesConj) :-
203 create_typing_predicate_from_info(Node,TypingPredicate) ,
204 create_typing_predicates_from_info(T,TypingPredicate,TypingPredicatesConj).
205
206 create_typing_predicates_from_info([],Acc,Acc).
207 create_typing_predicates_from_info([Node|T],Acc,TypingPredicatesConj) :-
208 create_typing_predicate_from_info(Node,TypingPredicate) ,
209 create_texpr(conjunct(Acc,TypingPredicate),pred,[],NewAcc) ,
210 create_typing_predicates_from_info(T,NewAcc,TypingPredicatesConj).
211
212 create_typing_predicate_from_info(Node,b(member(Node,TypeAst),pred,[])) :-
213 get_texpr_info(Node,Info) ,
214 member(synthesis(type,Type),Info) ,
215 Type \= pred , ! ,
216 get_type_ast(Type,TypeAst).
217 create_typing_predicate_from_info(_,b(truth,pred,[])).
218
219 get_type_ast(global(IndependentType),b(identifier(IndependentType),set(global(IndependentType)),[])).
220 get_type_ast(set(global(IndependentType)),b(pow_subset(b(identifier(IndependentType),set(global(IndependentType)),[])),set(set(global(IndependentType))),[])) :- !.
221 get_type_ast(Nested,b(pow_subset(TypeAst),set(InnerType),[])) :-
222 Nested =.. [Functor,Type] ,
223 (Functor = set ; Functor = seq) ,
224 get_type_ast(Type,TypeAst),
225 TypeAst = b(_,InnerType,_).
226 get_type_ast(couple(A,B),b(cartesian_product(TA,TB),set(couple(A,B)),[])) :-
227 get_type_ast(A,TA) ,
228 get_type_ast(B,TB).
229 get_type_ast(integer,b(integer_set('INTEGER'),set(integer),[])).
230 get_type_ast(real,b(real_set,set(real),[])).
231 get_type_ast(string,b(string_set,set(string),[])).
232 get_type_ast(boolean,b(bool_set,set(boolean),[])).
233
234 restrict_constant_domains(_,_,_,[],[]).
235 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,[Out|T],[ConstantRestriction|Restrictions]) :-
236 is_integer_constant(Out) ,
237 ConstantRestriction = b(member(Out,b(interval(IntLowerBound,IntUpperBound),set(integer),[])),pred,[]) ,
238 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,T,Restrictions).
239 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,[Out|T],[ConstantRestriction|Restrictions]) :-
240 is_set_or_seq_constant(Out) ,
241 ConstantRestriction = b(less_equal(b(card(Out),integer,[]),CardUpperBound),pred,[]) ,
242 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,T,Restrictions).
243 % skip constants like boolean
244 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,[_|T],Restrictions) :-
245 restrict_constant_domains(IntLowerBound,IntUpperBound,CardUpperBound,T,Restrictions).
246
247 get_max_cardinality_from_examples(InputExamples,MaxCard) :-
248 flatten(InputExamples,InputSet) ,
249 findall(SetOrSeqNode,(member(SetOrSeqNode,InputSet) , get_texpr_type(SetOrSeqNode,Type) , (Type = set(_) ; Type = seq(_)) ,
250 get_texpr_info(SetOrSeqNode,Info) , member(synthesis(initial_example),Info)),SetOrSeqNodes) ,
251 SetOrSeqNodes \= [] , ! ,
252 findall(Card,(member(Node,SetOrSeqNodes) , b_compute_expression_nowf_no_bindings(b(card(Node),integer,[]),Card)),Cards) ,
253 (Cards = []
254 -> MaxCardExamples = 0
255 ; b_compute_expression_nowf_no_bindings(b(max(b(value(Cards),set(integer),[])),integer,[]),Res) , Res = int(MaxCardExamples)) ,
256 % subjectively add a limit of MaxCard + 3
257 MaxCard is MaxCardExamples + 3.
258 % zero if no sets or seq are given
259 get_max_cardinality_from_examples(_,0).
260
261 % Get the range of integer nodes from the initial examples to restrict constant domains.
262 get_range_of_integer_nodes_from_examples(_,InputExamples,InMin,InMax) :-
263 flatten(InputExamples,InputSet) ,
264 get_values_of_integer_nodes(InputSet,[],IntegerValues) ,
265 IntegerValues \= [] , ! ,
266 min_member(TInMin,IntegerValues) , max_member(TInMax,IntegerValues) ,
267 InMin is TInMin - 10 , InMax is TInMax + 10.
268 get_range_of_integer_nodes_from_examples(MaxCard,_,0,NMaxCard) :- % at least MaxCard + 5, e.g. card(x) > 5 but no integer is given
269 NMaxCard is MaxCard + 5.
270
271 % TODO: consider nested sets and seqs of integer for domain restrictions?
272 get_values_of_integer_nodes([],Acc,Acc).
273 get_values_of_integer_nodes([Input|T],Acc,IntegerValues) :-
274 % type is integer, set(integer) or seq(integer)
275 get_texpr_type(Input,Type) ,
276 get_values_of_integer_nodes_aux(Type,Input,Integer) ,
277 get_values_of_integer_nodes(T,[Integer|Acc],IntegerValues).
278 get_values_of_integer_nodes([_|T],Acc,IntegerValues) :-
279 % other type or empty set/seq
280 get_values_of_integer_nodes(T,Acc,IntegerValues).
281 get_values_of_integer_nodes_aux(integer,Input,Integer) :-
282 b_compute_expression_nowf_no_bindings(Input,Value) , Value = int(Integer).
283 get_values_of_integer_nodes_aux(set(integer),Input,Integer) :-
284 not_empty_set_or_seq(Input) , % max([]) is not well-defined
285 b_compute_expression_nowf_no_bindings(b(max(Input),integer,[]),Value) , Value = int(Integer).
286 get_values_of_integer_nodes_aux(set(integer),Input,Integer) :-
287 not_empty_set_or_seq(Input) , % same for empty sequences
288 b_compute_expression_nowf_no_bindings(b(max(b(range(Input),set(integer),[])),integer,[]),Value) , Value = int(Integer).
289
290 not_empty_set_or_seq(Input) :-
291 b_compute_expression_nowf_no_bindings(Input,Value) , Value \= [].
292
293 % TODO: same here, consider nested sets and seqs of integer?
294 get_bounds_for_node(Node,LowerIntBound,UpperIntBound,_,Restriction) :-
295 Node = b(_,integer,_) ,
296 Restriction = b(member(Node,b(interval(LowerIntBound,UpperIntBound),set(integer),[])),pred,[]).
297 get_bounds_for_node(Node,LowerIntBound,UpperIntBound,CardUpperBound,Restriction) :-
298 Node = b(_,Type,_) ,
299 Type = set(integer) ,
300 % we restrict the cardinality of sets of integers as well as the domain of their elements
301 Restriction = b(conjunct(b(less_equal(b(card(Node),integer,[]),CardUpperBound),pred,[]),
302 b(member(Node,b(pow_subset(b(interval(LowerIntBound,UpperIntBound),set(integer),[])),set(set(integer)),[])),pred,[])),pred,[]).
303 get_bounds_for_node(Node,_LowerIntBound,_UpperIntBound,CardUpperBound,Restriction) :-
304 Node = b(_,Type,_) ,
305 Type = seq(integer) ,
306 % we restrict the size of seqs of integers
307 % TODO: restrict domain of elements of seq(integer)
308 Restriction = b(less_equal(b(card(Node),integer,[]),CardUpperBound),pred,[]).
309 get_bounds_for_node(Node,_,_,CardUpperBound,Restriction) :-
310 Node = b(_,Type,_) ,
311 % either card or size for sets or sequences
312 (Type = set(InnerType) , Functor = card ; Type = seq(InnerType) , Functor = size) ,
313 InnerType \= integer ,
314 RestrNode =.. [Functor,Node] ,
315 % we restrict cardinality/size of sets/seqs with an other type than integer
316 Restriction = b(less_equal(b(RestrNode,integer,[]),CardUpperBound),pred,[]).
317
318 is_integer_constant(b(Node,integer,Info)) :-
319 is_constant(b(Node,integer,Info)).
320
321 is_set_or_seq_constant(b(Node,Type,Info)) :-
322 (Type = set(_) ; Type = seq(_)) ,
323 is_constant(b(Node,Type,Info)).
324
325 % all temporary library variables like i0,i1,o1 in exists node except 'constant'
326 get_temporary_ids([],[]).
327 get_temporary_ids([ID|T],[ID|NT]) :-
328 get_texpr_id(ID,Name) ,
329 % filter identifier nodes e.g. referring to enumerated sets or independent types
330 get_texpr_info(ID,Info) ,
331 member(synthesis(_,_),Info) ,
332 atom_codes(Name,[Char|_]) ,
333 Char \= 108 ,
334 \+atom_concat(constant,_,Name) , ! ,
335 get_temporary_ids(T,NT).
336 get_temporary_ids([_|T],NT) :-
337 get_temporary_ids(T,NT).
338
339 % we can have duplicate nodes because of undefined types of sets
340 remove_dup_id_nodes(Nodes,Distinct) :-
341 remove_dup_id_nodes(Nodes,[],Distinct).
342 remove_dup_id_nodes([],Acc,Acc).
343 remove_dup_id_nodes([Node|T],Acc,Distinct) :-
344 Node = b(identifier(Name),_,_) ,
345 \+member(b(identifier(Name),_,_),Acc) , ! ,
346 remove_dup_id_nodes(T,[Node|Acc],Distinct).
347 remove_dup_id_nodes([_|T],Acc,Distinct) :-
348 remove_dup_id_nodes(T,Acc,Distinct).
349
350 % define connections of temporary inputs and outputs
351 get_connectivity_constraint(InputExampleNodes,OutputExampleNodes,InputVars,OutputVars,ConnectivityConstraint) :-
352 append([InputVars,OutputVars,InputExampleNodes,OutputExampleNodes],SetOfVars) ,
353 findall((X,Y),(member(X,SetOfVars) , member(Y,SetOfVars) , X \= Y , nth0(I1,SetOfVars,X) , nth0(I2,SetOfVars,Y) , I1 < I2),ListOfVarPairs) ,
354 maplist(get_single_connectivity_constraint,ListOfVarPairs,ConstraintList) ,
355 conjunct_predicates(ConstraintList,ConnectivityConstraint).
356
357 get_single_connectivity_constraint((Var1,Var2),ConnectivityConstraint) :-
358 get_location_var_from_ast_node(Var1,LocationVar1) ,
359 get_location_var_from_ast_node(Var2,LocationVar2) ,
360 % only connect two variables if they have the same type
361 (valid_connection(Var1,Var2)
362 -> LHS = b(equal(LocationVar1,LocationVar2),pred,[]) ,
363 RHS = b(equal(Var1,Var2),pred,[]) ,
364 create_implication(LHS,RHS,ConnectivityConstraint)
365 % prevent equality of such incompatible location variables
366 ; ConnectivityConstraint = b(not_equal(LocationVar1,LocationVar2),pred,[])).
367
368 valid_connection(Var1,Var2) :-
369 get_texpr_info(Var1,Info1) ,
370 get_texpr_info(Var2,Info2) ,
371 % same type, we use the term synthesis(type,Type) from each node's info instead of the ast node's type
372 % reason: we use the type boolean for predicates and real boolean values since one cannot define an identifier of type pred, and thus,
373 % a boolean node representing a predicate contains the term synthesis(type,pred) whereat the node itself has the type boolean.
374 valid_type_connection(Info1,Info2) , ! ,
375 valid_connection_aux(Info1,Info2).
376
377 % Check if a location variable refers to an input location.
378 refers_to_input(Info) :-
379 member(synthesis(_,left_input),Info) ; member(synthesis(_,right_input),Info) ; member(synthesis(_,input),Info).
380
381 % TODO: maybe rewrite this more pretty, but we definitely have to consider both cases like we do in here
382 valid_connection_aux(Info1,Info2) :-
383 % machineconstants have fixed values, and thus, are not mapped to program input parameters
384 member(synthesis(machineconstant,_),Info1) ,
385 \+member(synthesis(input(_)),Info2).
386 valid_connection_aux(Info2,Info1) :-
387 member(synthesis(machineconstant,_),Info1) ,
388 \+member(synthesis(input(_)),Info2).
389 valid_connection_aux(Info1,Info2) :-
390 % if_then_else only on the top level of a program output
391 member(synthesis(ComponentName,output),Info1) ,
392 delete_numbers_from_atom(ComponentName,RawName) ,
393 RawName = if_then_else ,
394 member(synthesis(output(_)),Info2).
395 valid_connection_aux(Info2,Info1) :-
396 member(synthesis(ComponentName,output),Info1) ,
397 delete_numbers_from_atom(ComponentName,RawName) ,
398 RawName = if_then_else , ! ,
399 member(synthesis(output(_)),Info2).
400 % input of skip component only from program parameters, i.e., the first lines of the program, or the input of another component to not create a contradiction
401 valid_connection_aux(Info1,Info2) :-
402 member(synthesis(ComponentName,input),Info1) ,
403 delete_numbers_from_atom(ComponentName,RawName) ,
404 RawName = skip ,
405 (member(synthesis(input(_)),Info2) ; refers_to_input(Info2)).
406 valid_connection_aux(Info2,Info1) :-
407 member(synthesis(ComponentName,input),Info1) ,
408 delete_numbers_from_atom(ComponentName,RawName) ,
409 RawName = skip , ! ,
410 (member(synthesis(input(_)),Info2) ; refers_to_input(Info2)).
411 % output of skip component only for program output parameters, i.e., the last lines of the program, or as an if-statement's output
412 valid_connection_aux(Info1,Info2) :-
413 member(synthesis(ComponentName,output),Info1) ,
414 delete_numbers_from_atom(ComponentName,RawName) ,
415 RawName = skip ,
416 (member(synthesis(output(_)),Info2) ; is_if_statement_output(Info2)).
417 valid_connection_aux(Info2,Info1) :-
418 member(synthesis(ComponentName,output),Info1) ,
419 delete_numbers_from_atom(ComponentName,RawName) ,
420 RawName = skip ,! ,
421 (member(synthesis(output(_)),Info2) ; is_if_statement_output(Info2)).
422 % constant_set only right input of member
423 valid_connection_aux(Info1,Info2) :-
424 member(synthesis(ConstantSet,output),Info1) ,
425 delete_numbers_from_atom(ConstantSet,constant_set) , ! ,
426 member(synthesis(Member,right_input),Info2) ,
427 delete_numbers_from_atom(Member,Op) ,
428 (Op = member ; Op = not_member).
429 valid_connection_aux(Info2,Info1) :-
430 member(synthesis(ConstantSet,output),Info1) ,
431 delete_numbers_from_atom(ConstantSet,constant_set) , ! ,
432 member(synthesis(Member,right_input),Info2) ,
433 delete_numbers_from_atom(Member,Op) ,
434 (Op = member ; Op = not_member).
435 valid_connection_aux(Info1,Info2) :-
436 member(synthesis(type,boolean),Info1) ,
437 (member(synthesis(input(_)),Info2) ;
438 (member(synthesis(Comp2,_),Info2) , atom_concat(constant,_,Comp2))).
439 valid_connection_aux(Info2,Info1) :-
440 member(synthesis(type,boolean),Info1) ,
441 (member(synthesis(input(_)),Info2) ;
442 (member(synthesis(Comp2,_),Info2) , atom_concat(constant,_,Comp2))).
443 valid_connection_aux(Info1,Info2) :-
444 % input to output mapping is not possible in the synthesis constraint anyway, but explicitly prevent this here to support the solver (we use skip components for that)
445 member(synthesis(input(_)),Info1) , ! ,
446 \+member(synthesis(output(_)),Info2).
447 valid_connection_aux(Info2,Info1) :-
448 member(synthesis(input(_)),Info1) , ! ,
449 \+member(synthesis(output(_)),Info2).
450 valid_connection_aux(_,_).
451
452 valid_type_connection(Info1,Info2) :-
453 member(synthesis(type,Type1),Info1) ,
454 member(synthesis(type,Type2),Info2) ,
455 valid_type_connection_aux(Type1,Type2).
456
457 valid_type_connection_aux(Type,Type).
458 % Sequences can also be mapped to set of couples with integer keys. Well definedness is ensured
459 % by the well-definedness constraint, i.e., sequences have to be enumerated from 1..n
460 valid_type_connection_aux(Type1,Type2) :-
461 (Type1 = seq(InnerType) ; Type1 = set(couple(integer,InnerType))) ,
462 (Type2 = seq(InnerType) ; Type2 = set(couple(integer,InnerType))).
463
464 is_if_statement_output(Info) :-
465 (member(synthesis(Component,true_out),Info) ; member(synthesis(Component,false_out),Info)) ,
466 delete_numbers_from_atom(Component,RawComponent) , ! ,
467 RawComponent = if_then_else.
468
469 get_well_definedness_constraint(VarAmount,LocationVarsIn,LocationVarsOut,M,WellDefinednessConstraint) :-
470 get_consistency_constraint(LocationVarsOut,ConsistencyConstraint) ,
471 get_acyclic_constraint(LocationVarsIn,LocationVarsOut,AcyclicConstraint) ,
472 NewM is M - 1 , % minus one to use an interval
473 NewMInput is NewM - 1 , % no input location can get its value from the last line of the internal program
474 get_location_constraint(LocationVarsIn,0,NewMInput,InputRestriction) ,
475 get_location_constraint(LocationVarsOut,VarAmount,NewM,OutputRestriction) ,
476 restrict_if_statements_output_location(LocationVarsOut,VarAmount,NewM,IfOutputRestrictions) ,
477 conjunct_predicates([IfOutputRestrictions,InputRestriction,OutputRestriction,ConsistencyConstraint,AcyclicConstraint],
478 WellDefinednessConstraint).
479
480 % If-statements can only be used on the top level, that is, one of the program outputs.
481 restrict_if_statements_output_location(LocationVarsOut,VarAmount,NewM,IfOutputRestrictions) :-
482 LowerBound is NewM - VarAmount + 1 , % + 1 to use an interval
483 findall(IfOutputRestriction,(member(IfOutputLocation,LocationVarsOut) , get_texpr_info(IfOutputLocation,Info) , member(synthesis(Component,output),Info) ,
484 delete_numbers_from_atom(Component,RawComponent) , RawComponent = if_then_else ,
485 IfOutputRestriction = b(member(IfOutputLocation,b(interval(b(integer(LowerBound),integer,[]),b(integer(NewM),integer,[])),set(integer),[])),pred,[])),IfOutputRestrictionList) ,
486 conjunct_predicates(IfOutputRestrictionList,IfOutputRestrictions).
487
488 % create restriction nodes (membership to an interval) to the domain of each location variable
489 get_location_constraint(LocationVars,A,B,RestrictionNode) :-
490 maplist(get_single_location_constraint(A,B),LocationVars,RestrictionList) ,
491 conjunct_predicates(RestrictionList,RestrictionNode).
492 get_single_location_constraint(A,B,LocationVar,RestrictionNode) :-
493 RestrictionNode = b(member(LocationVar,
494 b(interval(b(integer(A),integer,[]),b(integer(B),integer,[])),set(integer),[])),pred,[]).
495
496 % consistency constraint guarantees that there is only one output in each line
497 get_consistency_constraint(LocationVarsOut,Constraint) :-
498 % find all pairs of location variables (not redundant) and create "not_equal"-Node for each pair
499 get_consistency_constraint_aux(LocationVarsOut,TConstraint) ,
500 %findall(InequalityNode,
501 % (member(L1,LocationVarsOut) , member(L2,LocationVarsOut) ,
502 % L1 \= L2 , nth0(I1,LocationVarsOut,L1) , nth0(I2,LocationVarsOut,L2) ,
503 % I1 < I2 , create_texpr(not_equal(L1,L2),pred,[],InequalityNode)),InequalityList) ,
504 conjunct_predicates(TConstraint,Constraint).
505
506 get_consistency_constraint_aux([],[]).
507 get_consistency_constraint_aux([LocationVarOut|T],[Inequality|NT]) :-
508 findall(b(not_equal(LocationVarOut,LVar),pred,[]),member(LVar,T),InequalityList) ,
509 conjunct_predicates(InequalityList,Inequality) ,
510 get_consistency_constraint_aux(T,NT).
511
512 % acyclic constraint guarantees that every operator's input is defined before its corresponding output
513 get_acyclic_constraint(LocationVarsIn,LocationVarsOut,Constraint) :-
514 get_acyclic_constraint_list(LocationVarsIn,LocationVarsOut,ConstraintList) ,
515 conjunct_predicates(ConstraintList,Constraint).
516 get_acyclic_constraint_list(_,[],[]).
517 get_acyclic_constraint_list(LocationVarsIn,[Out|ROut],[Constraint|ConstraintList]) :-
518 get_texpr_info(Out,Info) , member(synthesis(ComponentID,output),Info) ,
519 get_location_var_node_by_info_term(LocationVarsIn,synthesis(ComponentID,left_input),In1) ,
520 get_location_var_node_by_info_term(LocationVarsIn,synthesis(ComponentID,right_input),In2) ,
521 create_texpr(less(In1,Out),pred,[],Node1) ,
522 create_texpr(less(In2,Out),pred,[],Node2) ,
523 conjunct_predicates([Node1,Node2],Constraint) ,
524 get_acyclic_constraint_list(LocationVarsIn,ROut,ConstraintList).
525 get_acyclic_constraint_list(LocationVarsIn,[Out|ROut],[Constraint|ConstraintList]) :-
526 get_texpr_info(Out,Info) , member(synthesis(ComponentID,output),Info) ,
527 get_location_var_node_by_info_term(LocationVarsIn,synthesis(ComponentID,input),In) ,
528 create_texpr(less(In,Out),pred,[],Constraint) ,
529 get_acyclic_constraint_list(LocationVarsIn,ROut,ConstraintList).
530 % skip constants
531 get_acyclic_constraint_list(LocationVarsIn,[_|ROut],ConstraintList) :-
532 get_acyclic_constraint_list(LocationVarsIn,ROut,ConstraintList).
533
534 % Construct the library constraint by encoding the given library components as logical formulas.
535 get_library_constraint(InputValues,Components,(ValidGuards,Operation),Constraint,InputVars,OutputVars,EnumeratedConstants) :-
536 create_fixed_constants_to_insert_to_sets(InputValues,FixedSetConstantsConstraint) ,
537 maplist(get_single_component_constraint,Components,ConstraintList) ,
538 get_machine_constants_constraint(MachineConstantsConstraint) ,
539 get_operation_parameters_constraint(ValidGuards,Operation,OperationParametersConstraint) ,
540 conjunct_predicates([OperationParametersConstraint,FixedSetConstantsConstraint,MachineConstantsConstraint|ConstraintList],TConstraint) ,
541 find_typed_identifier_uses_with_info(TConstraint,ListOfIDNodes) ,
542 % split used identifier by input and output
543 findall(I,(member(I,ListOfIDNodes) , get_texpr_id(I,IName) , is_component_input(I) , atom_concat(i,_,IName)),InputVars) ,
544 findall(O,(member(O,ListOfIDNodes) , get_texpr_id(O,OName) , is_component_output(O) , atom_concat(o,_,OName)),OutputVars) ,
545 findall(C,(member(C,ListOfIDNodes) , is_enumerated_constant(C)),EnumeratedConstants) ,
546 get_library_wd_constraints(ListOfIDNodes,ListOfIDNodes,[],WDConstraintList) ,
547 conjunct_predicates([TConstraint|WDConstraintList],Constraint).
548
549 is_component_input(Node) :-
550 get_texpr_info(Node,Info) ,
551 (member(synthesis(_,left_input),Info) ; member(synthesis(_,right_input),Info) ; member(synthesis(_,input),Info)
552 ; member(synthesis(_,condition),Info) ; member(synthesis(_,true_out),Info) ; member(synthesis(_,false_out),Info)) , !.
553
554 is_component_output(Node) :-
555 get_texpr_info(Node,Info) ,
556 member(synthesis(_,output),Info) , !.
557
558 is_enumerated_constant(b(identifier(Name),_,Info)) :-
559 atom_concat(constant,_,Name) ,
560 member(synthesis(enumerated_constant),Info) , !.
561
562 :- dynamic additional_set_constants/1.
563 :- volatile additional_set_constants/1.
564
565 % We analyze the current machine variables and add additional set constants.
566 % B does not provide an operator to directly insert an element in a set. We provide set constants that
567 % are enumerated by the solver, but in this connection the solver is not able to consider machine variables,
568 % like enumerating a set constant to be {1,2,i} where i is an integer valued machine variable.
569 % To that effect, we add set constants containing a single machine variable, like c = {i} which then
570 % can be unified with a set. This is only necessary if, for instance, a set of integers as well as at least one integer
571 % valued machine variable is given.
572 create_fixed_constants_to_insert_to_sets(InputValues,FixedSetConstantsConstraint) :-
573 findall((MachineVarName,Type),(member(InputValue,InputValues) , get_texpr_info(InputValue,Info) ,
574 member(synthesis(type,Type),Info) , member(synthesis(machinevar,MachineVarName),Info)),MachineVarNameTypeTuples) ,
575 create_fixed_constants_to_insert_to_sets_aux(MachineVarNameTypeTuples,FixedSetConstantsConstraint).
576 % We do not need to add additional constants if no set is given.
577 create_fixed_constants_to_insert_to_sets_aux(MachineVarNameTypeTuples,b(truth,pred,[])) :-
578 retractall(additional_set_constants(_)) ,
579 assertz(additional_set_constants([])) ,
580 \+member((_,set(_)),MachineVarNameTypeTuples) , !.
581 % Otherwise, create additional set constants.
582 create_fixed_constants_to_insert_to_sets_aux(MachineVarNameTypeTuples,FixedSetConstantsConstraint) :-
583 get_set_types(MachineVarNameTypeTuples,TempSetTypes) ,
584 findall(NonSetTypeTuple,(member(NonSetTypeTuple,MachineVarNameTypeTuples) , NonSetTypeTuple = (_,Type) , \+member(Type,TempSetTypes)),NonSetTypeTupleTuples) ,
585 remove_dups(TempSetTypes,SetTypes) , % we only need one constant for an arbitrary amount of sets of this specific type, like one constant c = {i} for several sets of type integer
586 maplist(create_fixed_constants_to_insert_to_sets_aux2(SetTypes,[]),NonSetTypeTupleTuples,TempFixedSetConstantsConstraintList) ,
587 findall(FixedConstraint,(member(FixedConstraint,TempFixedSetConstantsConstraintList) , FixedConstraint \= []),FixedSetConstantsConstraintList) ,
588 retractall(additional_set_constants(_)) ,
589 assertz(additional_set_constants(FixedSetConstantsConstraintList)) ,
590 conjunct_predicates(FixedSetConstantsConstraintList,FixedSetConstantsConstraint).
591
592 create_fixed_constants_to_insert_to_sets_aux2([],[],_,[]). % do not use conjunct_predicates if Acc is an empty list since this create b(truth,pred,[])
593 create_fixed_constants_to_insert_to_sets_aux2([],Acc,_,FixedSetConstantsConstraint) :-
594 conjunct_predicates(Acc,FixedSetConstantsConstraint).
595 create_fixed_constants_to_insert_to_sets_aux2([SetType|T],Acc,NonSetTypeTuple,FixedSetConstantsConstraint) :-
596 create_fixed_constant_for_set_and_machine_var_type(SetType,NonSetTypeTuple,FixedConstantValue) , ! ,
597 unique_typed_id("o",SetType,TempOut) ,
598 get_texpr_id(TempOut,OutId) ,
599 add_texpr_infos(TempOut,[synthesis(OutId,output),synthesis(type,SetType),synthesis(machineconstant,FixedConstantValue)],Out) ,
600 create_texpr(equal(Out,FixedConstantValue),pred,[],FixedConstant) ,
601 create_fixed_constants_to_insert_to_sets_aux2(T,[FixedConstant|Acc],NonSetTypeTuple,FixedSetConstantsConstraint).
602 create_fixed_constants_to_insert_to_sets_aux2([_|T],Acc,NonSetTypeTuple,FixedSetConstantsConstraint) :-
603 % skip: the set type does not match the machine var type, that is, NonSetTypeTuple
604 create_fixed_constants_to_insert_to_sets_aux2(T,Acc,NonSetTypeTuple,FixedSetConstantsConstraint).
605
606 % Fails if the inner type of the set does not match the machine var type, that is, NonSetTypeTuple
607 create_fixed_constant_for_set_and_machine_var_type(InnerType,(MachineVarName,InnerType),MachineVar) :-
608 b_get_machine_variables(MachineVars) ,
609 member(MachineVar,MachineVars) ,
610 get_texpr_id(MachineVar,IdName) , IdName = MachineVarName.
611 % We also consider nested sets of sets here.
612 create_fixed_constant_for_set_and_machine_var_type(set(InnerType),NonSetTypeTuple,b(set_extension([PartialFixedConstant]),set(InnerType),[])) :-
613 create_fixed_constant_for_set_and_machine_var_type(InnerType,NonSetTypeTuple,PartialFixedConstant).
614
615 get_set_types(MachineVarNameTypeTuples,SetTypes) :-
616 get_set_types_aux(MachineVarNameTypeTuples,[],SetTypes).
617 get_set_types_aux([],Acc,Acc).
618 get_set_types_aux([(_,set(InnerType))|T],Acc,SetTypes) :- ! ,
619 get_set_types_aux(T,[set(InnerType)|Acc],SetTypes).
620 get_set_types_aux([_|T],Acc,SetTypes) :-
621 get_set_types_aux(T,Acc,SetTypes).
622
623 % Create synthesis constants for operation parameters and consider the valid guards of the operation which hold
624 % the typing of each parameter (this assumption is a fact since otherwise the machine is not well-defined).
625 get_operation_parameters_constraint(ValidGuards,Operation,OperationParametersConstraint) :-
626 b_get_machine_operation(Operation,_,OperationParameters,_) , ValidGuards \= [] , ! ,
627 get_operation_parameters_constraint_aux(OperationParameters,[],ConstraintList) ,
628 get_operation_parameters_constraint_aux2(ValidGuards,ConstraintList,OperationParametersConstraint).
629 % The operation does not exist yet, e.g., because we synthesize a new operation from scratch.
630 get_operation_parameters_constraint(_,_,b(truth,pred,[])).
631
632 get_operation_parameters_constraint_aux([],Acc,Acc).
633 get_operation_parameters_constraint_aux([OperationParameter|T],Acc,ConstraintList) :-
634 get_texpr_type(OperationParameter,ParameterType) ,
635 get_texpr_id(OperationParameter,ParameterName) ,
636 unique_typed_id("o",ParameterType,TempOut) ,
637 add_texpr_infos(TempOut,[synthesis(ParameterName,output),synthesis(type,ParameterType),synthesis(operationparameter,OperationParameter)],Out) ,
638 create_texpr(equal(Out,OperationParameter),pred,[],Constraint) ,
639 get_machine_constants_constraint_aux(T,[Constraint|Acc],ConstraintList).
640
641 get_operation_parameters_constraint_aux2(_,[],b(truth,pred,[])).
642 get_operation_parameters_constraint_aux2(ValidGuards,ConstraintList,OperationParametersConstraint) :-
643 append(ValidGuards,ConstraintList,NewConstraintList) ,
644 conjunct_predicates(NewConstraintList,OperationParametersConstraint).
645
646 % Create synthesis constants for machine constants and consider the machine properties defining the values of
647 % machine constants. Therefore, these synthesis constants will not be enumerated by the solver.
648 get_machine_constants_constraint(MachineConstantsConstraint) :-
649 b_get_machine_constants(MachineConstants) ,
650 get_machine_constants_constraint_aux(MachineConstants,[],ConstraintList) ,
651 conjunct_predicates(ConstraintList,MachineConstantsConstraint).
652
653 get_machine_constants_constraint_aux([],Acc,[MachineProperties|Acc]) :-
654 % append the machine properties defining the machine constants
655 b_get_properties_from_machine(MachineProperties).
656 get_machine_constants_constraint_aux([MachineConstant|T],Acc,ConstraintList) :-
657 get_texpr_type(MachineConstant,ConstantType) ,
658 get_texpr_id(MachineConstant,ConstantName) ,
659 unique_typed_id("o",ConstantType,TempOut) ,
660 add_texpr_infos(TempOut,[synthesis(ConstantName,output),synthesis(type,ConstantType),synthesis(machineconstant,MachineConstant)],Out) ,
661 create_texpr(equal(Out,MachineConstant),pred,[],Constraint) ,
662 get_machine_constants_constraint_aux(T,[Constraint|Acc],ConstraintList).
663
664 % Create well-definedness constraints to prevent division by zero, max/min of empty sets or
665 % front/tail/last/first/perm on empty sequences or power_of with a negative number.
666 get_library_wd_constraints(_,[],Acc,Acc).
667 get_library_wd_constraints(ListOfIDNodes,[b(Node,Type,Info)|T],Acc,WDConstraintList) :-
668 \+member(synthesis(_,output),Info) ,
669 member(synthesis(OpName,_),Info) ,
670 get_library_wd_constraints_aux(ListOfIDNodes,OpName,b(Node,Type,Info),AccWDConstraint) ,
671 get_library_wd_constraints(ListOfIDNodes,T,[AccWDConstraint|Acc],WDConstraintList).
672 get_library_wd_constraints(ListOfIDNodes,[_|T],Acc,WDConstraintList) :-
673 get_library_wd_constraints(ListOfIDNodes,T,Acc,WDConstraintList).
674
675 get_library_wd_constraints_aux(ListOfIDNodes,OpName,_,b(less_equal(LeftInput,RightInput),pred,[])) :-
676 % left input of interval is smaller or equal than the right input
677 delete_numbers_from_atom(OpName,RawOpName) ,
678 RawOpName = interval ,
679 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,left_input),LeftInput) ,
680 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,right_input),RightInput).
681 get_library_wd_constraints_aux(ListOfIDNodes,OpName,_,b(conjunct(b(greater(LeftInput,b(integer(-1),integer,[])),pred,[]),b(greater(RightInput,b(integer(-1),integer,[])),pred,[])),pred,[])) :-
682 % modulo only for positive numbers
683 delete_numbers_from_atom(OpName,RawOpName) ,
684 RawOpName = modulo ,
685 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,left_input),LeftInput) ,
686 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,right_input),RightInput).
687 get_library_wd_constraints_aux(ListOfIDNodes,OpName,_,b(not_equal(LeftInput,RightInput),pred,[])) :-
688 % prohibit the same inputs for subset/subset_strict like 's <<: s'
689 delete_numbers_from_atom(OpName,RawOpName) ,
690 member(RawOpName,[subset]) , % subset_strict (union and intersection is too restrictive here)
691 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,left_input),LeftInput) ,
692 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,right_input),RightInput).
693 get_library_wd_constraints_aux(_,OpName,Node,b(not_equal(Node,b(integer(0),integer,[])),pred,[])) :-
694 % to only check division by zero we would need to check that the variable is the right input, thus the denominator,
695 % but we also want to prevent 0/c since this is just the constant value 0
696 delete_numbers_from_atom(OpName,div).
697 get_library_wd_constraints_aux(ListOfIDNodes,OpName,_,b(member(RightInput,b(interval(b(integer(0),integer,[]),b(integer(10),integer,[])),set(integer),[])),pred,[])) :-
698 % the exponent of power_of has to be positive and we furthermore restrict the exponent to be less or equal to 10
699 delete_numbers_from_atom(OpName,RawOpName) ,
700 RawOpName = power_of ,
701 get_var_node_by_info_term(ListOfIDNodes,synthesis(OpName,right_input),RightInput).
702 get_library_wd_constraints_aux(_,OpName,Node,b(greater(b(card(Node),integer,[]),b(integer(0),integer,[])),pred,[])) :-
703 delete_numbers_from_atom(OpName,RawOpName) ,
704 member(RawOpName,[max,min,front,tail,first,last,perm,general_intersection]).
705
706 % Library components represented as logical formulas.
707
708 get_single_component_constraint(if_then_else-Type,Constraint) :-
709 unique_typed_id("i",boolean,TempCondition) ,
710 unique_typed_id("i",Type,TempIn1) ,
711 unique_typed_id("i",Type,TempIn2) ,
712 unique_typed_id("o",Type,TempOut) ,
713 set_component_id(if_then_else,UniqueComponent) ,
714 % set information of identifier nodes
715 add_texpr_infos(TempCondition,[synthesis(type,pred),synthesis(UniqueComponent,condition)],Condition) ,
716 add_texpr_infos(TempIn1,[synthesis(type,Type),synthesis(UniqueComponent,true_out)],In1) ,
717 add_texpr_infos(TempIn2,[synthesis(type,Type),synthesis(UniqueComponent,false_out)],In2) ,
718 add_texpr_infos(TempOut,[synthesis(type,Type),synthesis(UniqueComponent,output)],Out) ,
719 Node = if_then_else(Condition,In1,In2) ,
720 Constraint = b(equal(b(Node,Type,[]),Out),pred,[]).
721 % (INTEGER,INTEGER) :: INTEGER
722 get_single_component_constraint(Component,Constraint) :-
723 member(Component,[add,minus,multiplication,div,modulo,power_of]) , ! ,
724 unique_typed_id("i",integer,TempIn1) ,
725 unique_typed_id("i",integer,TempIn2) ,
726 unique_typed_id("o",integer,TempOut) ,
727 set_component_id(Component,UniqueComponent) ,
728 % set information of identifier nodes
729 add_texpr_infos(TempIn1,[synthesis(type,integer),synthesis(UniqueComponent,left_input)],In1) ,
730 add_texpr_infos(TempIn2,[synthesis(type,integer),synthesis(UniqueComponent,right_input)],In2) ,
731 add_texpr_infos(TempOut,[synthesis(type,integer),synthesis(UniqueComponent,output)],Out) ,
732 Node =.. [Component,In1,In2] ,
733 Constraint = b(equal(b(Node,integer,[]),Out),pred,[]).
734 % TYPE :: TYPE
735 get_single_component_constraint(skip-Type,b(equal(In,Out),pred,[])) :-
736 % We can't map inputs to outputs directly since input parameters are located in the first lines of the program
737 % whereat output parameter are located in the last lines, and thus, their locations can't match.
738 % Therefore, we use a simple wrapper allowing to connect input to output locations implicitly to skip values.
739 unique_typed_id("i",Type,TempIn) ,
740 unique_typed_id("o",Type,TempOut) ,
741 set_component_id(skip,ComponentName) ,
742 add_texpr_infos(TempIn,[synthesis(ComponentName,input),synthesis(type,Type)],In) ,
743 add_texpr_infos(TempOut,[synthesis(ComponentName,output),synthesis(type,Type)],Out).
744 % (BOOLEAN,BOOLEAN) :: BOOLEAN
745 /*get_single_component_constraint(Operator,Constraint) :-
746 member(Operator,[conjunct,disjunct,implication,equivalence]) , ! ,
747 unique_typed_id("i",boolean,TempIn1) ,
748 unique_typed_id("i",boolean,TempIn2) ,
749 unique_typed_id("o",boolean,TempOut) ,
750 set_component_id(Operator,ComponentName) ,
751 % set information of identifier nodes
752 add_texpr_infos(TempIn1,[synthesis(ComponentName,left_input),synthesis(type,pred)],In1) ,
753 add_texpr_infos(TempIn2,[synthesis(ComponentName,right_input),synthesis(type,pred)],In2) ,
754 add_texpr_infos(TempOut,[synthesis(ComponentName,output),synthesis(type,pred)],Out) ,
755 Node =.. [Operator,In1,In2] ,
756 Constraint = b(equal(Out,b(convert_bool(b(Node,pred,[])),boolean,[])),pred,[]).*/
757 get_single_component_constraint(Operator,Constraint) :-
758 member(Operator,[conjunct,disjunct,implication,equivalence]) , ! ,
759 unique_typed_id("i",boolean,TempIn1) ,
760 unique_typed_id("i",boolean,TempIn2) ,
761 unique_typed_id("o",boolean,TempOut) ,
762 set_component_id(Operator,ComponentName) ,
763 % set information of identifier nodes
764 add_texpr_infos(TempIn1,[synthesis(ComponentName,left_input),synthesis(type,pred)],In1) ,
765 add_texpr_infos(TempIn2,[synthesis(ComponentName,right_input),synthesis(type,pred)],In2) ,
766 add_texpr_infos(TempOut,[synthesis(ComponentName,output),synthesis(type,pred)],Out) ,
767 get_logical_constraint(Operator,In1,In2,Out,Truth,Falsity) ,
768 disjunct_predicates([Truth,Falsity],Constraint).
769 % (PRED) :: BOOLEAN
770 get_single_component_constraint(convert_bool,Constraint) :-
771 unique_typed_id("i",boolean,TempIn) ,
772 unique_typed_id("o",boolean,TempOut) ,
773 set_component_id(convert_bool,ComponentName) ,
774 % set information of identifier nodes
775 add_texpr_infos(TempIn,[synthesis(ComponentName,input),synthesis(type,pred)],In) ,
776 add_texpr_infos(TempOut,[synthesis(ComponentName,output),synthesis(type,boolean)],Out) ,
777 Constraint = b(equal(Out,In),pred,[]).
778 % (BOOLEAN :: BOOLEAN)
779 get_single_component_constraint(negation,Constraint) :- ! ,
780 unique_typed_id("i",boolean,TempIn) ,
781 unique_typed_id("o",boolean,TempOut) ,
782 set_component_id(negation,Negation) ,
783 % set information of identifier nodes
784 add_texpr_infos(TempIn,[synthesis(Negation,input),synthesis(type,pred)],In) ,
785 add_texpr_infos(TempOut,[synthesis(Negation,output),synthesis(type,pred)],Out) ,
786 Truth = b(conjunct(b(equal(In,b(boolean_false,boolean,[])),pred,[]),
787 b(equal(Out,b(boolean_true,boolean,[])),pred,[])),pred,[]) ,
788 Falsity = b(conjunct(b(equal(In,b(boolean_true,boolean,[])),pred,[]),
789 b(equal(Out,b(boolean_false,boolean,[])),pred,[])),pred,[]) ,
790 disjunct_predicates([Truth,Falsity],Constraint).
791 % explicit set constants referring to enumerated/deferred sets accessed via operation parameters
792 % create two constants p and {p} for each operation parameter p
793 % both constants are set up in one call to ensure that the shared identifier p is the same
794 get_single_component_constraint(param_constant-global(_),b(truth,pred,[])). % so we skip here and set the constraint below
795 get_single_component_constraint(param_constant-set(global(IndependentType)),Constraint) :-
796 get_single_constant_or_set_operator_id(constant-global(IndependentType),TempOutSingle,ConstantSingle) ,
797 get_single_constant_or_set_operator_id(constant-set(global(IndependentType)),TempOutSet,ConstantSet) , ! ,
798 get_texpr_id(ConstantSingle,ConstantSingleName) ,
799 get_texpr_id(ConstantSet,ConstantSetName) ,
800 ParamId = b(identifier(ParamName),global(IndependentType),[synthesis(ConstantSingleName,output),synthesis(type,global(IndependentType)),synthesis(param_single,ParamName),synthesis(ConstantSetName,output),synthesis(type,set(global(IndependentType))),synthesis(param_set,ParamName)]) , % the same parameter identifier p for both constants c1 = p, c2 = {p}
801 % set information of identifier node
802 add_texpr_infos(TempOutSingle,[synthesis(ConstantSingleName,output),synthesis(type,global(IndependentType)),synthesis(param_single,ParamName)],OutSingle) ,
803 add_texpr_infos(TempOutSet,[synthesis(ConstantSetName,output),synthesis(type,set(global(IndependentType))),synthesis(param_set,ParamName)],OutSet) ,
804 atom_concat(p_,IndependentType,ParamName) ,
805 MachineSet = b(identifier(IndependentType),set(global(IndependentType)),[]) ,
806 Constraint = b(conjunct(b(conjunct(b(member(ParamId,MachineSet),pred,[]),b(equal(b(set_extension([ParamId]),set(global(IndependentType)),[]),OutSet),pred,[])),pred,[]),b(equal(ParamId,OutSingle),pred,[])),pred,[]).
807 % constant :: (INTEGER,BOOLEAN,SET)
808 get_single_component_constraint(constant-Type,Constraint) :-
809 get_single_constant_or_set_operator_id(constant-Type,TempOut,Constant) , ! ,
810 get_texpr_id(Constant,ConstantName) ,
811 % set information of identifier node
812 add_texpr_infos(TempOut,[synthesis(ConstantName,output),synthesis(type,Type)],Out) ,
813 Constraint = b(equal(Constant,Out),pred,[]).
814 % bool_set, string_set, integer_set,..
815 get_single_component_constraint(Operator,Constraint) :-
816 get_single_constant_or_set_operator_id(Operator,TempOut,b(_,Type,_)) , ! ,
817 unique_typed_id("constant_set",Type,b(identifier(ConstantName),Type,Info)) ,
818 add_texpr_infos(TempOut,[synthesis(ConstantName,output),synthesis(type,Type)],Out) ,
819 % TODO: define as subset to avoid infinite sets (virtual timeout) ?
820 Constraint = b(equal(Out,b(identifier(ConstantName),Type,Info)),pred,[]).
821 % set-expressions
822 % SET :: INTEGER
823 get_single_component_constraint(Operator,Constraint) :-
824 member(Operator,[min,max]) ,
825 unique_typed_id("i",set(integer),TempIn) ,
826 unique_typed_id("o",integer,TempOut) ,
827 set_component_id(Operator,InternalName) ,
828 add_texpr_infos(TempIn,[synthesis(InternalName,input),synthesis(type,set(integer))],In) ,
829 add_texpr_infos(TempOut,[synthesis(InternalName,output),synthesis(type,integer)],Out) ,
830 Node =.. [Operator,In] ,
831 Constraint = b(equal(b(Node,integer,[]),Out),pred,[]).
832 get_single_component_constraint(card-SetType,Constraint) :-
833 unique_typed_id("i",SetType,TempIn) ,
834 unique_typed_id("o",integer,TempOut) ,
835 set_component_id(card,InternalName) ,
836 add_texpr_infos(TempIn,[synthesis(InternalName,input),synthesis(type,SetType)],In) ,
837 add_texpr_infos(TempOut,[synthesis(InternalName,output),synthesis(type,integer)],Out) ,
838 Constraint = b(equal(b(card(In),integer,[]),Out),pred,[]).
839 % SET :: SET(SET)
840 get_single_component_constraint(Operator-SetType,Constraint) :-
841 member(Operator,[pow_subset,pow_subset1,fin_subset,fin1_subset]) ,
842 unique_typed_id("i",SetType,TempIn) ,
843 unique_typed_id("o",set(SetType),TempOut) ,
844 set_component_id(Operator,NOperator) ,
845 add_texpr_infos(TempIn,[synthesis(NOperator,input),synthesis(type,SetType)],In) ,
846 add_texpr_infos(TempOut,[synthesis(NOperator,output),synthesis(type,set(SetType))],Out) ,
847 Node =.. [Operator,In] ,
848 Constraint = b(equal(b(Node,set(SetType),[]),Out),pred,[]).
849 % SEQ(TYPE) :: SET(SEQ(TYPE))
850 get_single_component_constraint(Operator-SetType,Constraint) :-
851 member(Operator,[seq,seq1,iseq]) ,
852 SetType = set(InnerType) ,
853 unique_typed_id("i",SetType,TempIn) ,
854 unique_typed_id("o",set(seq(InnerType)),TempOut) ,
855 set_component_id(Operator,InternalName) ,
856 add_texpr_infos(TempIn,[synthesis(InternalName,input),synthesis(type,SetType)],In) ,
857 add_texpr_infos(TempOut,[synthesis(InternalName,output),synthesis(type,set(seq(InnerType)))],Out) ,
858 Node =.. [Operator,In] ,
859 Constraint = b(equal(b(Node,set(seq(InnerType)),[]),Out),pred,[]).
860 % SEQ(TYPE) :: SET(SEQ(TYPE))
861 get_single_component_constraint(perm-SeqType,b(equal(b(perm(In),OutputType,[]),Out),pred,[])) :-
862 get_perm_component_output_type(SeqType,OutputType) ,
863 unique_typed_id("i",SeqType,TempIn) ,
864 unique_typed_id("o",OutputType,TempOut) ,
865 set_component_id(perm,InternalName) ,
866 add_texpr_infos(TempIn,[synthesis(InternalName,input),synthesis(type,SeqType)],In) ,
867 add_texpr_infos(TempOut,[synthesis(InternalName,output),synthesis(type,OutputType)],Out).
868 % SEQ(TYPE) :: SET(SEQ(TYPE))
869 get_single_component_constraint(interval,b(equal(b(interval(In1,In2),set(integer),[]),Out),pred,[])) :-
870 unique_typed_id("i",integer,TempIn1) ,
871 unique_typed_id("i",integer,TempIn2) ,
872 unique_typed_id("o",set(integer),TempOut) ,
873 set_component_id(interval,InternalName) ,
874 add_texpr_infos(TempIn1,[synthesis(InternalName,left_input),synthesis(type,integer)],In1) ,
875 add_texpr_infos(TempIn2,[synthesis(InternalName,right_input),synthesis(type,integer)],In2) ,
876 add_texpr_infos(TempOut,[synthesis(InternalName,output),synthesis(type,set(integer))],Out).
877 % SET :: SET
878 get_single_component_constraint(Operator-SetType,Constraint) :-
879 member(Operator,[closure,reflexive_closure]) ,
880 unique_typed_id("i",SetType,TempIn) ,
881 unique_typed_id("o",SetType,TempOut) ,
882 set_component_id(Operator,NOperator) ,
883 add_texpr_infos(TempIn,[synthesis(NOperator,input),synthesis(type,SetType)],In) ,
884 add_texpr_infos(TempOut,[synthesis(NOperator,output),synthesis(type,SetType)],Out) ,
885 Node =.. [Operator,In] ,
886 Constraint = b(equal(b(Node,SetType,[]),Out),pred,[]).
887 % (SET,SET) :: SET
888 get_single_component_constraint(Operator-SetType,Constraint) :-
889 member(Operator,[union,intersection,concat,insert_front,insert_tail,restrict_front,
890 restrict_tail,overwrite,set_subtraction,image,cartesian_product,
891 domain_restriction,domain_subtraction,range_restriction,range_subtraction]) ,
892 get_single_component_constraint_aux3(Operator-SetType,TempIn1,TempIn2,TempOut,Operator) ,
893 set_component_id(Operator,NOperator) ,
894 get_texpr_type(TempIn1,In1Type) ,
895 get_texpr_type(TempIn2,In2Type) ,
896 get_texpr_type(TempOut,OutType) ,
897 add_texpr_infos(TempIn1,[synthesis(NOperator,left_input),synthesis(type,In1Type)],In1) ,
898 add_texpr_infos(TempIn2,[synthesis(NOperator,right_input),synthesis(type,In2Type)],In2) ,
899 add_texpr_infos(TempOut,[synthesis(NOperator,output),synthesis(type,OutType)],Out) ,
900 Node =.. [Operator,In1,In2] ,
901 Constraint = b(equal(b(Node,SetType,[]),Out),pred,[]).
902 get_single_component_constraint(Operator-SetType,Constraint) :-
903 member(Operator,[first,last,front,tail,general_union,general_intersection,reverse,range,domain]) ,
904 get_single_component_constraint_aux3(Operator-SetType,TempIn,_,TempOut,Operator) ,
905 set_component_id(Operator,NOperator) ,
906 get_texpr_type(TempIn,InType) ,
907 get_texpr_type(TempOut,OutType) ,
908 add_texpr_infos(TempIn,[synthesis(NOperator,input),synthesis(type,InType)],In) ,
909 add_texpr_infos(TempOut,[synthesis(NOperator,output),synthesis(type,OutType)],Out) ,
910 Node =.. [Operator,In] ,
911 Constraint = b(equal(b(Node,SetType,[]),Out),pred,[]).
912 get_single_component_constraint(size-SetType,Constraint) :-
913 get_fn_types(SetType,integer,Type) ,
914 unique_typed_id("i",seq(Type),TempIn) ,
915 unique_typed_id("o",integer,TempOut) ,
916 set_component_id(size,NOperator) ,
917 add_texpr_infos(TempIn,[synthesis(NOperator,input),synthesis(type,seq(Type))],In) ,
918 add_texpr_infos(TempOut,[synthesis(NOperator,output),synthesis(type,integer)],Out) ,
919 Constraint = b(equal(b(size(In),integer,[]),Out),pred,[]).
920
921 % (INTEGER,INTEGER) :: BOOLEAN || (BOOLEAN,BOOLEAN) :: BOOLEAN || (SET,SET) :: BOOLEAN
922 get_single_component_constraint(Operator,Truth) :-
923 get_single_component_constraint_aux2(Operator,TempIn1,TempIn2,TempOut,Op) ,
924 set_component_id(Op,NOperator) ,
925 add_texpr_infos(TempIn1,[synthesis(NOperator,left_input)],In1) ,
926 add_texpr_infos(TempIn2,[synthesis(NOperator,right_input)],In2) ,
927 add_texpr_infos(TempOut,[synthesis(NOperator,output)],Out) ,
928 TempTrueNode =.. [Op,In1,In2] ,
929 TrueNode = b(TempTrueNode,pred,[]) ,
930 BoolNodeTrue = b(equal(Out,b(boolean_true,boolean,[])),pred,[]) ,
931 create_equivalence(TrueNode,BoolNodeTrue,Truth).
932
933 get_single_component_constraint_aux2(Operator-Type,In1,In2,Out,Operator) :-
934 member(Operator,[equal,not_equal,subset,subset_strict,not_subset,not_subset_strict]) , ! ,
935 unique_typed_id("i",Type,TempIn1) ,
936 unique_typed_id("i",Type,TempIn2) ,
937 unique_typed_id("o",boolean,TempOut) ,
938 add_texpr_infos(TempIn1,[synthesis(type,Type)],In1) ,
939 add_texpr_infos(TempIn2,[synthesis(type,Type)],In2) ,
940 add_texpr_infos(TempOut,[synthesis(type,pred)],Out).
941 get_single_component_constraint_aux2(Operator-SetType,In1,In2,Out,Operator) :-
942 member(Operator,[member,not_member]) , ! ,
943 (SetType = set(Type) ; SetType = seq(Type)) ,
944 unique_typed_id("i",Type,TempIn1) ,
945 unique_typed_id("i",SetType,TempIn2) ,
946 unique_typed_id("o",boolean,TempOut) ,
947 add_texpr_infos(TempIn1,[synthesis(type,Type)],In1) ,
948 add_texpr_infos(TempIn2,[synthesis(type,SetType)],In2) ,
949 add_texpr_infos(TempOut,[synthesis(type,pred)],Out).
950 % greater,greater_equal,less,..
951 get_single_component_constraint_aux2(Operator,In1,In2,Out,Operator) :-
952 unique_typed_id("i",integer,TempIn1) ,
953 unique_typed_id("i",integer,TempIn2) ,
954 unique_typed_id("o",boolean,TempOut) ,
955 add_texpr_infos(TempIn1,[synthesis(type,integer)],In1) ,
956 add_texpr_infos(TempIn2,[synthesis(type,integer)],In2) ,
957 add_texpr_infos(TempOut,[synthesis(type,pred)],Out).
958
959 % set- and seq-expressions
960 get_single_component_constraint_aux3(Operator-SetType,TempIn,_,TempOut,Operator) :-
961 member(Operator,[general_union,general_intersection]) ,
962 unique_typed_id("i",SetType,TempIn) ,
963 SetType = set(InnerType) ,
964 unique_typed_id("o",InnerType,TempOut).
965 get_single_component_constraint_aux3(image-SetType,TempIn1,TempIn2,TempOut,image) :-
966 get_fn_types(SetType,A,B) ,
967 unique_typed_id("i",set(couple(A,B)),TempIn1) ,
968 unique_typed_id("i",set(A),TempIn2) ,
969 unique_typed_id("o",set(B),TempOut).
970 get_single_component_constraint_aux3(cartesian_product-SetType,TempIn1,TempIn2,TempOut,cartesian_product) :-
971 SetType = set(InnerType) , % TODO: what about cartesian product of two differently typed sets?
972 unique_typed_id("i",set(InnerType),TempIn1) ,
973 unique_typed_id("i",set(InnerType),TempIn2) ,
974 unique_typed_id("o",set(couple(InnerType,InnerType)),TempOut).
975 get_single_component_constraint_aux3(Operator-SetType,TempIn1,TempIn2,TempOut,Operator) :-
976 member(Operator,[domain_restriction,domain_subtraction]) ,
977 get_fn_types(SetType,A,B) ,
978 unique_typed_id("i",set(A),TempIn1) ,
979 unique_typed_id("i",set(couple(A,B)),TempIn2) ,
980 unique_typed_id("o",set(couple(A,B)),TempOut).
981 get_single_component_constraint_aux3(Operator-SetType,TempIn1,TempIn2,TempOut,Operator) :-
982 member(Operator,[range_restriction,range_subtraction]) ,
983 get_fn_types(SetType,A,B) ,
984 unique_typed_id("i",set(couple(A,B)),TempIn1) ,
985 unique_typed_id("i",set(B),TempIn2) ,
986 unique_typed_id("o",set(couple(A,B)),TempOut).
987 get_single_component_constraint_aux3(reverse-SeqType,TempIn,_,TempOut,reverse) :-
988 unique_typed_id("i",SeqType,TempIn) ,
989 unique_typed_id("o",SeqType,TempOut).
990 get_single_component_constraint_aux3(domain-SetType,TempIn,_,TempOut,domain) :-
991 get_fn_types(SetType,A,_) ,
992 unique_typed_id("i",SetType,TempIn) ,
993 unique_typed_id("o",set(A),TempOut).
994 get_single_component_constraint_aux3(range-SetType,TempIn,_,TempOut,range) :-
995 get_fn_types(SetType,_,B) ,
996 unique_typed_id("i",SetType,TempIn) ,
997 unique_typed_id("o",set(B),TempOut).
998 get_single_component_constraint_aux3(Operator-SetType,TempIn1,TempIn2,TempOut,Operator) :-
999 member(Operator,[union,intersection,set_subtraction]) ,
1000 unique_typed_id("i",SetType,TempIn1) ,
1001 unique_typed_id("i",SetType,TempIn2) ,
1002 unique_typed_id("o",SetType,TempOut).
1003 get_single_component_constraint_aux3(overwrite-SetType,TempIn1,TempIn2,TempOut,overwrite) :-
1004 get_fn_types(SetType,integer,Type) ,
1005 unique_typed_id("i",seq(Type),TempIn1) ,
1006 unique_typed_id("i",seq(Type),TempIn2) ,
1007 unique_typed_id("o",seq(Type),TempOut).
1008 get_single_component_constraint_aux3(concat-SeqType,TempIn1,TempIn2,TempOut,concat) :-
1009 unique_typed_id("i",SeqType,TempIn1) ,
1010 unique_typed_id("i",SeqType,TempIn2) ,
1011 unique_typed_id("o",SeqType,TempOut).
1012 get_single_component_constraint_aux3(Operator-SetType,TempIn,_,TempOut,Operator) :-
1013 member(Operator,[first,last]) ,
1014 unique_typed_id("i",SetType,TempIn) ,
1015 (SetType = seq(InnerType) ; SetType = set(couple(integer,InnerType))) ,
1016 unique_typed_id("o",InnerType,TempOut).
1017 get_single_component_constraint_aux3(Operator-SetType,TempIn,_,TempOut,Operator) :-
1018 member(Operator,[front,tail]) ,
1019 unique_typed_id("i",SetType,TempIn) ,
1020 unique_typed_id("o",SetType,TempOut).
1021 get_single_component_constraint_aux3(insert_front-SetType,TempIn1,TempIn2,TempOut,insert_front) :-
1022 get_fn_types(SetType,integer,InnerType) ,
1023 unique_typed_id("i",InnerType,TempIn1) ,
1024 unique_typed_id("i",SetType,TempIn2) ,
1025 unique_typed_id("o",SetType,TempOut).
1026 get_single_component_constraint_aux3(insert_tail-SetType,TempIn1,TempIn2,TempOut,insert_tail) :-
1027 get_fn_types(SetType,integer,InnerType) ,
1028 unique_typed_id("i",SetType,TempIn1) ,
1029 unique_typed_id("i",InnerType,TempIn2) ,
1030 unique_typed_id("o",SetType,TempOut).
1031 get_single_component_constraint_aux3(Operator-SetType,TempIn1,TempIn2,TempOut,Operator) :-
1032 member(Operator,[restrict_front,restrict_tail]) ,
1033 unique_typed_id("i",SetType,TempIn1) ,
1034 unique_typed_id("i",integer,TempIn2) ,
1035 unique_typed_id("o",SetType,TempOut).
1036
1037 % Operators
1038 % Use boolean instead of pred_true/pred_false. We can't define identifier ASTs of type predicate.
1039 get_logical_constraint(implication,In1,In2,Out,Truth,Falsity) :-
1040 Truth = b(conjunct(b(disjunct(
1041 b(equal(In1,b(boolean_false,boolean,[])),pred,[]),
1042 b(equal(In2,b(boolean_true,boolean,[])),pred,[])),pred,[]),
1043 b(equal(Out,b(boolean_true,boolean,[])),pred,[])),pred,[]) ,
1044 Falsity = b(conjunct(b(conjunct(
1045 b(equal(In1,b(boolean_true,boolean,[])),pred,[]),
1046 b(equal(In2,b(boolean_false,boolean,[])),pred,[])),pred,[]),
1047 b(equal(Out,b(boolean_false,boolean,[])),pred,[])),pred,[]).
1048 get_logical_constraint(equivalence,In1,In2,Out,Truth,Falsity) :-
1049 get_logical_constraint(implication,In1,In2,Out,TruthImpl1,FalsityImpl1) ,
1050 get_logical_constraint(implication,In2,In1,Out,TruthImpl2,FalsityImpl2) ,
1051 Truth = b(conjunct(TruthImpl1,TruthImpl2),pred,[]) ,
1052 Falsity = b(disjunct(FalsityImpl1,FalsityImpl2),pred,[]).
1053 get_logical_constraint(conjunct,In1,In2,Out,Truth,Falsity) :-
1054 Truth = b(conjunct(b(conjunct(
1055 b(equal(In1,b(boolean_true,boolean,[])),pred,[]),
1056 b(equal(In2,b(boolean_true,boolean,[])),pred,[])),pred,[]),
1057 b(equal(Out,b(boolean_true,boolean,[])),pred,[])),pred,[]) ,
1058 Falsity = b(conjunct(b(disjunct(
1059 b(equal(In1,b(boolean_false,boolean,[])),pred,[]),
1060 b(equal(In2,b(boolean_false,boolean,[])),pred,[])),pred,[]),
1061 b(equal(Out,b(boolean_false,boolean,[])),pred,[])),pred,[]).
1062 get_logical_constraint(disjunct,In1,In2,Out,Truth,Falsity) :-
1063 Truth = b(conjunct(b(disjunct(
1064 b(equal(In1,b(boolean_true,boolean,[])),pred,[]),
1065 b(equal(In2,b(boolean_true,boolean,[])),pred,[])),pred,[]),
1066 b(equal(Out,b(boolean_true,boolean,[])),pred,[])),pred,[]) ,
1067 Falsity = b(conjunct(b(conjunct(
1068 b(equal(In1,b(boolean_false,boolean,[])),pred,[]),
1069 b(equal(In2,b(boolean_false,boolean,[])),pred,[])),pred,[]),
1070 b(equal(Out,b(boolean_false,boolean,[])),pred,[])),pred,[]).
1071
1072 get_fn_types(seq(Type),integer,Type).
1073 get_fn_types(set(couple(A,B)),A,B).
1074
1075 % Get the output type of permutations component, i.e., perm(s) for a sequence s.
1076 get_perm_component_output_type(set(CoupleType),set(seq(CoupleType))) :-
1077 CoupleType = couple(integer,_).
1078 get_perm_component_output_type(seq(InnerType),set(seq(couple(integer,InnerType)))).
1079
1080 % Add prefix "l" to Var for connectivity constraint, add the type to the location variables
1081 % information and adopt the given information which encodes the location variables reference,
1082 % e.g. [synthesis(type,integer),synthesis(left_input,greater)]
1083 get_location_var_from_ast_node(b(identifier(Name),_,Info),b(identifier(LocationName),integer,Info)) :-
1084 ! , atom_concat(l,Name,LocationName).
1085 get_location_var_from_ast_node(b(_,Type,Info),b(identifier(LocationName),integer,Info)) :-
1086 get_location_var_from_ast_node_aux(Type,ValueCode) ,
1087 % set input/output enumeration as prefix to get unique name
1088 % output location names are like 'lovalue0boolean_true'
1089 member(synthesis(example(ExampleCount)),Info) ,
1090 number_codes(ExampleCount,ExampleCountCode) ,
1091 (member(synthesis(input(C)),Info)
1092 -> number_codes(C,NC) ,
1093 append([[105,110,112,117,116],NC,ExampleCountCode],CCode)
1094 ; member(synthesis(output(C)),Info) ,
1095 number_codes(C,NumberCodes) ,
1096 append([[111,118,97,108,117,101],NumberCodes,ExampleCountCode],CCode)) ,
1097 append(CCode,ValueCode,Codes) ,
1098 atom_codes(LocationName,[108|Codes]).
1099
1100 get_location_var_from_ast_node_aux(Type,ValueCode) :-
1101 functor(Type, Functor, _),
1102 atom_codes(Functor,ValueCode).
1103
1104 % Enumerate used components for identifier nodes information so we definitely
1105 % know which input/output locations belong together if a component is used multiple times.
1106 % Here, the library components are represented as tuples of the component name and its internal name with id as postfix.
1107 set_component_id(Component,ComponentWithId) :-
1108 used_library(Components) ,
1109 retract(used_library(_)) ,
1110 length(Components,OpAmount) ,
1111 ComponentId is OpAmount + 1 ,
1112 atom_number_concat(Component,ComponentId,ComponentWithId) ,
1113 assertz(used_library([(Component,ComponentWithId)|Components])).
1114
1115 % Evaluate M := |I| + N, i.e., the amount of variables considered in the examples plus the amount of library components.
1116 % We do not consider machine constants as explicit library components since their values are defined by the machine properties, i.e., the amount
1117 % of machine constants is not considered within N. Therefore, we have to add x lines to the program where x is the amount of machine constants.
1118 % Moreover, we may consider operation parameters if present which we handle equivalent to machine constants.
1119 % Generally, the value of M determines the amount of lines in the program
1120 get_line_amount(Operation,Components,InputVars,M) :-
1121 additional_set_constants(AdditionalSetConstants) ,
1122 length(AdditionalSetConstants,AC) ,
1123 length(InputVars,I) ,
1124 length(Components,N) ,
1125 b_get_machine_constants(MachineConstants) ,
1126 % if the operation exists consider the amount of operation parameters for that we consider synthesis constants
1127 (ground(Operation) , b_get_machine_operation(Operation,_,OperationParameters,_)
1128 -> length(OperationParameters,OperationParameterAmount)
1129 ; OperationParameterAmount = 0) ,
1130 length(MachineConstants,AmountOfMachineConstants) ,
1131 M is I + N + AmountOfMachineConstants + AC + OperationParameterAmount.
1132
1133 % Set the location variables of the program parameters and output given by I/O-Examples.
1134 % Each input parameters are defined in the first lines of the program
1135 set_input_location_vars(InputValueNodes,InputLocations) :-
1136 set_input_location_vars(InputValueNodes,0,[],InputLocationsList) ,
1137 conjunct_predicates(InputLocationsList,InputLocations).
1138 set_input_location_vars([],_,Acc,Acc).
1139 set_input_location_vars([InputValueNode|R],C,Acc,InputLocations) :-
1140 get_location_var_from_ast_node(InputValueNode,InputLocationNode) ,
1141 InputLocation = b(equal(InputLocationNode,b(integer(C),integer,[])),pred,[]) ,
1142 C1 is C + 1 ,
1143 set_input_location_vars(R,C1,[InputLocation|Acc],InputLocations).
1144 % We dispose output values in descending order starting at the last line of the program
1145 set_output_location_vars(OutputValueNodes,M,OutputLocations,OutputLocationVars) :-
1146 M1 is M - 1 ,
1147 set_output_location_vars(OutputValueNodes,M1,[],OutputLocationsList,[],OutputLocationVars) ,
1148 conjunct_predicates(OutputLocationsList,OutputLocations).
1149 set_output_location_vars([],_,Acc,Acc,VarAcc,VarAcc).
1150 set_output_location_vars([OutputValueNode|R],C,Acc,OutputLocations,VarAcc,OutputLocationVars) :-
1151 get_location_var_from_ast_node(OutputValueNode,OutputLocationNode) ,
1152 OutputLocation = b(equal(OutputLocationNode,b(integer(C),integer,[])),pred,[]) ,
1153 C1 is C - 1 ,
1154 add_texpr_infos(OutputLocationNode,[synthesis(program_line(C))],NewOutputLocationNode) ,
1155 set_output_location_vars(R,C1,[OutputLocation|Acc],OutputLocations,[NewOutputLocationNode|VarAcc],OutputLocationVars).
1156
1157 % Enumerate input nodes in the info to use within the connectivity constraint, the corresponding machine variable names have already been added to each node's info.
1158 % We also enumerate the examples in the order they are given to get unique identifier names for program input and output parameter later on and especially unique names that
1159 % can be reconstructed using the node's info. Using unique_typed_id/3 we get like any unique identifier without any pattern to reconstruct later on.
1160 enumerate_inputs_and_outputs(ExampleCount,InputValues,StateType,InputNodes) :-
1161 enumerate_inputs_and_outputs(ExampleCount,InputValues,StateType,0,InputNodes).
1162 enumerate_inputs_and_outputs(_,[],_,_,[]).
1163 enumerate_inputs_and_outputs(ExampleCount,[b(Node,Type,Info)|R],input,C,[b(Node,Type,[synthesis(input(C)),synthesis(example(ExampleCount)),synthesis(type,Type)|Info])|T]) :-
1164 C1 is C + 1 ,
1165 enumerate_inputs_and_outputs(ExampleCount,R,input,C1,T).
1166 enumerate_inputs_and_outputs(ExampleCount,[b(Node,Type,Info)|R],output,C,[b(Node,Type,[synthesis(output(C)),synthesis(example(ExampleCount)),synthesis(type,Type)|Info])|T]) :-
1167 C1 is C + 1 ,
1168 enumerate_inputs_and_outputs(ExampleCount,R,output,C1,T).
1169
1170 atom_number_concat(Atom,Number,Concatenation) :-
1171 number_codes(Number,NumberCodes) ,
1172 atom_codes(Atom,AtomCodes) ,
1173 append(AtomCodes,NumberCodes,ConcatCodes) ,
1174 atom_codes(Concatenation,ConcatCodes).
1175
1176 % Get an output ĺocation variable for a specific location value.
1177 get_output_location_for_location_value(LocationVars,SolutionBindings,LocationValue,OutputLocationVar) :-
1178 get_binding_for_name_or_value(SolutionBindings,OutputLocationName,LocationValue) ,
1179 atom_concat(lo,_,OutputLocationName) , ! ,
1180 member(OutputLocationVar,LocationVars) , OutputLocationVar = b(identifier(OutputLocationName),integer,_).
1181 % Return a node for the location value in case there is no explicit operators' output mapped, thus, it is an input parameter.
1182 % We know the first input parameter is in the first line of the program etc. which will not change, therefore we
1183 % do not need the explicit location variable name but only the location value.
1184 get_output_location_for_location_value(_,_,int(Value),b(integer(Value),integer,[])).
1185
1186 % add input location variables since the program asts contain explicit values
1187 accumulate_used_location_var_aux(Operator,LocationVars,Acc,NewAcc) :-
1188 findall(LocationVar,(member(LocationVar,LocationVars) , LocationVar = b(_,_,Info) ,
1189 member(synthesis(Operator,LocationType),Info) ,
1190 (LocationType = left_input ; LocationType = right_input)),InputLocationVars) ,
1191 append(Acc,InputLocationVars,NewAcc).
1192
1193 :- spec_pre(get_used_location_vars_and_op_names/6,[ast,list(ast),list(ast),list(atom),var,var]).
1194 :- spec_invariant(get_used_location_vars_and_op_names/6,[ast,list(ast),list(ast),list(atom),list(ast),list(atom)]).
1195 :- spec_post(get_used_location_vars_and_op_names/6,[ast,list(ast),list(ast),list(atom),var,var],
1196 [ast,list(ast),list(ast),list(atom),list(ast),list(atom)]).
1197 get_used_location_vars_and_op_names(b(Node,_,Info),LocationVars,LocationAcc,OpAcc,UsedLocationVars,UsedOperatorNames) :-
1198 Node = if_then_else(Condition,TrueOut,FalseOut) ,
1199 accumulate_used_location_var(Info,LocationVars,LocationAcc,OpAcc,LocationAcc1,OpAcc1) ,
1200 get_used_location_vars_and_op_names(Condition,LocationVars,LocationAcc1,OpAcc1,LocationAcc2,OpAcc2) ,
1201 get_used_location_vars_and_op_names(TrueOut,LocationVars,LocationAcc2,OpAcc2,LocationAcc3,OpAcc3) ,
1202 get_used_location_vars_and_op_names(FalseOut,LocationVars,LocationAcc3,OpAcc3,UsedLocationVars,UsedOperatorNames) , !.
1203 get_used_location_vars_and_op_names(b(Node,_,Info),LocationVars,LocationAcc,OpAcc,UsedLocationVars,UsedOperatorNames) :-
1204 Node =.. [_,LeftAST,RightAST] ,
1205 is_ast(LeftAST) , is_ast(RightAST) ,
1206 accumulate_used_location_var(Info,LocationVars,LocationAcc,OpAcc,LocationAcc1,OpAcc1) ,
1207 get_used_location_vars_and_op_names(LeftAST,LocationVars,LocationAcc1,OpAcc1,LocationAcc2,OpAcc2) ,
1208 get_used_location_vars_and_op_names(RightAST,LocationVars,LocationAcc2,OpAcc2,UsedLocationVars,UsedOperatorNames) , !.
1209 %findall(ParameterLocation,(member(ParameterLocation,LocationVars) ,
1210 % ParameterLocation = b(_,_,Info) , member(synthesis(input(_)),Info)),ParameterLocations) ,
1211 %append(TempUsedLocationVars,ParameterLocations,UsedLocationVars).
1212 get_used_location_vars_and_op_names(b(Node,_,Info),LocationVars,LocationAcc,OpAcc,UsedLocationVars,UsedOperatorNames) :-
1213 Node =.. [_,AST] ,
1214 accumulate_used_location_var(Info,LocationVars,LocationAcc,OpAcc,NewLocationAcc,NewOpAcc) ,
1215 (is_ast(AST)
1216 -> get_used_location_vars_and_op_names(AST,LocationVars,NewLocationAcc,NewOpAcc,UsedLocationVars,UsedOperatorNames)
1217 ; UsedLocationVars = NewLocationAcc , UsedOperatorNames = NewOpAcc).
1218 get_used_location_vars_and_op_names(_,_,_,_,Acc,Acc).
1219
1220 accumulate_used_location_var(Info,LocationVars,LocationAcc,OpAcc,NewLocationAcc,[Op|OpAcc]) :-
1221 member(synthesis(Op,output),Info) ,
1222 \+member(Op,OpAcc) ,
1223 member(b(identifier(_),integer,IdInfo),LocationVars) ,
1224 member(synthesis(Op,output),IdInfo) ,
1225 accumulate_used_location_var_aux(Op,LocationVars,LocationAcc,NewLocationAcc).
1226 accumulate_used_location_var(_,_,LocationAcc,OpAcc,LocationAcc,OpAcc).
1227
1228 :- spec_pre(get_input_location_nodes_for_operator_name/4,[atom,list(ast),list(ast),var]).
1229 :- spec_invariant(get_input_location_nodes_for_operator_name/4,[atom,list(ast),list(ast),list(ast)]).
1230 :- spec_post(get_input_location_nodes_for_operator_name/4,[atom,list(ast),list(ast),var],
1231 [atom,list(ast),list(ast),list(ast)]).
1232 get_input_location_nodes_for_operator_name(_,[],Acc,Acc).
1233 get_input_location_nodes_for_operator_name(OperatorName,[LocationVar|T],Acc,InputLocations) :-
1234 LocationVar = b(identifier(_),integer,Info) ,
1235 member(synthesis(OperatorName,LocationType),Info) ,
1236 LocationType \= output , ! ,
1237 get_input_location_nodes_for_operator_name(OperatorName,T,[LocationVar|Acc],InputLocations).
1238 get_input_location_nodes_for_operator_name(OperatorName,[_|T],Acc,InputLocations) :-
1239 get_input_location_nodes_for_operator_name(OperatorName,T,Acc,InputLocations).
1240
1241 %get_output_location_node_for_operator_name(OperatorName,[OutputLocationNode|_],OutputLocationNode) :-
1242 % OutputLocationNode = b(identifier(_),integer,Info) ,
1243 % member(synthesis(OperatorName,output),Info) , !.
1244 %get_output_location_node_for_operator_name(OperatorName,[_|T],OutputLocationNode) :-
1245 % get_output_location_node_for_operator_name(OperatorName,T,OutputLocationNode).
1246
1247 is_constant(b(identifier(Constant),_,_)) :-
1248 atom_concat(constant,_,Constant).
1249 is_constant(b(_,_,Info)) :-
1250 member(synthesis(OpName,output),Info) ,
1251 atom_concat(constant,_,OpName).
1252
1253 exclude_solution_for_further_search(UsedOperatorNames,LocationVars,SolutionBindings,Exclusion) :-
1254 maplist(exclude_output_to_input_mapping_for_operator(LocationVars,SolutionBindings),UsedOperatorNames,TExclusionList) ,
1255 remove_dups(TExclusionList,ExclusionList) ,
1256 disjunct_predicates(ExclusionList,TempExclusion) ,
1257 exclude_solution_for_further_search_aux(TempExclusion,Exclusion).
1258
1259 exclude_solution_for_further_search_aux(b(falsity,_,_),b(truth,pred,[])) :- !.
1260 exclude_solution_for_further_search_aux(Exclusion,Exclusion).
1261
1262 % constants: Inequality with the input location it is mapped to or with the explicit location value
1263 % in case the constant is the program output.
1264 exclude_output_to_input_mapping_for_operator(LocationVars,SolutionBindings,OperatorName,Exclusion) :-
1265 atom_concat(constant,_,OperatorName) , ! ,
1266 get_location_var_node_by_info_term(LocationVars,synthesis(OperatorName,output),ConstantLocation) ,
1267 ConstantLocation = b(identifier(ConstantLocationName),integer,_) ,
1268 get_binding_for_name_or_value(SolutionBindings,ConstantLocationName,LocationValue) ,
1269 get_binding_for_name_or_value(SolutionBindings,MappedInputLocationName,LocationValue) ,
1270 MappedInputLocationName \= ConstantLocationName ,
1271 % exclude connection for all constants to prevent swapping with other constants of the same type
1272 findall(E,(member(ConstantNode,LocationVars) , is_constant(ConstantNode) , ConstantNode = b(identifier(CName),_,_) ,
1273 get_binding_for_name_or_value(SolutionBindings,CName,LValue) ,
1274 ConstantLocationName \= CName ,
1275 exclude_output_to_input_mapping_for_constant_aux(LocationVars,LValue,ConstantLocation,CName,E)),TExclusions) ,
1276 flatten(TExclusions,Exclusions) ,
1277 exclude_output_to_input_mapping_for_constant_aux(LocationVars,LocationValue,ConstantLocation,MappedInputLocationName,TExclusion) ,
1278 conjunct_predicates([TExclusion|Exclusions],Exclusion).
1279 exclude_output_to_input_mapping_for_operator(LocationVars,SolutionBindings,OperatorName,Exclusion) :-
1280 get_location_var_node_by_info_term(LocationVars,synthesis(OperatorName,output),ConstantLocation) ,
1281 ConstantLocation = b(identifier(ConstantLocationName),integer,_) ,
1282 get_binding_for_name_or_value(SolutionBindings,ConstantLocationName,LocationValue) ,
1283 get_binding_for_name_or_value(SolutionBindings,MappedInputLocationName,LocationValue) ,
1284 MappedInputLocationName \= ConstantLocationName ,
1285 exclude_output_to_input_mapping_for_constant_aux(LocationVars,LocationValue,ConstantLocation,MappedInputLocationName,Exclusion).
1286 % Exclude the mapping of a given operators input locations to its corresponding output locations for the given solution.
1287 exclude_output_to_input_mapping_for_operator(LocationVars,SolutionBindings,OperatorName,Exclusion) :-
1288 get_input_location_nodes_for_operator_name(OperatorName,LocationVars,[],InputLocations) , InputLocations \= [] ,
1289 maplist(exclude_specific_input_output_mapping(LocationVars,SolutionBindings),InputLocations,InputOutputExclusions) ,
1290 disjunct_predicates(InputOutputExclusions,Exclusion).
1291
1292 exclude_output_to_input_mapping_for_constant_aux(LocationVars,_,ConstantLocation,MappedInputLocationName,Exclusion) :-
1293 member(MappedInputLocationVar,LocationVars) , MappedInputLocationVar = b(identifier(MappedInputLocationName),_,_) ,
1294 create_texpr(not_equal(ConstantLocation,MappedInputLocationVar),pred,[],Exclusion).
1295 %exclude_output_to_input_mapping_for_constant_aux(_,LocationValue,ConstantLocation,_,Exclusion) :-
1296 % create_texpr(not_equal(ConstantLocation,b(value(LocationValue),integer,[])),pred,[],Exclusion).
1297
1298 exclude_specific_input_output_mapping(LocationVars,SolutionBindings,b(identifier(Id),integer,Info),Exclusion) :-
1299 get_binding_for_name_or_value(SolutionBindings,Id,LocationValue) ,
1300 get_output_location_for_location_value(LocationVars,SolutionBindings,LocationValue,OutputLocationVar) ,
1301 create_texpr(not_equal(b(identifier(Id),integer,Info),OutputLocationVar),pred,[],Exclusion).
1302 exclude_specific_input_output_mapping(_,_,_,b(falsity,pred,[])).
1303
1304 % Using a component several times, e.g. with internal names add1,add2, we don't want to
1305 % swap both components when searching for a further solution.
1306 get_prevent_component_swap_constraint(UsedLVars,SolutionBindings,LocationVars,Constraint) :-
1307 get_input_location_vars_for_outputs(UsedLVars,LocationVars,OutputInputsTuples) ,
1308 maplist(exclude_swapping_for_component(SolutionBindings,LocationVars),OutputInputsTuples,TExclusions) ,
1309 remove_dups(TExclusions,Exclusions) ,
1310 conjunct_predicates(Exclusions,Constraint).
1311
1312 % TODO: Maybe consider constants too?
1313 get_input_location_vars_for_outputs(UsedLVars,LocationVars,OutputInputsTuples) :-
1314 % create tuples of component and an empty list to use as an accumulator
1315 findall((Component,[]),(member(OutLVar,UsedLVars) , get_texpr_info(OutLVar,Info) ,
1316 member(synthesis(Component,output),Info)),Acc) ,
1317 get_input_location_vars_for_outputs_aux(LocationVars,Acc,OutputInputsTuples).
1318 get_input_location_vars_for_outputs_aux([],Acc,Acc).
1319 get_input_location_vars_for_outputs_aux([LocationVar|T],Acc,OutputInputsTuples) :-
1320 get_texpr_info(LocationVar,Info) ,
1321 (member(synthesis(Component,left_input),Info) ; member(synthesis(Component,right_input),Info) ; member(synthesis(Component,input),Info)) ,
1322 member((Component,Inputs),Acc) ,
1323 delete(Acc,(Component,Inputs),TempAcc) ,
1324 remove_dups([LocationVar|Inputs],InputLVars),
1325 NewTuple = (Component,InputLVars) ,
1326 \+member(NewTuple,Acc) , % no duplicates
1327 get_input_location_vars_for_outputs_aux(T,[NewTuple|TempAcc],OutputInputsTuples).
1328 get_input_location_vars_for_outputs_aux([_|T],Acc,OutputInputsTuples) :-
1329 get_input_location_vars_for_outputs_aux(T,Acc,OutputInputsTuples).
1330
1331 % Given a tuple of an output location var and the corresponding component's inputs.
1332 % We search for the output locations that are mapped to the input locations.
1333 % Then, we search all equivalent component inputs and exclude mapping the output locations to
1334 % the equivalent input location.
1335 % Thus, we exclude swapping two equivalent operators when searching for a further solution for a given
1336 % synthesized program.
1337 exclude_swapping_for_component(SolutionBindings,LocationVars,(OutLVar,InLVars),ExclusionConstraint) :-
1338 maplist(get_lvar_name_and_input_type,InLVars,InLVarNames,InLVarTypes) ,
1339 % get the location values the inputs of OutLVar are mapped to
1340 maplist(get_binding_for_name_or_value(SolutionBindings),InLVarNames,InLVarValues) ,
1341 % create tuples of (lvar,lvalue)
1342 zip(InLVarNames,InLVarValues,VarValueTuples) ,
1343 zip(InLVarNames,InLVarTypes,VarTypeTuples) ,
1344 % then, get the output locations those inputs are mapped to
1345 maplist(get_corresponding_mapped_location(SolutionBindings,LocationVars),VarValueTuples,CorrespondingLocations) ,
1346 % and create tuples of output locations and the type of the input they are mapped to, i.e.,
1347 % either left_input or right_input
1348 findall((OutLVarName,InputType),(member((InLVar,OutLVarName),CorrespondingLocations) ,
1349 member((InLVar,InputType),VarTypeTuples)),OutLVarInTypeTuples) ,
1350 exclude_swapping_for_component_aux(LocationVars,(OutLVar,OutLVarInTypeTuples),ExclusionConstraint).
1351 exclude_swapping_for_component_aux(LocationVars,(OutLVarName,OutLVarInTypeTuples),ExclusionConstraint) :-
1352 get_equivalent_input_location_nodes(OutLVarName,LocationVars,EquivalentInputLocations) ,
1353 % find pairs of output and input location that correspond (are mapped) to the same input type, i.e.
1354 % either left_input, right_input or input
1355 findall(Exclusion,(member((CorOutLVarName,InputType),OutLVarInTypeTuples) ,
1356 get_location_var_node_by_name(CorOutLVarName,LocationVars,OutLVarNode) ,
1357 member((InLVarNode,InputType),EquivalentInputLocations) ,
1358 create_texpr(not_equal(OutLVarNode,InLVarNode),pred,[],Exclusion)),Exclusions) ,
1359 conjunct_predicates(Exclusions,ExclusionConstraint).
1360
1361 % Get all input locations that are equivalent to the component that LocationVarName belongs to.
1362 % Don't consider exactly the same location var.
1363 get_equivalent_input_location_nodes(LocationVarName,LocationVars,InputLocations) :-
1364 delete_numbers_from_atom(LocationVarName,RawName) ,
1365 get_equivalent_input_location_nodes_aux(LocationVarName,RawName,LocationVars,[],InputLocations).
1366 get_equivalent_input_location_nodes_aux(_,_,[],Acc,Acc).
1367 get_equivalent_input_location_nodes_aux(LocationVarName,RawName,[LocationVar|T],Acc,InputLocations) :-
1368 get_texpr_info(LocationVar,Info) ,
1369 member(synthesis(LVarName,InputType),Info) ,
1370 (InputType = left_input ; InputType = right_input ; InputType = input) ,
1371 delete_numbers_from_atom(LVarName,RawLVarName) ,
1372 RawLVarName = RawName ,
1373 % not exactly the same location
1374 LVarName \= LocationVarName ,
1375 \+member((LocationVar,InputType),Acc) , % no duplicates
1376 get_equivalent_input_location_nodes_aux(LocationVarName,RawName,T,[(LocationVar,InputType)|Acc],InputLocations).
1377 get_equivalent_input_location_nodes_aux(LocationVarName,RawName,[_|T],Acc,InputLocations) :-
1378 get_equivalent_input_location_nodes_aux(LocationVarName,RawName,T,Acc,InputLocations).
1379
1380 % Given a tuple of location var name and mapped value, we search for the other location var that
1381 % is mapped to this location value (line of the program).
1382 get_corresponding_mapped_location(SolutionBindings,_,(LVarName,LVarValue),(LVarName,LVarName2)) :-
1383 get_binding_for_name_or_value(SolutionBindings,LVarName2,LVarValue) ,
1384 delete_numbers_from_atom(LVarName2,RawName) ,
1385 RawName \= constant ,
1386 LVarName \= LVarName2.
1387
1388 get_lvar_name_and_input_type(b(identifier(LVarName),integer,Info),LVarName,InputType) :-
1389 get_input_type_from_info(Info,InputType).
1390
1391 get_input_type_from_info(Info,left_input) :-
1392 member(synthesis(_,left_input),Info).
1393 get_input_type_from_info(Info,right_input) :-
1394 member(synthesis(_,right_input),Info).
1395 get_input_type_from_info(Info,input) :-
1396 member(synthesis(_,input),Info).