why3doc index index


(* Define a (bare) Hoare-type intuitionnistic logic on games....
   TODO/FIXME: in practice, there does not seem to be a real role
   for the arrow... could simply remove it. *)
module Fmla

  use import ho_set.Set
  use import ho_set.SetBigOps
  use import ho_rel.Rel
  use import ho_rel.RelSet
  use import order.Ordered
  use import order.Chain
  use import fn.Fun
  use import fn.Image
  use import game.Game
  use import game_simulation.SimDef
  use import subgame.SubGame

  (* Game formula: monotonic predicates over games. *)
  type fmla 'a = { interp : set (game 'a) }
    invariant { forall g1 g2. interp g1 /\ subgame g1 g2 -> interp g2 }
    by { interp = fun _ -> false }

  (* Basic formula: enforce within the underlying game. *)
  let ghost function enforce (p q:{set 'a}) : {fmla 'a} =
    assert { forall s:set 'a. related (=) s = s by sext s (related (=) s) };
    { interp = fun g -> have_uniform_winning_strat g p q }

  (* Intuitionnistic arrow. *)
  let ghost function arrow (f1 f2:{fmla 'a}) : {fmla 'a} =
    { interp = pure { fun g ->
      forall g2. subgame g g2 /\ f1.interp g2 -> f2.interp g2 } }

  (* (Bounded) Universal quantification. *)
  let ghost function uquant (p:{set 'q}) (f:'q -> fmla 'a) : {fmla 'a} =
    { interp = pure { fun g -> forall y. p y -> (f y).interp g } }

  (* Conjonction. Could actually be defined from uquant,
     but that would be less practical. *)
  let ghost function conj (p q:{fmla 'a}) : {fmla 'a} =
    { interp = pure { fun g -> p.interp g /\ q.interp g } }

  let ghost function ordering (o:{erel 'a}) : {fmla 'a} =
    { interp = pure { fun g -> g.progress = o } }

  (* Sequent validity. *)
  predicate holds (c f:fmla 'a) = forall g. c.interp g -> f.interp g

  (* Predicate definitions for transfinite loop rules. *)
  (* State that is later than another (e.g one more loop turn) *)
  predicate later (o:erel 'b) (i:rel 'b 'a) (x:'b) (y:'a) =
    exists x'. i x' y /\ o x x' /\ x' <> x
  (* Same as later, but for limit steps. *)
  predicate later_limit (o:erel 'b) (i:rel 'b 'a) (h:set 'b) (y:'a) =
    exists x. i x y /\ upper_bound o h x
  (* Conditions for being an invariant. *)
  predicate is_inv (c:fmla 'a) (o:erel 'b) (go:erel 'a) (i:rel 'b 'a) =
    (forall x. holds c (enforce (i x) (later o i x)))
    /\ forall h f. chain o h /\ monotone_on h o f go /\ inhabited h /\
      not maximum o h (sup o h) /\ rel_mapping h f i ->
      holds c (enforce (supremum go (image f h)) (later_limit o i h))

  (* Predicate definition for transfinite recursion rule. *)

  function henforce (p q:rel 'b 'a) : 'b -> fmla 'a =
    fun x -> enforce (p x) (q x)
  predicate is_rec (c:fmla 'a) (o:erel 'b) (go:erel 'a) (p q:rel 'b 'a) =
    (forall x. let recursive = uquant (lower o x) (henforce p q) in
      holds (conj c recursive) (enforce (p x) (q x)))
  /\ (forall h f. chain o h /\ monotone_on h o f go /\ inhabited h /\
    not maximum o h (sup o h) /\ rel_mapping h f p ->
    let recursive = uquant (upper_bound o h) (henforce p q) in
    let target = bigunion (image q h) in
    let recover = enforce (supremum go (image f h)) target in
    holds (conj c recursive) recover)

end

module FmlaRules "W:non_conservative_extension:N" (* => FmlaProof *)

  use import ho_set.Set
  use import ho_rel.Rel
  use import game.Game
  use export Fmla

  (* Usual core rules of intuitionnistic logic. *)
  axiom abstraction : forall c f1 f2:fmla 'a.
    holds c (arrow f1 f2) <-> holds (conj c f1) f2
  axiom modus_ponens : forall c f1 f2:fmla 'a.
    holds c (arrow f1 f2) /\ holds c f1 -> holds c f2
  (* Combination of rules that corresponds to the variable rule. *)
  axiom reflexive : forall f:fmla 'a. holds f f
  axiom conj_left : forall c f1 f2:fmla 'a. holds c f2 -> holds (conj c f1) f2
  axiom conj_right : forall c f1 f2:fmla 'a. holds c f2 -> holds (conj f1 c) f2

  (* Consequence rule. *)
  axiom enforce_monotonic : forall c,p1 p2 q1 q2:set 'a.
    holds c (enforce p1 q1) /\ subset p2 p1 /\ subset q1 q2 ->
    holds c (enforce p2 q2)

  (* Other kind of consequence rules, coming from the underlying game order. *)
  axiom enforce_does_progress : forall c o x,q:set 'a.
    holds c (enforce ((=) x) q) /\ holds c (ordering o) ->
    holds c (enforce ((=) x) (inter q (o x)))

  (* Analog to the skip rule. *)
  axiom enforce_reflexivity : forall c,p q:set 'a.
    subset p q -> holds c (enforce p q)

  (* Sequence rule. *)
  axiom sequence : forall c,p q r:set 'a.
    holds c (enforce p q) /\ holds c (enforce q r) -> holds c (enforce p r)

  (* Extra program rule: Continuation rule. *)
  axiom kont_intro : forall c,p q:set 'a.
    holds (conj c (enforce q none)) (enforce p q) ->
    holds c (enforce p q)

  (* Externalize the precondition ('partition' rule, which
     is the essence of conditional rules) *)
  axiom external_pre : forall c,p q:set 'a.
    (forall y. p y -> holds c (enforce ((=) y) q)) -> holds c (enforce p q)

  (* Transfinite loop rule (analog to the while rule).
     If we have an invariant I such that (is_inv definition)
     . I enforce I at later moment for a user-given ordering
     . From supremum of an I-chain, we can reach I at a later point as
       well
     Then from I, we can enforce Nothing.
     Note that we can recover more classical statement
     (with a postcondition) thanks to the continuation rule.
     We can also introduce an exit guard using partitionning. *)
  axiom trampoline : forall c go,i:rel 'b 'a,o:erel 'b,x.
    holds c (ordering go) /\ order o /\ is_inv c o go i ->
    holds c (enforce (i x) none)

  (* Transfinite recursion rule.
     If we have a parametric pre/post couple P,Q such that for all x:
     G,(forall y > x. {P y -> Q y}) |- {P x -> Q x}
     And from any transfinite 'stack overflow' (H,f):
     G,(forall y >= H. { P y -> Q y }) |- { {sup f(H)} -> exists y\in H. Q y }
     Then G |- { P x -> Q x } unconditionnaly.
   *)
  axiom recursion : forall c go,p q:rel 'b 'a,o:erel 'b,x.
    holds c (ordering go) /\ order o /\ is_rec c o go p q ->
    holds c (enforce (p x) (q x))

end

module FmlaProof

  use import Fmla
  use import game.Game
  use import subgame.SubGame
  use import game.BasicStrats
  use import game_no_strat.WinAlt
  use import ho_set.Set
  use import order.Ordered
  use import transfinite.Extension

  (* Mostly proved in BasicStrats. *)
  lemma enforce_monotonic : forall c,p1 p2 q1 q2:set 'a.
    holds c (enforce p1 q1) /\ subset p2 p1 /\ subset q1 q2 ->
    holds c (enforce p2 q2)
    by forall g. c.interp g -> have_uniform_winning_strat g p2 q2
    by exists ang. uniform_winning_strat g p2 q2 ang
    by uniform_winning_strat g p1 q1 ang

  (* Direct from progression of the transfinite iteration process
     with respect to the winning strategies. *)
  lemma enforce_does_progress : forall c o x,q:set 'a.
    let ex = (=) x in let q2 = inter q (o x) in
    holds c (enforce ex q) /\ holds c (ordering o) -> holds c (enforce ex q2)
    by forall g. c.interp g -> have_uniform_winning_strat g ex q2
    by have_winning_strat g x q2
    by (have_winning_strat g x q by have_uniform_winning_strat g ex q)
    so exists ang. winning_strat g x q2 ang
    by winning_strat g x q ang
    so forall dmn. win_against g x q2 ang dmn
    by win_against g x q ang dmn
    so exists h. tr_ext o (step g ang dmn) ex h /\
      win_at g q ang dmn h
    so win_at g q2 ang dmn h

  (* Continuation introduction: the principle of the proof
     is to use a game with extra empty transitions on Q-states,
     on which (Q enforce Nothing) is trivial. Then, this larger game satisfy
     P enforce Q. But since those extra transitions are only used to exit Q,
     any winning strategy/victory invariant from this larger game can
     be readily mapped to the smaller one, hence ok.
     (Here, we choose the victory invariant path) *)
  let ghost function game_with_kont (g:{game 'a}) (q:{set 'a}) : {game 'a} =
    { progress = g.progress;
      transition = pure { fun x s -> g.transition x s \/ (q x /\ s = none) } }
  lemma kont_intro : forall c,p q:set 'a.
    holds (conj c (enforce q none)) (enforce p q) ->
    holds c (enforce p q)
    by forall g. c.interp g -> have_uniform_winning_strat g p q
    by let gk = game_with_kont g q in
      let o = g.progress in
      subgame g gk
    so ((enforce p q).interp gk by (enforce q none).interp gk
      by forall x. q x -> have_winning_strat gk x none by gk.transition x none)
    so exists i. victory_invariant g p q i by victory_invariant gk p q i
    so forall h x.
      (i h /\ not inhabited (inter h q) /\ maximum o h x so not q x) ->
      exists a. (g.transition x a by gk.transition x a) /\
        not a x /\ subset a (next_hist i h)

  lemma reflexivity : forall c,p q:set 'a. subset p q ->
    holds c (enforce p q)
    by holds c (enforce p p)
    by holds (conj c (enforce p none)) (enforce p p)
    by holds (conj c (enforce p none)) (enforce p none)
      /\ subset none p

  lemma external_pre : forall c,p q:set 'a.
    (forall y. p y -> holds c (enforce ((=) y) q)) -> holds c (enforce p q)
    by forall g. c.interp g -> have_uniform_winning_strat g p q
    by forall y. p y -> have_winning_strat g y q

  use import ho_rel.Prod
  use import ho_rel.RelSet
  use import order.Product
  use import order.Chain
  use import order.ProductChain
  use import choice.Choice
  use import fn.Fun
  use import fn.Image
  use import pfn.Pfun
  use import pfn.SubFunOrder
  use import order.SubChain
  use import order.SubFunLimit
  use import game_simulation.Sim

  (* Loop rule: direct consequence of the simulation theorem.
     Source game:
       . domain = transfinite (increasing) map-sequences: 'b -> 'a.
       . transitions = universal-type, can choose about anything later
     Destination game: current
     Relation:
       . invariant holds on the whole transfinite sequence
       . sequence is increasing (not easy to enforce directly on the domain)
       . Current state is the supremum of the mapped sequence.
       . domain = ('b,'a) with a modification of the product order
       (such that if (x,y) < (z,t), then x < z is mandatory)
       . transitions = universal-type, can choose anything later that
         satisfy the invariant.
       (the fact that the source game admit a winning strategy
        is basically Zorn's lemma, and is immediate via victory invariant
        since the set of all history is one.)
   *)
  predicate lorder (o:erel 'a) (f g:pfun 'a 'b) =
    subchain o f.domain g.domain /\ subfun f g
  predicate ltr (o:erel 'a) (f:pfun 'a 'b) (s:set (pfun 'a 'b)) =
    s = lower (lorder o) f
  predicate lrel (o1:erel 'a) (i:rel 'a 'b) (o2:erel 'b)
                 (f:pfun 'a 'b) (x:'b) =
    inhabited f.domain /\
    chain o1 f.domain /\
    monotone_on f.domain o1 f.eval o2 /\
    rel_mapping f.domain f.eval i /\
    supremum o2 (image f.eval f.domain) x
  let ghost function game_loop (o:{erel 'a}) : {game (pfun 'a 'b)}
    requires { order o }
  = { progress = lorder o; transition = ltr o }

  (* Builder lemma. *)
  lemma extends_pfun_related : forall o1 o2,i:rel 'a 'b,f y x' y'.
    order o1 /\ order o2 /\ lrel o1 i o2 f y /\ i x' y' /\ o2 y y' ->
    upper_bound o1 f.domain x' -> not f.domain x' ->
    let g = padd f x' y' in
    lorder o1 f g && (lrel o1 i o2 g y'
      by (monotone_on g.domain o1 g.eval o2
        by forall u v. g.domain u /\ g.domain v /\ o1 u v ->
          o2 (g.eval u) (g.eval v)
        by if u = v then true else if f.domain u /\ f.domain v then true
          else f.domain u so v = x' so o2 (g.eval u) y /\ o2 y y'
      ) so maximum o2 (image g.eval g.domain) y'
    )

  lemma trampoline : forall c go,i:rel 'b 'a,o:erel 'b,x.
    holds c (ordering go) /\ order o /\ is_inv c o go i ->
    holds c (enforce (i x) none)
    by forall g. c.interp g -> have_uniform_winning_strat g (i x) none
    by let gl = game_loop o in
      let r = lrel o i go in
      let p0 = fun z -> exists y. z = psing x y in
      (related r none = none by sext (related r none) none)
    /\ (related r p0 = i x by sext (i x) (related r p0)
      by (forall y. i x y -> related r p0 y by let z = psing x y in
        r z y by sext (image z.eval z.domain) ((=) y) so maximum go ((=) y) y
      )
      /\ (forall y. related r p0 y -> i x y by exists z. p0 z /\ r z y
        so exists y'. z = psing x y'
        so sext (image z.eval z.domain) ((=) y')
        so maximum go ((=) y') y'
        so y = y' /\ i x y')
    )
    /\ (have_uniform_winning_strat gl p0 none
      by victory_invariant gl p0 none all
      by forall h x. exists a. (gl.transition x a by ltr o x a)
        so not a x so subset a (next_hist all h)
    ) /\ (simulate gl r g
      by step_simulate gl r g
      by ("stop_split" forall f y s. gl.transition f s /\ r f y ->
        have_winning_strat g y (related r s)
        by let ey = (=) y in
          have_uniform_winning_strat g ey (related r s)
        by s = lower (lorder o) f
        so let h0 = f.domain in let f0 = f.eval in
          let x = sup o h0 in let h1 = image f0 h0 in
          (* Case-split: if there is a maximum, regular is_inv condition.
             Otherwise, limit one. *)
          "case_split" if maximum o h0 x
          then maximum go h1 (f0 x)
            so f0 x = y
            so let q = inter (later o i x) (go y) in
              (have_uniform_winning_strat g ey q by holds c (enforce ey q)
               by subset ey (i x))
            so subset q (related r s)
            by forall y'. go y y' /\ later o i x y' -> related r s y'
            by exists x'. i x' y' /\ o x x' /\ x' <> x
            so let g = padd f x' y' in
              (s g by lorder o f g /\ f <> g) /\ r g y'
            by upper_bound o h0 x'
          else
            let p1 = supremum go (image f0 h0) in
            let q1 = later_limit o i h0 in
            let q2 = inter q1 (go y) in
            (have_uniform_winning_strat g ey q2 by holds c (enforce p1 q1)
              so (holds c (enforce ey q1) by subset ey p1)
              so holds c (enforce ey q2))
            so subset q2 (related r s)
            by forall y'. q2 y' -> related r s y'
            by exists x'. i x' y' /\ upper_bound o h0 x'
            so let g = padd f x' y' in
              (s g by lorder o f g /\ f <> g) /\ r g y'
            by upper_bound o h0 x' so not (h0 x' so maximum o h0 x')
      ) /\ ("stop_split" forall ch fh y.
        chain (lorder o) ch /\ inhabited ch ->
        monotone_on ch (lorder o) fh go /\ rel_mapping ch fh r ->
        supremum go (image fh ch) y ->
        let target = related r (supremum (lorder o) ch) in
        have_winning_strat g y target
        by target y by let f = pbigunion ch in
          (forall a b:pfun 'b 'a. lorder o a b -> subfun a b)
        so chain subfun ch
        so supremum subfun ch f
        so (chain (subchain o) (image domain ch)
          by monotone (lorder o:erel (pfun 'b 'a)) domain (subchain o))
        so supremum (subchain o) (image domain ch) f.domain
        so (supremum (lorder o) ch f
            by (forall u. upper_bound (lorder o) ch u -> lorder o f u
              by upper_bound subfun ch u
              so upper_bound (subchain o) (image domain ch) u.domain
              by forall s. image domain ch s -> subchain o s u.domain
                by exists g. (lorder o g u by ch g) /\ g.domain = s)
            /\ (upper_bound (lorder o) ch f by
              forall u. ch u -> lorder o u f
              by image domain ch u.domain)
          )
        so r f y
        by (inhabited f.domain
            by exists g. ch g so r g (fh g)
            so exists x. f.domain x by g.domain x)
        so (chain o f.domain by forall s. image domain ch s ->
            chain o s by exists g. ch g /\ g.domain = s so r g (fh g))
        so (rel_mapping f.domain f.eval i by forall x. f.domain x ->
          i x (f.eval x) by exists s. image domain ch s /\ s x
          so exists g. ch g /\ g.domain = s so r g (fh g))
        so (monotone_on f.domain o f.eval go
          by forall a b. f.domain a /\ f.domain b /\ o a b ->
            go (f.eval a) (f.eval b)
          by exists s. image domain ch s /\ s b
          so exists g. ch g /\ g.domain = s
          so r g (fh g) /\ subchain o g.domain f.domain
          so s a)
        so let h = image f.eval f.domain in
          supremum go h y
        by (upper_bound go h y by forall u. h u -> go u y
          by exists a. f.domain a /\ f.eval a = u
          so exists s. image domain ch s /\ s a
          so exists g. ch g /\ g.domain = s
          so r g (fh g)
          so transitive go
          /\ (go (fh g) y by image fh ch (fh g))
          /\ (go u (fh g) by upper_bound go (image g.eval g.domain) (fh g))
        ) /\ (forall u. upper_bound go h u -> go y u
          by upper_bound go (image fh ch) u by forall v. image fh ch v ->
          go v u by exists g. ch g /\ fh g = v
          so supremum go (image g.eval g.domain) v
          so upper_bound go (image g.eval g.domain) u
          by forall v. image g.eval g.domain v -> go v u by h v
        )
      )
    )

  (* Immediately derive sequence from trampoline and continuation rules:
     {P -> Q}, {Q -> R}, {R -> Nothing} |- forall n. { I n -> I (n+1) }
       with I 0 = P, I 1 = Q, I 2 = R, others = Nothing.
       maxless I-chains cannot exists (at most 3 elements),
       hence limit condition is trivial.
       By trampoline:
     {P -> Q}, {Q -> R}, {R -> Nothing} |- { P = I 0 -> Nothing }
       By (weakening+) continuation:
     {P -> Q}, {Q -> R} |- {P -> R}
     Qed.
   *)
  use import int.Int

  lemma sequence : forall c,p q r:set 'a.
    holds c (enforce p q) /\ holds c (enforce q r) ->
    holds c (enforce p r)
    by forall g. c.interp g -> (enforce p r).interp g
    by let go = g.progress in let c = conj c (ordering go) in
      holds c (enforce p r)
    by let c = conj c (enforce r none) in
      holds c (enforce p r)
    by holds c (enforce p none) /\ subset none r
    by let i = fun n -> if n = 0 then p
                        else if n = 1 then q
                        else if n = 2 then r
                        else none
    in holds c (enforce (i 0) none)
    by let o = (<=) in order o so is_inv c o go i
    by (forall n. holds c (enforce (i n) (later o i n))
      by holds c (enforce (i n) (i (n+1))) /\ subset (i (n+1)) (later o i n))
    so forall h f.
      inhabited h /\ not maximum o h (sup o h) /\ rel_mapping h f i -> false
    by (forall x. h x -> 0 <= x <= 2 by i x (f x))
    so if h 2 then maximum o h 2 else if h 1 then maximum o h 1
      else maximum o h 0

  use import ho_set.SetBigOps

  (* Proof of transfinite loop rule: generic derecursification.
     Note that if:
     G,(forall y > x. {P y -> Q y}) |- {P x -> Q x} holds,
     then any game satisfying G can be (minimally) extended
     to a larger game that satisfy the recursive hypothesis.
     We then follow the invariant on that larger game.
     If any step that does not exists in the origin game is required,
     we recursively simulate this step by the same method.
     This process explicitly create a stack, which may overflow.
     This is where the transfinite overflow condition intervene:
       to continue the process util one of the underlying step can
       be closed, in which case a whole section of the stack is discarded.
     ===> Proof can be done through the trampoline rule, using stack
     as auxiliary data. In order to describe progress, we use a
     modified lexicographic order on the stack.
     Also, this mean that at first we will only prove G |- {P x -> Q x}
     when Q x = Nothing. Of course, the regular theorem can be recovered
     through continuations.
  *)

  (* Construction of an extended game that validates recursive calls. *)
  predicate tr_rec (o:erel 'a) (p q:rel 'a 'b) (g:game 'b) (h:set 'a)
                   (x:'b) (s:set 'b) =
    g.transition x s \/ exists z. upper_bound o h z /\ not h z /\ p z x
                                  /\ s = inter (q z) (g.progress x)
  let ghost function game_rec (o:{erel 'a}) (p q:{rel 'a 'b}) (g:{game 'b})
                              (h:{set 'a}) : {game 'b}
  = { progress = g.progress; transition = tr_rec o p q g h }

  (* Describe a 'stack frame'. *)
  type frame 'a = {
    str : 'a; (* Starting point of the frame. *)
    log : set 'a; (* History of the frame. *)
    inv : set (set 'a); (* Victory invariant for the current frame. *)
  }

  (* Raw stacks. *)
  type stack 'a 'b = pfun 'a (frame 'b)

  (* Lexicographic order on stack: either a prefix,
     or the stack goes from a structure a ++ [x] ++ b to a ++[y] ++ c
     and y is 'later' than x. Moreover, we enforce that
     (y/x) dominate a++[x]++b to control the progression
     within the underlying order. *)
  predicate stack_lex_witness (o1:erel 'a) (o2:erel 'b) (s1 s2:stack 'a 'b)
                              (h:set 'a) (x:'a) =
    maximum o1 h x /\ subchain o1 h s1.domain /\ subchain o1 h s2.domain /\
    lower (subchain o2) (s1.eval x).log (s2.eval x).log /\
    equalizer (remove h x) s1.eval s2.eval /\
    (s1.eval x).inv = (s2.eval x).inv /\
    (s1.eval x).str = (s2.eval x).str /\
    (forall y u. (s2.eval x).log u /\ not (s1.eval x).log u /\ s1.domain y ->
      upper_bound o2 (s1.eval y).log u)
  predicate stack_lex (o1:erel 'a) (o2:erel 'b) (s1 s2:stack 'a 'b) =
    lorder o1 s1 s2 \/ exists h x. stack_lex_witness o1 o2 s1 s2 h x

  lemma stack_less_order : forall o1:erel 'a,o2:erel 'b.
    let s_o = stack_lex o1 o2 in
    order o1 /\ order o2 -> order s_o
    by (forall s1 s2. s_o s1 s2 /\ s_o s2 s1 -> s1 = s2
      by (forall a b h x.
        subfun a b /\ stack_lex_witness o1 o2 a b h x -> false
      ) so (forall a b h1 x1 h2 x2. stack_lex_witness o1 o2 a b h1 x1 /\
        stack_lex_witness o1 o2 b a h2 x2 /\ subchain o1 h1 h2 -> false)
      so (forall h1 x1 h2 x2. stack_lex_witness o1 o2 s1 s2 h1 x1 /\
        stack_lex_witness o1 o2 s2 s1 h2 x2 -> false)
      so subfun s1 s2 /\ subfun s2 s1)
    so forall s1 s2 s3. s_o s1 s2 /\ s_o s2 s3 ->
      s_o s1 s3
    by (forall h x. stack_lex_witness o1 o2 s1 s2 h x /\ lorder o1 s2 s3 ->
      stack_lex_witness o1 o2 s1 s3 h x)
    so (forall h x. stack_lex_witness o1 o2 s2 s3 h x /\ lorder o1 s1 s2 ->
      not lorder o1 s1 s3 ->
      stack_lex_witness o1 o2 s1 s3 h x
      by if subchain o1 h s1.domain then true else false
      by subchain o1 s1.domain h so if not s1.domain x then true else false
      by sext s1.domain h by forall y. h y -> s1.domain y by o1 y x
    ) so (forall h1 h2 x. subchain o1 h1 h2 ->
       maximum o1 h1 x /\ maximum o1 h2 x -> h1 = h2
       by sext h1 h2 by forall y. h2 y -> h1 y by o1 y x
     )
    so (forall h1 x1 h2 x2. stack_lex_witness o1 o2 s1 s2 h1 x1 ->
      stack_lex_witness o1 o2 s2 s3 h2 x2 ->
      (exists h3 x3. stack_lex_witness o1 o2 s1 s3 h3 x3)
      by if h1 = h2
        then stack_lex_witness o1 o2 s1 s3 h1 x1
          by x1 = x2
          so forall y u.
            (s3.eval x1).log u /\ not (s1.eval x1).log u /\ s1.domain y ->
            upper_bound o2 (s1.eval y).log u
          by not (s2.eval x1).log u ->
          not sext (s2.eval x1).log (s1.eval x1).log
          so exists k. (s2.eval x1).log k /\ not (s1.eval x1).log k
          so upper_bound o2 (s1.eval y).log k
          so transitive o2 so o2 k u by upper_bound o2 (s2.eval x1).log u
        else if subchain o1 h1 h2
        then stack_lex_witness o1 o2 s1 s3 h1 x1 by x1 <> x2
        else stack_lex_witness o1 o2 s1 s3 h2 x2
          by subchain o1 h2 h1 so x1 <> x2
          so forall y u.
            (s3.eval x2).log u /\ not (s1.eval x2).log u /\ s1.domain y ->
            upper_bound o2 (s1.eval y).log u
            by not sext (s2.eval x1).log (s1.eval x1).log
            so exists k. (s2.eval x1).log k /\ not (s1.eval x1).log k
            so upper_bound o2 (s1.eval y).log k
            so transitive o2 so o2 k u by upper_bound o2 (s2.eval x1).log u
    )

  (* Return linking. *)
  predicate linked (o1:erel 'a) (s:stack (set 'a) 'b) (h:set 'a) (x:'b) =
    exists hl. s.domain hl /\ lower (subchain o1) hl h /\
    let f = s.eval hl in f.inv (add f.log x)
  (* Stack invariant. Note that we index the stack by chains
     in order to handle correctly limit frames. *)
  predicate is_stack (o1:erel 'a) (p q:rel 'a 'b) (g:game 'b)
                     (s:stack (set 'a) 'b) =
    (* Stack must be well-founded (to avoid infinite return chains) *)
    wf_chain (subchain o1) s.domain /\
    (* Stack must be downward closed (to get the correct limit
       behavior). *)
    (forall h1 h2. s.domain h2 /\ inhabited h1 /\ subchain o1 h1 h2 ->
      s.domain h1) /\
    (* Frame are correctly ordered. *)
    (forall h1 h2. s.domain h1 /\ s.domain h2 /\ subchain o1 h1 h2 ->
      h1 <> h2 -> upper_bound g.progress (s.eval h1).log (s.eval h2).str) /\
    (* Frame represent a proper 'victory path' in the
       associated recursive game, and their finishing condition is
       linked to a step in a lower frame. Also, keys must be chains. *)
    forall h. s.domain h ->
      let f = s.eval h in
      let target = bigunion (image q h) in
      let lg = game_rec o1 p q g h in
      f.inv f.log
      /\ chain o1 h /\ inhabited h
      /\ (maximum o1 h (sup o1 h) -> p (sup o1 h) f.str)
      /\ minimum g.progress f.log f.str
      /\ victory_invariant lg ((=) f.str) target f.inv
      /\ not inhabited (inter f.log target)
      /\ (forall x. target x /\ upper_bound g.progress f.log x ->
        linked o1 s h x)

  predicate is_stack_top (o1:erel 'a) (o2:erel 'b)
                         (s:stack (set 'a) 'b) (h:set 'a) (x:'b) =
    maximum (subchain o1) s.domain h /\ maximum o2 (s.eval h).log x

  (* Invariant to perform recursion from trampoline rule. *)
  predicate rc_inv (o1:erel 'a) (p q:rel 'a 'b) (g:game 'b)
                   (s:stack (set 'a) 'b) (x:'b) =
    is_stack o1 p q g s /\
    exists h. is_stack_top o1 g.progress s h x

  let ghost function glarger (g:{game 'a}) : {fmla 'a} =
    { interp = pure { subgame g } }

  lemma recursion_v1 : forall g,p q:rel 'b 'a,o:erel 'b,x_0.
    let c = glarger g in let go = g.progress in
    order o /\ is_rec c o go p q /\ q x_0 = none ->
    holds c (enforce (p x_0) none)
    by forall y_0. p x_0 y_0 -> holds c (enforce ((=) y_0) none)
    (* First remark: the 'recursive' game does satisfy
       the recursive context. *)
    by ("stop_split" forall h. not maximum o h (sup o h) ->
      let recursive = uquant (upper_bound o h) (henforce p q) in
      let c' = conj c recursive in
      let lg = game_rec o p q g h in
        c'.interp lg by recursive.interp lg by forall x. upper_bound o h x ->
        have_uniform_winning_strat lg (p x) (q x)
      by forall y. p x y -> have_winning_strat lg y (q x)
      by let q2 = inter (q x) (go y) in
        lg.transition y (inter (q x) (go y)) by not (h x so maximum o h x)
    ) /\ ("stop_split" forall h x. maximum o h x ->
      let recursive = uquant (lower o x) (henforce p q) in
      let c' = conj c recursive in
      let lg = game_rec o p q g h in
        c'.interp lg by recursive.interp lg by forall z. lower o x z ->
        have_uniform_winning_strat lg (p z) (q z)
      by forall y. p z y -> have_winning_strat lg y (q z)
      by let q2 = inter (q z) (go y) in
        lg.transition y (inter (q z) (go y))
      by upper_bound o h z so not h z
    )
      (* Second remark (consequence): for all stack identifiant
         admitting a max, the desired victory invariant exists. *)
    so ("stop_split" forall h x y. maximum o h x /\ p x y ->
      let lg = game_rec o p q g h in
      let target = bigunion (image q h) in
        (exists inv. victory_invariant lg ((=) y) target inv)
        by have_uniform_winning_strat lg ((=) y) target
        by let recursive = uquant (lower o x) (henforce p q) in
          let c' = conj c recursive in
          holds c' (enforce ((=) y) target)
        by holds c' (enforce (p x) (q x))
        so subset ((=) y) (p x)
        so subset (q x) target
      )
    (* Initialise the loop invariant. *)
    so let i = rc_inv o p q g in
      let s_o = stack_lex (subchain o) go in
      order s_o
    so let h0 = (=) x_0 in
      let lg0 = game_rec o p q g h0 in
      let tg0 = bigunion (image q h0) in
      maximum o h0 x_0
    so exists iv0. victory_invariant lg0 ((=) y_0) tg0 iv0
    so let f0 = { str = y_0; log = ((=) y_0); inv = iv0 } in
      let s0 = psing h0 f0 in
      (subset ((=) y_0) (i s0) by i s0 y_0
        by is_stack_top o go s0 h0 y_0 so is_stack o p q g s0
        by (tg0 = none by sext tg0 none by forall y. not (tg0 y
          so exists s. image q h0 s /\ s y
          so exists x. s = q x /\ h0 x
        )) so (forall h1. subchain o h1 h0 /\ inhabited h1 ->
          h1 = h0 by sext h0 h1)
    ) /\ (holds c (enforce (i s0) none)
      by is_inv c s_o go i
      (* First, prove a few practical lemma about stack manipulation. *)
      (* 'transversal run' lemma: under some ordering conditions,
         we can simply cut the stack to a frame and extends its log
         instead, creating a later state. Base for: transversal limits,
         in-frame run, and return lemma. *)
      by let tr_cond = fun s lg0 lg1 ->
          forall h x. s.domain h /\ lg1 x /\ not lg0 x ->
            upper_bound go (s.eval h).log x
      in
      ("stop_split" forall s h lg1. is_stack o p q g s /\ s.domain h ->
        let f0 = s.eval h in let target = bigunion (image q h) in
        lower (subchain go) f0.log lg1 /\ f0.inv lg1 ->
        not inhabited (inter lg1 target) /\ tr_cond s f0.log lg1 ->
        let under = flip (subchain o) h in
        let f1 = { f0 with log = lg1 } in
        let s_c = restrict under s in
        let s_r = padd s_c h f1 in
        s_o s s_r /\ s <> s_r /\ is_stack o p q g s_r
        /\ (maximum go lg1 (sup go lg1) ->
            is_stack_top o go s_r h (sup go lg1))
        by stack_lex_witness (subchain o) go s s_r s_c.domain h
        so (s_r.domain = s_c.domain = inter under s.domain
          by sext s_r.domain s_c.domain by s_c.domain h)
        so (forall h1 h2.
          s_r.domain h2 /\ inhabited h1 /\ subchain o h1 h2 ->
          s_r.domain h1 by s.domain h1 so under h)
        so (forall h1 h2.
          s_r.domain h1 /\ s_r.domain h2 /\ subchain o h1 h2 ->
            h1 <> h2 -> upper_bound go (s_r.eval h1).log (s_r.eval h2).str
          by not (h1 = h so subchain o h2 h)
          so s_r.eval h1 = s.eval h1
          so (s_r.eval h2).str = (s.eval h2).str)
        so (forall h_. s_r.domain h_ ->
          let f = s_r.eval h_ in
          let target = bigunion (image q h_) in
          let lg = game_rec o p q g h_ in
          ("case_split" if h_ = h then f = f1
                        else s.domain h_ /\ f = s.eval h_)
          so f.inv f.log
          so (victory_invariant lg ((=) f.str) target f.inv
            /\ (maximum o h_ (sup o h_) -> p (sup o h_) f.str)
            /\ (forall x. target x /\ upper_bound go f.log x ->
              linked o s_r h_ x
              by upper_bound go (s.eval h_).log x
              so linked o s h_ x
            )
            by f.str = (s.eval h_).str /\ f.inv = (s.eval h_).inv)
          so (minimum go f.log f.str by minimum go f0.log f0.str)
        )
      )
      (* 'return' lemma: if we satisfy the target of the stack,
         then the invariant is later-satisfied. Necessary stack is
         build through the transversal run at a well-chosen level. *)
      so let ret_cond = fun s x ->
        forall h. s.domain h ->
          upper_bound go (s.eval h).log x
      in
      ("stop_split" forall s h x. is_stack o p q g s /\ s.domain h ->
        bigunion (image q h) x /\ ret_cond s x -> later s_o i s x
        by let valid = fun h -> s.domain h /\ bigunion (image q h) x in
          let h0 = inf (subchain o) valid in
          (minimum (subchain o) valid h0 by valid h)
        so linked o s h0 x
        so exists hl. let f0 = s.eval hl in let lg1 = add f0.log x in
          s.domain hl /\ lower (subchain o) hl h0 /\ f0.inv lg1
        so let s_r = padd (restrict (flip (subchain o) hl) s)
                          hl { f0 with log = lg1 } in
          ("stop_split" s_o s s_r /\ s <> s_r /\ i s_r x)
        by let target = bigunion (image q hl) in
          (* Critical use of the well-foundedness hypothesis here. *)
          not (inhabited (inter lg1 target) so valid hl
            by (exists y. lg1 y /\ target y so y = x
                by not inter f0.log target y))
        so (lower (subchain go) f0.log lg1 by upper_bound go f0.log x
          so not (f0.log x so
            (subchain o hl h by subchain o h0 h by valid h)
            so h <> hl
            so upper_bound go f0.log (s.eval h).str
            so minimum go (s.eval h).log (s.eval h).str
            so upper_bound go (s.eval h).log x
            so (x = (s.eval h).str
              by go x (s.eval h).str /\ go (s.eval h).str x)
            so inter (s.eval h).log (bigunion (image q h)) x
        ))
        so tr_cond s f0.log lg1
        so maximum go lg1 x so sup go lg1 = x
      )
      (* 'next' lemma: Hybrid of the transversal and return lemmas
         (apply whichever is relevant).
         If we could extend a transversal frame by a single value
         (except that it may returns),
         then the invariant is later-satisfied. *)
      so ("stop_split" forall s h x. is_stack o p q g s /\ s.domain h ->
        let f0 = s.eval h in let lg = f0.log in let lg1 = add lg x in
        ret_cond s x /\ f0.inv lg1 /\ not lg x -> later s_o i s x
        by let target = bigunion (image q h) in
        not target x ->
          let s_r = padd (restrict (flip (subchain o) h) s)
                         h { f0 with log = lg1 }
        in
        (("stop_split" s_o s s_r /\ s <> s_r /\ is_stack o p q g s_r
         /\ is_stack_top o go s_r h x) so i s_r x)
        by (lower (subchain go) lg lg1)
        so (not inhabited (inter lg1 target)
          by not inhabited (inter lg target))
        so tr_cond s lg lg1
      )
      (* 'call' lemma: addition of a single stack frame on top
         of an extended target. *)
      so let call_cond = fun s h x ->
        (forall h2. inhabited h2 /\ lower (subchain o) h2 h -> s.domain h2)
        /\ (forall y. bigunion (image q h) y /\ go x y ->
          not bigunion (image q (bigunion s.domain)) y ->
          linked o s h y)
        /\ (forall h2. s.domain h2 -> upper_bound go (s.eval h2).log x)
      in
      ("stop_split" forall s h x iv. is_stack o p q g s ->
        let rg = game_rec o p q g h in
        let target = bigunion (image q h) in
        upper_bound (subchain o) s.domain h /\ not s.domain h /\ chain o h /\
        inhabited h ->
        call_cond s h x /\ victory_invariant rg ((=) x) target iv ->
        (maximum o h (sup o h) -> p (sup o h) x) /\ not target x ->
        let f0 = { str = x; log = (=) x; inv = iv } in
        let s_r = padd s h f0 in
        is_stack o p q g s_r /\ s_r <> s /\ s_o s s_r
        /\ is_stack_top o go s_r h x
        by lorder (subchain o) s s_r
        so (forall h1 h2.
          s_r.domain h2 /\ inhabited h1 /\ subchain o h1 h2 ->
          s_r.domain h1 by if h1 = h then true else s.domain h1
          by if h2 <> h then s.domain h2 else lower (subchain o) h1 h2)
        so (forall h1 h2.
          s_r.domain h1 /\ s_r.domain h2 /\ subchain o h1 h2 /\ h1 <> h2 ->
          upper_bound go (s_r.eval h1).log (s_r.eval h2).str
          by s.domain h1
        ) so forall h_. s_r.domain h_ ->
          let f = s_r.eval h_ in
          let target = bigunion (image q h_) in
          let lg = game_rec o p q g h_ in
          ("case_split" (h = h_ /\ f = f0) \/ (s.domain h_ /\ f = s.eval h_))
        so chain o h_ so inhabited h_
        so (f.inv f.log by f0.inv f0.log)
        so (maximum o h_ (sup o h_) -> p (sup o h_) f.str)
        so minimum go f.log f.str
        so victory_invariant lg ((=) f.str) target f.inv
        so not inhabited (inter f.log target)
        so (forall y. target y /\ upper_bound go f.log y ->
          linked o s_r h_ y
          by if h <> h_ then linked o s h_ y so linked o s_r h_ y
          else (exists h1. bigunion (image q h1) y /\ s.domain h1
            so let f1 = s.eval h1 in
              (upper_bound go f1.log y by upper_bound go f1.log x
               so go x y /\ transitive go)
            so linked o s h1 y so
              exists hl. let fl = s.eval hl in
                s.domain hl /\ lower (subchain o) hl h1 /\
                fl.inv (add fl.log y)
            so s_r.domain hl /\ lower (subchain o) hl h
          ) || (
            let bs = bigunion s.domain in
            let btg = bigunion (image q bs) in
            not (btg y so exists s0. image q bs s0 /\ s0 y
              so exists u. bs u /\ s0 = q u
              so exists h. s.domain h /\ h u
              so bigunion (image q h) y
            ) so linked o s h y so linked o s_r h y
          )
        )
      )
      (* Using those lemmas, establish that i is indeed
         an invariant. *)
      (* Prove the step case for invariant. Case disjunction,
         using exactly two of the above lemmas.
         . Try to use a present step ==> next lemma.
         . Try to use a recursive step ==> call lemma.
       *)
      so ("stop_split" forall s. holds c (enforce (i s) (later s_o i s))
        by forall x. i s x -> holds c (enforce ((=) x) (later s_o i s))
        (* Derive step from the victory invariant. *)
        by exists h. is_stack_top o go s h x
        so let f = s.eval h in
          let lg0 = f.log in
          let lg = game_rec o p q g h in
          let tg = bigunion (image q h) in
          victory_invariant lg ((=) f.str) tg f.inv
        so not inhabited (inter lg0 tg) so f.inv lg0
        so exists a.
          lg.transition x a /\ not a x /\ subset a (next_hist f.inv lg0)
        so (* Regular transition: process normally at the stack top
              (call lemma). *)
          if g.transition x a
          then
            (holds c (enforce ((=) x) a)
              by forall g2. c.interp g2 ->
                have_uniform_winning_strat g2 ((=) x) a
              by have_uniform_winning_strat g ((=) x) a
              by have_winning_strat g x a)
            so subset a (later s_o i s) by forall y. a y -> later s_o i s y
            by let lg1 = add lg0 y in
              (maximum go lg1 y
              by upper_bound go lg0 y by go x y /\ transitive go)
            so not (lg0 y so x = y by go y x /\ go x y)
            (* Shared because it implies tr_cond. *)
            so (ret_cond s y by forall h_. s.domain h_ ->
              let f0 = s.eval h_ in
              upper_bound go f0.log y
              by h <> h_ -> upper_bound go f0.log f.str
              so go f.str x /\ go x y /\ transitive go
            )
            (* 'Recursive call' transition: add a stack frame,
                use the call lemma. *)
          else
            exists z. upper_bound o h z /\ not h z /\ p z x /\
              a = inter (q z) (go x)
            so let hn = add h z in
              maximum o hn z
            so let lg = game_rec o p q g hn in
              let target = bigunion (image q hn) in
              exists iv. victory_invariant lg ((=) x) target iv
            so let f_ = { str = x; log = (=) x; inv = iv } in
            let s_r = padd s hn f_ in
            (("stop_split" is_stack o p q g s_r /\ s_r <> s /\ s_o s s_r
             /\ is_stack_top o go s_r hn x) so i s_r x)
            by z = sup o hn
            so subchain o h hn
            so (upper_bound (subchain o) s.domain hn
                by transitive (subchain o))
            so not (s.domain hn so hn = h by subchain o hn h)
            so not (target x so exists s0. image q hn s0 /\ s0 x
              so exists u. hn u /\ s0 = q u
              so (u = z by not (h u so tg x so inter lg0 tg x))
            )
            so call_cond s hn x
            by (forall h2. inhabited h2 /\ lower (subchain o) h2 hn ->
              s.domain h2 by subchain o h2 h || (false by subchain o h h2
                so sext h2 hn)
            )
            so (forall h2. s.domain h2 ->
              upper_bound go (s.eval h2).log x
              by h <> h2 -> subchain o h2 h
              so upper_bound go (s.eval h2).log f.str
              so (go f.str x by lg0 f.str) so transitive go)
            (* Establish extra return links. *)
            so (forall y. bigunion (image q hn) y /\ go x y ->
              not bigunion (image q (bigunion s.domain)) y ->
              linked o s hn y
              by s.domain h /\ lower (subchain o) h hn /\
                f.inv (add f.log y)
              by a y by exists s0. image q hn s0 /\ s0 y
              so exists u. hn u /\ s0 = q u
              so (u = z by not (h u so bigunion s.domain u
                so image q (bigunion s.domain) s0))
            )
      )
      (* Prove the limit case for invariant.
         Mostly a case disjunction on the limit nature:
         . Either the limit is obtained by a transversal limit
           at some fixed level. Then, one can obtain a valid
           stack by taking the chain supremum at the transversal
           level (transversal run lemma, giving the exact
           same mapping from all source)
           and then recover the invariant via the next lemma.
         . Either the limit corresponds to a transfinite stack overflow.
           In that case, we have an obvious 'supremum' for the
           stack chain, which is a stack by continuity.
           Now, either the supremum is a target by chance (===> return lemma),
           otherwise we use the call lemma to add a 'limit frame'.
         The nature of the limit is determined by analysing
         the set of eventually stable prefix of the stack.
       *)
      /\ ("stop_split" forall hs fs.
        chain s_o hs /\ monotone_on hs s_o fs go /\ inhabited hs /\
        not maximum s_o hs (sup s_o hs) /\ rel_mapping hs fs i ->
        let fhs = image fs hs in
        holds c (enforce (supremum go fhs) (later_limit s_o i hs))
        by forall xs. supremum go fhs xs ->
          holds c (enforce ((=) xs) (later_limit s_o i hs))
        by subset ((=) xs) (later_limit s_o i hs) by later_limit s_o i hs xs
        by (* Evident remark, but mostly out
              of reach of provers otherwise. *)
           (forall s. hs s -> is_stack o p q g s by i s (fs s))
        so (* Eventually stable prefixes of hs. *)
          let sb = subchain o in
          let sbb = subchain sb in
          let lo = lorder sb in
          let paf = fun p s0 ->
            forall s1. hs s1 /\ s_o s0 s1 -> lo p s1 in
          let evp = fun p -> exists s0. hs s0 /\ paf p s0 in
          (* Eventually stable prefixes form a chain for lorder. *)
        ("stop_split"
          chain lo evp /\ chain subfun evp
          by forall p1 p2. evp p1 /\ evp p2 ->
          (lo p1 p2 so subfun p1 p2) \/ (lo p2 p1 so subfun p2 p1)
          by (exists s3. lo p1 s3 /\ lo p2 s3
            so (lo p1 p2 by sbb p1.domain p2.domain)
            \/ (lo p2 p1 by sbb p2.domain p1.domain)
          )
          by exists s1. hs s1 /\ paf p1 s1 so exists s2. hs s2 /\ paf p2 s2
          so (lo p1 s2 /\ lo p2 s2 by s_o s1 s2)
          \/ (lo p1 s1 /\ lo p2 s1 by s_o s2 s1)
        )
          (* In particular, eventually stable prefixes have a supremum. *)
        so let limp = pbigunion evp in
        ("stop_split" supremum lo evp limp
          by supremum subfun evp limp
          so (chain sbb (image domain evp) by monotone lo domain sbb)
          so supremum sbb (image domain evp) limp.domain
          so (forall u. upper_bound lo evp u -> lo limp u
            by upper_bound subfun evp u
            so upper_bound sbb (image domain evp) u.domain
            by forall s. image domain evp s ->
              sbb s u.domain
              by exists g. (lo g u by evp g) /\ g.domain = s)
          /\ (upper_bound lo evp limp by
            forall u. evp u -> lo u limp
            by image domain evp u.domain)
        )
        so if evp limp
          then (* corresponds to transfinite transversal run.
                  The supremum corresponds to the level right
                  above limp. *)
            (* First, find a stack which is strictly bigger than
               limp (as well as all stack after it). *)
            ("stop_split" (exists s0. hs s0 /\ paf limp s0 /\ s0 <> limp)
             by exists s0. hs s0 /\ paf limp s0
             so limp = s0 -> not maximum s_o hs s0
             so exists s1. hs s1 /\ not s_o s1 s0
             so s_o s0 s1 so paf limp s1
             so s1 <> limp)
            so exists s0. hs s0 /\ paf limp s0 /\ s0 <> limp
            (* For those stack, find the relevant frame *)
            so ("stop_split" forall s. hs s /\ s_o s0 s ->
              let select = diff s.domain limp.domain in
              let h = inf sb select in
              let hh = add limp.domain h in
              minimum sb select h
              && subchain sb limp.domain hh && subchain sb hh s.domain
              by lo limp s so subchain sb limp.domain s.domain
              so not (not inhabited select
                  so (forall x. s.domain x -> limp.domain x by not select x)
                  so sext s.domain limp.domain so pext limp s)
              so subset select s.domain /\ wf_chain sb s.domain
             ) so let h0 = inf sb (diff s0.domain limp.domain) in
               let hh0 = add limp.domain h0 in
            (minimum sb (diff s0.domain limp.domain) h0
              /\ subchain sb limp.domain hh0
              /\ subchain sb hh0 s0.domain by s_o s0 s0)
            so maximum sb hh0 h0
            (* Show that the relevant frame is always at the
               same level. *)
            so ("stop_split" forall s. hs s /\ s_o s0 s ->
               let h = inf sb (diff s.domain limp.domain) in
               h = h0
               by minimum sb (diff s.domain limp.domain) h
               so (equalizer limp.domain limp.eval s.eval by lo limp s)
               /\ (equalizer limp.domain limp.eval s0.eval by lo limp s0)
               so if lo s0 s
               then h = h0 by
                 minimum sb (diff s.domain limp.domain) h0
                 by subchain sb s0.domain s.domain
                 so diff s.domain limp.domain h0
               else exists hh_ h_. stack_lex_witness sb go s0 s hh_ h_
                 so let hh = add limp.domain h in
                 (subchain sb hh0 hh_ || (false
                   by subchain sb hh_ hh0
                   so s0.eval h_ = s.eval h_ by limp.domain h_
                   by not (h_ = h0 so sext hh_ hh0 by forall u. hh0 u ->
                     hh_ u by u = h_ \/ not sb h_ u by sb u h_)
                 ))
                 /\ (subchain sb hh hh_ || (false
                   by subchain sb hh_ hh
                   so s0.eval h_ = s.eval h_ by limp.domain h_
                   by not (h_ = h so sext hh_ hh by forall u. hh u ->
                     hh_ u by u = h_ \/ not sb h_ u by sb u h_)
                 ))
                 so (subchain sb hh hh0 so hh0 h)
                 \/ (subchain sb hh0 hh so hh h0)
            )
            so let hsr = inter hs (s_o s0) in
            (* Deduce that all lex-witness within hsr occur above
               above hh0. *)
            ("stop_split" forall hh_ h_ s1 s2. hsr s1 /\ hsr s2 /\
              stack_lex_witness sb go s1 s2 hh_ h_ ->
              (subchain sb hh0 hh_ || (false
                by subchain sb hh_ hh0
                so s1.eval h_ = s2.eval h_ by limp.domain h_
                /\ (equalizer limp.domain limp.eval s1.eval by lo limp s1)
                /\ (equalizer limp.domain limp.eval s2.eval by lo limp s2)
                by not (h_ = h0 so sext hh_ hh0 by forall u. hh0 u ->
                  hh_ u by u = h_ \/ not sb h_ u by sb u h_)
              )) by subchain sb hh0 s1.domain
              by inf sb (diff s1.domain limp.domain) = h0
            )
            (* Prove that any element within the chain is eventually
               exceeded through a witness at lowest possible level. *)
            so ("stop_split" forall s. hsr s ->
              (exists s2. hsr s2 /\ stack_lex_witness sb go s s2 hh0 h0)
              by let sr = restrict hh0 s in
                (subchain sb hh0 s.domain
                 by inf sb (diff s.domain limp.domain) = h0)
              so (sr.domain = hh0 by sext hh0 sr.domain)
              so (lorder sb limp sr by lorder sb limp s
                 so forall x. limp.domain x ->
                 limp.eval x = s.eval x = sr.eval x by hh0 x)
              so not (evp sr so limp = sr by lo sr limp)
              so not paf sr s
              so exists s2. s_o s s2 /\ hs s2 /\ not lo sr s2
              so hsr s2 so stack_lex_witness sb go s s2 hh0 h0
              by (lorder sb sr s) so not lo s s2
              so exists hh_ h_. stack_lex_witness sb go s s2 hh_ h_
              so subchain sb hh0 hh_
              so if hh0 h_
                then (sext hh_ hh0 by forall u. hh_ u -> hh0 u
                    by u = h_ \/ not sb h_ u by sb u h_) so h_ = h0
                else false by equalizer sr.domain sr.eval s2.eval
                  so subchain sb sr.domain s2.domain
            )
            (* Now, we can introduce the chain of frames
               associated to h0, and prove that it is indeed
               a chain. *)
            so let fn = fun s -> (s.eval h0).log in
              let ch = image fn hsr in
            ("stop_split" forall a b. hsr a /\ hsr b /\ s_o a b ->
              subchain go (fn a) (fn b)
              /\ (a.eval h0).inv = (b.eval h0).inv
              /\ (a.eval h0).str = (b.eval h0).str
              by if lo a b
              then a.eval h0 = b.eval h0
                by subchain sb a.domain b.domain
                so (subchain sb hh0 a.domain
                  by inf sb (diff a.domain limp.domain) = h0)
                so equalizer a.domain a.eval b.eval /\ a.domain h0
              else exists hh_ h_. stack_lex_witness sb go a b hh_ h_
                so subchain sb hh0 hh_
                so if hh0 h_
                  then maximum sb hh0 h_ so h_ = h0
                    so lower (subchain go) (fn a) (fn b)
                  else a.eval h0 = b.eval h0
                    by equalizer (remove hh_ h_) a.eval b.eval
                    so remove hh_ h_ h0
            )
            so (chain (subchain go) ch by chain s_o hsr /\
              monotone_on hsr s_o fn (subchain go))
            so (inhabited ch by ch (fn s0))
            (* We build the 'limit frame' by completion. *)
            so let hl = bigunion ch in
              supremum (subchain go) ch hl
            so let fl = { (s0.eval h0) with log = hl } in
              let s_cl = restrict hh0 s0 in
              let s_rl = padd s_cl h0 fl in
            (s_cl.domain = hh0 by sext s_cl.domain hh0)
            so (s_rl.domain = hh0 by sext s_rl.domain hh0)
            (* Prove that it is a true limit. *)
            so ("stop_split" not (ch hl so exists a. hsr a /\ fn a = hl
              so exists b. hsr b /\ stack_lex_witness sb go a b hh0 h0
              so lower (subchain go) hl (fn b) so ch (fn b)
              so subchain go (fn b) hl
            ))
            (* Prove that the 'limit stack' is
               the output of the transversal run lemma for ANY
               element of hsr (this is the place where we need
               the statement of the lemma to be explicit). *)
            so ("stop_split" forall s. hsr s ->
              ("stop_split"
                s_o s s_rl /\ s <> s_rl /\ is_stack o p q g s_rl)
              by let f0 = s.eval h0 in
                let f1 = { f0 with log = hl } in
                let under = flip sb h0 in
                let s_c = restrict under s in
                let s_r = padd s_c h0 f1 in
                (fl = f1 by s_o s0 s /\ hsr s0 /\ hsr s)
              so (s_r = s_rl by pext s_r s_rl
                by (s_r.domain = s_rl.domain
                  by sext s_c.domain hh0
                  by subchain sb hh0 s.domain
                  so (forall u. hh0 u -> under u /\ s.domain u)
                  so forall u. under u /\ s.domain u -> hh0 u
                  by u = h0 \/ not sb h0 u by sb u h0)
                so forall h_. s_r.domain h_ ->
                  s_r.eval h_ = s_rl.eval h_
                by if h_ = h0 then true else
                  s_r.eval h_ = s.eval h_
                  so s_rl.eval h_ = s0.eval h_
                  so s.eval h_ = s0.eval h_
                  by s_o s0 s
                  so if lo s0 s
                  then subchain sb s0.domain s.domain
                    so equalizer s0.domain s0.eval s.eval
                    so s0.domain h_
                  else exists hh_ h2. stack_lex_witness sb go s0 s hh_ h2
                    so subchain sb hh0 hh_
                    so equalizer (remove hh_ h2) s0.eval s.eval
                    so remove hh_ h2 h_ by hh0 h_ so hh_ h_
                    so h_ = h2 -> false by maximum sb hh0 h_
              )
              so let target = bigunion (image q h0) in
                (victory_invariant (game_rec o p q g h0)
                                     ((=) fl.str) target fl.inv
                by exists h. ch h so exists a. hsr a /\ fn a = h
                so fl.inv = (a.eval h0).inv /\ fl.str = (a.eval h0).str
              )
              so (f0.inv hl by subset ch fl.inv by forall h. ch h -> fl.inv h
                by exists a. hsr a /\ fn a = h
                so (a.eval h0).inv = fl.inv)
              so not (inhabited (inter hl target) so exists x.
                hl x /\ target x so exists h. ch h /\ h x
                so exists a. hsr a /\ fn a = h
                so not inhabited (inter h target)
                so inter h target x
              )
              so (s.domain h0 by subchain sb hh0 s.domain)
              so (lower (subchain go) f0.log hl
                by ch f0.log so hl <> f0.log /\ subchain go f0.log hl
                so order (subchain go)
              )
              so is_stack o p q g s
              so tr_cond s f0.log hl
                by forall h x. s.domain h /\ hl x /\ not f0.log x ->
                upper_bound go (s.eval h).log x
                by exists hx. ch hx /\ hx x
                so exists sx. hsr sx /\ fn sx = hx
                so s_o s sx \/ (false by s_o sx s so subchain go hx (fn s)
                                so f0.log x)
                so not (lorder sb s sx so s.domain h0)
                so exists hh_ h_. stack_lex_witness sb go s sx hh_ h_
                so subchain sb hh0 hh_
                so hh_ h0 so (h0 = h_ by not remove hh_ h_ h0)
            )
            so ("stop_split" upper_bound s_o hs s_rl by
              forall s. hs s -> s_o s s_rl
              by if hsr s then true else hsr s0 so s_o s s0
                so s_o s0 s_rl so transitive s_o
            )
            so (is_stack o p q g s_rl by hsr s0)
            (* However, the obtained stack is not correlated with xs.
               We use the 'next' lemma to add it on top and be done.
               For this, we first need to establish that xs is the (strict)
               supremum of hl. *)
            so ("stop_split" supremum go hl xs
              by transitive go
              so (forall x. hl x -> go x xs
                by exists h. ch h /\ h x
                so exists a. hsr a /\ fn a = h
                so go x (fs a) /\ (go (fs a) xs by image fs hs (fs a))
                by upper_bound go h (fs a)
                by i a (fs a) so exists ht. is_stack_top o go a ht (fs a)
                so maximum go (a.eval ht).log (fs a)
                so h0 <> ht -> a.domain h0 so subchain o h0 ht
                so upper_bound go (fn a) (a.eval ht).str
                so go (a.eval ht).str (fs a)
                by minimum go (a.eval ht).log (a.eval ht).str
              ) /\ forall x. upper_bound go hl x -> go xs x
                by upper_bound go (image fs hs) x
                by (forall a. hsr a -> go (fs a) x
                  by exists b. hsr b /\ stack_lex_witness sb go a b hh0 h0
                  so lower (subchain go) (fn a) (fn b)
                  so not sext (fn a) (fn b) so subset (fn a) (fn b)
                  so exists y. fn b y /\ not fn a y
                  so i a (fs a) so exists ht. is_stack_top o go a ht (fs a)
                  so upper_bound go (a.eval ht).log y so (hl y by ch (fn b))
                  so go (fs a) y /\ go y x
                ) so (forall a. hs a -> go (fs a) x
                  by not hsr a -> s_o a s0 /\ hsr s0
                  so go (fs a) (fs s0) /\ go (fs s0) x
                )
            ) so ("stop_split" not (hl xs so exists h. ch h /\ h xs
              so subchain go h hl so sext h hl by forall x. hl x -> h x
              by x = xs \/ not go xs x by go x xs
            ))
            so ("stop_split" (s_rl.eval h0).inv (add hl xs)
              by s_rl.eval h0 = fl
              so victory_invariant (game_rec o p q g h0)
                                   ((=) fl.str) (bigunion (image q h0)) fl.inv
              so fl.inv hl
            )
            so ("stop_split" ret_cond s_rl xs
              by forall h. s_rl.domain h ->
                let lg0 = (s_rl.eval h).log in
                upper_bound go lg0 xs
              by if h = h0 then lg0 = hl else
                subchain o h h0
              so upper_bound go lg0 (s_rl.eval h0).str
              so minimum go (s_rl.eval h0).log (s_rl.eval h0).str
              so transitive go /\ go (s_rl.eval h0).str xs
            )
            so s_rl.domain h0
            so later s_o i s_rl xs
          else (* corresponds to transfinite stack overflow,
                  and limp is a perfect candidate for the limit stack.
                  However, showing that it is indeed an upper bound
                  is quite tricky due to the order structure.
                *)
            ("stop_split"
              upper_bound s_o hs limp by forall s. hs s -> s_o s limp
                by transitive sbb /\ transitive lo
                so (exists p. evp p /\ not paf p s
                  so exists s2. hs s2 /\ s_o s s2 /\ not lo p s2
                  so exists s3. hs s3 /\ paf p s3
                  so lo p s3 so s_o s2 s3 || (false by s_o s3 s2)
                  so lo p limp so s_o s2 limp
                  by if lo s2 s3
                  then lo s2 p by sbb s2.domain p.domain
                    || (false by sbb p.domain s2.domain
                    )
                  else exists h x.
                      stack_lex_witness (subchain o) go s2 s3 h x
                    so stack_lex_witness (subchain o) go s2 limp h x
                    by sbb h p.domain
                    || (false by sbb p.domain h
                      so not (p.domain x so sext p.domain h
                        by forall u. h u -> p.domain u
                          by (x = u \/ not sb x u) by sb u x)
                      so sbb p.domain s2.domain
                      so equalizer p.domain p.eval s2.eval
                      by forall u. p.domain u ->
                        s2.eval u = s3.eval u = p.eval u
                        by remove h x u
                    )
                    so h x so p.domain x so lo p limp so sbb h limp.domain
                    so limp.eval x = p.eval x = s3.eval x
                    so forall z. remove h x z ->
                      s2.eval z = s3.eval z = p.eval z = limp.eval z
                    by p.domain z
                ) || (false by paf limp s
                  by forall s2. hs s2 /\ s_o s s2 -> lo limp s2
                  by upper_bound lo evp s2
                )
            )
            (* Moreover, limp has the nice property of being a stack
               (is_stack is continuous over lo) *)
            so ("stop_split" is_stack o p q g limp
              by ("stop_split" wf_chain sb limp.domain
                by (forall d. image domain evp d -> wf_chain sb d
                  by exists p. evp p /\ d = p.domain
                  so exists s. hs s /\ paf p s
                  so lo p s so subchain sb p.domain s.domain
                  so wf_chain sb s.domain)
                so chain sbb (image domain evp)
                by monotone lo domain sbb
              )
              so ("stop_split" forall h1 h2.
                limp.domain h2 /\ inhabited h1 /\ subchain o h1 h2 ->
                limp.domain h1 by exists d. image domain evp d /\ d h2
                so exists p. evp p /\ p.domain = d
                so exists s. hs s && (lo p s by paf p s)
                so d h1 by s.domain h1 so subchain sb d s.domain
                so h1 = h2 \/ not sb h2 h1
              )
              so ("stop_split" forall h1 h2.
                limp.domain h1 /\ limp.domain h2 /\ subchain o h1 h2 ->
                h1 <> h2 ->
                upper_bound go (limp.eval h1).log (limp.eval h2).str
                by exists d. image domain evp d /\ d h2
                so exists p. evp p /\ p.domain = d
                so lo p limp
                so (d h1 by not sb h2 h1 /\ sbb d limp.domain)
                so exists s. hs s && (lo p s by paf p s)
                so limp.eval h1 = p.eval h1 = s.eval h1
                /\ limp.eval h2 = p.eval h2 = s.eval h2
                by equalizer d p.eval s.eval
              )
              so ("stop_split" forall h. limp.domain h ->
                let f = limp.eval h in
                let target = bigunion (image q h) in
                let lg = game_rec o p q g h in
                f.inv f.log
                /\ chain o h
                /\ inhabited h
                /\ (maximum o h (sup o h) -> p (sup o h) f.str)
                /\ minimum g.progress f.log f.str
                /\ victory_invariant lg ((=) f.str) target f.inv
                /\ not inhabited (inter f.log target)
                /\ (forall x. target x /\ upper_bound go f.log x ->
                    linked o limp h x)
                by exists d. image domain evp d /\ d h
                so exists p_. evp p_ /\ p_.domain = d
                so exists s. hs s && (lo p_ s by paf p_ s)
                so lo p_ limp
                so equalizer d p_.eval s.eval
                so limp.eval h = p_.eval h = s.eval h
                so is_stack o p q g s
                so s.domain h
                so forall x. target x /\ upper_bound go f.log x ->
                  linked o limp h x by linked o s h x
                so exists hl. let fl = s.eval hl in
                  s.domain hl /\ lower sb hl h /\
                  fl.inv (add fl.log x)
                so limp.domain hl /\ fl = p_.eval hl = limp.eval hl
                by d hl by not sb h hl /\ sbb d limp.domain
              )
            )
            so let hf = bigunion limp.domain in
              let target = bigunion (image q hf) in
              (* Necessary for both branches: xs completely
                 dominate the remaining logs. *)
            ("stop_split" forall h. limp.domain h ->
                  upper_bound go (limp.eval h).log xs
              by exists d. image domain evp d /\ d h
              so exists p. evp p /\ p.domain = d
              so exists s. hs s && (lo p s by paf p s)
              so s.domain h
              so (s.eval h = p.eval h = limp.eval h
                by equalizer p.domain p.eval s.eval)
              so i s (fs s)
              so exists ht. is_stack_top o go s ht (fs s)
              so s.domain ht /\ maximum go (s.eval ht).log (fs s)
              so transitive go /\ (go (fs s) xs by image fs hs (fs s))
              so if h = ht then upper_bound go (s.eval h).log (fs s)
              else (lower sb h ht by sb h ht)
                so upper_bound go (s.eval h).log (s.eval ht).str
                so minimum go (s.eval ht).log (s.eval ht).str
                so transitive go
                so go (s.eval ht).str xs
            )
            so ("stop_split" forall h x. maximum o h x /\ subchain o h hf ->
              limp.domain h by exists h'. limp.domain h' /\ h' x
              so (subchain o h' hf by supremum sb limp.domain hf)
              so subchain o h h' || (false by subchain o h' h
               so sext h' h by forall u. h u -> h' u
               by x = u \/ not o x u by o u x
            ))
            (* New case disjonction: if by chance we land on the target,
               done by return lemma. Otherwise, we need to perform
               a 'limit' call. *)
            so if target xs
            then exists s. image q hf s /\ s xs
              so exists u. hf u /\ s = q u
              so exists h. limp.domain h /\ h u
              so bigunion (image q h) xs
              so (ret_cond limp xs)
              so later s_o i limp xs
              so later_limit s_o i hs xs
            else (* To perform a call, it only remains
               to find the correct instance of the limit. *)
              let fn =
              fun x -> (limp.eval (inter hf (flip o x))).str in
              chain sb limp.domain
              so ("stop_split" chain o hf
                so forall h. limp.domain h -> chain o h
              )
              so ("stop_split" forall x. hf x ->
                let h = inter hf (flip o x) in
                maximum o h x && subchain o h hf && limp.domain h)
              so ("stop_split" rel_mapping hf fn p
                by forall x. hf x -> p x (fn x)
                by let h = inter hf (flip o x) in
                  inhabited h so x = sup o h
              )
              so ("stop_split" monotone_on hf o fn go
                by forall x y. hf x /\ hf y /\ o x y -> go (fn x) (fn y)
                by x <> y -> let hx = inter hf (flip o x) in
                  let hy = inter hf (flip o y) in
                  subchain o hx hy
                so upper_bound go (limp.eval hx).log (limp.eval hy).str
                so minimum go (limp.eval hx).log (limp.eval hx).str
              )
              so ("stop_split" not (limp.domain hf
                so exists d. d hf /\ image domain evp d
                so exists p. evp p /\ p.domain = d
                so maximum sb limp.domain hf
                so (subchain sb d limp.domain by lo p limp)
                so (sext p.domain limp.domain by forall u. limp.domain u ->
                  p.domain u by hf = u \/ not sb hf u by sb u hf)
                so pext p limp))
              so not maximum o hf (sup o hf)
              so ("stop_split" not (not inhabited hf so
                (forall h. not (limp.domain h so (h = none by sext h none
                  by subchain o h hf) so inhabited h))
                so exists s. hs s so paf limp s
                by forall s. lo limp s
              ))
              (* Establishing the supremum is a tricky,
                 especially the second part. To establish it,
                 we must analyse both cases of lexicographic
                 increase (in fact, first one is impossible,
                 but it is simpler to prove the goal directly) *)
              so ("stop_split" supremum go (image fn hf) xs
                by (forall u. image fn hf u -> go u xs
                  by exists k. hf k /\ fn k = u
                  so let hk = inter hf (flip o k) in
                    upper_bound go (limp.eval hk).log xs
                  so minimum go (limp.eval hk).log u
                )
                /\ (forall u. upper_bound go (image fn hf) u -> go xs u
                  by upper_bound go fhs u
                  by forall v. image fs hs v -> go v u
                  by exists s. hs s /\ fs s = v
                  so i s (fs s) so exists ht. is_stack_top o go s ht v
                  so s_o s limp
                  so transitive go
                  so (forall h x. limp.domain h /\ (limp.eval h).log x ->
                    go x u
                    by limp.domain h so not sext h hf /\ subset h hf
                    so exists k. hf k /\ not h k
                    so let hk = inter hf (flip o k) in
                      maximum o hk k so subchain o hk hf so limp.domain hk
                    so (subchain o h hf by supremum sb limp.domain hf)
                    so subchain o hk hf
                    so subchain o h hk
                      || (false by subchain o hk h so sext hk h
                        by forall u. h u -> hk u by u = k \/ not o k u
                        by o u k)
                    so h <> hk
                    so upper_bound go (limp.eval h).log (fn k)
                    so go x (fn k) so go (fn k) u
                  )
                  so if lo s limp
                  then s.domain ht
                    so limp.domain ht /\ limp.eval ht = s.eval ht
                    so go v u
                  else exists hh h.
                    stack_lex_witness (subchain o) go s limp hh h
                    so not sext (limp.eval h).log (s.eval h).log
                    so subset (s.eval h).log (limp.eval h).log
                    so exists x. (limp.eval h).log x /\ not (s.eval h).log x
                    so upper_bound go (s.eval ht).log x
                    so go v x so go x u
                )
              )
              so let rg = game_rec o p q g hf in
                let recursive = uquant (upper_bound o hf) (henforce p q) in
                holds (conj c recursive)
                      (enforce (supremum go (image fn hf)) target)
              so (holds (conj c recursive) (enforce ((=) xs) target)
                by subset ((=) xs) (supremum go (image fn hf)))
              so have_uniform_winning_strat rg ((=) xs) target
              so exists iv. victory_invariant rg ((=) xs) target iv
              so upper_bound (subchain o) limp.domain hf
              (* Setting up the limit call. Most conditions are already
                   ok (including no new return links), we only need
                   to check saturation. *)
              so ("stop_split" call_cond limp hf xs
                by (forall h2. inhabited h2 /\ lower (subchain o) h2 hf ->
                  limp.domain h2
                  by supremum (subchain o) limp.domain hf
                  so not upper_bound (subchain o) limp.domain h2
                  so exists h. limp.domain h /\ not subchain o h h2
                  so subchain o h hf so subchain o h2 h
                )
              )
              so let s_r = padd limp hf
                                { str = xs; log = (=) xs; inv = iv } in
                (("stop_split"
                  is_stack o p q g s_r /\ s_r <> limp /\ s_o limp s_r
                 /\ is_stack_top o go s_r hf xs) so i s_r xs)
              so later s_o i limp xs
              so later_limit s_o i hs xs
      )
    )

  lemma recursion_v2 : forall c go,p q:rel 'b 'a,o:erel 'b,x0.
    holds c (ordering go) /\ order o /\ is_rec c o go p q ->
    holds c (enforce (p x0) (q x0))
    by let c1 = conj c (enforce (q x0) none) in
      holds c1 (enforce (p x0) (q x0))
    by subset none (q x0) so holds c1 (enforce (p x0) none)
    by let q' = q[x0 <- none] in
      forall g. c1.interp g -> (enforce (p x0) none).interp g
    by let c2 = glarger g in
      holds c2 (enforce (p x0) none)
    by q' x0 = none so is_rec c2 o go p q'
    by (forall s. let rec1 = uquant s (henforce p q') in
      let rec2 = uquant s (henforce p q) in
      holds (conj c2 rec1) rec2 by forall x. s x ->
      holds (conj c2 rec1) (enforce (p x) (q x))
      by holds (enforce (p x) (q' x)) (enforce (p x) (q x))
      by holds (enforce (p x) (q' x)) (enforce (p x) (q' x))
      so subset (q' x) (q x)
    )
    so (forall x. let rec1 = uquant (lower o x) (henforce p q') in
      holds (conj c2 rec1) (enforce (p x) (q' x))
      by let rec2 = uquant (lower o x) (henforce p q) in
        holds (conj c rec2) (enforce (p x) (q x))
      so holds (conj c2 rec2) (enforce (p x) (q x))
      so (holds (conj c2 rec2) (enforce (p x) (q' x))
        by x = x0 -> holds (conj c2 rec2) (enforce (q x) (q' x))
      )
    ) /\ (forall h f. chain o h /\ monotone_on h o f go /\ inhabited h /\
      not maximum o h (sup o h) /\ rel_mapping h f p ->
      let rec1 = uquant (upper_bound o h) (henforce p q') in
      let rec2 = uquant (upper_bound o h) (henforce p q) in
      let tg1 = bigunion (image q' h) in
      let tg2 = bigunion (image q h) in
      let src = supremum go (image f h) in
      holds (conj c2 rec1) (enforce src tg1)
      by holds (conj c2 rec2) (enforce src tg1)
      by holds (conj c2 rec2) (enforce src tg2)
      so holds (conj c2 rec2) (enforce tg2 tg1)
      by forall y. tg2 y -> holds (conj c2 rec2) (enforce ((=) y) tg1)
      by exists s. image q h s /\ s y so exists x. h x /\ s = q x
      so if x = x0 then holds (conj c2 rec2) (enforce s none)
          so subset ((=) y) s /\ subset none tg1
        else subset ((=) y) tg1 by image q' h s
    )

  clone FmlaRules with goal abstraction,
    goal modus_ponens,
    goal reflexive,
    goal conj_left,
    goal conj_right,
    goal enforce_monotonic,
    goal enforce_does_progress,
    goal enforce_reflexivity,
    goal sequence,
    goal kont_intro,
    goal external_pre,
    goal trampoline,
    goal recursion

end


Generated by why3doc 0.90+git