liquidhaskell-0.8.0.2: tests/todo/AmortizedQueue.hs
module AmortizedQueue where
import Prelude hiding (head)
data AbsQueue a = AQ { front :: [a]
, rear :: [a] }
{-@ data AbsQueue a = AQ { front :: [a]
, rear :: {v:[a] | size v <= size front} } @-}
{-@ die :: {v:String | false} -> a @-}
die :: String -> a
die x = error x
{-@ measure size @-}
size :: [a] -> Int
size [] = 0
size (x:xs) = 1 + size xs
{-@ measure qsize @-}
qsize :: AbsQueue a -> Int
qsize (AQ xs ys) = size xs + size ys
{-@ invariant {v:[a] | size v >= 0} @-}
{-@ invariant {v:AbsQueue a | qsize v >= 0} @-}
{-@ type NEList a = {v:[a] | size v > 0} @-}
{-@ type NEQueue a = {v:AbsQueue a | qsize v > 0} @-}
makeQueue :: [a] -> [a] -> AbsQueue a
makeQueue f b
| size b <= size f = AQ f b
| otherwise = AQ (f ++ reverse b) []
{- measure qhead @-}
{-@ qhead :: NEQueue a -> a @-}
qhead (AQ f _) = head f
qhead _ = die "never"
{- measure head @-}
{-@ head :: NEList a -> a @-}
head (x:_) = x
-- head _ = die "never"
{- toList :: q:AbsQueue a -> {v:[a] | 0 < len v => head v = front q} @-}
toList :: AbsQueue a -> [a]
toList = undefined
-- forall q :: AbsQueue a, xs:: [a], x::a.
-- not (isEmpty(q)) && asList(q) == xs =>
{-
import leon.lang._
import leon.annotation._
object AmortizedQueue {
sealed abstract class List
case class Cons(head : Int, tail : List) extends List
case object Nil extends List
sealed abstract class AbsQueue
case class Queue(front : List, rear : List) extends AbsQueue
def size(list : List) : Int = (list match {
case Nil => 0
case Cons(_, xs) => 1 + size(xs)
}) ensuring(_ >= 0)
def content(l: List) : Set[Int] = l match {
case Nil => Set.empty[Int]
case Cons(x, xs) => Set(x) ++ content(xs)
}
def asList(queue : AbsQueue) : List = queue match {
case Queue(front, rear) => concat(front, reverse(rear))
}
def concat(l1 : List, l2 : List) : List = (l1 match {
case Nil => l2
case Cons(x,xs) => Cons(x, concat(xs, l2))
}) ensuring (res => size(res) == size(l1) + size(l2) && content(res) == content(l1) ++ content(l2))
def isAmortized(queue : AbsQueue) : Boolean = queue match {
case Queue(front, rear) => size(front) >= size(rear)
}
def isEmpty(queue : AbsQueue) : Boolean = queue match {
case Queue(Nil, Nil) => true
case _ => false
}
def reverse(l : List) : List = (l match {
case Nil => Nil
case Cons(x, xs) => concat(reverse(xs), Cons(x, Nil))
}) ensuring (content(_) == content(l))
def amortizedQueue(front : List, rear : List) : AbsQueue = {
if (size(rear) <= size(front))
Queue(front, rear)
else
Queue(concat(front, reverse(rear)), Nil)
} ensuring(isAmortized(_))
def enqueue(queue : AbsQueue, elem : Int) : AbsQueue = (queue match {
case Queue(front, rear) => amortizedQueue(front, Cons(elem, rear))
}) ensuring(isAmortized(_))
def tail(queue : AbsQueue) : AbsQueue = {
require(isAmortized(queue) && !isEmpty(queue))
queue match {
case Queue(Cons(f, fs), rear) => amortizedQueue(fs, rear)
}
} ensuring (isAmortized(_))
def front(queue : AbsQueue) : Int = {
require(isAmortized(queue) && !isEmpty(queue))
queue match {
case Queue(Cons(f, _), _) => f
}
}
@induct
def propFront(queue : AbsQueue, list : List) : Boolean = {
require(!isEmpty(queue) && isAmortized(queue))
if (asList(queue) == list) {
list match {
case Cons(x, _) => front(queue) == x
}
} else
true
} holds
def enqueueAndFront(queue : AbsQueue, elem : Int) : Boolean = {
if (isEmpty(queue))
front(enqueue(queue, elem)) == elem
else
true
} holds
def enqueueDequeueThrice(queue : AbsQueue, e1 : Int, e2 : Int, e3 : Int) : Boolean = {
if (isEmpty(queue)) {
val q1 = enqueue(queue, e1)
val q2 = enqueue(q1, e2)
val q3 = enqueue(q2, e3)
val e1prime = front(q3)
val q4 = tail(q3)
val e2prime = front(q4)
val q5 = tail(q4)
val e3prime = front(q5)
e1 == e1prime && e2 == e2prime && e3 == e3prime
} else
true
} holds
}
-}