Résolution stellaire en OCaml
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

260 lines
7.8 KiB

module Resolution where
import qualified Unification
import Data.Maybe
import Data.List
import Data.Tuple
import PrettyPrinter as PrettyPrinter
import Control.Arrow
import Control.Monad
import Data.Semigroup
import qualified Data.Set as Set
{- ========================================
Definitions
======================================== -}
data Polarized a = Pos a | Neg a | NC a deriving (Ord, Eq)
type Ray = Polarized Unification.Term
newtype Star = Star { get_star :: [Ray] }
newtype Constellation = Const { get_const :: [Star] }
newtype Link = Link { get_link :: ((Ray, Ray), Int, Int) }
newtype StarGraph = StarGraph { get_graph :: ([Star], [Link]) }
type UGraph = StarGraph
type Diagram = StarGraph
instance Functor Polarized where
fmap f (Pos t) = Pos (f t)
fmap f (Neg t) = Neg (f t)
fmap f (NC t) = NC (f t)
instance Eq Star where
(Star s1) == (Star s2) = sort s1 == sort s2
instance Eq Constellation where
(Const s1) == (Const s2) = sort s1 == sort s2
instance Eq Link where
Link (e, i, j) == Link (e', i', j') =
(i==i' && j==j' && i/=j) || (i==i' && j==j' && i==j && e==swap e')
instance Ord Star where
compare (Star s1) (Star s2) = compare s1 s2
instance Show a => Show (Polarized a) where
show (Pos t) = "+" ++ show t
show (Neg t) = "-" ++ show t
show (NC t) = show t
instance Show Star where
show (Star s) = show s
instance Show Constellation where
show (Const c) = show $ PrettyPrinter.addop '+' (map show c)
instance Show Link where
show (Link x) = show x
instance Show StarGraph where
show (StarGraph (v, e)) =
"------------------------\n" ++
"Vertices:\n" ++ unlines (mapInd (\x i -> show i ++ ":" ++ show x) v) ++
"Edges:\n" ++ unlines (map show e)
instance Semigroup Constellation where
(Const c1) <> (Const c2) = Const (c1 ++ c2)
mapInd :: (a -> Int -> b) -> [a] -> [b]
mapInd f l = zipWith f l [0..]
change_color :: String -> String -> Ray -> Ray
change_color s s' r@(Neg (Unification.Func f ts))
| f==s = Neg (Unification.Func s' ts)
change_color s s' r@(Pos (Unification.Func f ts))
| f==s = Neg (Unification.Func s' ts)
change_color _ _ r = r
dual :: Ray -> Ray -> Bool
dual (Pos _) (Neg _) = True
dual (Neg _) (Pos _) = True
dual _ _ = False
get_term :: Ray -> Unification.Term
get_term (Pos t) = t
get_term (Neg t) = t
get_term (NC t) = t
vars_ray :: Ray -> [Unification.Id]
vars_ray (Pos t) = Unification.vars t
vars_ray (Neg t) = Unification.vars t
vars_ray (NC t) = Unification.vars t
vars_star :: Star -> [Unification.Id]
vars_star (Star s) = concat $ map vars_ray s
subst_ray :: Unification.Subst -> Ray -> Ray
subst_ray = fmap . Unification.subst
subst_rays :: Unification.Subst -> [Ray] -> [Ray]
subst_rays = map . subst_ray
extends_ray :: String -> Ray -> Ray
extends_ray = fmap . Unification.extends_varname
extends_star :: String -> Star -> Star
extends_star s (Star e) = Star (map (extends_ray s) e)
rays :: Constellation -> [Ray]
rays (Const cs) = [r | s<-cs, r<-(get_star s)]
{- ========================================
Unification graph
======================================== -}
matchable_rays :: Ray -> Ray -> Bool
matchable_rays r1 r2 = dual r1 r2 &&
Unification.matchable (get_term r1, get_term r2)
get_links :: Star -> Star -> [(Ray, Ray)]
get_links (Star s1) (Star s2) =
[(r1, r2) | r1<-s1, r2<-s2, matchable_rays r1 r2]
ugraph :: Constellation -> UGraph
ugraph (Const cs) =
let imax = length cs - 1 in
let pairs = [(i, j) | i<-[0..imax], j<-[0..imax], i<=j] in
let e = foldl (\acc (i, j) ->
let links = get_links (cs!!i) (cs!!j) in
let make_edge e = Link (e, i, j) in
if links==[] then acc else (map make_edge links) ++ acc) [] pairs in
StarGraph (cs, nub e)
{- ========================================
Actualisation
======================================== -}
make_edge :: [Star] -> (Int, Int) -> (Int, Int) -> Link
make_edge xs (is1, ir1) (is2, ir2) =
let (Star s1) = xs !! is1 in
let (Star s2) = xs !! is2 in
Link ((s1!!ir1, s2!!ir2), is1, is2)
equations :: Diagram -> [Unification.Equation]
equations (StarGraph (v, e)) =
map (\(Link ((t, u), i, j)) ->
let new_t = Unification.extends_varname (show i) (get_term t) in
let new_u = Unification.extends_varname (show j) (get_term u) in
(new_t, new_u)) e
appears_in_link :: Ray -> Link -> Bool
appears_in_link r (Link ((t, u), _, _)) = r==t || r==u
already_linked :: Link -> [Link] -> Bool
already_linked (Link ((t, u), i, j)) ls =
any (\(Link ((t', u'), i', j')) ->
(t==t' && i==i') || (u==u' && j==j') ||
(t==u' && i==j') || (u==t' && j==i')) ls
free_rays :: Diagram -> [Ray]
free_rays (StarGraph (v, e)) =
let linked = concat [[(extends_ray (show i) r, i), (extends_ray (show j) r', j)] | (Link ((r, r'), i, j))<-e] in
let stars = mapInd (curry id) v in
let rays = concat $ map (\(Star s, i) -> map (\r -> (extends_ray (show i) r, i)) s) stars in
map fst (rays \\ linked)
correct :: Diagram -> Bool
correct d = free_rays d /= [] && (isJust $ Unification.solution (equations d))
actualise :: Diagram -> Maybe Star
actualise d = do
u <- Unification.solution (equations d)
pure $ Star (subst_rays u (free_rays d))
fusions :: Star -> Star -> [Star]
fusions (Star star1) (Star star2) = do
ray1 <- star1
ray2 <- star2
guard (ray1 `matchable_rays` ray2)
u <- maybeToList $ Unification.solution [(get_term ray1, get_term ray2)]
[Star (subst_rays u (delete ray1 star1 ++ delete ray2 star2))]
{- ========================================
Execution
======================================== -}
connect :: (Star, Int) -> (Star, Int) -> [Link]
connect (Star s1, i) (Star s2, j) = do
r1 <- s1
r2 <- s2
guard (r1 `matchable_rays` r2)
[Link ((r1, r2), i, j)]
saturated :: Constellation -> Diagram -> Bool
saturated cs d =
let free = free_rays d in
let rs = rays cs in
free_rays d /= [] &&
[(r1, r2) | r1<-free, r2<-rs, r1 `matchable_rays` r2] == []
shift_link :: Int -> Link -> Link
shift_link k (Link (e, i, j)) = Link (e, i+k, j+k)
singleStep :: Constellation -> Diagram -> [Diagram]
singleStep (Const cs) d@(StarGraph (stars, links)) =
let cs' = mapInd (curry id) cs in
let stars' = mapInd (curry id) stars in
do
(s1, i) <- cs'
(s2, j) <- stars'
link <- connect (s1, 0) (s2, j+1)
guard (not $ already_linked link (map (shift_link 1) links))
pure (StarGraph (s1:stars, link:map (shift_link 1) links))
allCorrectDiagrams :: Constellation -> [Diagram]
allCorrectDiagrams (Const []) = []
allCorrectDiagrams (Const cs) = go [StarGraph ([cs!!0], [])] where
go (d : ds) = do
d : go (ds ++ filter correct (singleStep (Const cs) d))
go [] = []
allCorrectSaturatedDiagrams :: Constellation -> [Diagram]
allCorrectSaturatedDiagrams cs = filter (saturated cs) $ allCorrectDiagrams cs
execution :: Constellation -> Constellation
execution cs = Const (catMaybes $ map actualise (allCorrectSaturatedDiagrams cs))
skeleton :: Constellation -> Constellation
deleteAt :: Int -> [a] -> [a]
deleteAt idx xs = lft ++ rgt
where (lft, (_:rgt)) = splitAt idx xs
fusion :: (Star, Int) -> (Star, Int) -> [Star]
fusion (Star s1, i) (Star s2, j) =
let r1 = s1 !! i in
let r2 = s2 !! j in
case Unification.solution [(get_term r1, get_term r2)] of
Just u -> [Star (subst_rays u (deleteAt i s1 ++ deleteAt j s2))]
Nothing -> []
step :: Constellation -> [Star] -> [Star]
step (Const cs) stars = do
s1' <- cs
s2' <- stars
let s1 = get_star s1'
let s2 = get_star s2'
guard (s1 /= s2)
i <- [0..length s1 - 1]
j <- [0..length s2 - 1]
guard ((s1 !! i) `matchable_rays` (s2 !! j))
fusion (s1', i) (s2', j)
steps :: Int -> Constellation -> [Star] -> [Star]
steps 0 _ mem = mem
steps k cs mem =
let new = step cs mem in
if new == [] then mem else mem ++ steps (k-1) cs new
exec :: Constellation -> Constellation
exec wcs@(Const cs) = Const (steps 0 wcs cs)