module Math.Grads.Algo.Interaction
(
areAdjacent
, getEnds
, getOtherEnd
, getSharedVertex
, getVertexAdjacent
, getVertexIncident
, getVertexIncidentIdx
, haveSharedVertex
, isIncident
, (~=)
, (/~=)
, matchEdges
, getEdgeIncident
, doubleEdgeList
, edgeListToMap
, haveSharedEdge
, sortBondList
, getIndices
) where
import Data.List (find, findIndices, intersect, sortOn)
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe (fromJust, isJust)
import Math.Grads.Graph (EdgeList, GraphEdge, edgeType)
import Math.Grads.Utils (nub)
(~=) :: GraphEdge e1 -> GraphEdge e2 -> Bool
(b, e, _) ~= (b', e', _) = (b == b' && e == e') || (b == e' && e == b')
(/~=) :: GraphEdge e1 -> GraphEdge e2 -> Bool
b1 /~= b2 = not $ b1 ~= b2
isIncident :: GraphEdge e -> Int -> Bool
isIncident (b, e, _) n = b == n || e == n
getVertexIncident :: EdgeList e -> Int -> EdgeList e
getVertexIncident bs n = filter (`isIncident` n) bs
getVertexIncidentIdx :: EdgeList e -> Int -> [Int]
getVertexIncidentIdx bs n = findIndices (`isIncident` n) bs
getOtherEnd :: GraphEdge e -> Int -> Int
getOtherEnd (b, e, _) n | b == n = e
| e == n = b
| otherwise = error "There is no such index in edge."
getVertexAdjacent :: EdgeList e -> Int -> [Int]
getVertexAdjacent bs n = (`getOtherEnd` n) <$> getVertexIncident bs n
areAdjacent :: EdgeList e -> Int -> Int -> Bool
areAdjacent bs n n' = n' `elem` getVertexAdjacent bs n
getEnds :: GraphEdge e -> [Int]
getEnds (b, e, _) = [b, e]
haveSharedVertex :: GraphEdge e1 -> GraphEdge e2 -> Bool
haveSharedVertex b1 b2 = isJust $ getSharedVertex b1 b2
getSharedVertex :: GraphEdge e1 -> GraphEdge e2 -> Maybe Int
getSharedVertex b1 b2 | null is = Nothing
| length is == 2 = Nothing
| otherwise = Just $ head is
where
is = getEnds b1 `intersect` getEnds b2
matchEdges :: EdgeList e -> [(Int, Int)] -> EdgeList e
matchEdges bonds = fmap (\(a, b) -> fromJust (find (~= (a, b, undefined)) bonds))
getEdgeIncident :: Ord e => EdgeList e -> Int -> EdgeList e
getEdgeIncident bs n | n >= length bs = []
| otherwise = filter (/= (beg, end, typ)) $ getVertexIncident bs beg ++ getVertexIncident bs end
where
(beg, end, typ) = bs !! n
doubleEdgeList :: EdgeList e -> EdgeList e
doubleEdgeList = concatMap (\(a, b, t) -> [(a, b, t), (b, a, t)])
edgeListToMap :: EdgeList e -> Map Int [Int]
edgeListToMap bonds' = M.fromList (fmap (toVertex bonds) (getIndices bonds))
where
bonds = doubleEdgeList bonds'
toVertex :: EdgeList e -> Int -> (Int, [Int])
toVertex bs i = (i, concatMap (\(a, b, _) -> [a | b == i]) bs)
haveSharedEdge :: Eq e => EdgeList e -> EdgeList e -> Bool
haveSharedEdge b1 b2 = or $ fmap (`elem` b2) b1
sortBondList :: Ord e => EdgeList e -> EdgeList e
sortBondList = sortOn left . sortOn right . sortOn edgeType
where
left (a, _, _) = a
right (_, b, _) = b
getIndices :: EdgeList e -> [Int]
getIndices = nub . concatMap getEnds