Skip to content

Commit eeca69f

Browse files
committed
[documentation]: document if
1 parent a0bf172 commit eeca69f

1 file changed

Lines changed: 227 additions & 0 deletions

File tree

doc/tactics/if.rst

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
========================================================================
2+
Tactic: ``if``
3+
========================================================================
4+
5+
In EasyCrypt, the ``if`` tactic is a way of reasoning about program(s)
6+
that use conditionals. When a program begins with an if statement,
7+
execution will follow one path if the condition is ``true`` and another
8+
path if it is ``false``. The tactic says that to prove the program is
9+
correct, you must consider both cases: you assume the condition holds
10+
and show that the *then* branch establishes the desired result, and you
11+
assume the condition does not hold and show that the *else* branch
12+
establishes the same result. EasyCrypt allows you to apply this rule
13+
only when the program starts with an if, so the proof can split immediately
14+
from the initial state. If the conditional appears deeper in the code,
15+
you must first use the ``seq`` tactic to separate the earlier commands
16+
from the conditional.
17+
18+
.. contents::
19+
:local:
20+
21+
------------------------------------------------------------------------
22+
Variant: ``if`` (HL)
23+
------------------------------------------------------------------------
24+
25+
.. ecproof::
26+
:title: Hoare logic example
27+
28+
require import AllCore.
29+
30+
module M = {
31+
proc f(x : int) = {
32+
var y : int;
33+
34+
if (x < 0) {
35+
y <- -x;
36+
} else {
37+
y <- x;
38+
}
39+
40+
return y;
41+
}
42+
}.
43+
44+
pred p : glob M.
45+
46+
lemma L : hoare[M.f : p (glob M) ==> 0 <= res].
47+
proof.
48+
proc.
49+
(*$*) if.
50+
(* First goal: (x < 0) holds *)
51+
- wp. skip. smt().
52+
(* Second goal: (x < 0) does not hold *)
53+
- wp. skip. smt().
54+
qed.
55+
56+
------------------------------------------------------------------------
57+
Variant: ``if`` (pRHL)
58+
------------------------------------------------------------------------
59+
60+
In probabilistic relational Hoare logic, the ``if`` tactic is applied
61+
in a lock-step manner, meaning that the two programs being compared must
62+
proceed through the conditional in sync. This requires that their guards
63+
evaluate to the same boolean value in the related states, so that either
64+
both programs take the *then* branch or both take the *else* branch.
65+
66+
As a result, using the ``if`` tactic involves establishing that the two
67+
conditions are equal under the current relational invariant before
68+
splitting into the two synchronized cases.
69+
70+
Although synchronization ensures both guards take the same value, the
71+
implementation splits only on the left guard (rather than explicitly
72+
stating both are true or both are false).
73+
74+
.. ecproof::
75+
:title: Relational Hoare logic example (2-sided)
76+
77+
require import AllCore.
78+
79+
module M = {
80+
proc f(x : int) = {
81+
var y : int;
82+
83+
if (x < 0) {
84+
y <- -x;
85+
} else {
86+
y <- x;
87+
}
88+
89+
return y;
90+
}
91+
}.
92+
93+
lemma L : equiv[M.f ~ M.f: x{1} = x{2} ==> res{1} = res{2}].
94+
proof.
95+
proc.
96+
(*$*) if.
97+
(* First goal: we prove that the guards are in sync. *)
98+
- smt().
99+
(* First goal: (x < 0) holds *)
100+
- wp; skip. smt().
101+
(* Second goal: (x < 0) does not hold *)
102+
- wp; skip. smt().
103+
qed.
104+
105+
106+
------------------------------------------------------------------------
107+
Variant: ``if {side}`` (pRHL)
108+
------------------------------------------------------------------------
109+
110+
In the one-sided ``if`` tactic used in pRHL, the user specifies whether
111+
the conditional reasoning should be applied to the left or the right
112+
program. The tactic then performs a case analysis only on the ``if``
113+
statement at the top of that chosen program, generating separate goals
114+
for the ``true`` and ``false`` branches on that side. Unlike the lock-step
115+
relational ``if`` tactic, no synchronization of guards is required, and
116+
the other program is not constrained to take the same branch or even to
117+
have a similar structure.
118+
119+
.. ecproof::
120+
:title: Relational Hoare logic example (1-sided)
121+
122+
require import AllCore.
123+
124+
module M = {
125+
proc f(x : int) = {
126+
var y : int;
127+
128+
if (x < 0) {
129+
y <- -x;
130+
} else {
131+
y <- x;
132+
}
133+
134+
return y;
135+
}
136+
137+
proc g(x : int) = {
138+
return `|x|;
139+
}
140+
}.
141+
142+
lemma L : equiv[M.f ~ M.g: x{1} = x{2} ==> res{1} = res{2}].
143+
proof.
144+
proc.
145+
(*$*) if{1}.
146+
(* First goal: (x < 0) holds (left program) *)
147+
- wp; skip. smt().
148+
(* Second goal: (x < 0) does not hold (left program) *)
149+
- wp; skip. smt().
150+
qed.
151+
152+
------------------------------------------------------------------------
153+
Variant: ``if`` (pHL)
154+
------------------------------------------------------------------------
155+
156+
In probabilistic Hoare logic, the ``if`` tactic behaves much like in
157+
standard Hoare logic, except that the postcondition is expressed in terms
158+
of a probability bound. Since the if statement is the first command of
159+
the program, its guard is evaluated immediately in the initial state and
160+
therefore deterministically takes either the ``true`` or the ``false``
161+
value, with probability 1. As a result, the program execution splits into
162+
one of the two branches without introducing any additional probabilistic
163+
choice at the level of control flow, and the probability bound is preserved
164+
by reasoning separately about each branch under the corresponding
165+
assumption on the guard.
166+
167+
.. ecproof::
168+
:title: Probabilistic Hoare logic example
169+
170+
require import AllCore.
171+
172+
module M = {
173+
proc f(x : int) = {
174+
var y : int;
175+
176+
if (x < 0) {
177+
y <- -x;
178+
} else {
179+
y <- x;
180+
}
181+
182+
return y;
183+
}
184+
}.
185+
186+
lemma L : phoare[M.f : true ==> 0 <= res] = 1%r.
187+
proof.
188+
proc.
189+
(*$*) if.
190+
(* First goal: (x < 0) holds *)
191+
- wp; skip. smt().
192+
(* Second goal: (x < 0) does not hold *)
193+
- wp; skip. smt().
194+
qed.
195+
196+
------------------------------------------------------------------------
197+
Variant: ``if`` (eHL)
198+
------------------------------------------------------------------------
199+
200+
.. ecproof::
201+
:title: Expectation Hoare logic example
202+
203+
require import AllCore Xreal.
204+
205+
module M = {
206+
proc f(x : int) = {
207+
var y : int;
208+
209+
if (x < 0) {
210+
y <- -x;
211+
} else {
212+
y <- x;
213+
}
214+
215+
return y;
216+
}
217+
}.
218+
219+
lemma L : ehoare[M.f : 0%xr ==> (0 <= res)%xr].
220+
proof.
221+
proc.
222+
(*$*) if.
223+
(* First goal: (x < 0) holds *)
224+
- wp; skip. admit. (* FIXME *)
225+
(* Second goal: (x < 0) does not hold *)
226+
- wp; skip. admit. (* FIXME *)
227+
qed.

0 commit comments

Comments
 (0)