diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Notraits.thy | 114 | ||||
| -rw-r--r-- | ROOT | 7 | ||||
| -rw-r--r-- | Verification.thy | 122 | ||||
| -rw-r--r-- | document/root.tex | 60 | ||||
| -rw-r--r-- | notes.md | 17 | ||||
| -rw-r--r-- | src/main.rs | 43 | 
7 files changed, 341 insertions, 24 deletions
@@ -4,3 +4,5 @@  /lake-packages/*  .lake  *.llbc +/output +*.thy~ diff --git a/Notraits.thy b/Notraits.thy new file mode 100644 index 0000000..fd459f7 --- /dev/null +++ b/Notraits.thy @@ -0,0 +1,114 @@ +(** THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS *) +(** [avl_verification] *) +theory "Notraits" imports +  "Aeneas.Primitives" +  "HOL-Library.Datatype_Records" +begin + + +(*[avl_verification::Ordering] +   Source: 'src/main.rs', lines 1:0-1:17*) +datatype Ordering = Ordering_Less | Ordering_Equal | Ordering_Greater + + +(*[avl_verification::AVLNode] +   Source: 'src/main.rs', lines 10:0-10:14*) +datatype AVLNode = mkAVLNode +  (val: "u32") (left: "AVLNode option") (right: "AVLNode option") +local_setup \<open>Datatype_Records.mk_update_defs \<^type_name>\<open>AVLNode\<close>\<close> + +(*[avl_verification::AVLTreeSet] +   Source: 'src/main.rs', lines 18:0-18:17*) +datatype AVLTreeSet = mkAVLTreeSet (root: "AVLNode option") +local_setup \<open>Datatype_Records.mk_update_defs \<^type_name>\<open>AVLTreeSet\<close>\<close> + +(*[avl_verification::{avl_verification::AVLTreeSet}::new]: +   Source: 'src/main.rs', lines 23:4-23:24*) +definition aVLTreeSet_new :: "AVLTreeSet result" where +  "aVLTreeSet_new = Ok (\<lparr> root = None \<rparr>)" + +(*[avl_verification::cmp]: +   Source: 'src/main.rs', lines 61:0-61:40*) +fun cmp :: "u32 \<Rightarrow> u32 \<Rightarrow> Ordering result" where +  "cmp a other = +    (if u32_lt a other +    then Ok Ordering_Less +    else (if a = other then Ok Ordering_Equal else Ok Ordering_Greater))" + +(*[avl_verification::{avl_verification::AVLTreeSet}::find]: loop 0: +   Source: 'src/main.rs', lines 27:4-39:5*) +function aVLTreeSet_find_loop +  :: "u32 \<Rightarrow> AVLNode option \<Rightarrow> (bool * AVLNode option) result" where +  "aVLTreeSet_find_loop value1 current_tree = +    (case current_tree of +      None \<Rightarrow> Ok (False, None) +    | Some current_node \<Rightarrow> +      do { +        o1 \<leftarrow> cmp (val current_node) value1; +        (case o1 of +          Ordering_Less \<Rightarrow> +          do { +            (b, current_tree1) \<leftarrow> +              aVLTreeSet_find_loop value1 (right current_node); +            Ok (b, Some +              (current_node \<lparr> right := current_tree1 \<rparr>)) +            } +        | Ordering_Equal \<Rightarrow> Ok (True, Some current_node) +        | Ordering_Greater \<Rightarrow> +          do { +            (b, current_tree1) \<leftarrow> +              aVLTreeSet_find_loop value1 (left current_node); +            Ok (b, Some (current_node \<lparr> left := current_tree1 \<rparr>)) +            }) +        })"  by auto + +(*[avl_verification::{avl_verification::AVLTreeSet}::find]: +   Source: 'src/main.rs', lines 27:4-27:46*) +fun aVLTreeSet_find +  :: "AVLTreeSet \<Rightarrow> u32 \<Rightarrow> (bool * AVLTreeSet) result" where +  "aVLTreeSet_find self value1 = +    do { +      (b, as) \<leftarrow> aVLTreeSet_find_loop value1 (root self); +      Ok (b, (\<lparr> root = as \<rparr>)) +      }" + +(*[avl_verification::{avl_verification::AVLTreeSet}::insert]: loop 0: +   Source: 'src/main.rs', lines 40:4-58:5*) +function aVLTreeSet_insert_loop +  :: "u32 \<Rightarrow> AVLNode option \<Rightarrow> (bool * AVLNode option) result" where +  "aVLTreeSet_insert_loop value1 current_tree = +    (case current_tree of +      None \<Rightarrow> +      let a = (\<lparr> val = value1, left = None, right = None \<rparr>) in +        Ok (True, Some a) +    | Some current_node \<Rightarrow> +      do { +        o1 \<leftarrow> cmp (val current_node) value1; +        (case o1 of +          Ordering_Less \<Rightarrow> +          do { +            (b, current_tree1) \<leftarrow> +              aVLTreeSet_insert_loop value1 (right current_node); +            Ok (b, Some +              (current_node \<lparr> right := current_tree1 \<rparr>)) +            } +        | Ordering_Equal \<Rightarrow> Ok (False, Some current_node) +        | Ordering_Greater \<Rightarrow> +          do { +            (b, current_tree1) \<leftarrow> +              aVLTreeSet_insert_loop value1 (left current_node); +            Ok (b, Some (current_node \<lparr> left := current_tree1 \<rparr>)) +            }) +        })"  by auto + +(*[avl_verification::{avl_verification::AVLTreeSet}::insert]: +   Source: 'src/main.rs', lines 40:4-40:48*) +fun aVLTreeSet_insert +  :: "AVLTreeSet \<Rightarrow> u32 \<Rightarrow> (bool * AVLTreeSet) result" where +  "aVLTreeSet_insert self value1 = +    do { +      (b, as) \<leftarrow> aVLTreeSet_insert_loop value1 (root self); +      Ok (b, (\<lparr> root = as \<rparr>)) +      }" + +end
\ No newline at end of file @@ -0,0 +1,7 @@ +session "avl-verification" = "Aeneas" + +  options [document = pdf, document_output = "output"] +  theories +    Notraits +    Verification +  document_files +    "root.tex" diff --git a/Verification.thy b/Verification.thy new file mode 100644 index 0000000..bdb1743 --- /dev/null +++ b/Verification.thy @@ -0,0 +1,122 @@ +theory Verification imports + Notraits +begin + + +fun height_of_node :: "AVLNode option \<Rightarrow> nat" where +  "height_of_node None = 0" +| "height_of_node (Some (mkAVLNode _ l r)) = +     max (height_of_node l) (height_of_node r) + 1" + +   + +fun is_ok :: "'a result \<Rightarrow> bool" where +  "is_ok (Ok _) = True" +| "is_ok _ = False" + + +lemma[simp]: "is_ok (cmp a b)" +  by simp + + +(* nicer induction rule for type AVLNode option *) +lemma AVLNode_option_induct:  +  assumes "\<And>v l r. (\<And>x. x \<in> set_option l \<Longrightarrow> P (Some x)) +  \<Longrightarrow> (\<And>x. x \<in> set_option r \<Longrightarrow> P (Some x)) +  \<Longrightarrow> P (Some (mkAVLNode v l r))" +  and "P None" +  shows "P AVLNodeOption" +proof (cases AVLNodeOption) +  case None +  then show ?thesis using assms by simp +next +  case (Some a) +  then show ?thesis  +    apply (induction a arbitrary: AVLNodeOption) +    using Some assms(1) by blast +qed + + +lemma right_is_smaller: "height_of_node r < height_of_node (Some (mkAVLNode v l r))" +  by (cases l) auto +   +lemma left_is_smaller: "height_of_node l < height_of_node (Some (mkAVLNode v l r))" +  by (cases r) auto +   + +(* the loop in find always terminates (important for using \<open>obtain\<close> further down *) +termination aVLTreeSet_find_loop +proof (relation "measure (\<lambda>(v, t). height_of_node t)") +  show "wf (measure (\<lambda>(v, t). height_of_node t))" by simp +next +  fix value1 current_tree and x2 :: "AVLNode" +  assume "current_tree = Some x2" +  then show "((value1, right x2), value1, current_tree) \<in> measure (\<lambda>(v, t). height_of_node t)" +  using right_is_smaller in_measure  +  by (metis AVLNode.collapse case_prod_conv) +next +  fix value1 current_tree and x2 :: "AVLNode" +  assume "current_tree = Some x2" +  then show "((value1, left x2), value1, current_tree) \<in> measure (\<lambda>(v, t). height_of_node t)" +  using left_is_smaller in_measure  +  by (metis AVLNode.collapse case_prod_conv) +qed + + +value "cmp (u32 1) (u32 1)" + +value "left (mkAVLNode (u32 0) None (Some (mkAVLNode (u32 0) None None)))" + +lemma find_loop_ok: "is_ok (aVLTreeSet_find_loop v n)" +proof (induction n arbitrary: v rule: AVLNode_option_induct) +  case (1 u l r) +  obtain ordering where order: "Ok ordering = cmp u v" +    by force +  then show ?case  +  proof (cases ordering) +    case Ordering_Less +    hence "is_ok (aVLTreeSet_find_loop v r)"  +      using 1 by (simp add: option.split_sel_asm) +    then obtain b r' where a: "Ok (b, r') = aVLTreeSet_find_loop v r" +       by (auto elim: is_ok.elims) +    hence "aVLTreeSet_find_loop v (Some (mkAVLNode u l r)) = +               Ok (b, Some (mkAVLNode u l r'))" +      using Ordering_Less order apply simp +      by (smt (verit) AVLNode.expand AVLNode.record_simps(12) AVLNode.record_simps(13) AVLNode.record_simps(14) AVLNode.sel(1) AVLNode.sel(2) AVLNode.sel(3) case_prod_conv result.simps(4)) +    then show ?thesis by simp +  next +    case Ordering_Equal +    hence "aVLTreeSet_find_loop v (Some (mkAVLNode u l r)) = Ok (True, Some (mkAVLNode u l r))" +      using 1 order by simp +    then show ?thesis by simp +  next +    case Ordering_Greater +    hence "is_ok (aVLTreeSet_find_loop v l)"  +      using 1 by (simp add: option.split_sel_asm) +    then obtain b l' where a: "Ok (b, l') = aVLTreeSet_find_loop v l" +       by (auto elim: is_ok.elims) +    hence "aVLTreeSet_find_loop v (Some (mkAVLNode u l r)) = +               Ok (b, Some (mkAVLNode u l' r))" +      using Ordering_Greater order apply simp +      by (smt (verit, ccfv_threshold) AVLNode.expand AVLNode.record_simps(6) AVLNode.record_simps(7) AVLNode.record_simps(8) AVLNode.sel(1) AVLNode.sel(2) AVLNode.sel(3) case_prod_conv result.simps(4)) +    then show ?thesis by simp +  qed +next +  case 2 +  then show ?case by simp +qed + +(* find never produces an error *) +lemma find_ok: "\<exists>res. aVLTreeSet_find t v = Ok res" +proof - +  obtain b as where "Ok (b, as) = aVLTreeSet_find_loop v (root t)" +    using find_loop_ok by (metis is_ok.elims(2) old.prod.exhaust) +  then have "aVLTreeSet_find t v = Ok (b, \<lparr> root = as \<rparr>)"  +    apply simp unfolding bind_def +    by (metis old.prod.case result.simps(4)) +  thus ?thesis  +    by simp +qed + + +end
\ No newline at end of file diff --git a/document/root.tex b/document/root.tex new file mode 100644 index 0000000..1924cf3 --- /dev/null +++ b/document/root.tex @@ -0,0 +1,60 @@ +\documentclass[11pt,a4paper]{article} +\usepackage[T1]{fontenc} +\usepackage{isabelle,isabellesym} + +% further packages required for unusual symbols (see also +% isabellesym.sty), use only when needed + +%\usepackage{amssymb} +  %for \<leadsto>, \<box>, \<diamond>, \<sqsupset>, \<mho>, \<Join>, +  %\<lhd>, \<lesssim>, \<greatersim>, \<lessapprox>, \<greaterapprox>, +  %\<triangleq>, \<yen>, \<lozenge> + +%\usepackage{eurosym} +  %for \<euro> + +%\usepackage[only,bigsqcap,bigparallel,fatsemi,interleave,sslash]{stmaryrd} +  %for \<Sqinter>, \<Parallel>, \<Zsemi>, \<Parallel>, \<sslash> + +%\usepackage{eufrak} +  %for \<AA> ... \<ZZ>, \<aa> ... \<zz> (also included in amssymb) + +%\usepackage{textcomp} +  %for \<onequarter>, \<onehalf>, \<threequarters>, \<degree>, \<cent>, +  %\<currency> + +% this should be the last package used +\usepackage{pdfsetup} + +% urls in roman style, theory text in math-similar italics +\urlstyle{rm} +\isabellestyle{it} + +% for uniform font size +%\renewcommand{\isastyle}{\isastyleminor} + + +\begin{document} + +\title{avl-verification} +\author{stuebinm} +\maketitle + +\tableofcontents + +% sane default for proof documents +\parindent 0pt\parskip 0.5ex + +% generated text of all theories +\input{session} + +% optional bibliography +%\bibliographystyle{abbrv} +%\bibliography{root} + +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: @@ -1,3 +1,20 @@ +# Isabelle + +build with + +``` +❯ isabelle build -d path/to/aeneas/backends/IsabelleHOL/ -D . +``` + +or open in jedit via + +``` +❯ isabelle jedit -d path/to/aeneas/backends/IsabelleHOL/ Verification.thy +``` + +(there is no nix flake output for Isabelle. Isabelle is unpackagable and the +one that exists in nixpkgs is but a mirage) +  # Formalization notes  - Inhabited is not synthesized systematically for any type. diff --git a/src/main.rs b/src/main.rs index 1fa0f35..f42ef81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,47 +4,44 @@ pub enum Ordering {      Greater,  } -trait Ord { -    fn cmp(&self, other: &Self) -> Ordering; -}  // TODO: la structure AVLNode est extrait comme un inductif à un cas  // au lieu d'être extrait comme une structure -struct AVLNode<T> { -    value: T, -    left: AVLTree<T>, -    right: AVLTree<T>, +struct AVLNode { +    val: u32, +    left: AVLTree, +    right: AVLTree,  } -type AVLTree<T> = Option<Box<AVLNode<T>>>; +type AVLTree = Option<Box<AVLNode>>; -struct AVLTreeSet<T> { -    root: AVLTree<T>, +struct AVLTreeSet { +    root: AVLTree,  } -impl<T: Ord> AVLTreeSet<T> { +impl AVLTreeSet {      pub fn new() -> Self {          Self { root: None }      } -    pub fn find(&self, value: T) -> bool { -        let mut current_tree = &self.root; +    pub fn find(&mut self, value: u32) -> bool { +        let mut current_tree = &mut self.root;          while let Some(current_node) = current_tree { -            match current_node.value.cmp(&value) { -                Ordering::Less => current_tree = ¤t_node.right, +            match cmp(¤t_node.val, &value) { +                Ordering::Less => current_tree = &mut current_node.right,                  Ordering::Equal => return true, -                Ordering::Greater => current_tree = ¤t_node.left, +                Ordering::Greater => current_tree = &mut current_node.left,              }          }          false      } -    pub fn insert(&mut self, value: T) -> bool { +    pub fn insert(&mut self, value: u32) -> bool {          let mut current_tree = &mut self.root;          while let Some(current_node) = current_tree { -            match current_node.value.cmp(&value) { +            match cmp(¤t_node.val, &value) {                  Ordering::Less => current_tree = &mut current_node.right,                  Ordering::Equal => return false,                  Ordering::Greater => current_tree = &mut current_node.left, @@ -52,7 +49,7 @@ impl<T: Ord> AVLTreeSet<T> {          }          *current_tree = Some(Box::new(AVLNode { -            value, +            val: value,              left: None,              right: None,          })); @@ -61,14 +58,12 @@ impl<T: Ord> AVLTreeSet<T> {      }  } -impl Ord for u32 { -    fn cmp(&self, other: &Self) -> Ordering { -        if *self < *other { +fn cmp(a: &u32, other: &u32) -> Ordering { +        if *a < *other {              Ordering::Less -        } else if *self == *other { +        } else if *a == *other {              Ordering::Equal          } else {              Ordering::Greater          }      } -}  | 
