1 % (c) 2009-2019 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(ltl_translate,[pp_ltl_formula/2, pp_formulas/2, pp_ap/2, pp_tp/2]).
6
7 /* SICSTUS Libraries */
8 :- use_module(library(lists)).
9 %% :- use_module(library(codesio)).
10 %% :- use_module(library(terms)).
11
12 /* ProB Libraries */
13 %% :- use_module(probsrc(error_manager)).
14 %% :- use_module(probsrc(debug)).
15 :- use_module(probsrc(self_check)).
16 :- use_module(probsrc(specfile),[csp_with_bz_mode/0]).
17 :- use_module(probsrc(tools),[ajoin/2]).
18 :- use_module(probsrc(translate), [translate_bexpression/2,translate_event/2]).
19 :- use_module(probsrc(state_space),[transition/4]).
20 :- use_module(library(codesio),[write_to_codes/2]).
21
22 :- use_module(probsrc(module_information),[module_info/2]).
23 :- module_info(group,ltl).
24 :- module_info(description,'This module provides utility predicates for pretty-printing LTL and CTL formulae.').
25
26 pp_ltl_formula(Formula,Text) :-
27 pp_ltl(Formula,Atoms,[]),
28 ajoin(Atoms,Text).
29
30 /* Pretty printer predicates */
31 :- public pp_op/2.
32 pp_op(Id,PP) :-
33 transition(_Src,Action,Id,_Dst),!,
34 translate_event(Action,PP).
35
36 pp_formulas([],[]).
37 pp_formulas([ApTp|Rest],[PP|PPrest]) :-
38 ( pp_formula(ApTp,PP) -> true
39 ; otherwise -> PP = '???'),
40 pp_formulas(Rest,PPrest).
41 pp_formula(ap(AP),ap(PP)) :-
42 pp_ap(AP,PP).
43 pp_formula(action(AP),tp(PP)) :-
44 pp_tp(AP,PP).
45
46 pp_ap(bpred(B),PP) :- !,
47 translate_bexpression(B,PP1),
48 ajoin(['{',PP1,'}'],PP).
49 pp_ap(enabled(TP),PP) :- !,
50 pp_tp2(TP,TPP),
51 ajoin(['e(',TPP,')'],PP).
52 pp_ap(available(TP),PP) :- !, % TO DO: check_ap currently has no rule for Av(.) / available Operator !!
53 % Was introduced for David Williams.
54 % Only relevant for CSP and rewritten to [tau] U (e(tau) & not [tau]) or (e(a) & not e(tau))).
55 % This is done in the Prolog module with the C interface for LTL.
56 pp_tp2(TP,TPP),
57 ajoin(['Av(',TPP,')'],PP).
58 pp_ap(weak_fair(TP),PP) :- !,
59 pp_tp2(TP,TPP),
60 ajoin(['WF(',TPP,')'],PP).
61 pp_ap(strong_fair(TP),PP) :- !,
62 pp_tp2(TP,TPP),
63 ajoin(['SF(',TPP,')'],PP).
64 pp_ap(dlk(L),PP) :- !,
65 maplist(pp_tp2,L,S),
66 tools: ajoin_with_sep(S,',',SText),
67 ajoin(['deadlock(',SText,')'],PP).
68 pp_ap(ctrl(L),PP) :- !,
69 maplist(pp_tp2,L,S),
70 tools: ajoin_with_sep(S,',',SText),
71 ajoin(['controller(',SText,')'],PP).
72 pp_ap(det(L),PP) :- !,
73 maplist(pp_tp2,L,S),
74 tools: ajoin_with_sep(S,',',SText),
75 ajoin(['deterministic(',SText,')'],PP).
76 pp_ap(Expr,PP) :-
77 write_to_codes(Expr,Codes),
78 atom_codes(PP,Codes).
79
80 pp_tp(T,PP) :-
81 pp_tp2(T,PP1),
82 ajoin(['[',PP1,']'],PP).
83 pp_tp2(btrans(event(Name)),Name) :- !.
84 pp_tp2(btrans(event(Name,Predicate,_)),PP) :- !,
85 translate_bexpression(Predicate,PP1),
86 ajoin([Name,' | ',PP1],PP).
87 pp_tp2(csp(tau,_Arity,[]),PP) :- !, PP = tau.
88 pp_tp2(csp(tick,_Arity,[]),PP) :- !, PP = tick.
89 pp_tp2(xtl(Op,0,[]),PP) :- !, PP = Op.
90 pp_tp2(xtl(Op,_Arity,PatternArgs),PP) :- !, Term =.. [Op|PatternArgs], pp_tp2(Term,PP).
91 pp_tp2(Action,PP) :-
92 translate_action(Action,PP),!.
93 pp_tp2(F,AF) :-
94 (translate: translate_event(F,AF) -> true; AF='???').
95
96 translate_action(bop(Name,_NumberArgs,_NumberResults,ArgPatterns,_ResPatterns),Transition) :- !,
97 maplist(get_arg,ArgPatterns,ArgPatterns1),
98 maplist(translate_bexpression,ArgPatterns1,PPArgPatterns),
99 Op =.. [Name|PPArgPatterns],
100 Transition = Op.
101 /* ( NumberResults == 0 ->
102 Transition = Op
103 ; otherwise ->
104 maplist(translate:translate_bexpression,ResPatterns,PPResPatterns),
105 Transition = '-->'(Op,PPResPatterns)
106 ).
107 */
108 translate_action(csp(Channel,_Arity,Args),PP) :-
109 (csp_with_bz_mode ->
110 % in this mode we need to remove 'CSP:'
111 translate: translate_event2(io(Args,Channel,_SPan),[_|S],[])
112 ; otherwise ->
113 translate: translate_event2(io(Args,Channel,_SPan),S,[])
114 ), ajoin(S,PP).
115
116 get_arg(N/Arg,Arg) :- nonvar(N),!.
117 get_arg(Arg,Arg).
118
119 /* Tests for pp_ltl_formula/2 */
120
121 :- assert_must_succeed((pp_ltl_formula(implies(globally(finally(until(true,false))),true),Text),
122 Text = '(G (F ((true U false))) => true)')).
123
124 :- assert_must_succeed((pp_ltl_formula(historically(not(release(yesterday(sink),next(deadlock)))),Text),
125 Text = 'H (not((Y (sink) R X (deadlock))))')).
126
127 :- assert_must_succeed((
128 pp_ltl_formula(implies(
129 ap(enabled(btrans(event('A')))),
130 or(weakuntil(
131 ap(bpred(equal(identifier(op('x')),integer(1)))),
132 ap(bpred(equal(identifier(op('x')),integer(2)))) ),
133 finally(action(btrans(event('A')))))),Text),
134 Text = '(e(A) => (({x = 1} W {x = 2}) or F ([A])))')).
135
136 :- assert_must_succeed((
137 pp_ltl_formula(implies(
138 current,
139 and(once(ap(bpred(equal(identifier(op('x')),integer(1))))),
140 action(btrans(event('A',equal(identifier(op('x')),integer(2)),_))))),Text),
141 Text = '(current => (O ({x = 1}) & [A | x = 2]))')).
142
143 :- assert_must_succeed((
144 pp_ltl_formula(fairnessimplication(
145 and(strongassumptions(and(ap(strong_fair(btrans(event('A')))),
146 ap(strong_fair(btrans(event('B')))))),
147 weakassumptions(or(ap(weak_fair(btrans(event('A')))),
148 ap(weak_fair(btrans(event('B'))))))),
149 true),Text),
150 Text = '(((SF(A) & SF(B))) & (WF(A) or WF(B)) => true)')).
151
152 :- assert_must_succeed((
153 pp_ltl_formula(fairnessimplication(
154 and(weakassumptions(and(ap(weak_fair(btrans(event('A')))),
155 ap(weak_fair(btrans(event('B')))))),
156 strongassumptions(or(ap(strong_fair(btrans(event('A')))),
157 ap(strong_fair(btrans(event('B'))))))),
158 true),Text),
159 Text = '(((WF(A) & WF(B))) & (SF(A) or SF(B)) => true)')).
160
161 :- assert_must_succeed((
162 pp_ltl_formula(globally(finally(ap(available(btrans(event('A')))))),Text),
163 Text = 'G (F (Av(A)))')).
164
165 /* Simple Pretty Printer for LTL/CTL Formulas */
166
167 pp_ltl(true,['true'|S],S).
168 pp_ltl(false,['false'|S],S).
169 pp_ltl(deadlock,['deadlock'|S],S).
170 pp_ltl(sink,['sink'|S],S).
171 pp_ltl(current,['current'|S],S).
172 pp_ltl(globally(F),['G ('| S],T) :- !, pp_ltl(F,S,[')'|T]).
173 pp_ltl(finally(F),['F ('| S],T) :- !, pp_ltl(F,S,[')'|T]).
174 pp_ltl(next(F),['X ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
175 pp_ltl(yesterday(F),['Y ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
176 pp_ltl(since(F,G),['('|S],T) :- !,
177 pp_ltl(F,S,[' S '| S1]),
178 pp_ltl(G,S1,[')'|T]).
179 pp_ltl(once(F),['O ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
180 pp_ltl(historically(F),['H ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
181 pp_ltl(until(F,G),['('|S],T) :- !,
182 pp_ltl(F,S,[' U '| S1]),
183 pp_ltl(G,S1,[')'|T]).
184 pp_ltl(weakuntil(F,G),['('|S],T) :- !,
185 pp_ltl(F,S,[' W '| S1]),
186 pp_ltl(G,S1,[')'|T]).
187 pp_ltl(release(F,G),['('|S],T) :- !,
188 pp_ltl(F,S,[' R '| S1]),
189 pp_ltl(G,S1,[')'|T]).
190 pp_ltl(implies(F,G),['('|S],T) :- !,
191 pp_ltl(F,S,[' => '| S1]),
192 pp_ltl(G,S1,[')'|T]).
193 pp_ltl(fairnessimplication(FairAssump,Formula),['('|S],T) :- !,
194 pp_ltl_fairness(FairAssump,S,[' => '| S1]),
195 pp_ltl(Formula,S1,[')'|T]).
196 pp_ltl(or(F,G),['('|S],T) :- !,
197 pp_ltl(F,S,[' or '| S1]),
198 pp_ltl(G,S1,[')'|T]).
199 pp_ltl(and(F,G),['('|S],T) :- !,
200 pp_ltl(F,S,[' & '| S1]),
201 pp_ltl(G,S1,[')'|T]).
202 pp_ltl(not(F),['not('| S],T) :- !, pp_ltl(F,S,[')'|T]).
203 pp_ltl(ap(AP),[Pred|S],S) :- !, pp_ap(AP,Pred).
204 pp_ltl(action(A),[Action|S],S) :- !, pp_tp(A,Action).
205
206 /* Pretty Print CTL Part */
207 pp_ltl(ena(F),['EX ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
208 pp_ltl(en(F), ['EX ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
209 pp_ltl(an(F), ['AX ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
210 pp_ltl(eg(F), ['EG ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
211 pp_ltl(ef(F), ['EF ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
212 pp_ltl(ag(F), ['AG ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
213 pp_ltl(af(F), ['AF ('|S],T) :- !, pp_ltl(F,S,[')'|T]).
214 pp_ltl(eu(F,G), ['( E '|S],T) :- !,
215 pp_ltl(F,S,[' U '|S1]),
216 pp_ltl(G,S1,[')'|T]).
217
218 /* Pretty Print Fairness Assumptions */
219 pp_ltl_fairness(strongassumptions(F),S1,T) :- !,
220 (F=all ->
221 S1 = ['SEF'|S], T = S
222 ; otherwise ->
223 S1 = ['('|S], pp_ltl_fairness1(F,S,[')'|T])
224 ).
225 pp_ltl_fairness(weakassumptions(F),S1,T) :- !,
226 (F=all ->
227 S1 = ['WEF'|S], T = S
228 ; otherwise ->
229 S1 = ['('|S], pp_ltl_fairness1(F,S,[')'|T])
230 ).
231 pp_ltl_fairness(and(F,G),S,T) :- !,
232 pp_ltl_fairness(F,S,[' & '|S1]),
233 pp_ltl_fairness(G,S1,T).
234
235 pp_ltl_fairness1(and(F,G),['('|S],T) :- !,
236 pp_ltl_fairness1(F,S,[' & '|S1]),
237 pp_ltl_fairness1(G,S1,[')'|T]).
238 pp_ltl_fairness1(or(F,G),S,T) :- !,
239 pp_ltl_fairness1(F,S,[' or '|S1]),
240 pp_ltl_fairness1(G,S1,T).
241 pp_ltl_fairness1(ap(AP),[Pred|S],S) :- !,
242 pp_ap(AP,Pred).