Extracting programs from proofs Helmut Schwichtenberg Mathematisches Institut, LMU, M¨ unchen JAIST, 7. March 2014 1 / 41
Overview ◮ Parsing balanced lists of parentheses ◮ Informal proof ◮ Discussion of the extracted term ◮ Formalization, extraction and testing ◮ Ishihara’s trick ◮ Computing with infinite data 2 / 41
The Dyck language of balanced lists of L and R E : expressions formed as lists of left and right parentheses L , R . Dyck language of balanced parentheses is generated by either of grammar U : E ::= Nil | ELER grammar S : E ::= Nil | LER | EE Restrict attention to U (has unique generation trees). 3 / 41
◮ Parsing balanced lists of parentheses ◮ Informal proof ◮ Discussion of the extracted term ◮ Formalization, extraction and testing ◮ Ishihara’s trick ◮ Computing with infinite data 4 / 41
Parsing Goal: recognize whether a list of left and right parentheses is balanced, and if so produce a generating tree (i.e., a parse tree). ◮ Write-and-verify method: write a parser as a shift-reduce syntax analyser, and verify that it is correct and complete. ◮ Prove-and-extract method: Prove the specification A and extract its computational content in the form of a realizing term t . Since t is in T + , we can automatically prove (verify) t r A , by means of a formalization of the soundness theorem. 5 / 41
◮ Formulate the grammar U as an inductively defined predicate over lists x , y , z of parentheses L , R given by the clauses InitU : U ( Nil ) GenU : Ux → Uy → U ( xLyR ) ◮ Work with RP ( n , x ) meaning U ( xR n ) and LP ( n , y ) meaning U ( L n y ). For RP we have an inductive definition RP (0 , Nil ) Uz → RP ( n , x ) → RP ( n + 1 , xzL ) LP can be defined via a boolean valued function LP (0 , Nil ) = tt LP ( n + 1 , Nil ) = ff LP ( n , Lx ) = LP ( n + 1 , x ) LP (0 , Rx ) = ff LP ( n + 1 , Rx ) = LP ( n , x ) 6 / 41
Closure property of U n , x , z ( RP ( n , x ) → c Uz → c LP ( n , y ) → U ( xzy )) . ∀ c y ∀ nc Proof. Show by induction on y that the claim holds for all n . Base Nil . Use elimination for RP ( n , x ). Step. In case L :: y use IHy for n + 1. In case R :: y again use elimination for RP ( n , x ). The first RP clause uses Efq, the second one IHy, GenU and equality arguments. 7 / 41
Have n , x , z ( RP ( n , x ) → c Uz → c LP ( n , y ) → U ( xzy )) . ∀ c y ∀ nc ◮ In particular ∀ c y ( LP (0 , y ) → Uy ). ◮ Conversely ∀ y ( Uy → LP (0 , y )) (by elimination for U ). ◮ Hence the test LP (0 , y ) is correct (all y in U satisfies it) and complete (it implies y in U ). ◮ Because of LP (0 , y ) ↔ Uy we have a decision procedure for U . With p a boolean variable we can express this by a proof of p (( p → Uy ) ∧ l (( p → F ) → Uy → F )) . ∀ c y ∃ d The computational content of this proof is a parser for U . Given y it returns a boolean saying whether or not y is in U , and if so it also returns a generation tree (i.e., a parse tree) for Uy . 8 / 41
Extracted term [x] LP 0 x@ (Rec list par=>list bin=>bin=>bin)x ([as,a][case as ((Nil bin) -> a) (a0::as0 -> O)]) ([par,x0,f,as,a] [case par (L -> f(a::as)O) (R -> [case as ((Nil bin) -> O) (a0::as0 -> f as0(a0 B a))])]) (Nil bin) O 9 / 41
◮ Parsing balanced lists of parentheses ◮ Informal proof ◮ Discussion of the extracted term ◮ Formalization, extraction and testing ◮ Ishihara’s trick ◮ Computing with infinite data 10 / 41
[x] LP 0 x@ (Rec list par=>list bin=>bin=>bin)x ([as,a][case as ((Nil bin) -> a) (a0::as0 -> O)]) ([par,x0,f,as,a] [case par (L -> f(a::as)O) (R -> [case as ((Nil bin) -> O) (a0::as0 -> f as0(a0 B a))])]) (Nil bin) O It amounts to applying a function g to x , Nil and O , where � if a s = Nil a g ( Nil , a s , a ) = O else g ( L :: x 0 , a s , a ) = g ( x 0 , a :: a s , O ) � O if a s = Nil g ( R :: x 0 , a s , a ) = g ( x 0 , a s 0 , a 0 B a ) if a s = a 0 :: a s 0 11 / 41
� a if a s = Nil g ( Nil , a s , a ) = O else g ( L :: x 0 , a s , a ) = g ( x 0 , a :: a s , O ) � O if a s = Nil g ( R :: x 0 , a s , a ) = g ( x 0 , a s 0 , a 0 B a ) if a s = a 0 :: a s 0 In g ( x , a s , a ) ◮ x is a list of parentheses L , R to be parsed. ◮ a s is a stack of parse trees. ◮ a is the working memory of the parser which stores the parse tree being generated. Initially g is called with x , the empty stack Nil and the empty parse tree O . 12 / 41
� if a s = Nil a g ( Nil , a s , a ) = else O g ( L :: x 0 , a s , a ) = g ( x 0 , a :: a s , O ) � if a s = Nil O g ( R :: x 0 , a s , a ) = g ( x 0 , a s 0 , a 0 B a ) if a s = a 0 :: a s 0 ◮ Read x from left to right. ◮ Suppose x = L :: x 0 . Push the current parse tree a (corresponding to E 0 in E 0 LE 1 R ) onto the stack. Then g starts generating a parse tree for the rest x 0 of x , with O in its working memory. ◮ Suppose x = R :: x 0 . If the stack is Nil , return O . If not, pop the top element a 0 from the stack. Then g starts generating a parse tree for the rest x 0 of x , the tail a s 0 of the stack, and as current parse tree a 0 B a in its working memory. 13 / 41
◮ Parsing balanced lists of parentheses ◮ Informal proof ◮ Discussion of the extracted term ◮ Formalization, extraction and testing ◮ Ishihara’s trick ◮ Computing with infinite data 14 / 41
(load "~/minlog/init.scm") (add-algs "bin" ’("bin" "O") ’("bin=>bin=>bin" "BinBranch")) (add-infix-display-string "BinBranch" "B" ’pair-op) (set! COMMENT-FLAG #f) (libload "nat.scm") (libload "list.scm") (set! COMMENT-FLAG #t) (add-algs "par" ’("L" "par") ’("R" "par")) (add-totality "par") (add-var-name "p" (py "boole")) (add-var-name "x" "y" "z" (py "list par")) 15 / 41
(add-ids (list (list "U" (make-arity (py "list par")) "bin")) ’("U(Nil par)" "InitU") ’("allnc x,y(U x -> U y -> U(x++L: ++y++R:))" "GenU")) (add-program-constant "LP" (py "nat=>list par=>boole")) (add-computation-rules "LP 0(Nil par)" "True" "LP(Succ n)(Nil par)" "False" "LP n(L::x)" "LP(Succ n)x" "LP 0(R::x)" "False" "LP(Succ n)(R::x)" "LP n x") 16 / 41
;; RP (with a parameter predicate to be substituted by U) (add-pvar-name "P" (make-arity (py "list par"))) (add-ids (list (list "RP" (make-arity (py "nat") (py "list par")) "list")) ’("RP 0(Nil par)" "InitRP") ’("allnc n,x,z(P z -> RP n x -> RP(Succ n)(x++z++L:))" "GenRP")) 17 / 41
;; ClosureU (set-goal "all y allnc n,x,z( (RP (cterm (x^) U x^))n x -> U z -> LP n y -> U(x++z++y))") ;; Soundness (set-goal "allnc y(U y -> LP 0 y)") ;; Completeness (set-goal "all y(LP 0 y -> U y)") ;; ParseLemma (set-goal "all y ex p((p -> U y) & ((p -> F) -> U y -> F))") 18 / 41
(animate "ClosureU") (animate "Completeness") (add-var-name "a" (py "bin")) (add-var-name "as" (py "list bin")) (add-var-name "f" (py "list bin=>bin=>bin")) (define eterm (proof-to-extracted-term (theorem-name-to-proof "ParseLemma"))) (define parser-term (rename-variables (nt eterm))) (ppc parser-term) 19 / 41
(test-parser-term parser-term 6) Testing on L::R::R::R::R::R: No Testing on L::L::R::R::R::R: No Testing on L::R::L::R::R::R: No Testing on L::L::L::R::R::R: Parse tree: O B O B O B O Testing on L::R::R::L::R::R: No Testing on L::L::R::L::R::R: Parse tree: O B(O B O)B O Testing on L::R::L::L::R::R: Parse tree: (O B O)B O B O Testing on L::L::L::L::R::R: No Testing on L::R::R::R::L::R: No Testing on L::L::R::R::L::R: Parse tree: (O B O B O)B O Testing on L::R::L::R::L::R: Parse tree: ((O B O)B O)B O Testing on L::L::L::R::L::R: No Testing on L::R::R::L::L::R: No Testing on L::L::R::L::L::R: No Testing on L::R::L::L::L::R: No Testing on L::L::L::L::L::R: No 20 / 41
◮ Parsing balanced lists of parentheses ◮ Informal proof ◮ Discussion of the extracted term ◮ Formalization, extraction and testing ◮ Ishihara’s trick ◮ Computing with infinite data 21 / 41
Theorem (Ishihara’s trick) Let f be a linear map from a Banach space X into a normed space Y , and let ( u n ) be a sequence in X converging to 0 . Then for 0 < a < b either a ≤ | | fu n | | for some n or | | fu n | | ≤ b for all n. Proof. Let M be a modulus of convergence of ( u n ) to 0; assume M 0 = 0. Call m a hit on n if M n ≤ m < M n +1 and a ≤ | | fu m | | . First goal: define a function h : ◆ → ◆ such that ◮ h n = 0 if for all n ′ ≤ n there is no hit; ◮ h n = m + 2 if at n for the first time we have a hit, with m ; ◮ h n = 1 if there is an n ′ < n with a hit. 22 / 41
We will need the bounded least number operator µ n g defined recursively as follows ( g a variable of type ◆ → ❇ ). µ 0 g := 0 , � 0 if g 0 µ S n g := S µ n ( g ◦ S ) otherwise . From µ n g we define � ( µ n − n 0 λ m g ( m + n 0 )) + n 0 if n 0 ≤ n µ n n 0 g := 0 otherwise . 23 / 41
Recommend
More recommend