Maram proof files index
module Tree use export int.Int use import map.Map as M use import set.Fset as F use seq.Seq, seq.Mem, seq.Distinct (* auxiliary lemmas on sequences *) lemma append_empty: forall s: seq 'a. s ++ empty == s lemma empty_length: forall s: seq 'a. length s = 0 <-> s == empty predicate disjoint_seq (s1 s2: seq 'a) = forall i j. 0 <= i < length s1 -> 0 <= j < length s2 -> s1[i] <> s2[j] (* Arbitrary type for a tree node *) type elt (* Verifies if two nodes are equal *) val equal (e1 e2 : elt) : bool ensures { result <-> e1 = e2 } (* Indicates if two nodes are connected by an edge in the tree *) predicate edge (x y : elt) (f : elt -> elt) = x <> y /\ f x = y (* recursive predicate for expressing a path between two nodes *) (* in the main text a few cosmetic changes were done, namely *) (* rename of -f- to -parent- and expand the edge definition *) predicate path (f: elt -> elt) (x y: elt) (p: seq elt) = let n = length p in n = 0 /\ x = y \/ n > 0 /\ p[0] = x /\ edge p[n - 1] y f /\ distinct p /\ (forall i. 0 <= i < n - 1 -> edge p[i] p[i + 1] f) /\ (forall i. 0 <= i < n -> p[i] <> y) predicate reachability (f: elt -> elt) (x y: elt) = exists p. path f x y p (* If there is an edge between nodes x and y the path is defined as the singleton seq with node x *) axiom path_to_parent: forall x y : elt, f : elt -> elt. edge x y f -> path f x y (cons x empty) (* If there is a path from [from] to [middle] and a path from [middle] to [until] then there is a path from [from] to [until] *) axiom path_transitivity: forall from middle until f pth1 pth2. path f from middle pth1 -> path f middle until pth2 -> disjoint_seq pth1 pth2 -> from <> until -> (forall j. 0 <= j < length pth1 -> pth1[j] <> until) -> path f from until (pth1 ++ pth2) (* Recursive path composition *) axiom path_composition: forall n x y: elt, f : elt -> elt, pth : seq elt. n <> y -> not (mem y pth) -> distinct (snoc pth x) -> path f n x pth -> edge x y f -> path f n y (snoc pth x) (* If there is a path between two nodes, that path is unique *) axiom path_uniqueness: forall x y: elt, f: elt -> elt, pth1 pth2: seq elt. path f x y pth1 -> path f x y pth2 -> pth1 == pth2 (* If node np is not reachable to node c, then np will not belong to any path that contains node c *) axiom path_exclusion: forall f x c np p. not (reachability f np c) -> path f x c p -> not (mem np p) (* Given a path between two nodes, there is no overlap between any two consecutive subpaths *) axiom path_separation: forall final initial middle : elt, f : elt -> elt, p1 p2 : seq elt. path f middle final p2 -> path f initial middle p1 -> final <> initial -> middle <> initial -> middle <> final -> disjoint_seq p1 p2 constant n: elt (* constant used for defining a state witness *) type state [@state] = { (* parent relation: up-pointers to direct ancestor *) mutable parent : elt -> elt; (* parent root *) mutable root : elt; (* nodes in the parent *) mutable nodes : fset elt; } invariant { F.mem root nodes } invariant { parent root = root } invariant { forall x. F.mem x nodes -> F.mem (parent x) nodes } invariant { forall x. F.mem x nodes -> reachability parent x root } invariant { forall x. F.mem x nodes -> reachability parent root x -> x = root } by { parent = (fun _ -> n); root = n; nodes = F.singleton n } (* Paths already present in the tree remain in the tree after executing the add operation *) axiom remaining_nodes_add: forall n w p: elt, s: state, l: seq elt. path s.parent w s.root l -> not (mem n l) -> F.mem w s.nodes -> F.mem p s.nodes -> not (F.mem n s.nodes) -> w <> n -> n <> p -> path (M.set s.parent n p) w s.root l (* Descendants of the node being moved continue to be its descendants *) axiom descendants_move: forall x c np: elt, f: elt -> elt, p: seq elt. x <> np -> c <> np -> x <> c -> not (reachability f np c) -> path f x c p -> distinct (cons c p) -> not (mem np p) -> (path (M.set f c np) x c p) (* Paths nodes unreachable to the node being moved are not affected *) axiom remaining_nodes_move: forall x c np: elt, s: state, p: seq elt. c <> np -> x <> c -> not (reachability s.parent np c) -> path s.parent x s.root p -> (not reachability s.parent x c) -> distinct p -> (path (M.set s.parent c np) x s.root p) let ghost add (n p : elt) (s : state) : unit requires { [@expl:pre_add1] not F.mem n s.nodes } requires { [@expl:pre_add2] F.mem p s.nodes } ensures { s.parent = M.set (old s.parent) n p } ensures { edge n p s.parent } ensures { s.nodes = F.add n (old s).nodes } = s.parent <- M.set s.parent n p; s.nodes <- F.add n s.nodes let ghost remove (n : elt) (s : state) : unit requires { [@expl:pre_remove1] forall x. s.parent x <> n } requires { [@expl:pre_remove2] n <> s.root } ensures { s.nodes = F.remove n (old s).nodes } = s.nodes <- F.remove n s.nodes let ghost move (c np : elt) (s : state) : unit requires { [@expl:pre_move1] F.mem np s.nodes } requires { [@expl:pre_move2] F.mem c s.nodes} requires { [@expl:pre_move3] not (reachability s.parent np c) } requires { [@expl:pre_move4] c <> s.root } requires { [@expl:pre_move5] c <> np } ensures { edge c np s.parent } ensures { s.parent = M.set (old s.parent) c np } = s.parent <- M.set s.parent c np end
Generated by why3doc 1.3.1+git