1 type Subgraph = [([Resource], [Resource])]
2 data Subgraphs = Subgraphs Resource Subgraph
5 floodFill :: Resource -> <ReadGraph, Proc> Subgraph
6 floodFill fromVertex = do
7 processVertex fromVertex
8 (MSet.toList vertices, MSet.toList edges)
10 edgesOf vertex = (vertex # DN.HasStartVertex_Inverse, vertex # DN.HasEndVertex_Inverse)
11 vertices = MSet.create ()
12 edges = MSet.create ()
13 processVertex vertex = if MSet.add vertices vertex then do
14 (starts, ends) = edgesOf vertex
15 for starts processEdgeStart
16 for ends processEdgeEnd
18 processEdgeStart edge = if MSet.add edges edge then for (edge # DN.HasEndVertex) processVertex else ()
19 processEdgeEnd edge = if MSet.add edges edge then for (edge # DN.HasStartVertex) processVertex else ()
22 findDisconnectedSubnetworksFromDiagram :: Resource -> <ReadGraph, Proc> Subgraphs
23 findDisconnectedSubnetworksFromDiagram networkDiagram = let
24 all = networkDiagram # L0.ConsistsOf
25 vertices = filter (flip isInstanceOf DN.Vertex) all
26 edges = filter (flip isInstanceOf DN.Edge) all
27 vertexSet = MSet.fromList vertices
28 edgeSet = MSet.fromList edges
29 result = MList.create ()
30 take1 set = MSet.mapFirst Just vertexSet
33 loop (Just vertex) = do
34 subgraph = floodFill vertex
35 MList.add result subgraph
37 MSet.removeAll vertexSet vs
38 MSet.removeAll edgeSet es
39 if not (MSet.isEmpty vertexSet) then
40 loop (take1 vertexSet)
43 print "Total number of vertices: \(length vertices)"
44 print "Total number of edges: \(length edges)"
45 loop (take1 vertexSet)
46 if MSet.size edgeSet > 0 then
47 MList.add result ([], MSet.toList edgeSet)
49 print "Found \(MList.size result) disconnected sub-networks"
50 Subgraphs networkDiagram (MList.freeze result)
53 Finds disconnected district subnetworks from the provided district network diagram.
54 The input can be either the network diagram resource or the configuration composite
55 resource of the network diagram.
57 See [reportDisconnectedSubnetworks](#reportDisconnectedSubnetworks) for reporting
59 findDisconnectedSubnetworks :: Resource -> <ReadGraph, Proc> Subgraphs
60 findDisconnectedSubnetworks networkDiagramOrComposite = findDisconnectedSubnetworksFromDiagram (toDiagram networkDiagramOrComposite)
62 toDiagram d = if isInstanceOf d DN.Diagram then d
63 else match (possibleObject d MOD.CompositeToDiagram) with
64 Just dia -> toDiagram dia
65 Nothing -> fail "Provided diagram is not a district network diagram or configuration composite: \(possibleUriOf d)"
69 importJava "org.simantics.utils.strings.AlphanumComparator" where
70 @JavaName CASE_INSENSITIVE_COMPARATOR
71 alphanumericComparator :: Comparator String
73 reportDisconnectedSubnetworks :: Integer -> Subgraphs -> <ReadGraph, Proc> ()
74 reportDisconnectedSubnetworks vertexThreshold (Subgraphs diagram subgraphs) = do
75 print "## Disconnected sub-network analysis of district network \(relativeUri diagram)"
76 print "* Detailed reporting vertex count threshold is <= \(vertexThreshold)"
77 for subgraphs reportGraph
79 rootUri = match possibleIndexRoot diagram with
81 Just root -> uriOf (parent root)
82 relativeUri r = drop (length rootUri) (uriOf r)
84 showVertex v = nameOf v
86 edgeEnds e = (possibleObject e DN.HasStartVertex, possibleObject e DN.HasEndVertex)
87 showEdgeEnds (Nothing, Nothing) = "(null, null)"
88 showEdgeEnds (Just s, Nothing) = "(\(nameOf s), null)"
89 showEdgeEnds (Nothing, Just e) = "(null, \(nameOf e))"
90 showEdgeEnds (Just s, Just e) = "(\(nameOf s), \(nameOf e))"
91 showEdge e = (nameOf e) + " - " + (showEdgeEnds (edgeEnds e))
92 sortStrings l = sortWithComparator alphanumericComparator l
94 reportGraph (vs, es) | length vs > vertexThreshold = reportShort vs es
95 | otherwise = reportFull vs es
96 reportSubgraphTitle vs es = print "\n### Disconnected sub-network of \(length vs) vertices and \(length es) edges"
97 reportShort vs es = do
98 reportSubgraphTitle vs es
99 print "* Details not reported because vertex count exceeds threshold"
100 reportFull vs es = do
101 reportSubgraphTitle vs es
102 forI (sortStrings (map showVertex vs)) (\i s -> print "* v\(i): \(s)")
104 forI (sortStrings (map showEdge es)) (\i s -> print "* e\(i): \(s)")