lambdabot-4.0: scripts/Djinn/MJ.hs
module MJ(module LJTFormula, provable, prove, buildGraph) where
--import Monad
import Control.Monad.State
import List((\\), partition, nubBy, sort)
import qualified Data.Set as S
import qualified Data.Map as M
import Data.Map(Map, (!), empty, insert, member, assocs, filterWithKey)
import Data.Map(toList, size)
import Data.Queue as Q
import Util(mapFst)
import MonadBFS
import Poly
import LJTFormula
import Debug.Trace
mtrace :: String -> a -> a
mtrace a x = if debug then trace ("*** " ++ a) x else x
debug :: Bool
debug = False
------------------------------
----- Our Proof monad, P, a monad with state and multiple results
type P a = StateT Integer BFS a
nextInt :: P Integer
nextInt = do
i <- get
put (i+1)
return i
none :: P a
none = lift mzero
many :: [a] -> P a
many xs = lift $ msum $ map return xs
wrap :: P a -> P a
wrap (StateT f) = StateT $ \ s -> mwrap (f s)
runP :: P a -> [a]
runP pa = runBFS $ evalStateT pa 0
{-
--runForest :: Forest a -> [a]
runForest' fr = run [fr]
where run [] = []
run (Forest xs : q) =
mtrace ("Q " ++ show q) $
[x | Tip x <- xs] ++
run (q ++ [ f | Fork f <- xs])
-}
------------------------------
----- Generate a new unique variable
newSym :: String -> P Symbol
newSym pre = do
i <- nextInt
return $ Symbol $ pre ++ show i
------------------------------
provable :: Formula -> Bool
provable = not . null . prove False []
prove :: Bool -> [(Symbol, Formula)] -> Formula -> [Term]
prove more as f = runP $ proveP more as f
data M
= Semi V Ms
| VLam V M
| In ConsDesc Int M
| Tuple [M]
-- | WLam W M
-- | PairQ T M
deriving (Show)
infixr 5 :::
data Ms
= Nil
| M ::: Ms
| When [ConsDesc] [(V,M)]
| Sel Int Int Ms
-- | Apq T Ms
-- | Spl W V M
deriving (Show)
data V = V Symbol
deriving (Show)
--data W = W Symbol
-- deriving (Show)
--data T = T
-- deriving (Show)
------------------------------
proveP :: Bool -> [(Symbol, Formula)] -> Formula -> P Term
proveP _ env f = do
let s = initialSequent (map snd env) f
g = buildGraph s
vcs = countSequents g s
g' = pruneGraph g vcs
() <- mtrace (unlines ("---------" : show f : show (size g) : map show (toList g))) $ return ()
-- () <- trace (unlines (show f : show (size g) : map show vcs)) $ return ()
() <- mtrace (unlines ("---------" : show f : show (lookup (SVar s) vcs) : show (size g') : map show (toList g'))) $ return ()
if size g' == 0 then
none
else do
m <- unfold (recGraph s g') (mapFst V env)
let t = theta m
insertSplit t
collectSels :: Term -> [Term]
collectSels (Lam _ t) = collectSels t
collectSels (Apply f a) = collectSels f ++ collectSels a
collectSels e@(Xsel _ _ b) = collectSels b ++ [e]
collectSels _ = []
insertSplit :: Term -> P Term
insertSplit t = do
let sels = nubBy (\ (Xsel _ _ e) (Xsel _ _ e') -> e == e') $ collectSels t
selTbl = [ (e, n, freeVars e) | Xsel _ n e <- sels ]
ins :: [(Term, Int, [Symbol])] -> Map Term [Term] -> Term -> P Term
ins tbl stbl (Lam s b) = do
let tbl' = [ (e, n, fv \\ [s]) | (e, n, fv) <- tbl ]
(spls, tbl'') = partition (\ (_,_,fv) -> null fv) tbl'
mkSplit (f, sps) (e, n, _) = do
vars <- mapM (const (newSym "s")) [1..n]
let sps' = insert e (map Var vars) sps
e' <- ins tbl'' sps' e
let fun oe = Apply (Apply (Csplit n) (foldr Lam oe vars)) e'
return (f . fun, sps')
(trfun, stbl') <- foldM mkSplit (id, stbl) spls
e' <- ins tbl'' stbl' b
return $ Lam s (trfun e')
ins tbl stbl (Apply f a) = liftM2 Apply (ins tbl stbl f) (ins tbl stbl a)
ins _tbl stbl (Xsel i _ e) = --trace ("Xsel " ++ show (_tbl, stbl, i, e)) $
return $ (stbl ! e) !! i
ins _tbl _stbl e = return e
-- () <- trace ("insertSplit " ++ show (t, selTbl)) $ return ()
t' <- ins selTbl empty t
if t == t' then
return t
else
-- trace ("insertSplit recurses") $
insertSplit t'
------------------------------
theta :: M -> Term
theta (Semi (V s) ms) = theta' (Var s) ms
theta (VLam (V s) m) = Lam s (theta m)
theta (In cd i m) = Apply (Cinj cd i) (theta m)
theta (Tuple ms) = foldl Apply (Ctuple (length ms)) (map theta ms)
theta' :: Term -> Ms -> Term
theta' a Nil = a
theta' a (m ::: ms) = theta' (Apply a (theta m)) ms
theta' a (When cds vms) = foldl Apply (Ccases cds) (a : [ Lam s $ theta m | (V s, m) <- vms ])
theta' a (Sel i n ms) = theta' (Xsel i n a) ms
-- where sel = Apply (Csplit n) (foldr Lam (Var (xs!!i)) xs) where xs = [ Symbol ("_x" ++ show j) | j <- [0..n-1] ]
------------------------------
type Context = [(V, Formula)]
addCtx :: V -> Formula -> Context -> Context
addCtx v f ctx = (v, f) : ctx
data Gamma = Gamma (S.Set Formula)
deriving (Show, Eq, Ord)
addEnv :: Formula -> Gamma -> Gamma
addEnv f (Gamma fs) = Gamma $ S.insert f fs
envList :: Gamma -> [Formula]
envList (Gamma fs) = S.elems fs
data Sequent = S Gamma (Maybe Formula) Formula
deriving (Show, Eq, Ord)
initialSequent :: [Formula] -> Formula -> Sequent
initialSequent g f = S (Gamma $ S.fromList g) Nothing f
data Rule = OrL [(ConsDesc, Formula)] | OrR ConsDesc Int | AndL Int Int
| AndR | ImpL | ImpR Formula | Ax | Cont Formula
deriving (Show, Eq, Ord)
data VP a = VP Rule [a]
deriving (Show, Eq, Ord)
type Graph = Map Sequent [VP Sequent]
type GraphRec = Next
data Next = Next { unNext :: [VP Next] }
buildG :: Queue Sequent -> Graph -> Graph
buildG q g =
case deQueue q of
Nothing -> g
Just (sq, q') ->
let vps = getVPs sq ++ getVpCont sq
g' = insert sq vps g
(q'', g'') = foldr addSeq (q', g') [ s | VP _ ss <- vps, s <- ss ]
in buildG q'' g''
where addSeq s o@(oq, og) = if member s og then o else (addToQueue oq s, insert s [] og)
getVPs (S env (Just (Disj ds)) c) =
[ VP (OrL ds) [ S (addEnv a env) Nothing c | (_, a) <- ds ] ]
getVPs (S env (Just (Conj as)) b) =
[ VP (AndL i (length as)) [S env (Just a) b] | (a, i) <- zip as [0..] ]
getVPs (S env (Just (a :-> b)) c) =
[ VP ImpL [S env Nothing a, S env (Just b) c] ]
getVPs (S _env (Just x) x') | x == x' =
[ VP Ax [] ]
getVPs (S env Nothing (Disj ds)) =
[ VP (OrR (fst (ds!!i)) i) [S env Nothing a] | ((_,a), i) <- zip ds [0..] ]
getVPs (S env Nothing (Conj as)) =
[ VP AndR [ S env Nothing a | a <- as ] ]
getVPs (S env Nothing (a :-> b)) =
[ VP (ImpR a) [ S (addEnv a env) Nothing b ] ]
getVPs (S _ _ _) =
[ ]
getVpCont (S env Nothing b) =
[ VP (Cont a) [S env (Just a) b] | a <- envList env ]
getVpCont (S _ _ _) =
[ ]
buildGraph :: Sequent -> Graph
buildGraph s = buildG (addToQueue emptyQueue s) empty
data SVar = SVar Sequent
deriving (Eq, Ord, Show)
newtype TV = TV Int
deriving (Eq, Ord)
instance Show TV where
show (TV i) = "x" ++ show i
countSequents :: Graph -> Sequent -> [(SVar, Ninf)]
--countSequents g s = solveEqnSystem $ buildEqns g (const Nothing) s
countSequents g s =
let eqns = buildEqns g (const Nothing) s
subst = [(v, TV i) | ((v, _), i) <- zip eqns [0..]]
eqns' = zip (map snd subst) (map (substPolyVars subst . snd) eqns)
sol = solveEqnSystem eqns'
in zip (map fst eqns) (map snd (sort sol))
buildEqns :: Graph -> (Sequent -> Maybe Ninf) -> Sequent -> EqnSystem SVar
buildEqns graph oracle seqnt = assocs $ build seqnt empty
where build :: Sequent -> Map SVar (Poly SVar) -> Map SVar (Poly SVar)
build s r =
let sv = SVar s in
if sv `member` r then
r
else case oracle s of
Just n -> insert sv (constp n) r
Nothing ->
let v = sum [ product [ var (SVar n) | n <- ns ] | VP _ ns <- graph!s ]
r' = insert sv v r
l = [ n | VP _ ns <- graph!s, n <- ns ]
in foldr build r' l
pruneGraph :: Graph -> [(SVar, Ninf)] -> Graph
pruneGraph g vcs =
let zset = S.fromList [ s | (SVar s, 0) <- vcs ]
g' = filterWithKey (\ k _ -> not (S.member k zset)) g
g'' = M.map (\ vps -> filter (\ (VP _ ns) -> not (any (`S.member` zset) ns)) vps) g'
in g''
recGraph :: Sequent -> Graph -> GraphRec
recGraph s g =
let m :: M.Map Sequent GraphRec
m = M.map (\ vps -> Next $ map (\ (VP r ss) -> VP r (map (m M.!) ss)) vps) g
in m M.! s
------------------------------
unfold :: GraphRec -> Context -> P M
unfold graph context = unfoldM context graph
where unfoldM ctx s = wrap $ msum $ map (unfoldVPM ctx) (unNext s)
unfoldMs ctx s = wrap $ msum $ map (unfoldVPMs ctx) (unNext s)
unfoldVPMs ctx (VP (OrL cfs) ns) = do
vms <- zipWithM (\ n (_, a) -> do
x <- liftM V $ newSym "c"
m <- unfoldM (addCtx x a ctx) n
return (x, m)
) ns cfs
return $ When (map fst cfs) vms
unfoldVPMs ctx (VP (AndL i n) [s]) = do
m <- unfoldMs ctx s
return $ Sel i n m
unfoldVPMs ctx (VP ImpL [sa, sc]) = do
u <- unfoldM ctx sa
l <- unfoldMs ctx sc
return $ u ::: l
unfoldVPMs _ctx (VP Ax []) =
return Nil
unfoldVPMs _ctx _vp = error $ "unfoldVPMs " -- ++ show vp
unfoldVPM ctx (VP (OrR c i) [s]) = do
u <- unfoldM ctx s
return $ In c i u
unfoldVPM ctx (VP AndR ns) = do
ts <- mapM (unfoldM ctx) ns
return $ Tuple ts
unfoldVPM ctx (VP (ImpR a) [s]) = do
x <- liftM V $ newSym "i"
u <- unfoldM (addCtx x a ctx) s
return $ VLam x u
unfoldVPM ctx (VP (Cont ca) [s]) = do
(x, _a) <- many $ filter ((== ca) . snd) ctx
l <- unfoldMs ctx s
return $ Semi x l
unfoldVPM _ctx _vp = error $ "unfoldVPM " -- ++ show vp