@@ -16,7 +16,7 @@ Regarding incident classes:
1616 - Symmetric: reflexive + edges are undirected ('a' points to 'b' => 'b' points to 'a').
1717 In this *bidirectional* situation: the number of edges
1818 is the number of conceptual *undirected* edges,
19- And their order is the row-wise lower triangular only: (source < = target) pairs.
19+ And their order is the row-wise lower triangular only: (source > = target) pairs.
2020
2121Regarding edges density:
2222
@@ -82,7 +82,7 @@ export edges
8282"""
8383Obtain a nested iterable over edges:
8484first level are sources, second level are their incident targets and edges.
85- Collecting the two levels yields [(source, [(target, edge), ..]), ..]
85+ Collecting the two levels yields [(source, [(target, edge), ..]), ..].
8686Raise flag to skip over sources with no targets.
8787"""
8888forward(:: Topology ; skip = false ) = throw(" unimplemented" )
@@ -91,12 +91,47 @@ export forward
9191"""
9292Obtain a nested iterable over edges:
9393first level are targets, second level are their incident sources and edges.
94- Collecting the two levels yields [(target, [(source, edge), ..]), ..]
94+ Collecting the two levels yields [(target, [(source, edge), ..]), ..].
9595Raise flag to skip over targets with no sources.
9696"""
9797backward(:: Topology ; skip = false ) = throw(" unimplemented" )
9898export backward
9999
100+ # -------------------------------------------------------------------------------------------
101+ # Extend interface for constrained topologies.
102+ """
103+ A 'square' topology within one class, both source and target of the web.
104+ """
105+ abstract type ReflexiveTopology <: Topology end
106+ """
107+ A 'bidirectional' reflexive topology:
108+ if a targets b then b targets a, and this only counts for one edge.
109+ """
110+ abstract type SymmetricTopology <: ReflexiveTopology end
111+
112+ """
113+ Obtain the number of nodes in the topology.
114+ """
115+ n_nodes(:: ReflexiveTopology ) = throw(" unimplemented" )
116+ export n_nodes
117+
118+ """
119+ Obtain neighbours in a symmetric topology, neither/both targets or/and sources.
120+ """
121+ neighbours(:: SymmetricTopology , :: Int ) = throw(" unimplemented" )
122+ neighbours_nodes(:: SymmetricTopology , :: Int ) = throw(" unimplemented" )
123+ neighbours_edges(:: SymmetricTopology , :: Int ) = throw(" unimplemented" )
124+ n_neighbours(:: SymmetricTopology , :: Int ) = throw(" unimplemented" )
125+ export neighbours, neighbour_nodes, neighbour_edges, n_neighbours
126+
127+ """
128+ Obtain a nested iterable over neighbours and edges like 'forward' or 'backward'.
129+ Lower 'upper' flag to skip over duplicate edges and yield only lower-triangular ones,
130+ with (source >= target).
131+ """
132+ adjacency(:: SymmetricTopology ; skip = false , upper = true ) = throw(" unimplemented" )
133+ export adjacency
134+
100135Map = OrderedDict{Int,Int} # Used by the sparse variants.
101136vecmap(n:: Int ) = [Map() for _ in 1 : n]
102137
@@ -181,7 +216,7 @@ function SparseForeign(m::AbstractMatrix{Bool})
181216end
182217
183218# ==========================================================================================
184- struct SparseReflexive <: Topology
219+ struct SparseReflexive <: ReflexiveTopology
185220 # [node: ({source: edge}, {target: edge})]
186221 nodes:: Vector{Tuple{Map,Map}}
187222 n_edges:: Int
@@ -220,10 +255,8 @@ backward(s::S; skip = false) =
220255 end ))
221256 end
222257
223- # -------------------------------------------------------------------------------------------
224- # Extra dedicated interface.
258+ # Duties to ReflexiveTopology.
225259n_nodes(s:: S ) = length(s. nodes)
226- export n_nodes
227260
228261# -------------------------------------------------------------------------------------------
229262# Construct.
@@ -266,7 +299,7 @@ function SparseReflexive(m::AbstractMatrix{Bool})
266299end
267300
268301# ==========================================================================================
269- struct SparseSymmetric <: Topology
302+ struct SparseSymmetric <: SymmetricTopology
270303 nodes:: Vector{Map} # [node: {neighbour: edge}]
271304 n_edges:: Int
272305end
@@ -293,9 +326,10 @@ edges(s::S) =
293326forward(s:: S ; skip = false ) = adjacency(s; skip)
294327backward(s:: S ; skip = false ) = adjacency(s; skip)
295328
296- # -------------------------------------------------------------------------------------------
297- # Extra dedicated interface.
329+ # Duties to ReflexiveTopology.
298330n_nodes(s:: S ) = length(s. nodes)
331+
332+ # Duties to SymmetricTopology.
299333neighbours(s:: S , src:: Int ) = I. map(p -> (first(p), last(p)), s. nodes[src])
300334neighbour_nodes(s:: S , src:: Int ) = I. map(first, neighbours(s, src))
301335neighbour_edges(s:: S , src:: Int ) = I. map(last, neighbours(s, src))
@@ -312,7 +346,6 @@ adjacency(s::S; skip = false, upper = true) =
312346 end ,
313347 ))
314348 end
315- export neighbours, neighbour_nodes, neighbour_edges, n_neighbours, adjacency
316349
317350# -------------------------------------------------------------------------------------------
318351# Construct.
@@ -351,3 +384,34 @@ function SparseSymmetric(m::AbstractMatrix{Bool})
351384 end
352385 SparseSymmetric(nodes, n_edges)
353386end
387+
388+ # ==========================================================================================
389+ struct FullForeign <: Topology
390+ n_sources:: Int
391+ n_targets:: Int
392+ end
393+ export FullForeign
394+
395+ S = FullForeign # "Self"
396+ n_sources(s:: S ) = s. n_sources
397+ n_targets(s:: S ) = s. n_targets
398+ targets(s:: S , :: Int ) = 1 : n_targets(s)
399+ sources(s:: S , :: Int ) = 1 : n_sources(s)
400+ n_sources(s:: S , :: Int ) = n_sources(s)
401+ n_targets(s:: S , :: Int ) = n_targets(s)
402+ is_edge(:: S , :: Int , :: Int ) = true # Assuming correct input.
403+ n_edges(s:: S ) = n_sources(s) * n_targets(s)
404+ edge(s:: S , src:: Int , tgt:: Int ) = (src - 1 ) * n_targets(s) + tgt
405+ edges(s:: S ) = ((src, tgt) for src in 1 : n_sources(s) for tgt in 1 : n_targets(s))
406+ forward(s:: S ; skip = false ) =
407+ I. map(1 : n_sources(s)) do src
408+ (src, I. map(1 : n_targets(s)) do tgt
409+ (tgt, edge(s, src, tgt))
410+ end )
411+ end
412+ backward(s:: S ; skip = false ) =
413+ I. map(1 : n_targets(s)) do tgt
414+ (tgt, I. map(1 : n_sources(s)) do src
415+ (src, edge(s, src, tgt))
416+ end )
417+ end
0 commit comments