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). |