INblobs-0.1.1: src/Network.hs
module Network
(
-- * Types
Network, Node, Edge
, NodeNr, EdgeNr, ViaNr
, networkNodes -- dangerous
, networkEdges -- dangerous
-- * Creating and printing a network
, Network.empty
, Network.isEmpty
, dumpNetwork
-- ** Set\'s e get\'s
, getNodeNrs
, getNodeAssocs, setNodeAssocs
, getEdgeAssocs, setEdgeAssocs
, getCanvasSize, setCanvasSize
, getGlobalInfo, setGlobalInfo
-- ** Get usefull information from 'Network'
, getNode
, getEdge
, getNodes
, getEdges
, getChildren
, getParents
, getParentMap, ParentMap
-- ** Search\'s
, nodeExists, edgeExists
, findEdge, findNodeNrsByName
, edgeConnectedOnPort
, otherExtremeOfEdgeConnectedOnPort
-- ** update network elements
, updateNode
, updateEdge
, updateVia
, mapNodeNetwork
-- ** add and remove network elements
, addNode, addNodes, removeNode, addNodeEx, addExistingNode
, addEdge, addEdges, removeEdge
, removeAllEdges
, newViaEdge, removeVia
-- * Node
, constructNode
-- ** get and set node data in a network by 'NodeNr'
, getNodeInfo, getNodeName, getNodePosition, getNodeNameAbove, getNodeShape
, setNodeInfo, setNodeName, setNodePosition, setNodeNameAbove, setNodeShape
-- ** get\'s and set\'s of a node
, getInfo, getName, getPosition, getNameAbove, getShape
, setInfo, setName, setPosition, setNameAbove, setShape
-- * Edge
, constructEdge
, getEdgeFrom, getPortFrom, getEdgeTo, getPortTo, getEdgeVia, getEdgeInfo, getFullPortFrom, getFullPortTo
, setEdgeFrom, setPortFrom, setEdgeTo, setPortTo, setEdgeVia, setEdgeInfo
-- * Interaction Nets functionality
, getPorts
, getPort
, isPrincipalPort
, showEdge
) where
import Common
import Math
import InfoKind
import Shape
import Ports
import Palette (Palette, shapes, ShapeName, getSymbol)
import Data.IntMap as IntMap hiding (map)
import qualified Data.List as List
data Network g n e = Network
{ networkNodes :: !(IntMap (Node n)) -- ^ maps node numbers to nodes
, networkEdges :: !(IntMap (Edge e)) -- ^ maps edge numbers to edges
, networkCanvasSize :: (Double, Double)
, networkInfo :: g
} deriving Show
data Edge e = Edge
{ edgeFrom :: !NodeNr -- ^ the number of the node where the edge starts
, portFrom :: PortName --
, edgeTo :: !NodeNr -- ^ the number of the node the edge points to
, portTo :: PortName --
, edgeVia :: [DoublePoint] -- ^ intermediate vertices when drawing
, edgeInfo :: e
} deriving (Show, Read, Eq)
showEdge :: Edge e -> String
showEdge edge =
"Node " ++ show (edgeFrom edge) ++ showPort (portFrom edge)
++ " |-> " ++
"Node " ++ show (edgeTo edge) ++ showPort (portTo edge)
where
showPort name = '@' : name
data Node n = Node
{ nodePosition :: DoublePoint -- ^ the position of the node on screen
, nodeName :: !String
, nodeNameAbove :: Bool -- ^ should the name be displayed above (True) of below (False)
, nodeShape :: ShapeName -- ^ symbol name from palette,
, nodeInfo :: n
} deriving (Show, Read)
type NodeNr = Int
type EdgeNr = Int
type ViaNr = Int
-- | Create an empty network
empty :: (InfoKind n g, InfoKind e g) => g -> n -> e -> Network g n e
empty g _ _ = Network
{ networkNodes = IntMap.empty
, networkEdges = IntMap.empty
, networkCanvasSize = (15, 9)
, networkInfo = g
}
-- | Map a function over the nodes, possibly changes the type
-- of the Network (i.e. the kind of values stored in the
-- probability tables)
mapNodeNetwork :: InfoKind m g =>
(Node n->Node m) -> Network g n e -> Network g m e
mapNodeNetwork nodeFun network =
let numberedNodes = getNodeAssocs network
newNodes = [ (nr, nodeFun node) | (nr, node) <- numberedNodes ]
in Network
{ networkNodes = IntMap.fromList newNodes
, networkEdges = networkEdges network
, networkCanvasSize = networkCanvasSize network
, networkInfo = networkInfo network
}
constructEdge :: NodeNr -> PortName -> NodeNr -> PortName -> [DoublePoint] -> e -> Edge e
constructEdge fromNr fromPort toNr toPort via info =
Edge
{ edgeFrom = fromNr
, portFrom = fromPort
, edgeTo = toNr
, portTo = toPort
, edgeVia = via
, edgeInfo = info
}
getEdgeFrom :: Edge e -> NodeNr
getEdgeFrom = edgeFrom
getPortFrom :: Edge e -> PortName
getPortFrom = portFrom
getFullPortFrom :: Edge e -> (NodeNr, PortName)
getFullPortFrom e = (edgeFrom e, portFrom e)
getEdgeTo :: Edge e -> NodeNr
getEdgeTo = edgeTo
getPortTo :: Edge e -> PortName
getPortTo = portTo
getFullPortTo :: Edge e -> (NodeNr, PortName)
getFullPortTo e = (edgeTo e, portTo e)
getEdgeVia :: Edge e -> [DoublePoint]
getEdgeVia = edgeVia
getEdgeInfo :: Edge e -> e
getEdgeInfo = edgeInfo
setEdgeFrom :: NodeNr -> Edge e -> Edge e
setEdgeFrom fromNr edge = edge { edgeFrom = fromNr }
setPortFrom :: NodeNr -> PortName -> Edge e -> Edge e
setPortFrom fromNr fromPort edge = edge { edgeFrom = fromNr, portFrom = fromPort }
setEdgeTo :: NodeNr -> Edge e -> Edge e
setEdgeTo toNr edge = edge { edgeTo = toNr }
setPortTo :: NodeNr -> PortName -> Edge e -> Edge e
setPortTo toNr toPort edge = edge { edgeTo = toNr, portTo = toPort }
setEdgeVia :: [DoublePoint] -> Edge e -> Edge e
setEdgeVia via edge = edge { edgeVia = via }
setEdgeInfo :: e -> Edge oldInfo -> Edge e
setEdgeInfo info edge =
constructEdge (getEdgeFrom edge) (portFrom edge)
(getEdgeTo edge) (portTo edge)
(getEdgeVia edge) info
constructNode :: (InfoKind n g) => String -> DoublePoint -> Bool
-> ShapeName -> n -> Node n
constructNode name position nameAbove shape info =
Node
{ nodeName = name
, nodePosition = position
, nodeNameAbove = nameAbove
, nodeShape = shape
, nodeInfo = info
}
getNodeName :: Network g n e -> NodeNr -> String
getNodeName network nodeNr = nodeName (networkNodes network ! nodeNr)
setNodeName :: NodeNr -> String -> Network g n e -> Network g n e
setNodeName nodeNr name network =
network { networkNodes = insert nodeNr (node { nodeName = name }) (networkNodes network) }
where node = networkNodes network ! nodeNr
getNodePosition :: Network g n e -> NodeNr -> DoublePoint
getNodePosition network nodeNr = nodePosition (networkNodes network ! nodeNr)
setNodePosition :: NodeNr -> DoublePoint -> Network g n e -> Network g n e
setNodePosition nodeNr position network =
network { networkNodes = insert nodeNr (node { nodePosition = position }) (networkNodes network) }
where node = networkNodes network ! nodeNr
getNodeNameAbove :: Network g n e -> NodeNr -> Bool
getNodeNameAbove network nodeNr = nodeNameAbove (networkNodes network ! nodeNr)
setNodeNameAbove :: NodeNr -> Bool -> Network g n e -> Network g n e
setNodeNameAbove nodeNr nameAbove network =
network { networkNodes = insert nodeNr (node { nodeNameAbove = nameAbove }) (networkNodes network) }
where node = networkNodes network ! nodeNr
getNodeShape :: Network g n e -> NodeNr -> ShapeName
getNodeShape network nodeNr = nodeShape (networkNodes network ! nodeNr)
setNodeShape :: NodeNr -> ShapeName -> Network g n e -> Network g n e
setNodeShape nodeNr shape network =
network { networkNodes = insert nodeNr (node { nodeShape = shape })
(networkNodes network) }
where node = networkNodes network ! nodeNr
getNodeInfo :: Network g n e -> NodeNr -> n
getNodeInfo network nodeNr = nodeInfo (networkNodes network ! nodeNr)
setNodeInfo :: NodeNr -> n -> Network g n e -> Network g n e
setNodeInfo nodeNr info network =
network { networkNodes = insert nodeNr (node { nodeInfo = info }) (networkNodes network) }
where node = networkNodes network ! nodeNr
getNameAbove :: Node a -> Bool
getNameAbove node = nodeNameAbove node
getName :: Node a -> String
getName node = nodeName node
getShape :: Node a -> ShapeName
getShape node = nodeShape node
getPosition :: Node a -> DoublePoint
getPosition node = nodePosition node
getInfo :: Node a -> a
getInfo node = nodeInfo node
-- | Set whether the name should appear above (True) or below (False) the node
setNameAbove :: Bool -> Node a -> Node a
setNameAbove above node = node { nodeNameAbove = above }
setName :: String -> Node a -> Node a
setName name node = node { nodeName = name }
setShape :: ShapeName -> Node a -> Node a
setShape s node = node { nodeShape = s }
setPosition :: DoublePoint -> Node a -> Node a
setPosition position node = node { nodePosition = position }
setInfo :: a -> Node a -> Node a
setInfo info node = node { nodeInfo = info }
-- | Get the next unused node number
getUnusedNodeNr :: Network g n e -> NodeNr
getUnusedNodeNr network | List.null used = 1
| otherwise = maximum used + 1
where
used = keys (networkNodes network)
-- | Get the next unused edge number
getUnusedEdgeNr :: Network g n e -> EdgeNr
getUnusedEdgeNr network | List.null used = 1
| otherwise = maximum used + 1
where
used = keys (networkEdges network)
-- | Get the node numbers of the parents of a given node
getParents :: Network g n e -> NodeNr -> [NodeNr]
getParents network child =
[ parent
| edge <- getEdges network
, edgeTo edge == child
, let parent = edgeFrom edge
]
type ParentMap = IntMap.IntMap [NodeNr]
-- | getParents is quite expensive (see above) and so
-- we store the parent relationship in an IntMap
getParentMap :: Network g n e -> ParentMap
getParentMap network =
IntMap.fromList
[ (nodeNr, getParents network nodeNr)
| nodeNr <- getNodeNrs network
]
-- | Get the node numbers of the children of a given node
getChildren :: Network g n e -> NodeNr -> [NodeNr]
getChildren network parent =
[ child
| edge <- getEdges network
, edgeFrom edge == parent
, let child = edgeTo edge
]
-- | Get node with given index, raises exception if node number does not exist
getNode :: NodeNr -> Network g n e -> Node n
getNode nodeNr network
| member nodeNr nodesMap = nodesMap ! nodeNr
| otherwise = internalError "Network" "getNode" "illegal node number"
where
nodesMap = networkNodes network
-- | Get edge with given index, raises exception if edge number does not exist
getEdge :: EdgeNr -> Network g n e -> Edge e
getEdge edgeNr network = networkEdges network ! edgeNr
-- | Get all of the nodes in the network
getNodes :: Network g n e -> [Node n]
getNodes network = elems (networkNodes network)
-- | Get all of the edges in the network
getEdges :: Network g n e -> [Edge e]
getEdges network = elems (networkEdges network)
-- | Get all of the node numbers in the network
getNodeNrs :: Network g n e -> [NodeNr]
getNodeNrs network = keys (networkNodes network)
getCanvasSize :: Network g n e -> (Double, Double)
getCanvasSize network = networkCanvasSize network
getGlobalInfo :: Network g n e -> g
getGlobalInfo network = networkInfo network
-- | Find the number of an edge given start and end node number
findEdge :: NodeNr -> PortName -> NodeNr -> PortName -> Network g n e -> Maybe EdgeNr
findEdge fromNodeNr fromPort toNodeNr toPort network =
let hits = IntMap.filter
(\edge ->
sameFromAndTo (Edge { edgeFrom = fromNodeNr
, portFrom = fromPort
, edgeTo = toNodeNr
, portTo = toPort
, edgeVia = undefined
, edgeInfo = undefined }) edge
|| sameFromAndTo (Edge { edgeFrom = toNodeNr
, portFrom = toPort
, edgeTo = fromNodeNr
, portTo = fromPort
, edgeVia = undefined
, edgeInfo = undefined }) edge)
(networkEdges network)
in case IntMap.keys hits of
[key] -> Just key
_ -> Nothing
-- | Find node numbers given a node name
findNodeNrsByName :: String -> Network g n e -> [NodeNr]
findNodeNrsByName theNodeName network =
[ nodeNr
| nodeNr <- getNodeNrs network
, getNodeName network nodeNr == theNodeName
]
-- | Get a list of pairs where each pair contains a node number and the corresponding node
getNodeAssocs :: Network g n e -> [(NodeNr, Node n)]
getNodeAssocs network = assocs (networkNodes network)
setNodeAssocs :: [(NodeNr, Node n)] -> Network g n e -> Network g n e
setNodeAssocs nodeAssocs network =
network { networkNodes = IntMap.fromList nodeAssocs }
-- | Get a list of pairs where each pair contains a edge number and the corresponding edge
getEdgeAssocs :: Network g n e -> [(EdgeNr, Edge e)]
getEdgeAssocs network = assocs (networkEdges network)
setEdgeAssocs :: [(EdgeNr, Edge e)] -> Network g n e -> Network g n e
setEdgeAssocs edgeAssocs network =
network { networkEdges = IntMap.fromList edgeAssocs }
-- | Check if a network is empty. A network is empty is it has no nodes.
isEmpty :: Network g n e -> Bool
isEmpty = IntMap.null . networkNodes
-- | Create a string that describes the network
dumpNetwork :: InfoKind e g => Network g String e -> String
dumpNetwork network = show (getNodeAssocs network) ++ "\n" ++ show (getEdgeAssocs network)
-- | Test for existence of a node number
nodeExists :: NodeNr -> Network g n e -> Bool
nodeExists nodeNr network =
member nodeNr (networkNodes network)
-- | Test for existence of an edge number
edgeExists :: EdgeNr -> Network g n e -> Bool
edgeExists edgeNr network =
member edgeNr (networkEdges network)
{-----------------------------------
Functions that change the network
-----------------------------------}
-- | Add a node to the network
addNode :: InfoKind n g
=> ShapeName -- ^ the current shape's name
-> Palette n -- ^ the palette
-> Network g n e -- ^ the network to add the node to
-> (NodeNr, Network g n e) -- ^ the number of the new node and
-- the extended network
addNode shape palette network =
addNodeEx ("Node " ++ show nodeNr)
(DoublePoint 0.0 0.0)
True
shape
blank
network
where
nodeNr = getUnusedNodeNr network
palette' = shapes palette
addNodes :: InfoKind n g => ShapeName -> Palette n -> Int -> Network g n e -> ([NodeNr], Network g n e)
addNodes _ _ 0 network = ([], network)
addNodes shapeName palette n network1 =
let (nodeNr, network2) = addNode shapeName palette network1
(nodeNrs, network3) = addNodes shapeName palette (n-1) network2
in (nodeNr:nodeNrs, network3)
addNodeEx :: InfoKind n g =>
String -> DoublePoint -> Bool -> ShapeName -> n
-> Network g n e -> (NodeNr, Network g n e)
addNodeEx name position labelAbove shape info network =
( nodeNr
, network { networkNodes = insert nodeNr node (networkNodes network) }
)
where
nodeNr = getUnusedNodeNr network
node = constructNode name position labelAbove shape info
addExistingNode :: InfoKind n g => Node n -> Network g n e -> (NodeNr, Network g n e)
addExistingNode node network =
( nodeNr
, network { networkNodes = insert nodeNr node' (networkNodes network) }
)
where
nodeNr = getUnusedNodeNr network
node' = setName ("Node " ++ show nodeNr) node
-- | Add an edge to the network. The probability table of the target node is updated:
-- a dimension is added and all values are zeroed.
addEdge :: InfoKind e g => Palette n -> NodeNr -> PortName -> NodeNr -> PortName -> Network g n e -> Network g n e
addEdge palette fromNodeNr fromPort toNodeNr toPort network
| any (sameFromAndTo edge) edgesList || -- prohibit double edges
any (sameFromAndTo (reverseEdge edge)) edgesList || -- prohibit edges in opposite direction
anyPortAlreadyUsed edge edgesList -- only one connection per port is allowed
|| (fromNodeNr, fromPort) == (toNodeNr, toPort) -- prohibit edges from a port to itself
= network
| otherwise =
let edgeNr = getUnusedEdgeNr network
networkPlusEdge = network { networkEdges = insert edgeNr edge (networkEdges network) }
in networkPlusEdge
where
edge = Edge { edgeFrom = fromNodeNr, portFrom = fromPort
, edgeTo = toNodeNr, portTo = toPort
, edgeVia = if fromNodeNr /= toNodeNr then [] else [point2EdgeInNode palette fromNodeNr fromPort toPort network]
, edgeInfo = blank }
edgesList = elems (networkEdges network)
addEdges :: InfoKind e g => Palette n -> [( (NodeNr, PortName), (NodeNr, PortName) )]
-> Network g n e -> Network g n e
addEdges palette edgeTuples network =
foldr (\((fromNr, fromMPort), (toNr, toMPort)) net -> addEdge palette fromNr fromMPort toNr toMPort net)
network edgeTuples
-- | Insert a new 'via' control point in the middle of an edge.
newViaEdge :: EdgeNr -> ViaNr -> DoublePoint
-> Network g n e -> Network g n e
newViaEdge edgeNr viaNr point network =
network { networkEdges = adjust (\e->e{ edgeVia= take viaNr (edgeVia e)
++[point]
++drop viaNr (edgeVia e) })
edgeNr
(networkEdges network) }
-- | Remove node with given index, raises exception if node number does not exist.
-- This function also removes all edges that start or end in this node.
removeNode :: NodeNr -> Network g n e -> Network g n e
removeNode nodeNr network =
let involvedEdges = [ i
| (i, edge) <- getEdgeAssocs network
, edgeFrom edge == nodeNr || edgeTo edge == nodeNr
]
networkWithoutEdges = foldr removeEdge network involvedEdges
networkWithoutNode = networkWithoutEdges { networkNodes = delete nodeNr (networkNodes networkWithoutEdges) }
in networkWithoutNode
-- | Remove an edge from the network. The probability table of the target node is updated:
-- the corresponding dimension is removed and all values are zeroed.
-- An exception is raised if edge number does not exist.
removeEdge :: EdgeNr -> Network g n e -> Network g n e
removeEdge edgeNr network =
network { networkEdges = delete edgeNr (networkEdges network) }
-- | Remove all edges from the network. The probability tables of all node are zeroed.
removeAllEdges :: Network g n e -> Network g n e
removeAllEdges network =
let networkWithoutEdges = network { networkEdges = IntMap.empty }
in networkWithoutEdges
-- | Remove a control point from an edge.
removeVia :: EdgeNr -> ViaNr -> Network g n e -> Network g n e
removeVia edgeNr viaNr network =
let remove n e = e { edgeVia = take n (edgeVia e)
++ drop (n+1) (edgeVia e) } in
network { networkEdges = adjust (remove viaNr)
edgeNr (networkEdges network) }
setCanvasSize :: (Double, Double) -> Network g n e -> Network g n e
setCanvasSize canvasSize network = network { networkCanvasSize = canvasSize }
setGlobalInfo :: g -> Network g n e -> Network g n e
setGlobalInfo info network = network { networkInfo = info }
{-----------------------------------
Local functions
-----------------------------------}
{- | Checks if two edges are equal. Equality in edges is:
* if the edges have information of ports then the edges are equal when the pairs
(node,port) from and to of the two edges are the same
* otherwise the edges are equal if the from and to Nodes are the same
-}
sameFromAndTo :: Edge e -> Edge e -> Bool
sameFromAndTo edge1 edge2 =
getFullPortFrom edge1 == getFullPortFrom edge2 && getFullPortTo edge1 == getFullPortTo edge2 -- equality on nodes and ports
reverseEdge :: Edge e -> Edge e
reverseEdge edge =
edge { edgeFrom = edgeTo edge
, portFrom = portTo edge
, edgeTo = edgeFrom edge
, portTo = portFrom edge}
-- | Avoid the introduction of connections on ports that already are used.
-- So only one connection per port is allowed.
anyPortAlreadyUsed :: Edge e -> [Edge e] -> Bool
anyPortAlreadyUsed edge edgesList =
(edgeFrom edge, portFrom edge) `elem` portsList
|| (edgeTo edge, portTo edge) `elem` portsList
where portsList = concatMap f edgesList
f e = [(edgeFrom e, portFrom e), (edgeTo e, portTo e)]
-- | Update node with given number by applying the function to it
-- Dangerous (wrt network consistency, do not export)
updateNode :: NodeNr -> (Node n -> Node n) -> Network g n e -> Network g n e
updateNode nodeNr nodeFunction network =
let node = getNode nodeNr network in
network { networkNodes = insert nodeNr (nodeFunction node)
(networkNodes network) }
updateEdge :: EdgeNr -> (Edge e -> Edge e) -> Network g n e -> Network g n e
updateEdge edgeNr edgeFunction network =
network { networkEdges = adjust edgeFunction edgeNr
(networkEdges network) }
updateVia :: EdgeNr -> ViaNr -> DoublePoint -> Network g n e -> Network g n e
updateVia edgeNr viaNr v network =
network { networkEdges =
adjust (\e-> e { edgeVia = take viaNr (edgeVia e)
++[v]++drop (viaNr+1) (edgeVia e) })
edgeNr (networkEdges network) }
edgeConnectedOnPort :: Network g n e -> NodeNr -> PortName -> Maybe EdgeNr
edgeConnectedOnPort network nodeNr port =
case IntMap.keys (IntMap.filter f (networkEdges network) ) of
[edgeNr] -> Just edgeNr
_ -> Nothing
where f :: Edge e -> Bool
f edge =
getFullPortFrom edge == (nodeNr, port)
|| getFullPortTo edge == (nodeNr, port)
otherExtremeOfEdgeConnectedOnPort :: Network g n e -> NodeNr -> PortName
-> Maybe (NodeNr, PortName)
otherExtremeOfEdgeConnectedOnPort network nodeNr port =
case edgeConnectedOnPort network nodeNr port of
Just edgeNr | getFullPortFrom (getEdge edgeNr network) == (nodeNr, port) -> Just $ getFullPortTo (getEdge edgeNr network)
Just edgeNr | getFullPortTo (getEdge edgeNr network) == (nodeNr, port) -> Just $ getFullPortFrom (getEdge edgeNr network)
_ -> Nothing
point2EdgeInNode :: Palette n -> NodeNr -> PortName -> PortName -> Network g n e -> DoublePoint
point2EdgeInNode palette nodeNr fromPort toPort network =
case getPorts palette network nodeNr of
Just ports ->
case (Prelude.lookup fromPort ports, Prelude.lookup toPort ports) of
(Just fromPortPos, Just toPortPos) ->
g (portZone (fromPort,fromPortPos)) (portZone (toPort,toPortPos))
_ -> error "unexpected situation"
Nothing -> f 1 1
where g Ztop Ztop = top
g Zbottom Zbottom = bottom
g Zleft Zleft = left
g Zright Zright = right
g Ztop Zbottom = right
g Zbottom Ztop = right
g Zleft Zright = top
g Zright Zleft = top
g Ztop Zleft = q2
g Ztop Zright = q1
g Zbottom Zleft = q3
g Zbottom Zright = q4
g Zleft Ztop = q2
g Zleft Zbottom = q3
g Zright Ztop = q1
g Zright Zbottom = q4
param = 2.0
f x y = translate (getNodePosition network nodeNr) $ DoublePoint (x * param) (y * param)
top = f 0 (-1)
bottom = f 0 1
left = f (-1) 0
right = f 1 0
q1 = f 1 (-1)
q2 = f (-1) (-1)
q3 = f (-1) 1
q4 = f 1 1
isPrincipalPort :: Palette n -> Network g n e -> NodeNr -> PortName -> Bool
isPrincipalPort palette network nodeNr port =
maybe False f $ getPorts palette network nodeNr
where
f ((port2,_):_) = port2 == port
f _ = False
getPorts :: Palette n -> Network g n e -> NodeNr -> Maybe Ports
getPorts palette network nodeNr =
case getSymbol (getNodeShape network nodeNr) palette of
Just (_,ports,_) -> Just ports
_ -> Nothing
getPort :: Palette n -> Network g n e -> (NodeNr,PortName) -> Maybe Port
getPort palette network (nodeNr,portName) =
case getSymbol (getNodeShape network nodeNr) palette of
Just (_,ports,_) ->
case Prelude.lookup portName ports of
Just portPosition -> Just (portName, portPosition)
_ -> Nothing
_ -> Nothing