2019-05-05 12:27:50 +02:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2019-05-06 08:21:04 +02:00
|
|
|
{-# LANGUAGE DeriveFunctor #-}
|
2019-05-05 12:27:50 +02:00
|
|
|
module Graph (
|
2019-05-06 08:21:04 +02:00
|
|
|
Graph(..)
|
2019-05-06 21:51:59 +02:00
|
|
|
, Vertex(..)
|
2019-05-09 17:14:56 +02:00
|
|
|
, editVertex
|
2019-05-06 16:47:29 +02:00
|
|
|
, follow
|
2019-05-06 08:21:04 +02:00
|
|
|
, rewind
|
|
|
|
, singleton
|
2019-05-09 17:14:56 +02:00
|
|
|
, stitch
|
2019-05-06 08:21:04 +02:00
|
|
|
, weave
|
2019-05-05 12:27:50 +02:00
|
|
|
) where
|
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
import Data.Map ((!), Map)
|
|
|
|
import qualified Data.Map as Map (adjust, empty, insert, lookup, singleton, size, toList)
|
|
|
|
import Data.Set (Set)
|
|
|
|
import qualified Data.Set as Set (insert, member, singleton)
|
2019-05-06 08:21:04 +02:00
|
|
|
import Tree (Tree(..), Structure(..))
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
type VertexID = Int
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
data Vertex edge label = Vertex {
|
2019-05-05 12:27:50 +02:00
|
|
|
label :: label
|
2019-05-09 17:14:56 +02:00
|
|
|
, edges :: Map edge VertexID
|
2019-05-06 08:21:04 +02:00
|
|
|
} deriving (Functor, Show)
|
|
|
|
|
|
|
|
data Graph edge label = Graph {
|
2019-05-09 17:14:56 +02:00
|
|
|
vertices :: Map VertexID (Vertex edge label)
|
|
|
|
, focus :: VertexID
|
|
|
|
, root :: VertexID
|
2019-05-06 08:21:04 +02:00
|
|
|
} deriving (Functor, Show)
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
getStructureWithoutLoop :: Show edge => Set VertexID -> Graph edge String -> Structure
|
|
|
|
getStructureWithoutLoop visitedIDs graph@(Graph {focus, vertices}) = Node [(
|
|
|
|
"(" ++ show focus ++ ":" ++ label ++ ")"
|
|
|
|
, Node $ recurseOnEdge <$> Map.toList edges
|
|
|
|
)]
|
|
|
|
where
|
|
|
|
Vertex label edges = vertices ! focus
|
|
|
|
recurseOnEdge (edge, vertexID) = (
|
|
|
|
show edge
|
|
|
|
, if Set.member vertexID visitedIDs
|
|
|
|
then Node [("(:" ++ show vertexID ++ ")", Node [])]
|
|
|
|
else getStructureWithoutLoop (Set.insert vertexID visitedIDs) $ graph {focus = vertexID}
|
|
|
|
)
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
instance Show edge => Tree (Graph edge) where
|
|
|
|
getStructure graph =
|
|
|
|
getStructureWithoutLoop (Set.singleton $ root graph) (rewind graph)
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
vertex :: label -> Vertex edge label
|
|
|
|
vertex label = Vertex {label, edges = Map.empty}
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
singleton :: label -> Graph edge label
|
|
|
|
singleton label = Graph {
|
|
|
|
vertices = Map.singleton 0 $ vertex label
|
|
|
|
, focus = 0
|
|
|
|
, root = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
rewind :: Graph edge label -> Graph edge label
|
|
|
|
rewind graph = graph {focus = root graph}
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
follow :: Ord edge => Graph edge label -> edge -> Maybe (Graph edge label)
|
2019-05-09 17:14:56 +02:00
|
|
|
follow graph@(Graph {vertices, focus}) edge =
|
2019-05-13 18:27:49 +02:00
|
|
|
setFocus <$> Map.lookup edge (edges $ vertices ! focus)
|
|
|
|
where
|
|
|
|
setFocus vertexID = graph {focus = vertexID}
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
stitch :: (Monoid label, Ord edge) => Graph edge label -> edge -> Graph edge label
|
|
|
|
stitch graph edge =
|
2019-05-05 12:27:50 +02:00
|
|
|
case graph `follow` edge of
|
2019-05-09 17:14:56 +02:00
|
|
|
Nothing ->
|
|
|
|
let newVertexID = Map.size $ vertices graph in
|
|
|
|
let link aVertex = aVertex {edges = Map.insert edge newVertexID $ edges aVertex} in
|
|
|
|
graph {
|
|
|
|
vertices =
|
|
|
|
Map.adjust link (focus graph) . Map.insert newVertexID (vertex mempty) $ vertices graph
|
|
|
|
, focus = newVertexID
|
2019-05-05 12:27:50 +02:00
|
|
|
}
|
|
|
|
Just newGraph -> newGraph
|
|
|
|
|
2019-05-09 17:14:56 +02:00
|
|
|
weave :: (Monoid label, Ord edge) => Graph edge label -> [edge] -> Graph edge label
|
|
|
|
weave = foldl stitch
|
|
|
|
|
|
|
|
editVertex :: Graph edge label -> (Vertex edge label -> Vertex edge label) -> Graph edge label
|
|
|
|
editVertex graph@(Graph {vertices, focus}) vertexEditor =
|
|
|
|
graph {vertices = Map.adjust vertexEditor focus vertices}
|