Sized Types Inference1 “Calculating Sized Types” by Wei-Ngan Chin and Siau-Cheng Khoo published in PEPM00 and HOSC01 Presented by Xu Na
Sized Types Inference2 Int m – size of an integer is the integer itself [ ] m – size of a recursive data consists of its maximum depth. Bool m – m=0 for False and m=1 for True append :: [ ] m ! [ ] n ! [ ] p s.t. m ¸ 0 Æ n ¸ 0 Æ p=m+n – size of a function is a relation between its input and output sizes. Meaning of Size
Sized Types Inference3 Syntax of Sized Type e :: ( , ) annotated type size constraint Examples: 3 :: (Int i, (i = 3) ) [3] :: ([Int i ] j, (i = 3) (j = 1) ) [3,4] :: ([Int i ] j, ((i = 3) (i = 4)) (j = 2) ) :: ([Int ] j, (j = 2) ) True :: (Bool b, (b = 1) ) False :: (Bool b, (b = 0) ) append :: ([ ] m [ ] n [ ] p, (m 0) (n 0) (p=m+n) )
Sized Types Inference4 What is Sized Type? An advanced type system to capture size relation of: output in terms of inputs pre-conditions on inputs input invariant across recursion
Sized Types Inference5 Example: tail (x:xs) = xs polymorphic type: tail :: [ ] [ ] sized type: tail :: [ ] m [ ] p size size (m>0) // pre-condition (p+1=m) // output relation size variables of integer types linear arithmetic constraints on size variables
Sized Types Inference6 Example: zip :: [ ] [ ] [( , )] zip [] [] = [] zip (x:xs) (y:ys) = (x,y):(zip xs ys) Sized type: zip :: [ ] m [ ] n [( , )] p size size (m 0) (n 0) (n=m) // pre-condition (p=m) // output relation inv inv (0 m + <m) (0 n + <n) (m – m + = n – n + ) // invariant (zip xs m ys n ) …(zip xs 1 m 1 ys 1 n 1 )… …(zip xs 2 m 2 ys 2 n 2 )… … (m +,n + ) {(m 1,n 1 ),(m 2,n 2 ),…,…}
Sized Types Inference7 Syntax of Constraints
Sized Types Inference8 Sized Type Inference 1. Extension of Polymorphic Type Rules. 2. Requires linear arithmetic constraint solver. 3. Recursive letrec requires new fixed point computation.
Sized Types Inference9 Example f b xs = case b of False -> xs True -> append xs xs Assume: st append :: [ ] m [ ] n [ ] p st (m 0) (n 0) (p=m+n) f :: Bool i [ ] j [ ] k infer : infer : ((i = 0) (k = j)) ((i = 1) (k = j+j)) What is the sized type for f?
Sized Types Inference10 Example (non-recursive) f b xs = case b of False -> xs True -> append xs xs f :: Bool i [ ] j [ ] k st append :: [ ] m [ ] n [ ] p st (m 0) (n 0) (p=m+n) st xs :: [ ] k st (k = j) st ( append xs xs) :: [ ] k st (k = j+j) variable-rule application-rule
Sized Types Inference11 Example (non-recursive) f :: Bool i [ ] j [ ] k f b xs = case b of False -> xs True -> append xs xs case-rule st ( case b...) :: [ ] k st ((i = 0) (k = j)) ((i = 1) (k = j+j)) st :: [ ] k st (k = j) st :: [ ] k st (k = j+j)
Sized Types Inference12 Sized Inference : Recursive Function Steps: 1. Infer recursive call constraint & terminating constraint. 2. Calculate a generalised transitive constraint. 3. Incorporate terminating constraint.
Sized Types Inference13 Example (recursive) append xs ys = case xs of [] -> ys (x:xs’) -> x:(append xs’ ys) Terminating Constraint: B :: [ m, n, p ] = = (m = 0) (n 0) (p=n) [ ] m [ ] n [ ] p [ ] i [ ] j [ ] k Recursive Call Constraint: U :: [ m, n, p ] [ i, j, k ] = = (i+1 = m) (j = n) (p=k+1)
Sized Types Inference14 Fixed Point via Omega Calculator Theoretic Closure (Least fixed point) U + = k=1 U k U :: [m,n,p] [i,j,k] =(i+1=m) (j = n) (p=k+1) closure(U) ::[m,n,p] [m +,n +,p + ] = (0 m + <m) (n 0) (n + = n) (m - m + = p - p + ) Practical Fixed Point (via Omega Calculator ) R. P=closure(R) R P R + Fixed-Point Check: (P=R + ) (P o R P)
Sized Types Inference15 Recursive Call Constraint: U :: [ m, n, p ] [ i, j, k ] = = (i+1 = m) (j = n) (p=k+1) Terminating Constraint: B :: [ m, n, p ] = = (m = 0) (n 0) (p=n) U + ::[m,n,p] [m +,n +,p + ] = (0 m + <m) (n 0) (n + = n) (m - m + = p - p + ) Append :: [m,n,p] = B[m,n,p] ( m +,n +,p + : U + (m, n, p, m +,n +,p + ) B[m +,n +,p + ] ) = ((m=0) (n 0) (p=n)) ((m 1) (n 0) (p=m+n)) = (m 0) (n 0) (p=m+n)
Sized Types Inference16 Prototype System Fun f x y = x + y {[s4,s5] -> [w3] :w3 = s4+s5 } Fun f1 x = f 0 x {[s14] -> [w3] :s14 = w3 } Fun append xs ys = case xs of { [] -> ys ; (x:xs') -> x : append xs' ys } {[s26,s27] -> [s28] :s28 = s27+s26 && 0 <= s27 && 0 <= s26 } Fun f4 xs = append xs xs {[s74] -> [w3] :w3 = 2s74 && 0 <= s74 } Fun filter p s = case s of { [] -> [] ; (x:xs) -> case p s of { True -> x : filter p xs ; False -> filter p xs } } {[s120,s121,s122] -> [s123] :0 <= s121 <= 1 && 0 <= s123 <= s122 && 0 <= s120 }
Sized Types Inference17 Prototype System Fun zipB xs ys = case xs of { [] -> ys ; (x:xs') -> case ys of { [] -> [] ; (y:ys') -> x : zipB xs' ys' } } {[s201,s202] -> [s203] :s203 = s202 && 0 <= s202 && 0 <= s201 } Fun zipA xs ys = case xs of { [] -> [] ; (x:xs') -> case ys of { [] -> [] ; (y:ys') -> x : zipA xs' ys' } } {[s235,s236] -> [s237] :0 <= s237 <= s235, s236 } Fun zip xs ys = case xs of { [] -> ys ; (x:xs') -> case ys of { [] -> xs ; (y:ys') -> x : zip xs' ys' } } {[s167,s168] -> [s169] :(s167<=s168 && s168 = s169) OR :(s168<s167 && s167 = s169) }
Sized Types Inference18 Why Sized Type is Useful? Safety Analysis: termination, bounded space. Vector-Based Memoisation. Array Bounds Check Elimination. Context-based Specialisation.
Sized Types Inference19 ack 0 m = m+1 ack (n+1) 0= ack n 1 ack (n+1) (m+1)= ack n (ack (n+1) m) Previous work based on abstract interpretation. e.g. Ullman, Jones, Plumer etc. KEY : Does a given recursion terminate? Termination Analysis Sized type: ack :: Int i Int j Int k size size (0 i) (0 j) // pre-condition inv inv (0 i + < i) ((i + = i) (1 i + ) (0 j + < j)) // rec. invariant
Sized Types Inference20 Eliminate redundant calls [Chin & Hagiya ICFP97] via vectorisation. Vector-Based Memoisation bin(n,k) = case n of 0 -> 1 m+1 -> if (k = n) then 1 else bin(m-1,k-1) + bin(m,k) Sized type bin :: (Int n, Int k ) -> Int p inv inv.(k+,1 k < n) (k +,1 n + < n) (k+n + n+k + ) 0 k + max(0,n + +k-n) k+ min(n +,k) Problem - Bounds Analysis
Sized Types Inference21 Vector-Based Memoisation bin(n,k) = case n of 0 -> 1 m+1 -> if (k = n) then 1 else bin(m-1,k-1) + bin(m,k) bin(n,k) = let bin’(n + ) = case n + of 0 -> \ k + -> 1 m+1 -> let z = bin’(m) bn k + = if (k + = n) then 1 else z(k + -1) + z(k + ) l = max(0,n++k-n) u = min(n+,k) vec = array(l,u)[a:=bn(a)| a<-[l..u]] in (!)vec in if (0<=k && max(1,k)<=n) then bin’(n)(k) else 1 max(0,n + +k-n) k + min(n +,k)
Sized Types Inference22 Bounds check can be eliminated by invariants over indexes. Bound Checks Elimination bsearch cmp key arr = let look:: (Int lo,Int hi ) Int k INV (lo lo + ) (hi + hi) look(lo,hi) = if (hi>=lo) then let m=lo+(hi-lo)/2; x=arr!m in case cmp(key,x) of LESS -> look(lo,m-1) EQUAL -> m MORE -> look(m+1,hi) else -1 in look(0,(length arr)-1) arr ! m = if (0 m <length(arr)) then sub(arr,m) else 0 lo m hi < length(arr)
Sized Types Inference23 size zip :: [ ] m [ ] n [( , )] p size ((0 m n) (p=m)) ((0 n m) (p=n)) zip xs ys = case xs of [] -> [] (x:xs’) -> case ys of [] -> [] (y:ys’) -> (x,y):(zip xs’ ys’) Specialisation can eliminate redundant tests. Context Specialisation size zip1 :: [ ] m [ ] n [( , )] p size (0 m n) (p=m) zip1 xs ys = case xs of [] -> [] (x:xs’) -> (x,head ys):(zip1 xs’ (tail ys)) zip1 xs ys = zip xs ys st st (xs::[ ] m ) (ys::[ ] n ) (m n)
Sized Types Inference24 size zip :: [ ] m [ ] n [( , )] p size ((0 n m) (p=n)) ((0 m n) (p=m)) zip xs ys = case xs of [] -> [] (x:xs’) -> case ys of [] -> [] (y:ys) -> (x,y):(zip xs’ ys’) Specialisation can eliminate redundant tests. Context Specialisation size zip2 :: [ ] m [ ] n [( , )] p size (0 n m) (p=n) zip2 xs ys = case ys of [] -> [] (y:ys’) -> (head xs,y):(zip2 (tail xs) ys’) zip2 xs ys = zip xs ys st st (xs::[ ] m ) (ys::[ ] n ) (n m)