packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/nople/pos/Solver.hs

-- | Correctness of sat solver as in Trellys
-- | http://www.seas.upenn.edu/~sweirich/papers/popl14-trellys.pdf

-- | This code is terrible.
-- | Should use cases and auto translate like in the paper's theory
-- | Also, &&, not and rest logical operators are not in scope in the axioms

{-@ LIQUID "--higherorder"     @-}
{-@ LIQUID "--exact-data-cons" @-}
{-@ LIQUID "--pruneunsorted"   @-}

-- TAG: absref 
-- TAG: termination

module Solver where

import Data.Tuple
import Data.List (nub)
import Language.Haskell.Liquid.Prelude ((==>))
import Prelude hiding (map)

-- | Formula
type Var     = Int
data Lit     = Pos Var | Neg Var
type Clause  = L Lit
type Formula = L Clause

-- | Assignment

type Asgn = L (P Var Bool)

-- | Top-level "solver"


{-@ solve :: f:Formula -> Maybe {a:Asgn | sat a f } @-}
solve   :: Formula -> Maybe Asgn
solve f = find (`sat` f) (asgns f)

{-@ find :: forall <p :: a -> Bool, w :: a -> Bool -> Bool>. 
            {y::a, b::{v:Bool<w y> | v} |- {v:a | v == y} <: a<p>}
            (x:a -> Bool<w x>) -> [a] -> Maybe (a<p>) @-}
find :: (a -> Bool) -> [a] -> Maybe a
find f [] = Nothing
find f (x:xs) | f x       = Just x
              | otherwise = Nothing


-- | Generate all assignments

asgns :: Formula -> [Asgn] -- generates all possible T/F vectors
asgns = go . vars
  where
  	go []     = []
  	go (x:xs) = let ass = go xs in (inject (P x True) ass) ++ (inject (P x False) ass)

  	inject x xs = (\y -> x:::y) <$> xs

vars :: Formula -> [Var]
vars = nub . toList .  go
  where
  	go Emp       = Emp
  	go (ls:::xs) = map go' ls `append` go xs

  	go' (Pos x) = x
  	go' (Neg x) = x


{-@ axiomatize sat @-}
sat :: Asgn -> Formula -> Bool
{-@ sat :: Asgn -> f:Formula -> Bool / [llen f] @-}
sat a f
  | llen f == 0
  = True
  | satClause a (hd f)
  = sat a (tl f)
  | otherwise
  = False

{-@ axiomatize satClause @-}
{-@ satClause :: Asgn -> c:Clause -> Bool /[llen c] @-}
satClause :: Asgn -> Clause -> Bool
satClause a c
  | llen c == 0
  = False
  | satLit a (hd c)
  = True
  | otherwise
  = satClause a (tl c)

{-@ axiomatize satLit @-}
satLit :: Asgn -> Lit -> Bool
satLit a l
  | isPos l   = isPosVar (fromPos l) a
  | isNeg l   = isNegVar (fromNeg l) a
  | otherwise = False

{-@ axiomatize isPosVar @-}
{-@ axiomatize isNegVar @-}
{-@ isNegVar :: Var -> a:Asgn -> Bool / [llen a] @-}
{-@ isPosVar :: Var -> a:Asgn -> Bool / [llen a] @-}
isNegVar, isPosVar :: Var -> Asgn -> Bool
isPosVar v a
  | llen a == 0
  = False
  | (myfst (hd a)) == v
  = mysndB (hd a)
  | otherwise
  = isPosVar v (tl a)


isNegVar v a
  | llen a == 0
  = False
  | (myfst (hd a)) == v
  = if mysndB (hd a) then False else True
  | otherwise
  = isNegVar v (tl a)


{-@ measure myfst @-}
myfst :: P a b -> a
myfst (P x _) = x


{-@ measure mysndB @-}
mysndB :: P a Bool -> Bool
mysndB (P _ x) = x

{-@ measure isPos @-}
isPos (Pos _) = True
isPos _       = False

{-@ measure fromPos @-}
{-@ fromPos :: {l:Lit | isPos l} -> Var @-}
fromPos :: Lit -> Var
fromPos (Pos v) = v

{-@ measure isNeg @-}
isNeg (Neg _) = True
isNeg _       = False

{-@ measure fromNeg @-}
{-@ fromNeg :: {l:Lit | isNeg l} -> Var @-}
fromNeg :: Lit -> Var
fromNeg (Neg v) = v


-- Pairs
data P a b = P a b

-- List definition
data L a = Emp | a ::: L a
{-@ data L [llen] @-}

toList Emp      = []
toList (x ::: xs) = x:toList xs

{-@ measure llen @-}
llen :: L a -> Int
{-@ llen :: L a -> Nat @-}
llen Emp        = 0
llen (_ ::: xs) = 1 + llen xs

{-@ measure hd @-}
{-@ hd :: {v:L a | llen v > 0 } -> a @-}
hd :: L a -> a
hd (x ::: _) = x

{-@ measure tl @-}
{-@ tl :: xs:{L a | llen xs > 0 } -> {v:L a | llen v == llen xs - 1 } @-}
tl :: L a -> L a
tl (_ ::: xs) = xs


{-@ axiomatize append @-}
append :: L a -> L a -> L a
append xs ys
  | llen xs == 0 = ys
  | otherwise    = hd xs ::: append (tl xs) ys
  {-@ axiomatize map @-}

map :: (a -> b) -> L a -> L b
map f xs
    | llen xs == 0 = Emp
    | otherwise    = f (hd xs) ::: map f (tl xs)