why3doc index index
(* Encodings of transition systems into games. *) (* Axiomatic definition of (potentially infinite) evolution traces within a transition ystem. In order to avoid bringing in the context the full invariant that enforces extensionality, the actual type of trace is defined in another module. *) module Trace "W:non_conservative_extension:N" (* => TraceDef *) use import int.Int use import ho_set.Set use import ho_rel.Rel use import order.Ordered use import order.Chain (* FIXME: weird that witness obligation is generated here (cause abstract type anyway), and not possible to use 'by' witness introduction because there is no way to generate a polymorphic computable witness of (int -> 'a) (only (int -> {'a}) is possible, but that type is rejected). Since we must move the lemma out, this also force a very inelegant context disposal. *) lemma existence : exists rel:erel 'a,finite length nth. length >= 0 /\ (forall n. 0 < n /\ (finite -> n <= length) -> rel (nth (n-1)) (nth n)) by finite = true /\ length = 0 type trace 'a = private { rel : erel 'a; finite : bool; length : int; nth : int -> 'a; } invariant { length >= 0 } invariant { forall n. 0 < n /\ (finite -> n <= length) -> rel (nth (n-1)) (nth n) } meta remove_prop lemma existence (* Prefix comparisons for traces. *) predicate subtrace (t1 t2:trace 'a) = t1.rel = t2.rel && (t2.finite -> t1.finite && t1.length <= t2.length) && forall n. 0 <= n /\ (t1.finite -> n <= t1.length) -> t1.nth n = t2.nth n axiom subtrace_order : order (subtrace:erel (trace 'a)) (* Minimal trace constructor: comprehension. *) val ghost create_trace (r:erel {'a}) (fn:bool) (len:int) (f:int -> {'a}) : trace {'a} requires { fn -> 0 <= len } requires { forall n. 0 < n /\ (fn -> n <= len) -> r (f (n-1)) (f n) } ensures { result.rel = r } ensures { result.finite = fn } ensures { fn -> result.length = len } ensures { forall n. 0 <= n /\ (fn -> n <= len) -> result.nth n = f n } (*(* Minimal trace constructors: singleton (base case), addition (successor case), and supremum (limit case). *) val ghost function singleton_trace (r:erel {'a}) (x:{'a}) : trace {'a} ensures { result.finite /\ result.length = 0 } ensures { result.rel = r /\ result.nth 0 = x } val ghost function add_to_trace (t:trace {'a}) (x:{'a}) : trace {'a} requires { t.finite /\ t.rel (t.nth t.length) x } ensures { result.finite /\ result.length = t.length + 1 } ensures { result.nth result.length = x } ensures { subtrace t result } val ghost function sup_chain_trace (h:set (trace {'a})) : trace {'a} requires { chain subtrace h /\ inhabited h } ensures { supremum subtrace h result } ensures { forall x. h x -> result.rel = x.rel } ensures { result.finite -> maximum subtrace h result } ensures { not maximum subtrace h result -> forall x. h x -> x.finite } ensures { not maximum subtrace h result -> forall n. 0 <= n -> exists x. h x /\ n <= x.length }*) end (* Additional constructors for evolution traces, defined on top of comprehension: singleton trace, addition of an element to any end, catenation, pre/suffix extraction and chain supremum. *) module TraceConstructors use import int.Int use import option.Option use import fn.Image use import ho_set.Set use import ho_rel.Rel use import order.Ordered use import order.Chain use import choice.Choice use export Trace let ghost function singleton_trace (r:erel {'a}) (x:{'a}) : trace {'a} ensures { result.finite /\ result.length = 0 } ensures { result.rel = r /\ result.nth 0 = x } = create_trace r true 0 (fun _ -> x) let ghost function add_suffix_trace (t:trace {'a}) (x:{'a}) : trace {'a} requires { t.finite -> t.rel (t.nth t.length) x } ensures { result.finite = t.finite } ensures { t.finite -> result.length = t.length + 1 } ensures { not t.finite -> result = t } ensures { t.finite -> result.nth result.length = x } ensures { subtrace t result } = if not t.finite then t else let function nt n = if n = t.length + 1 then x else t.nth n in create_trace t.rel true (t.length + 1) nt let ghost function add_prefix_trace (x:{'a}) (t:trace {'a}) : trace {'a} requires { t.rel x (t.nth 0) } ensures { result.finite = t.finite } ensures { t.finite -> result.length = t.length + 1 } ensures { forall n. 0 <= n /\ (result.finite -> n <= result.length) -> result.nth n = if n = 0 then x else t.nth (n-1) } = let function nt n = if n = 0 then x else t.nth (n-1) in create_trace t.rel t.finite (t.length + 1) nt let ghost function cat_trace (t1 t2:trace {'a}) : trace {'a} requires { t1.rel = t2.rel } requires { t1.finite -> t1.nth t1.length = t2.nth 0 } ensures { subtrace t1 result /\ (not t1.finite -> result = t1) } ensures { result.finite <-> t1.finite /\ t2.finite } ensures { result.finite -> result.length = t1.length + t2.length } ensures { forall n. 0 <= n /\ (t1.finite -> n <= t1.length) -> result.nth n = t1.nth n } ensures { t1.finite -> forall n. t1.length <= n /\ (result.finite -> n <= result.length) -> result.nth n = t2.nth (n - t1.length) } = let fn = pure { t1.finite /\ t2.finite } in let ln = t1.length + t2.length in let function nt (n:int) = if pure { t1.finite -> n <= t1.length } then t1.nth n else t2.nth (n - t1.length) in assert { forall n. 0 < n /\ (fn -> n <= ln) -> t1.rel (nt (n-1)) (nt n) by if (t1.finite -> n <= t1.length) then t1.rel (t1.nth (n-1)) (t1.nth n) else let m = n - t1.length in (t2.nth (m-1) = nt (n-1) by n > t1.length + 1 -> t2.nth (m-1) = nt (n-1)) so t2.rel (t2.nth (m-1)) (t2.nth m) }; let res = create_trace t1.rel fn ln nt in assert { subtrace t1 res && (not t1.finite -> res = t1 by subtrace res t1) }; res let ghost function prefix_trace (l:int) (t:trace {'a}) : trace {'a} requires { 0 <= l /\ (t.finite -> l <= t.length) } ensures { subtrace result t } ensures { result.finite /\ result.length = l } = create_trace t.rel true l t.nth let ghost function suffix_trace (l:int) (t:trace {'a}) : trace {'a} requires { 0 <= l /\ (t.finite -> l <= t.length) } ensures { cat_trace (prefix_trace l t) result = t } = let function nt n = t.nth (n+l) in assert { forall n. 0 < n /\ (t.finite -> n <= t.length - l) -> t.rel (nt (n-1)) (nt n) by 0 < n+l /\ (t.finite -> n + l <= t.length) }; let sf = create_trace t.rel t.finite (t.length - l) (fun n -> t.nth (n+l)) in let pr = prefix_trace l t in let t0 = cat_trace pr sf in assert { subtrace t0 t }; assert { subtrace t t0 }; sf let ghost function sup_chain_trace (h:set (trace {'a})) : trace {'a} requires { chain subtrace h /\ inhabited h } ensures { supremum subtrace h result } ensures { forall x. h x -> result.rel = x.rel } ensures { result.finite -> maximum subtrace h result } ensures { not h result -> forall x. h x -> x.finite } ensures { not h result -> forall n. 0 <= n -> exists x. h x /\ n <= x.length } = let res = match choose_if (maximum subtrace h) with | Some u -> u | None -> assert { forall x. h x -> if x.finite then true else false by maximum subtrace h x }; let s = pure { image length h } in assert { forall x. h x -> not (upper_bound (<=) s x.length so maximum subtrace h x by forall u. h u -> if subtrace u x then true else false by subtrace x u so u.length > x.length /\ s u.length )}; let w = choose h in assert { forall x. h x -> x.rel = w.rel by subtrace x w \/ subtrace w x }; let function nth0 (n:int) ensures { n >= 0 -> forall x. h x /\ n <= x.length -> x.nth n = result } ensures { n >= 0 -> exists x. h x /\ n <= x.length } = if n < 0 then witness else let t = pure { fun x -> h x /\ n <= x.length } in match choose_if t with | None -> let rec aux (m:int) : 'a requires { upper_bound (<=) s m } ensures { false } variant { m } = if s m then absurd else aux (m-1) in assert { forall l. s l -> l <= n by exists x. h x /\ x.length = l so not t x }; aux n | Some u -> assert { forall x. h x /\ n <= x.length -> x.nth n = u.nth n by subtrace x u \/ subtrace u x }; u.nth n end in assert { forall n. 0 < n -> w.rel (nth0 (n-1)) (nth0 n) by exists x. h x /\ n < x.length so (n-1) <= x.length so x.rel (x.nth (n-1)) (x.nth n) }; let res = create_trace w.rel false 42 nth0 in assert { upper_bound subtrace h res }; assert { forall u. upper_bound subtrace h u -> subtrace res u by not (u.finite so exists x. h x /\ u.length + 1 <= x.length so subtrace x u) so (u.rel = res.rel by subtrace w u) so forall n. n >= 0 -> res.nth n = u.nth n by exists x. h x /\ n <= x.length so subtrace x u so res.nth n = x.nth n = u.nth n }; res end in assert { forall x. h x -> res.rel = x.rel by subtrace x res }; res end module TraceDef use import int.Int use import fn.Fun use import fn.Image use import ho_set.Set use import ho_rel.Rel use import order.Ordered use import order.Chain use import option.Option use import choice.Choice (* FIXME: not possible to use 'by' witness introduction because [witness] is purely logical, and cannot be used in code. *) lemma existence : exists rel:erel 'a,finite length nth. length >= 0 /\ (not finite -> length = 0) /\ (forall n. 0 < n /\ (finite -> n <= length) -> rel (nth (n-1)) (nth n)) /\ (forall x. x < 0 \/ (finite /\ x > length) -> nth x = witness) by length = 0 /\ finite = true /\ nth = (fun _ -> witness) type t 'a = { rel : erel 'a; finite : bool; length : int; nth : int -> 'a; } invariant { length >= 0 } invariant { not finite -> length = 0 } invariant { forall n. 0 < n /\ (finite -> n <= length) -> rel (nth (n-1)) (nth n) } invariant { forall x. x < 0 \/ (finite /\ x > length) -> nth x = witness } (* FIXME: no way to recover extensionality from a 'subtype', so we make it axiomatic.... *) axiom extensionality : forall t1 t2:t 'a. t1.rel = t2.rel /\ t1.finite = t2.finite /\ t1.length = t2.length /\ t1.nth = t2.nth -> t1 = t2 predicate subtrace (t1 t2:t 'a) = t1.rel = t2.rel && (t2.finite -> t1.finite && t1.length <= t2.length) && forall n. 0 <= n /\ (t1.finite -> n <= t1.length) -> t1.nth n = t2.nth n lemma sorder : order (subtrace:erel (t 'a)) by forall x y:t 'a. subtrace x y /\ subtrace y x -> x = y let ghost create_trace (r:erel {'a}) (fn:bool) (len:int) (f:int -> {'a}) : t {'a} requires { fn -> 0 <= len } requires { forall n. 0 < n /\ (fn -> n <= len) -> r (f (n-1)) (f n) } ensures { result.rel = r } ensures { result.finite = fn } ensures { fn -> result.length = len } ensures { forall n. 0 <= n /\ (fn -> n <= len) -> result.nth n = f n } = { rel = r; finite = fn; length = if fn then len else 0; nth = fun n -> pure { if 0 <= n /\ (fn -> n <= len) then f n else witness } } meta compute_max_steps 0x1000000 (* FIXME: no way to collapse both defined symbols subtrace ! Although they can be fully unrolled with compute, this is quite ugly. *) clone Trace with type trace 'a = t 'a, goal subtrace_order, val create_trace = create_trace end (* Trace conversion from transition systems to games. *) module TraceGameCommon use import int.Int use import fn.Image use import ho_set.Set use import ho_rel.Rel use import game.Game use import Trace predicate next_trace (t1 t2:trace 'a) = subtrace t1 t2 /\ t2.finite /\ t2.length = t1.length + 1 predicate maximal_trace (t:trace 'a) = not inhabited (next_trace t) predicate has_midpoint_in (a b:trace 'a) (q:set (trace 'a)) = exists c. subtrace a c /\ subtrace c b /\ q c predicate will_reach_trace_in (t:trace 'a) (q:set (trace 'a)) = forall t2. subtrace t t2 /\ maximal_trace t2 -> has_midpoint_in t t2 q let ghost constant game_ex_trace : game (trace {'a}) = { progress = subtrace; transition = fun t1 s -> pure { image (=) (next_trace t1) s } } let ghost constant game_unv_trace : game (trace {'a}) = { progress = subtrace; transition = fun t1 s -> pure { inhabited s /\ s = next_trace t1 } } end module TraceGame "W:non_conservative_extension:N" (* => TraceGameProof *) use import Trace use import game.Game use export TraceGameCommon axiom trace_enforce_ex : forall t:trace 'a,q. have_winning_strat game_ex_trace t q <-> exists tex. q tex /\ subtrace t tex axiom trace_enforce_unv : forall t:trace 'a,q. have_winning_strat game_unv_trace t q <-> will_reach_trace_in t q end module TraceGameProof use import int.Int use import TraceConstructors use import TraceGameCommon use import fn.Fun use import fn.Image use import ho_set.Set use import ho_set.SetBigOps use import game.Game use import game.BasicStrats use import game_no_strat.WinAlt use import choice.Choice use import transfinite.Extension use import order.LimUniq use import order.Chain use import order.SubChain constant gex : game (trace 'a) = game_ex_trace constant gun : game (trace 'a) = game_unv_trace lemma trace_enforce_ex_1 : forall t:trace 'a,q. have_winning_strat gex t q -> (exists tex. q tex /\ subtrace t tex) by exists ang. winning_strat gex t q ang so let dmn = choice in win_against gex t q ang dmn so exists h. tr_ext subtrace (step gex ang dmn) ((=) t) h /\ win_at gex q ang dmn h so chain subtrace h /\ (inhabited h by h t) so let tex = sup_chain_trace h in tex = sup subtrace h so if q tex then subtrace t tex else false by let a = ang h in gex.transition tex a /\ not a (dmn a) so exists t2. next_trace tex t2 /\ a = (=) t2 so a t2 lemma trace_enforce_ex_2 : forall t:trace 'a,q tex. q tex /\ subtrace t tex -> have_winning_strat gex t q by have_uniform_winning_strat game_ex_trace ((=) t) q by let inv = fun h -> forall x. h x -> subtrace x tex in victory_invariant gex ((=) t) q inv by forall h t. inv h /\ not inhabited (inter h q) /\ maximum subtrace h t -> exists a. gex.transition t a /\ not a t /\ subset a (next_hist inv h) by let t2 = prefix_trace (t.length + 1) tex in a = (=) t2 so not (q t so inter h q t) so (if t.finite /\ (tex.finite -> t.length < tex.length) then true else false by tex = t by subtrace tex t) so next_trace t t2 let rec ghost function uacc_prefix (t1 t2:trace {'a}) (ang:angel (trace {'a})) (q:set {trace 'a}) (l:int) : set (trace {'a}) requires { t1.finite /\ winning_strat gun t1 q ang } requires { not has_midpoint_in t1 t2 q } requires { subtrace t1 t2 } requires { t1.length <= l /\ (t2.finite -> l <= t2.length) } ensures { strong_u_acc gun ang t1 result } ensures { maximum subtrace result (prefix_trace l t2) } ensures { forall t3. subtrace t1 t3 -> subtrace t3 (prefix_trace l t2) -> result t3 } variant { l } = let p2 = prefix_trace l t2 in if l = t1.length then begin assert { t1 = p2 by subtrace t1 p2 so subtrace p2 t1 }; pure { (=) t1 } end else let h0 = uacc_prefix t1 t2 ang q (l-1) in let p1 = prefix_trace (l-1) t2 in let a = pure { ang h0 } in assert { u_acc_step gun ang h0 p2 by (if gun.transition p1 a then true else false by lose_at gun ang q h0 by forall u. h0 u -> not (q u so subtrace t1 u by subchain subtrace ((=) t1) h0)) so a p2 by next_trace p1 p2 }; assert { subtrace p1 p2 }; assert { forall t3. subtrace t1 t3 /\ subtrace t3 p2 /\ t3 <> p2 -> h0 t3 by not subtrace p2 t3 so subtrace t3 p1 }; add h0 p2 lemma trace_enforce_unv_1 : forall t t2:trace 'a,q. let gun = game_unv_trace in have_winning_strat gun t q /\ subtrace t t2 /\ maximal_trace t2 -> not has_midpoint_in t t2 q -> false by exists ang. winning_strat gun t q ang so exists h. (strong_u_acc gun ang t h /\ maximum subtrace h t2 so not lose_at gun ang q h so (forall u. h u -> not (q u so subtrace t u /\ subtrace u t2)) so let a = ang h in gun.transition t2 (ang h) /\ not ang h t2 so exists t3. a t3 so t3 = t2 by subtrace t3 t2 ) by if not t.finite then h = (=) t so t = t2 by subtrace t2 t else let lens = fun l -> t.length <= l /\ (t2.finite -> l <= t2.length) in let fn = uacc_prefix t t2 ang q in let ch = image fn lens in let hl = bigunion ch in let sp = sup_chain_trace hl in let hr = add hl sp in h = hr so (ch (fn t.length) by lens t.length) so inhabited ch so (inhabited hl by hl (prefix_trace t.length t2)) so (forall h. ch h -> chain subtrace h /\ minimum subtrace h t by strong_u_acc gun ang t h /\ chain subtrace ((=) t) so subchain subtrace ((=) t) h) so ("stop_split" chain (subchain subtrace) ch by monotone_on lens (<=) fn (subchain subtrace) by forall i j. lens i /\ lens j /\ i <= j -> let hi = fn i in let hj = fn j in subchain subtrace hi hj by ch hi /\ ch hj so let pi = prefix_trace i t2 in let pj = prefix_trace j t2 in subtrace pi pj so maximum subtrace hi pi /\ maximum subtrace hj pj so (forall a. hi a -> hj a by subtrace t a so subtrace a pj by subtrace a pi) so forall a b. hi a /\ hj b /\ not hi b -> subtrace a b by chain subtrace hj so subtrace t b so not (subtrace b a so subtrace b pi) ) so chain subtrace hl so supremum subtrace hl sp so (upper_bound subtrace hl t2 by forall u. hl u -> subtrace u t2 by exists h. h u /\ ch h so exists l. lens l /\ fn l = h so maximum subtrace h (prefix_trace l t2) ) so ("stop_split" sp = t2 by subtrace sp t2 so subtrace t2 sp by if t2.finite then hl t2 by ch (fn t2.length) /\ fn t2.length t2 by let p2 = prefix_trace t2.length t2 in p2 = t2 by subtrace p2 t2 so subtrace t2 p2 else not (sp.finite so let c = sp.length + t.length + 1 in let pc = prefix_trace c t2 in subtrace pc sp by hl pc by ch (fn c) /\ fn c pc) ) so (forall h. ch h -> strong_u_acc gun ang t h) so strong_u_acc gun ang t hl so (hl sp so hl = hr) \/ u_acc_step gun ang hl sp lemma trace_enforce_unv_2 : forall t:trace 'a,q. will_reach_trace_in t q -> have_winning_strat gun t q by have_uniform_winning_strat gun ((=) t) q by let inv = fun h -> minimum subtrace h t /\ (forall u v. h v /\ subtrace t u /\ subtrace u v -> h u) in victory_invariant gun ((=) t) q inv by (forall ch. subset ch inv /\ chain (subchain subtrace) ch /\ inhabited ch -> let hl = bigunion ch in inv hl by supremum (subchain subtrace) ch hl so (minimum subtrace hl t by exists h0. ch h0 so subchain subtrace ((=) t) hl by subchain subtrace ((=) t) h0 /\ subchain subtrace h0 hl ) so (forall u v. hl v /\ subtrace t u /\ subtrace u v -> hl u by exists h. ch h /\ h v so h u) ) /\ (forall h tl. inv h /\ supremum subtrace h tl -> let ht = add h tl in inv ht by (forall u v. ht v /\ subtrace t u /\ subtrace u v -> ht u by if v <> tl then h u by h v else u <> tl -> not upper_bound subtrace h u so exists w. h w /\ not subtrace w u so subtrace w tl so subtrace u w so h u ) ) /\ (forall h tm. inv h /\ not inhabited (inter h q) -> maximum subtrace h tm -> exists a. gun.transition tm a /\ not a tm /\ subset a (next_hist inv h) by a = next_trace tm so not (has_midpoint_in t tm q so exists t0. subtrace t t0 /\ subtrace t0 tm /\ q t0 so inter h q t0) so inhabited a so forall t2. next_trace tm t2 -> let ht = add h t2 in inv ht by (forall u v. ht v /\ subtrace t u /\ subtrace u v -> ht u by if v <> t2 then h u by h v else u <> t2 -> h u by subtrace u tm by not subtrace t2 u ) ) clone TraceGame with goal trace_enforce_ex, goal trace_enforce_unv end
Generated by why3doc 0.90+git