module Nominal.Permutation where
import Data.List
import Data.Map (Map)
import qualified Data.Map as Map
import Nominal.Atom
newtype Perm = Perm (Map Atom Atom)
deriving (Eq, Show)
p_identity :: Perm
p_identity = Perm Map.empty
p_composeR :: Perm -> Perm -> Perm
p_composeR s@(Perm sigma) (Perm tau) = Perm rho
where
rho = Map.foldrWithKey f sigma tau
f a b rho = rho'
where
c = p_apply_atom s b
rho'
| a == c = Map.delete a rho
| otherwise = Map.insert a c rho
p_composeL :: Perm -> Perm -> Perm -> Perm
p_composeL (Perm sigma) (Perm tau) t'@(Perm tau_inv) = Perm rho
where
rho = Map.foldrWithKey f tau sigma
f a b rho = rho'
where
c = p_apply_atom t' a
rho'
| c == b = Map.delete c rho
| otherwise = Map.insert c b rho
p_apply_atom :: Perm -> Atom -> Atom
p_apply_atom (Perm sigma) a =
case Map.lookup a sigma of
Nothing -> a
Just b -> b
p_swap :: Atom -> Atom -> Perm
p_swap a b
| a == b = p_identity
| otherwise = Perm (Map.singleton a b `Map.union` Map.singleton b a)
p_domain :: Perm -> [Atom]
p_domain (Perm sigma) = Map.keys sigma
data NominalPermutation = Permutation Perm Perm
deriving (Eq)
type Permutation = NominalPermutation
perm_identity :: Permutation
perm_identity = Permutation p_identity p_identity
perm_composeR :: Permutation -> Permutation -> Permutation
perm_composeR (Permutation sigma sinv) (Permutation tau tinv) = Permutation rho rinv
where
rho = p_composeR sigma tau
rinv = p_composeL tinv sinv sigma
perm_composeL :: Permutation -> Permutation -> Permutation
perm_composeL (Permutation sigma sinv) (Permutation tau tinv) = Permutation rho rinv
where
rho = p_composeL sigma tau tinv
rinv = p_composeR tinv sinv
perm_invert :: Permutation -> Permutation
perm_invert (Permutation sigma sinv) = Permutation sinv sigma
perm_apply_atom :: Permutation -> Atom -> Atom
perm_apply_atom (Permutation sigma sinv) = p_apply_atom sigma
perm_swap :: Atom -> Atom -> Permutation
perm_swap a b = Permutation sigma sigma
where
sigma = p_swap a b
perm_swaps :: [(Atom,Atom)] -> Permutation
perm_swaps [] = perm_identity
perm_swaps ((a,b):xs) = perm_swap a b `perm_composeL` perm_swaps xs
perm_domain :: Permutation -> [Atom]
perm_domain (Permutation sigma sinv) = p_domain sigma
perm_of_swaps :: [(Atom, Atom)] -> Permutation
perm_of_swaps xs = aux xs where
aux [] = perm_identity
aux ((a,b):t) = perm_swap a b `perm_composeL` perm_of_swaps t
swaps_of_perm :: Permutation -> [(Atom, Atom)]
swaps_of_perm sigma = [ y | Just y <- ys ]
where
domain = perm_domain sigma
(tau, ys) = mapAccumL f sigma domain
f acc a
| a == b = (acc', Nothing)
| otherwise = (acc', Just (a, b))
where
b = perm_apply_atom acc a
acc' = perm_composeL (perm_swap a b) acc