| 1 | :- module(kodkod_annotator, [annotate_kodkod_constraints/3, | |
| 2 | contains_higher_order_or_int_ast/1, | |
| 3 | preferred_by_kodkod/1]). | |
| 4 | ||
| 5 | :- use_module(probsrc(bsyntaxtree), [find_typed_identifier_uses/3, get_texpr_type/2]). | |
| 6 | ||
| 7 | :- use_module(probsrc(module_information),[module_info/2]). | |
| 8 | :- module_info(group,kodkod). | |
| 9 | :- module_info(description,'Annotate specific constraints within a typed B or Event-B AST with external predicate calls to be solved by Kodkod.'). | |
| 10 | ||
| 11 | %% join_using_couples(+Ids, -Couples). | |
| 12 | % | |
| 13 | % Join a non-empty list of identifiers to a single (possibly nested) couple. | |
| 14 | join_using_couples([Id|T], Couples) :- | |
| 15 | join_using_couples(T, Id, Couples). | |
| 16 | ||
| 17 | join_using_couples([], Couples, Couples). | |
| 18 | join_using_couples([Id|T], Acc, Couples) :- | |
| 19 | get_texpr_type(Id, Type1), | |
| 20 | get_texpr_type(Acc, Type2), | |
| 21 | NewAcc = b(couple(Id, Acc), couple(Type1, Type2), []), | |
| 22 | join_using_couples(T, NewAcc, Couples). | |
| 23 | ||
| 24 | %% annotate_kodkod_constraints(+AnnotationType, +Ast, -AnnotatedAst). | |
| 25 | % | |
| 26 | % AnnotationType is either 'greedy' (send all possible constraints to Kodkod) or | |
| 27 | % 'preferred' (only send preferred constraints to Kodkod, see preferred_by_kodkod/1). | |
| 28 | % Annotate specific constraints to be solved by Kodkod. | |
| 29 | % Currently preferred by Kodkod: implication, equal, not_equal, card | |
| 30 | % Exclude: Operations on integers and higher-order quantification. | |
| 31 | annotate_kodkod_constraints(_, Ast, AnnotatedAst) :- | |
| 32 | Ast = b(kodkod(_,_),_,_), | |
| 33 | !, | |
| 34 | AnnotatedAst = Ast. | |
| 35 | annotate_kodkod_constraints(AnnotationType, Ast, AnnotatedAst) :- | |
| 36 | annotate_kodkod_constraints(AnnotationType, Ast, [], NewVarsAcc, TAnnotatedAst), | |
| 37 | NewVarsAcc = [CoupledVars], | |
| 38 | EmptySet = b(empty_set,set(any),[]), | |
| 39 | KodkodSolve = b(external_pred_call('KODKOD_SOLVE',[b(integer(1),integer,[]), CoupledVars, EmptySet]),pred,[]), | |
| 40 | AnnotatedAst = b(conjunct(TAnnotatedAst, KodkodSolve),pred,[]). | |
| 41 | annotate_kodkod_constraints(_, Ast, Ast). | |
| 42 | ||
| 43 | %% annotate_kodkod_constraints(AnnotationType, +Ast, +VarsAcc, -NewVarsAcc, -AnnotatedAst). | |
| 44 | % | |
| 45 | % AnnotationType is either greedy (use Kodkod wherever possible) | |
| 46 | % or preferred (see preferred_by_kodkod/1). | |
| 47 | % True if NewVarsAcc is a singleton list containing a couple of local identifiers of annotated constraints, | |
| 48 | % and AnnotatedAst the equivalent ast with Kodkod annotations. | |
| 49 | annotate_kodkod_constraints(greedy, b(Node,Type,Info), VarsAcc, NewVarsAcc, AnnotatedAst) :- | |
| 50 | functor(Node, _, Arity), | |
| 51 | Arity == 2, | |
| 52 | arg(1, Node, Lhs), | |
| 53 | arg(2, Node, Rhs), | |
| 54 | \+contains_higher_order_or_int_ast([Lhs]), | |
| 55 | \+contains_higher_order_or_int_ast([Rhs]), | |
| 56 | !, | |
| 57 | annotate_constraint_for_kodkod(b(Node,Type,Info), VarsAcc, NewVarsAcc, AnnotatedAst). | |
| 58 | annotate_kodkod_constraints(preferred, b(Node,Type,Info), VarsAcc, NewVarsAcc, AnnotatedAst) :- | |
| 59 | functor(Node, Functor, _), | |
| 60 | preferred_by_kodkod(Functor), | |
| 61 | !, | |
| 62 | annotate_constraint_for_kodkod(b(Node,Type,Info), VarsAcc, NewVarsAcc, AnnotatedAst). | |
| 63 | annotate_kodkod_constraints(AnnotationType, b(Node,Type,Info), VarsAcc, NewVarsAcc, AnnotatedAst) :- | |
| 64 | functor(Node, Functor, Arity), | |
| 65 | Arity == 2, | |
| 66 | arg(1, Node, Lhs), | |
| 67 | arg(2, Node, Rhs), | |
| 68 | !, | |
| 69 | annotate_kodkod_constraints(AnnotationType, Lhs, VarsAcc, VarsAcc1, ALhs), | |
| 70 | annotate_kodkod_constraints(AnnotationType, Rhs, VarsAcc1, NewVarsAcc, ARhs), | |
| 71 | NNode =.. [Functor, ALhs, ARhs], | |
| 72 | AnnotatedAst = b(NNode,Type,Info). | |
| 73 | annotate_kodkod_constraints(greedy, b(forall(Ids, Lhs, Rhs),pred,Info), VarsAcc, NewVarsAcc, AnnotatedAst) :- | |
| 74 | \+contains_higher_order_or_int_ast([Ids]), | |
| 75 | \+contains_higher_order_or_int_ast([Lhs]), | |
| 76 | \+contains_higher_order_or_int_ast([Rhs]), | |
| 77 | !, | |
| 78 | annotate_kodkod_constraints(greedy, Lhs, VarsAcc, VarsAcc1, ALhs), | |
| 79 | annotate_kodkod_constraints(greedy, Rhs, VarsAcc1, NewVarsAcc, ARhs), | |
| 80 | AnnotatedAst = b(forall(Ids, ALhs, ARhs),pred,Info). | |
| 81 | annotate_kodkod_constraints(greedy, b(exists(Ids, Pred),pred,Info), VarsAcc, NewVarsAcc, AnnotatedAst) :- | |
| 82 | \+contains_higher_order_or_int_ast([Ids]), | |
| 83 | \+contains_higher_order_or_int_ast([Pred]), | |
| 84 | !, | |
| 85 | annotate_kodkod_constraints(greedy, Pred, VarsAcc, NewVarsAcc, APred), | |
| 86 | AnnotatedAst = b(exists(Ids, APred),pred,Info). | |
| 87 | % Note: skips let etc. if on the top-level | |
| 88 | annotate_kodkod_constraints(_, Ast, VarsAcc, VarsAcc, Ast). | |
| 89 | ||
| 90 | annotate_constraint_for_kodkod(Ast, VarsAcc, [CoupledVars], AnnotatedAst) :- | |
| 91 | AstAsBool = b(convert_bool(Ast),boolean,[]), | |
| 92 | find_typed_identifier_uses(Ast, [], LocalIds), | |
| 93 | join_using_couples(LocalIds, CoupledLocalIds), | |
| 94 | join_using_couples([CoupledLocalIds|VarsAcc], CoupledVars), | |
| 95 | EmptySet = b(empty_set,set(any),[]), | |
| 96 | AnnotatedAst = b(external_pred_call('KODKOD',[b(integer(1),integer,[]), CoupledLocalIds, EmptySet, AstAsBool]),pred,[]). | |
| 97 | ||
| 98 | %% contains_higher_order_or_int_ast(+ListOfAst). | |
| 99 | % | |
| 100 | % True if list contains an ast of type integer or a higher order quantification. | |
| 101 | contains_higher_order_or_int_ast([b(Node,Type,Info)|_]) :- | |
| 102 | get_texpr_type(b(Node,Type,Info), Type), | |
| 103 | ( Type == integer | |
| 104 | ; Type = set(A), | |
| 105 | set_or_seq(A) | |
| 106 | ; Type = seq(A), | |
| 107 | set_or_seq(A) | |
| 108 | ), | |
| 109 | !. | |
| 110 | contains_higher_order_or_int_ast([Ast|T]) :- | |
| 111 | Ast =.. [_|Args], | |
| 112 | ( contains_higher_order_or_int_ast(Args), | |
| 113 | ! | |
| 114 | ; contains_higher_order_or_int_ast(T)). | |
| 115 | ||
| 116 | set_or_seq(set(_)). | |
| 117 | set_or_seq(seq(_)). | |
| 118 | ||
| 119 | % TO DO: find more suitable operators for Kodkod annotations | |
| 120 | preferred_by_kodkod(equal). | |
| 121 | preferred_by_kodkod(not_equal). | |
| 122 | preferred_by_kodkod(not_member). | |
| 123 | preferred_by_kodkod(member). | |
| 124 | preferred_by_kodkod(subset). | |
| 125 | preferred_by_kodkod(not_subset). | |
| 126 | preferred_by_kodkod(subset_strict). | |
| 127 | preferred_by_kodkod(not_subset_strict). | |
| 128 | preferred_by_kodkod(exists). | |
| 129 | preferred_by_kodkod(forall). | |
| 130 | preferred_by_kodkod(pow_subset). | |
| 131 | preferred_by_kodkod(pow1_subset). | |
| 132 | preferred_by_kodkod(fin_subset). | |
| 133 | preferred_by_kodkod(fin1_subset). |