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
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)
|
|
|