https://github.com/EasyCrypt/easycrypt
Tip revision: f89ce0747dd04c0f3559e1aa1daea211efe94549 authored by Antoine Séré on 17 March 2023, 14:32:04 UTC
Bug equal and hash fixed
Bug equal and hash fixed
Tip revision: f89ce07
WF.ec
(* An axiom-free formalization of well-founded relations, induction
and recursion.
Makes no use of smt. *)
require import AllCore StdOrder.
import IntOrder.
(* ------------- predicates, expanding on prelude/Logic.ec ------------ *)
type 'a predi = 'a -> bool.
(* if pr : 'a predi and x : 'a, then we read "pr x" as "x satisfies
pr"; we can think of predicates as representing sets - the elements
they map to true *)
op is_empty (xs : 'a predi) : bool = forall (y : 'a), ! xs y.
op is_nonempty (xs : 'a predi) : bool = ! is_empty xs.
lemma is_nonempty (xs : 'a predi) :
is_nonempty xs <=> exists (y : 'a), xs y.
proof.
rewrite /is_nonempty /is_empty.
by rewrite negb_forall.
qed.
op sub (xs ys : 'a predi) : bool =
forall (z : 'a), xs z => ys z.
lemma sub_trans (zs xs ys : 'a predi) :
sub xs zs => sub zs ys => sub xs ys.
proof.
rewrite /sub => sub_xs_zs sub_zs_ys z xs_z.
by rewrite sub_zs_ys sub_xs_zs.
qed.
(* ----------------------------- relations ---------------------------- *)
(* the type of relations is defined in prelude/Logic.ec as
type 'a rel = 'a -> 'a -> bool.
if rel : 'a rel and x, y : 'a, then we read "rel x y" as "the pair
(x, y) is in rel" *)
(* ---------------------- well-founded relations ---------------------- *)
op wf (rel : 'a rel) : bool =
forall (xs : 'a predi),
is_nonempty xs =>
exists (x : 'a), xs x /\ ! exists (y : 'a), xs y /\ rel y x.
(* predecessors of x in rel *)
op predecs (rel : 'a rel, x : 'a) : 'a predi =
fun y => rel y x.
(* ----------- induction principle on well-founded relations ---------- *)
lemma wf_ind (rel : 'a rel, P : 'a -> bool) :
wf rel =>
(forall (x : 'a),
(forall (y : 'a), rel y x => P y) =>
P x) =>
(forall (x : 'a), P x).
proof.
move => wf_rel H.
case (forall x, P x) => //.
rewrite negb_forall => [[z not_P_z]].
have [x [#] not_P_x not_ex] := wf_rel (predC P) _.
rewrite is_nonempty.
by exists z.
have P_x : P x.
apply (H x) => y rel_y_x.
case (P y) => [// | not_P_y].
have // : exists y, predC P y /\ rel y x.
by exists y.
by rewrite /predC in not_P_x.
qed.
(* ---------------- constructing well-founded relations --------------- *)
(* restriction of Int.(<) to natural numbers *)
op lt_nat (x y : int) = 0 <= x < y.
lemma wf_lt_nat : wf lt_nat.
proof.
move => xs is_ne_xs.
have H :
forall n,
0 <= n => xs n =>
exists x, xs x /\ ! exists y, xs y /\ lt_nat y x.
apply sintind => i ge0_i IH xs_i.
case (exists y, xs y /\ lt_nat y i) =>
[[y [#] xs_y] | not_ex].
rewrite /lt_nat => [[ge0_y lt_y_i]].
by apply (IH y).
by exists i.
have [x xs_x] : exists x, xs x.
by apply is_nonempty.
case (0 <= x) => [ge0_x | lt0_x].
by apply (H x).
rewrite -ltzNge in lt0_x.
exists x; split => //.
case (exists y, xs y /\ lt_nat y x) => [[y [xs_y]] | //].
rewrite /lt_nat => [[ge0_y lt_y_x]].
have lt0_y : y < 0.
by rewrite (ltz_trans x).
have // : y < y.
by rewrite (ltr_le_trans 0).
qed.
(* lexicographic orderings *)
op wf_lex (wfr1 : 'a rel, wfr2 : 'b rel) : ('a * 'b) rel =
fun (p1 p2 : 'a * 'b) =>
wfr1 p1.`1 p2.`1 \/ (p1.`1 = p2.`1 /\ wfr2 p1.`2 p2.`2).
lemma wf_lex (wfr1 : 'a rel, wfr2 : 'b rel) :
wf wfr1 => wf wfr2 => wf (wf_lex wfr1 wfr2).
proof.
move => wf_wfr1 wf_wfr2.
rewrite /wf_lex /wf => xs /is_nonempty [x xs_x].
have [y1 [] /= [y [xs_y y1_eq]] not_y1_pred]
:= wf_wfr1 (fun y1 => exists p, xs p /\ p.`1 = y1) _.
rewrite /is_nonempty /is_empty negb_forall /=.
by exists x.`1; exists x.
rewrite negb_exists /= in not_y1_pred.
have [z2 [] /= [z [xs_z [z1_eq z2_eq]]] not_z2_pred]
:= wf_wfr2
(fun z2 =>
exists (p : 'a * 'b), xs p /\ p.`1 = y1 /\ p.`2 = z2) _.
rewrite /is_nonempty /is_empty negb_forall /=.
by exists y.`2; exists y.
rewrite negb_exists /= in not_z2_pred.
exists z.
rewrite xs_z /=.
case (exists y0,
xs y0 /\ (wfr1 y0.`1 z.`1 \/ y0.`1 = z.`1 /\ wfr2 y0.`2 z.`2)) =>
// [[p] [xs_p [wfr1_p1_z1 | [eq_p1_z1 wfr2_p2_z2]]]].
have contrad : (exists p', xs p' /\ p'.`1 = p.`1) /\ wfr1 p.`1 y1.
split.
exists p; by rewrite xs_p.
by rewrite -z1_eq.
have // := not_y1_pred p.`1.
have contrad :
(exists (p' : 'a * 'b), xs p' /\ p'.`1 = y1 /\ p'.`2 = p.`2) /\
wfr2 p.`2 z2.
split.
exists p; by rewrite xs_p eq_p1_z1 z1_eq.
rewrite -z2_eq wfr2_p2_z2.
have // := not_z2_pred p.`2.
qed.
(* restrictions of well-founded relations *)
op wf_restr (wfr : 'a rel, rel : 'a rel) : 'a rel =
fun (x : 'a, y : 'a) => wfr x y /\ rel x y.
lemma wf_restr (wfr : 'a rel, rel : 'a rel) :
wf wfr => wf (wf_restr wfr rel).
proof.
move => wf_wfr.
rewrite /wf /wf_restr => xs ne_xs.
have [x [xs_x not_ex_x_pred]] := wf_wfr xs _.
trivial.
exists x.
rewrite xs_x /=.
case (exists y, xs y /\ wfr y x /\ rel y x) =>
[[y [#] xs_y wfr_y_x rel_y_x] | //].
have // : exists y, xs y /\ wfr y x.
by exists y.
qed.
(* precomposing well-founded relation with function *)
op wf_pre (f : 'a -> 'b, wfr : 'b rel) : 'a rel =
fun (x : 'a, y : 'a) => wfr (f x) (f y).
lemma wf_pre (f : 'a -> 'b, wfr : 'b rel) :
wf wfr => wf (wf_pre f wfr).
proof.
move => wf_wfr.
rewrite /wf /wf_pre => xs.
rewrite /is_nonempty /is_empty negb_forall => /= [[x xs_x]].
have [y /= [[x' [xs_x' <-]] not_ex_f_x'_pred]]
:= (wf_wfr (fun y => exists x, xs x /\ f x = y) _).
rewrite /is_nonempty /is_empty negb_forall /=.
by exists (f x); exists x.
exists x'.
rewrite xs_x' /=.
case (exists x'', xs x'' /\ wfr (f x'') (f x')) =>
[[x'' [xs_x'' wfr_f_x''_f_x']] | //].
have // :
exists y', (exists x'', xs x'' /\ f x'' = y') /\ wfr y' (f x').
exists (f x'').
rewrite wfr_f_x''_f_x' /=.
by exists x''.
qed.
(* ---------------------- well-founded recursion ---------------------- *)
(* if you just want to *use* well-founded recursion, skip ahead to
definitions of wf_rec_def and wf_recur *)
(* generalized relations *)
type ('a, 'b) grel = 'a -> 'b -> bool.
op grel0 : ('a, 'b) grel = (* empty relation *)
fun (x : 'a, y : 'b) => false.
op grelT : ('a, 'b) grel = (* relation with all elements *)
fun (x : 'a, y : 'b) => true.
op grel_sub (r1 r2 : ('a, 'b) grel) : bool =
forall (x : 'a, y : 'b), r1 x y => r2 x y.
lemma grel_sub_trans (grel' grel1 grel2 : ('a, 'b) grel) :
grel_sub grel1 grel' => grel_sub grel' grel2 => grel_sub grel1 grel2.
proof.
rewrite /grel_sub => sub_grel1_grel' sub_grel'_grel2 x y grel1_x_y.
by rewrite sub_grel'_grel2 sub_grel1_grel'.
qed.
op grel_dom (grel : ('a, 'b) grel) : 'a predi =
fun (x : 'a) => exists (y : 'b), grel x y.
op grel_rng (grel : ('a, 'b) grel) : 'b predi =
fun (y : 'b) => exists (x : 'a), grel x y.
op grel_is_fun (grel : ('a, 'b) grel) : bool =
forall (x : 'a, y z : 'b), grel x y => grel x z => y = z.
lemma grel_eq_same_dom (grel1 grel2 : ('a, 'b) grel, xs : 'a predi) :
grel_dom grel1 = xs => grel_dom grel2 = xs =>
(forall (x : 'a), xs x => grel1 x = grel2 x) =>
grel1 = grel2.
proof.
move => dom_grel1_xs dom_grel2_xs grel1_grel2_agree_dom.
apply fun_ext => x.
case (xs x) => [xs_x | not_xs_x].
by apply grel1_grel2_agree_dom.
have @/grel_dom not_grel1_x : ! grel_dom grel1 x.
by rewrite dom_grel1_xs.
have @/grel_dom not_grel2_x : ! grel_dom grel2 x.
by rewrite dom_grel2_xs.
apply fun_ext => y.
have -> : grel1 x y = false.
case (grel1 x y) => [grel1_x_y | //].
have // : exists y, grel1 x y.
by exists y.
have -> // : grel2 x y = false.
case (grel2 x y) => [grel2_x_y | //].
have // : exists y, grel2 x y.
by exists y.
qed.
lemma grel_funs_eq_on_first (grel1 grel2 : ('a, 'b) grel, x : 'a, y : 'b) :
grel_is_fun grel1 => grel_is_fun grel2 =>
grel1 x y => grel2 x y => grel1 x = grel2 x.
proof.
move => is_fun_grel1 is_fun_grel2 grel1_x_y grel2_x_y.
apply fun_ext => y'.
case (y' = y) => [-> | ne_y'_y].
by rewrite grel1_x_y grel2_x_y.
have -> : grel1 x y' = false.
case (grel1 x y') => [grel1_x_y' | //].
have // : y' = y.
by apply (is_fun_grel1 x).
have -> // : grel2 x y' = false.
case (grel2 x y') => [grel2_x_y' | //].
have // : y' = y.
by apply (is_fun_grel2 x).
qed.
op grel_restr (grel : ('a, 'b) grel, xs : 'a predi) : ('a, 'b) grel =
fun (x : 'a) => if xs x then grel x else fun (y : 'b) => false.
lemma grel_restr (grel : ('a, 'b) grel, xs : 'a predi) :
sub xs (grel_dom grel) =>
grel_dom (grel_restr grel xs) = xs /\
(forall (x : 'a, y : 'b),
grel_restr grel xs x y <=>
grel x y /\ xs x).
proof.
rewrite /sub /grel_restr /grel_dom => sub_xs_dom_grel.
split => [| x y].
rewrite fun_ext => x.
rewrite eqboolP.
case (xs x) => [xs_x | //].
by rewrite sub_xs_dom_grel.
by case (xs x).
qed.
lemma grel_restr_grel_sub (grel : ('a, 'b) grel, xs : 'a predi) :
grel_sub (grel_restr grel xs) grel.
proof.
rewrite /grel_sub /grel_restr => x y.
by case (xs x).
qed.
lemma grel_restr_dom (grel : ('a, 'b) grel, xs : 'a predi) :
sub xs (grel_dom grel) =>
grel_dom (grel_restr grel xs) = xs.
proof.
move => sub_xs_dom_grel.
have // := grel_restr grel xs _.
trivial.
qed.
lemma grel_restr_is_fun (grel : ('a, 'b) grel, xs : 'a predi) :
sub xs (grel_dom grel) => grel_is_fun grel =>
grel_is_fun (grel_restr grel xs).
proof.
move => sub_xs_dom_grel grel_is_fun_grel.
rewrite /grel_is_fun /grel_restr => x y z.
case (xs x) => [xs_x | //].
apply grel_is_fun_grel.
qed.
op grel_to_fun (def : 'b, grel : ('a, 'b) grel) : 'a -> 'b =
fun (x : 'a) => choiceb (grel x) def.
op grel_choose_sub_fun (grel : ('a, 'b) grel) : ('a, 'b) grel =
fun (x : 'a, y : 'b) =>
grel_dom grel x /\ y = choiceb (grel x) witness.
lemma grel_choose_sub_fun (grel : ('a, 'b) grel) :
let grel' = grel_choose_sub_fun grel in
grel_is_fun grel' /\ grel_sub grel' grel /\
grel_dom grel' = grel_dom grel.
proof.
rewrite /=.
split.
by rewrite /grel_choose_sub_fun /grel_is_fun => x y z.
split.
rewrite /grel_choose_sub_fun /grel_sub => x y [dom_grel_x ->].
by apply (choicebP (grel x)).
rewrite /grel_choose_sub_fun /grel_dom fun_ext => x.
rewrite eqboolP.
split => [[y [] -> //] | [y grel_x_y]].
exists (choiceb (grel x) witness).
split; [by exists y | trivial].
qed.
lemma grel_exists_sub_fun (grel : ('a, 'b) grel, xs : 'a predi) :
sub xs (grel_dom grel) =>
exists (grel' : ('a, 'b) grel),
grel_sub grel' grel /\ grel_is_fun grel' /\ grel_dom grel' = xs.
proof.
move => sub_xs_dom_grel.
exists (grel_restr (grel_choose_sub_fun grel) xs).
have /= [#] is_fun_choose_grel sub_choose_grel_grel dom_eq_choose_grel_grel
:= grel_choose_sub_fun grel.
split.
rewrite (grel_sub_trans (grel_choose_sub_fun grel))
1:(grel_restr_grel_sub (grel_choose_sub_fun grel)).
have /= [#] _ -> // := (grel_choose_sub_fun grel).
split.
by rewrite (grel_restr_is_fun (grel_choose_sub_fun grel))
1:dom_eq_choose_grel_grel.
by rewrite grel_restr_dom 1:dom_eq_choose_grel_grel.
qed.
type ('a, 'b) grels = ('a, 'b) grel predi. (* represents set of grels *)
(* generalized intersection
the intersection of the empty grels is the universal relation,
which exists because we are working in a typed setting *)
op grels_inter (grels : ('a, 'b) grels) : ('a, 'b) grel =
fun (x : 'a, y : 'b) =>
forall (grel : ('a, 'b) grel), grels grel => grel x y.
lemma grels_inter_sub (grels : ('a, 'b) grels, grel : ('a, 'b) grel) :
grels grel => grel_sub (grels_inter grels) grel.
proof.
move => grels_grel.
rewrite /grel_sub => x y.
rewrite /grels_inter => all_x_y.
by apply all_x_y.
qed.
(* body of well-founded recursive definition: given an input (x : 'a)
and a function (f : 'a -> 'b) for doing recursive calls, produce an
answer of type 'b *)
type ('a, 'b) wf_rec_def = 'a -> ('a -> 'b) -> 'b.
(* when grel is closed with respect to a well-founded relation wfr, a
default element def, and a body wfrd of a recursive definition
the default element is returned if wfrd calls (grel_to_fun def
grel') on a value not in the domain of grel', i.e., one that is
not a predecessor of x in wfr *)
op wf_closed
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def,
grel : ('a, 'b) grel) : bool =
forall (x : 'a, grel' : ('a, 'b) grel),
grel_sub grel' grel => grel_is_fun grel' =>
grel_dom grel' = predecs wfr x =>
grel x (wfrd x (grel_to_fun def grel')).
lemma wfc_total
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def,
grel : ('a, 'b) grel, x : 'a) :
wf wfr => wf_closed wfr def wfrd grel => grel_dom grel x.
proof.
move => wf_wfr wfc_grel.
move : x.
apply (wf_ind wfr) => //= x IH.
have [grel' [#] sub_grel'_grel is_fun_grel' dom_grel'_eq_preds_x]
:= grel_exists_sub_fun grel (predecs wfr x) _.
apply IH.
have grel_x_witness := wfc_grel x grel' _ _ _; first 3 trivial.
by exists (wfrd x (grel_to_fun def grel')).
qed.
lemma wfc_inter
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def,
grels : ('a, 'b) grels) :
(forall (grel : ('a, 'b) grel),
grels grel => wf_closed wfr def wfrd grel) =>
wf_closed wfr def wfrd (grels_inter grels).
proof.
rewrite /wf_closed =>
all_closed x grel' grel'_sub_inter is_fun_grel' dom_grel'_preds.
rewrite /grels_inter in grel'_sub_inter.
rewrite /grels_inter => grel grels_grel.
rewrite all_closed // /grel_sub => x' y' grel'_x'_y'.
by rewrite grel'_sub_inter.
qed.
(* this is our candidate for the recursively defined function, as a
grel: the intersection of the set of all closed grels *)
op wfc_least
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) : ('a, 'b) grel =
grels_inter (wf_closed wfr def wfrd).
lemma wfc_least_closed
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) :
wf_closed wfr def wfrd (wfc_least wfr def wfrd).
proof.
by rewrite /wfc_least wfc_inter.
qed.
lemma wfc_least_total
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def, x : 'a) :
wf wfr => grel_dom (wfc_least wfr def wfrd) x.
proof.
move => wf_wfr.
rewrite (wfc_total wfr def wfrd) // wfc_least_closed.
qed.
lemma wfc_least_dom_predT
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) :
wf wfr => grel_dom (wfc_least wfr def wfrd) = predT.
proof.
move => wf_wfr.
apply fun_ext => x.
by rewrite wfc_least_total.
qed.
lemma wfc_least_least
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def,
grel : ('a, 'b) grel) :
wf_closed wfr def wfrd grel =>
grel_sub (wfc_least wfr def wfrd) grel.
proof.
rewrite /wfc_least => grel_closed.
by apply grels_inter_sub.
qed.
op wfc_least_char_aux
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) : ('a, 'b) grel =
fun (x : 'a, y : 'b) =>
wfc_least wfr def wfrd x y /\
exists (grel' : ('a, 'b) grel),
grel_sub grel' (wfc_least wfr def wfrd) /\ grel_is_fun grel' /\
grel_dom grel' = predecs wfr x /\ y = wfrd x (grel_to_fun def grel').
lemma wfc_least_char
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def,
x : 'a, y : 'b) :
wfc_least wfr def wfrd x y =>
exists (grel' : ('a, 'b) grel),
grel_sub grel' (wfc_least wfr def wfrd) /\ grel_is_fun grel' /\
grel_dom grel' = predecs wfr x /\ y = wfrd x (grel_to_fun def grel').
proof.
have aux_closed :
wf_closed wfr def wfrd (wfc_least_char_aux wfr def wfrd).
rewrite /wf_closed =>
x' grel' sub_grel'_aux is_fun_grel' dom_grel'_preds_x.
rewrite /wfc_least_char_aux.
have sub_grel'_least : grel_sub grel' (wfc_least wfr def wfrd).
rewrite (grel_sub_trans (wfc_least_char_aux wfr def wfrd)) //
/wfc_least_char_aux => x'' y'' //.
split.
by apply wfc_least_closed.
by exists grel'.
move => least_x_y.
have @/wfc_least_char_aux [_ ->] // :
wfc_least_char_aux wfr def wfrd x y.
by rewrite (wfc_least_least wfr def wfrd
(wfc_least_char_aux wfr def wfrd)).
qed.
op wfc_least_is_fun_aux
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) : ('a, 'b) grel =
fun (x : 'a, y : 'b) =>
wfc_least wfr def wfrd x y /\
forall (z : 'b), wfc_least wfr def wfrd x z => y = z.
lemma wfc_least_is_fun
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) :
grel_is_fun (wfc_least wfr def wfrd).
proof.
have aux_closed :
wf_closed wfr def wfrd (wfc_least_is_fun_aux wfr def wfrd).
rewrite /wf_closed =>
x' grel' grel'_sub_aux is_fun_grel' dom_grel'_preds_x'.
rewrite /wfc_least_is_fun_aux.
have sub_grel'_least : grel_sub grel' (wfc_least wfr def wfrd).
by rewrite (grel_sub_trans (wfc_least_is_fun_aux wfr def wfrd)) //
/wfc_least_is_fun_aux => x'' y''.
have -> /= z' least_x'_z' :
wfc_least wfr def wfrd x' (wfrd x' (grel_to_fun def grel')).
by apply wfc_least_closed.
have [grel'' [#] sub_grel''_least is_fun_grel''
dom_grel''_preds_x' ->]
:= wfc_least_char wfr def wfrd x' z' _.
trivial.
congr; congr.
rewrite (grel_eq_same_dom grel' grel'' (predecs wfr x')) // =>
a preds_wfr_x'_a.
have @/grel_dom [b grel'_a_b] : grel_dom grel' a.
by rewrite dom_grel'_preds_x'.
have @/grel_dom [b' grel''_a_b']: grel_dom grel'' a.
by rewrite dom_grel''_preds_x'.
have @/wfc_least_is_fun_aux [_ least_a_uniq_b] := grel'_sub_aux a b _.
trivial.
have least_a_b' := sub_grel''_least a b' _.
trivial.
have eq_b_b' := least_a_uniq_b b' _.
trivial.
move : grel''_a_b'; rewrite -eq_b_b'; move => grel''_a_b.
by apply (grel_funs_eq_on_first grel' grel'' a b).
rewrite /grel_is_fun => x y z least_x_y least_x_z.
have @/wfc_least_is_fun_aux [_ least_x_uniq_y] :
wfc_least_is_fun_aux wfr def wfrd x y.
by rewrite (wfc_least_least wfr def wfrd
(wfc_least_is_fun_aux wfr def wfrd)).
by apply least_x_uniq_y.
qed.
lemma wfc_least_result
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def, x : 'a) :
wf wfr =>
wfc_least wfr def wfrd x
(wfrd x
(grel_to_fun def
(grel_restr (wfc_least wfr def wfrd) (predecs wfr x)))).
proof.
move => wf_wfr.
apply (wfc_least_closed wfr def wfrd x
(grel_restr (wfc_least wfr def wfrd) (predecs wfr x))).
apply grel_restr_grel_sub.
apply grel_restr_is_fun.
by rewrite wfc_least_dom_predT.
apply wfc_least_is_fun.
by rewrite grel_restr_dom 1:wfc_least_dom_predT.
qed.
(* well-founded recursion operator - smt solvers treat as black box,
but can use wf_recur lemma *)
op nosmt wf_recur
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def) : 'a -> 'b =
grel_to_fun def (wfc_least wfr def wfrd).
lemma choiceb_grel_fun (grel : ('a, 'b) grel, x : 'a, y, def : 'b) :
grel_is_fun grel => grel x y => choiceb (grel x) def = y.
proof.
move => grel_is_fun_grel grel_x_y.
have grel_x_choice_grel_x := choicebP (grel x) def _.
by exists y.
by apply (grel_is_fun_grel x).
qed.
(* the recursion lemma *)
lemma wf_recur
(wfr : 'a rel, def : 'b, wfrd : ('a, 'b) wf_rec_def, x : 'a) :
wf wfr =>
wf_recur wfr def wfrd x =
wfrd x
(fun y =>
if wfr y x
then wf_recur wfr def wfrd y
else def).
proof.
move => wf_wfr.
rewrite /wf_recur /grel_to_fun.
apply (choiceb_grel_fun (wfc_least wfr def wfrd) x).
apply wfc_least_is_fun.
have least_result := wfc_least_result wfr def wfrd x _.
trivial.
have -> :
(fun (y : 'a) =>
if wfr y x then choiceb (wfc_least wfr def wfrd y) def
else def) =
(grel_to_fun def (grel_restr (wfc_least wfr def wfrd) (predecs wfr x))).
rewrite /grel_to_fun.
apply fun_ext => y.
case (wfr y x) => [wfr_y_x | not_wfr_y_x].
by rewrite /grel_restr /predecs wfr_y_x.
rewrite eq_sym choiceb_dfl //.
- by rewrite /grel_restr /predecs 1:not_wfr_y_x.
- by rewrite least_result.
qed.