diff --git a/examples/multidimgraph_1d.jl b/examples/multidimgraph_1d.jl index 845c9b4..59ea353 100644 --- a/examples/multidimgraph_1d.jl +++ b/examples/multidimgraph_1d.jl @@ -2,9 +2,9 @@ using Graphs: grid, has_edge, has_vertex, ne, nv using NamedGraphs: NamedGraph using NamedGraphs.GraphsExtensions: ⊔, subgraph -ordinal_graph = grid((4,)) +one_based_graph = grid((4,)) vs = ["A", "B", "C", "D"] -g = NamedGraph(ordinal_graph, vs) +g = NamedGraph(one_based_graph, vs) @show has_vertex(g, "A") @show !has_vertex(g, "E") diff --git a/examples/multidimgraph_2d.jl b/examples/multidimgraph_2d.jl index 9ec86fb..8fdf7cd 100644 --- a/examples/multidimgraph_2d.jl +++ b/examples/multidimgraph_2d.jl @@ -2,10 +2,10 @@ using Graphs: grid, has_edge, has_vertex, nv using NamedGraphs: NamedGraph using NamedGraphs.GraphsExtensions: ⊔, subgraph -ordinal_graph = grid((2, 2)) +one_based_graph = grid((2, 2)) vs = [("X", 1), ("X", 2), ("Y", 1), ("Y", 2)] -g = NamedGraph(ordinal_graph, vs) +g = NamedGraph(one_based_graph, vs) @show has_vertex(g, ("X", 1)) @show has_edge(g, ("X", 1) => ("X", 2)) @@ -42,9 +42,9 @@ g_sub = subgraph(v -> v[2] == 2, g) @show !has_vertex(g_sub, ("Y", 1)) @show has_vertex(g_sub, ("Y", 2)) -ordinal_graph = grid((2, 2)) -g1 = NamedGraph(ordinal_graph, Tuple.(CartesianIndices((2, 2)))) -g2 = NamedGraph(ordinal_graph, Tuple.(CartesianIndices((2, 2)))) +one_based_graph = grid((2, 2)) +g1 = NamedGraph(one_based_graph, Tuple.(CartesianIndices((2, 2)))) +g2 = NamedGraph(one_based_graph, Tuple.(CartesianIndices((2, 2)))) g_disjoint_union = g1 ⊔ g2 diff --git a/ext/NamedGraphsGraphsFlowsExt/NamedGraphsGraphsFlowsExt.jl b/ext/NamedGraphsGraphsFlowsExt/NamedGraphsGraphsFlowsExt.jl index 7f3e300..f7eb9c5 100644 --- a/ext/NamedGraphsGraphsFlowsExt/NamedGraphsGraphsFlowsExt.jl +++ b/ext/NamedGraphsGraphsFlowsExt/NamedGraphsGraphsFlowsExt.jl @@ -6,14 +6,14 @@ using NamedGraphs: AbstractNamedGraph, DefaultNamedCapacity, _symmetrize, - dist_matrix_to_ordinal_dist_matrix, - ordinal_graph, - ordinal_vertex_to_vertex, - vertex_to_ordinal_vertex + dist_matrix_to_one_based_dist_matrix, + one_based_graph, + one_based_vertex_to_vertex, + vertex_to_one_based_vertex using NamedGraphs.GraphsExtensions: GraphsExtensions, directed_graph using SimpleTraits: SimpleTraits, @traitfn -@traitfn function NamedGraphs.dist_matrix_to_ordinal_dist_matrix( +@traitfn function NamedGraphs.dist_matrix_to_one_based_dist_matrix( graph::AbstractNamedGraph::IsDirected, dist_matrix::DefaultNamedCapacity ) return GraphsFlows.DefaultCapacity(graph) @@ -26,15 +26,15 @@ end capacity_matrix=DefaultNamedCapacity(graph), algorithm::GraphsFlows.AbstractFlowAlgorithm=GraphsFlows.PushRelabelAlgorithm(), ) - ordinal_part1, ordinal_part2, flow = GraphsFlows.mincut( - directed_graph(ordinal_graph(graph)), - vertex_to_ordinal_vertex(graph, source), - vertex_to_ordinal_vertex(graph, target), - dist_matrix_to_ordinal_dist_matrix(graph, capacity_matrix), + one_based_part1, one_based_part2, flow = GraphsFlows.mincut( + directed_graph(one_based_graph(graph)), + vertex_to_one_based_vertex(graph, source), + vertex_to_one_based_vertex(graph, target), + dist_matrix_to_one_based_dist_matrix(graph, capacity_matrix), algorithm, ) - (part1, part2) = map((ordinal_part1, ordinal_part2)) do ordinal_part - return map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_part) + (part1, part2) = map((one_based_part1, one_based_part2)) do one_based_part + return map(v -> one_based_vertex_to_vertex(graph, v), one_based_part) end return (part1, part2, flow) end diff --git a/src/NamedGraphs.jl b/src/NamedGraphs.jl index 23f7f15..a004a77 100644 --- a/src/NamedGraphs.jl +++ b/src/NamedGraphs.jl @@ -1,6 +1,8 @@ module NamedGraphs include("lib/SimilarType/src/SimilarType.jl") include("lib/Keys/src/Keys.jl") +include("lib/OrdinalIndexing/src/OrdinalIndexing.jl") +include("lib/OrdinalIndexedDictionaries/src/OrdinalIndexedDictionaries.jl") include("lib/GraphGenerators/src/GraphGenerators.jl") include("lib/GraphsExtensions/src/GraphsExtensions.jl") include("utils.jl") diff --git a/src/abstractnamedgraph.jl b/src/abstractnamedgraph.jl index 45148dd..682a01d 100644 --- a/src/abstractnamedgraph.jl +++ b/src/abstractnamedgraph.jl @@ -44,7 +44,7 @@ abstract type AbstractNamedGraph{V} <: AbstractGraph{V} end # Graphs.vertices(graph::AbstractNamedGraph) = not_implemented() -ordinal_graph(graph::AbstractNamedGraph) = not_implemented() +one_based_graph(graph::AbstractNamedGraph) = not_implemented() Graphs.rem_vertex!(graph::AbstractNamedGraph, vertex) = not_implemented() Graphs.add_vertex!(graph::AbstractNamedGraph, vertex) = not_implemented() @@ -52,17 +52,17 @@ Graphs.add_vertex!(graph::AbstractNamedGraph, vertex) = not_implemented() GraphsExtensions.rename_vertices(f::Function, g::AbstractNamedGraph) = not_implemented() function GraphsExtensions.permute_vertices(graph::AbstractNamedGraph, permutation) - return subgraph(graph, map(v -> ordinal_vertex_to_vertex(graph, v), permutation)) + return subgraph(graph, map(v -> one_based_vertex_to_vertex(graph, v), permutation)) end # Convert vertex to ordinal (parent) vertex -# Inverse map of `ordinal_vertex_to_vertex`. -vertex_to_ordinal_vertex(graph::AbstractNamedGraph, vertex) = not_implemented() +# Inverse map of `one_based_vertex_to_vertex`. +vertex_to_one_based_vertex(graph::AbstractNamedGraph, vertex) = not_implemented() # Convert ordinal (parent) vertex to vertex. # Use `vertices`, assumes `vertices` is indexed by a parent vertex # (a Vector for linear indexed parent vertices, a dictionary in general). -function ordinal_vertex_to_vertex(graph::AbstractNamedGraph, ordinal_vertex::Integer) +function one_based_vertex_to_vertex(graph::AbstractNamedGraph, one_based_vertex::Integer) return not_implemented() end @@ -72,14 +72,14 @@ Graphs.edgetype(graph::AbstractNamedGraph) = not_implemented() GraphsExtensions.directed_graph_type(G::Type{<:AbstractNamedGraph}) = not_implemented() GraphsExtensions.undirected_graph_type(G::Type{<:AbstractNamedGraph}) = not_implemented() -# In terms of `ordinal_graph_type` +# In terms of `one_based_graph_type` # is_directed(::Type{<:AbstractNamedGraph}) = not_implemented() GraphsExtensions.convert_vertextype(::Type, ::AbstractNamedGraph) = not_implemented() # TODO: implement as: # -# graph = set_ordinal_graph(graph, copy(ordinal_graph(graph))) +# graph = set_one_based_graph(graph, copy(one_based_graph(graph))) # graph = set_vertices(graph, copy(vertices(graph))) # # or: @@ -100,16 +100,16 @@ end # Derived interface # -ordinal_graph_type(graph::AbstractNamedGraph) = typeof(ordinal_graph(graph)) +one_based_graph_type(graph::AbstractNamedGraph) = typeof(one_based_graph(graph)) function Graphs.has_vertex(graph::AbstractNamedGraph, vertex) # TODO: `vertices` should have fast lookup! return vertex ∈ vertices(graph) end -ordinal_vertextype(graph::AbstractNamedGraph) = vertextype(ordinal_graph(graph)) +one_based_vertextype(graph::AbstractNamedGraph) = vertextype(one_based_graph(graph)) -Graphs.SimpleDiGraph(graph::AbstractNamedGraph) = SimpleDiGraph(ordinal_graph(graph)) +Graphs.SimpleDiGraph(graph::AbstractNamedGraph) = SimpleDiGraph(one_based_graph(graph)) Base.zero(G::Type{<:AbstractNamedGraph}) = G() @@ -126,32 +126,32 @@ end # Default, can overload Base.eltype(graph::AbstractNamedGraph) = eltype(vertices(graph)) -ordinal_vertices(graph::AbstractNamedGraph) = vertices(ordinal_graph(graph)) -ordinal_edges(graph::AbstractNamedGraph) = edges(ordinal_graph(graph)) -ordinal_edgetype(graph::AbstractNamedGraph) = edgetype(ordinal_graph(graph)) +one_based_vertices(graph::AbstractNamedGraph) = vertices(one_based_graph(graph)) +one_based_edges(graph::AbstractNamedGraph) = edges(one_based_graph(graph)) +one_based_edgetype(graph::AbstractNamedGraph) = edgetype(one_based_graph(graph)) -function edge_to_ordinal_edge(graph::AbstractNamedGraph, edge::AbstractEdge) - ordinal_src = vertex_to_ordinal_vertex(graph, src(edge)) - ordinal_dst = vertex_to_ordinal_vertex(graph, dst(edge)) - return ordinal_edgetype(graph)(ordinal_src, ordinal_dst) +function edge_to_one_based_edge(graph::AbstractNamedGraph, edge::AbstractEdge) + one_based_src = vertex_to_one_based_vertex(graph, src(edge)) + one_based_dst = vertex_to_one_based_vertex(graph, dst(edge)) + return one_based_edgetype(graph)(one_based_src, one_based_dst) end -function edge_to_ordinal_edge(graph::AbstractNamedGraph, edge) - return edge_to_ordinal_edge(graph, edgetype(graph)(edge)) +function edge_to_one_based_edge(graph::AbstractNamedGraph, edge) + return edge_to_one_based_edge(graph, edgetype(graph)(edge)) end -function ordinal_edge_to_edge(graph::AbstractNamedGraph, ordinal_edge::AbstractEdge) - source = ordinal_vertex_to_vertex(graph, src(ordinal_edge)) - destination = ordinal_vertex_to_vertex(graph, dst(ordinal_edge)) +function one_based_edge_to_edge(graph::AbstractNamedGraph, one_based_edge::AbstractEdge) + source = one_based_vertex_to_vertex(graph, src(one_based_edge)) + destination = one_based_vertex_to_vertex(graph, dst(one_based_edge)) return edgetype(graph)(source, destination) end -function ordinal_edge_to_edge(graph::AbstractNamedGraph, ordinal_edge) - return ordinal_edge_to_edge(graph, ordinal_edgetype(ordinal_edge)) +function one_based_edge_to_edge(graph::AbstractNamedGraph, one_based_edge) + return one_based_edge_to_edge(graph, one_based_edgetype(one_based_edge)) end function Graphs.edges(graph::AbstractNamedGraph) - return map(e -> ordinal_edge_to_edge(graph, e), ordinal_edges(graph)) + return map(e -> one_based_edge_to_edge(graph, e), one_based_edges(graph)) end # TODO: write in terms of a generic function. @@ -163,14 +163,18 @@ for f in [ ] @eval begin function $f(graph::AbstractNamedGraph, vertex) - ordinal_vertices = $f(ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex)) - return map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_vertices) + one_based_vertices = $f( + one_based_graph(graph), vertex_to_one_based_vertex(graph, vertex) + ) + return map(v -> one_based_vertex_to_vertex(graph, v), one_based_vertices) end # Ambiguity errors with Graphs.jl function $f(graph::AbstractNamedGraph, vertex::Integer) - ordinal_vertices = $f(ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex)) - return map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_vertices) + one_based_vertices = $f( + one_based_graph(graph), vertex_to_one_based_vertex(graph, vertex) + ) + return map(v -> one_based_vertex_to_vertex(graph, v), one_based_vertices) end end end @@ -223,12 +227,17 @@ end function namedgraph_neighborhood( graph::AbstractNamedGraph, vertex, d, distmx=weights(graph); dir=:out ) - ordinal_distmx = dist_matrix_to_ordinal_dist_matrix(graph, distmx) - ordinal_vertices = neighborhood( - ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex), d, ordinal_distmx; dir + one_based_distmx = dist_matrix_to_one_based_dist_matrix(graph, distmx) + one_based_vertices = neighborhood( + one_based_graph(graph), + vertex_to_one_based_vertex(graph, vertex), + d, + one_based_distmx; + dir, ) return [ - ordinal_vertex_to_vertex(graph, ordinal_vertex) for ordinal_vertex in ordinal_vertices + one_based_vertex_to_vertex(graph, one_based_vertex) for + one_based_vertex in one_based_vertices ] end @@ -253,13 +262,17 @@ function Graphs.neighborhood( end function namedgraph_neighborhood_dists(graph::AbstractNamedGraph, vertex, d, distmx; dir) - ordinal_distmx = dist_matrix_to_ordinal_dist_matrix(graph, distmx) - ordinal_vertices_and_dists = neighborhood_dists( - ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex), d, ordinal_distmx; dir + one_based_distmx = dist_matrix_to_one_based_dist_matrix(graph, distmx) + one_based_vertices_and_dists = neighborhood_dists( + one_based_graph(graph), + vertex_to_one_based_vertex(graph, vertex), + d, + one_based_distmx; + dir, ) return [ - (ordinal_vertex_to_vertex(graph, ordinal_vertex), dist) for - (ordinal_vertex, dist) in ordinal_vertices_and_dists + (one_based_vertex_to_vertex(graph, one_based_vertex), dist) for + (one_based_vertex, dist) in one_based_vertices_and_dists ] end @@ -284,9 +297,9 @@ function Graphs.neighborhood_dists( end function namedgraph_mincut(graph::AbstractNamedGraph, distmx) - ordinal_distmx = dist_matrix_to_ordinal_dist_matrix(graph, distmx) - ordinal_parity, bestcut = Graphs.mincut(ordinal_graph(graph), ordinal_distmx) - return Dictionary(vertices(graph), ordinal_parity), bestcut + one_based_distmx = dist_matrix_to_one_based_dist_matrix(graph, distmx) + one_based_parity, bestcut = Graphs.mincut(one_based_graph(graph), one_based_distmx) + return Dictionary(vertices(graph), one_based_parity), bestcut end function Graphs.mincut(graph::AbstractNamedGraph, distmx=weights(graph)) @@ -302,14 +315,14 @@ function GraphsExtensions.partitioned_vertices( graph::AbstractNamedGraph; npartitions=nothing, nvertices_per_partition=nothing, kwargs... ) vertex_partitions = partitioned_vertices( - ordinal_graph(graph); npartitions, nvertices_per_partition, kwargs... + one_based_graph(graph); npartitions, nvertices_per_partition, kwargs... ) - #[inv(vertex_to_ordinal_vertex(g))[v] for v in partitions] + #[inv(vertex_to_one_based_vertex(g))[v] for v in partitions] # TODO: output the reverse of this dictionary (a Vector of Vector # of the vertices in each partition). # return Dictionary(vertices(g), partitions) return map(vertex_partitions) do vertex_partition - return map(v -> ordinal_vertex_to_vertex(graph, v), vertex_partition) + return map(v -> one_based_vertex_to_vertex(graph, v), vertex_partition) end end @@ -321,16 +334,16 @@ function namedgraph_a_star( heuristic::Function=(v -> zero(eltype(distmx))), edgetype_to_return=edgetype(graph), ) - ordinal_distmx = dist_matrix_to_ordinal_dist_matrix(graph, distmx) - ordinal_shortest_path = a_star( - ordinal_graph(graph), - vertex_to_ordinal_vertex(graph, source), - vertex_to_ordinal_vertex(graph, destination), - dist_matrix_to_ordinal_dist_matrix(graph, distmx), + one_based_distmx = dist_matrix_to_one_based_dist_matrix(graph, distmx) + one_based_shortest_path = a_star( + one_based_graph(graph), + vertex_to_one_based_vertex(graph, source), + vertex_to_one_based_vertex(graph, destination), + dist_matrix_to_one_based_dist_matrix(graph, distmx), heuristic, SimpleEdge, ) - return map(e -> ordinal_edge_to_edge(graph, e), ordinal_shortest_path) + return map(e -> one_based_edge_to_edge(graph, e), one_based_shortest_path) end function Graphs.a_star(graph::AbstractNamedGraph, source, destination, args...) @@ -347,34 +360,34 @@ end function Graphs.spfa_shortest_paths( graph::AbstractNamedGraph, vertex, distmx=weights(graph) ) - ordinal_distmx = dist_matrix_to_ordinal_dist_matrix(graph, distmx) - ordinal_shortest_paths = spfa_shortest_paths( - ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex), ordinal_distmx + one_based_distmx = dist_matrix_to_one_based_dist_matrix(graph, distmx) + one_based_shortest_paths = spfa_shortest_paths( + one_based_graph(graph), vertex_to_one_based_vertex(graph, vertex), one_based_distmx ) - return Dictionary(vertices(graph), ordinal_shortest_paths) + return Dictionary(vertices(graph), one_based_shortest_paths) end function Graphs.boruvka_mst( g::AbstractNamedGraph, distmx::AbstractMatrix{<:Real}=weights(g); minimize=true ) - ordinal_mst, weights = boruvka_mst(ordinal_graph(g), distmx; minimize) - return map(e -> ordinal_edge_to_edge(g, e), ordinal_mst), weights + one_based_mst, weights = boruvka_mst(one_based_graph(g), distmx; minimize) + return map(e -> one_based_edge_to_edge(g, e), one_based_mst), weights end function Graphs.kruskal_mst( g::AbstractNamedGraph, distmx::AbstractMatrix{<:Real}=weights(g); minimize=true ) - ordinal_mst = kruskal_mst(ordinal_graph(g), distmx; minimize) - return map(e -> ordinal_edge_to_edge(g, e), ordinal_mst) + one_based_mst = kruskal_mst(one_based_graph(g), distmx; minimize) + return map(e -> one_based_edge_to_edge(g, e), one_based_mst) end function Graphs.prim_mst(g::AbstractNamedGraph, distmx::AbstractMatrix{<:Real}=weights(g)) - ordinal_mst = prim_mst(ordinal_graph(g), distmx) - return map(e -> ordinal_edge_to_edge(g, e), ordinal_mst) + one_based_mst = prim_mst(one_based_graph(g), distmx) + return map(e -> one_based_edge_to_edge(g, e), one_based_mst) end function Graphs.add_edge!(graph::AbstractNamedGraph, edge::AbstractEdge) - add_edge!(ordinal_graph(graph), edge_to_ordinal_edge(graph, edge)) + add_edge!(one_based_graph(graph), edge_to_one_based_edge(graph, edge)) return graph end @@ -383,12 +396,12 @@ Graphs.add_edge!(g::AbstractNamedGraph, edge) = add_edge!(g, edgetype(g)(edge)) Graphs.add_edge!(g::AbstractNamedGraph, src, dst) = add_edge!(g, edgetype(g)(src, dst)) function Graphs.rem_edge!(graph::AbstractNamedGraph, edge) - rem_edge!(ordinal_graph(graph), edge_to_ordinal_edge(graph, edge)) + rem_edge!(one_based_graph(graph), edge_to_one_based_edge(graph, edge)) return graph end function Graphs.has_edge(graph::AbstractNamedGraph, edge::AbstractNamedEdge) - return has_edge(ordinal_graph(graph), edge_to_ordinal_edge(graph, edge)) + return has_edge(one_based_graph(graph), edge_to_one_based_edge(graph, edge)) end # handles two-argument edge constructors like src,dst @@ -399,10 +412,10 @@ function Graphs.has_path( graph::AbstractNamedGraph, source, destination; exclude_vertices=vertextype(graph)[] ) return has_path( - ordinal_graph(graph), - vertex_to_ordinal_vertex(graph, source), - vertex_to_ordinal_vertex(graph, destination); - exclude_vertices=map(v -> vertex_to_ordinal_vertex(graph, v), exclude_vertices), + one_based_graph(graph), + vertex_to_one_based_vertex(graph, source), + vertex_to_one_based_vertex(graph, destination); + exclude_vertices=map(v -> vertex_to_one_based_vertex(graph, v), exclude_vertices), ) end @@ -430,16 +443,16 @@ function Base.union( return union(union(graph1, graph2), graph3, graph_rest...) end -Graphs.is_directed(G::Type{<:AbstractNamedGraph}) = is_directed(ordinal_graph_type(G)) +Graphs.is_directed(G::Type{<:AbstractNamedGraph}) = is_directed(one_based_graph_type(G)) -Graphs.is_directed(graph::AbstractNamedGraph) = is_directed(ordinal_graph(graph)) +Graphs.is_directed(graph::AbstractNamedGraph) = is_directed(one_based_graph(graph)) -Graphs.is_connected(graph::AbstractNamedGraph) = is_connected(ordinal_graph(graph)) +Graphs.is_connected(graph::AbstractNamedGraph) = is_connected(one_based_graph(graph)) -Graphs.is_cyclic(graph::AbstractNamedGraph) = is_cyclic(ordinal_graph(graph)) +Graphs.is_cyclic(graph::AbstractNamedGraph) = is_cyclic(one_based_graph(graph)) @traitfn function Base.reverse(graph::AbstractNamedGraph::IsDirected) - reversed_ordinal_graph = reverse(ordinal_graph(graph)) + reversed_one_based_graph = reverse(one_based_graph(graph)) return h end @@ -450,25 +463,25 @@ end # TODO: Move to `namedgraph.jl`, or make the output generic? function Graphs.blockdiag(graph1::AbstractNamedGraph, graph2::AbstractNamedGraph) - new_ordinal_graph = blockdiag(ordinal_graph(graph1), ordinal_graph(graph2)) + new_one_based_graph = blockdiag(one_based_graph(graph1), one_based_graph(graph2)) new_vertices = vcat(vertices(graph1), vertices(graph2)) @assert allunique(new_vertices) - return GenericNamedGraph(new_ordinal_graph, new_vertices) + return GenericNamedGraph(new_one_based_graph, new_vertices) end # TODO: What `args` are needed? -Graphs.nv(graph::AbstractNamedGraph, args...) = nv(ordinal_graph(graph), args...) +Graphs.nv(graph::AbstractNamedGraph, args...) = nv(one_based_graph(graph), args...) # TODO: What `args` are needed? -Graphs.ne(graph::AbstractNamedGraph, args...) = ne(ordinal_graph(graph), args...) +Graphs.ne(graph::AbstractNamedGraph, args...) = ne(one_based_graph(graph), args...) # TODO: What `args` are needed? function Graphs.adjacency_matrix(graph::AbstractNamedGraph, args...) - return adjacency_matrix(ordinal_graph(graph), args...) + return adjacency_matrix(one_based_graph(graph), args...) end function Graphs.connected_components(graph::AbstractNamedGraph) - ordinal_connected_components = connected_components(ordinal_graph(graph)) - return map(ordinal_connected_components) do ordinal_connected_component - return map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_connected_component) + one_based_connected_components = connected_components(one_based_graph(graph)) + return map(one_based_connected_components) do one_based_connected_component + return map(v -> one_based_vertex_to_vertex(graph, v), one_based_connected_component) end end @@ -527,8 +540,8 @@ end # Returns a Dictionary mapping a vertex to it's parent # vertex in the traversal/spanning tree. function namedgraph_bfs_parents(graph::AbstractNamedGraph, vertex; kwargs...) - ordinal_bfs_parents = bfs_parents( - ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex); kwargs... + one_based_bfs_parents = bfs_parents( + one_based_graph(graph), vertex_to_one_based_vertex(graph, vertex); kwargs... ) # Works around issue in this `Dictionary` constructor: # https://github.com/andyferris/Dictionaries.jl/blob/v0.4.1/src/Dictionary.jl#L139-L145 @@ -536,9 +549,9 @@ function namedgraph_bfs_parents(graph::AbstractNamedGraph, vertex; kwargs...) # TODO: Raise an issue with `Dictionaries.jl`. ## vertices_graph = Indices(collect(vertices(graph))) # This makes the vertices ordered according to the parent vertices. - vertices_graph = map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_vertices(graph)) + vertices_graph = map(v -> one_based_vertex_to_vertex(graph, v), one_based_vertices(graph)) return Dictionary( - vertices_graph, map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_bfs_parents) + vertices_graph, map(v -> one_based_vertex_to_vertex(graph, v), one_based_bfs_parents) ) end # Disambiguation from Graphs.jl diff --git a/src/dfs.jl b/src/dfs.jl index 8eb8eb9..ad7071e 100644 --- a/src/dfs.jl +++ b/src/dfs.jl @@ -2,7 +2,9 @@ using Graphs: Graphs, dfs_parents, dfs_tree, topological_sort_by_dfs using SimpleTraits: SimpleTraits, Not, @traitfn @traitfn function Graphs.topological_sort_by_dfs(g::AbstractNamedGraph::IsDirected) - return map(v -> ordinal_vertex_to_vertex(g, v), topological_sort_by_dfs(ordinal_graph(g))) + return map( + v -> one_based_vertex_to_vertex(g, v), topological_sort_by_dfs(one_based_graph(g)) + ) end function namedgraph_dfs_tree(graph::AbstractNamedGraph, vertex; kwargs...) @@ -18,8 +20,8 @@ end # Returns a Dictionary mapping a vertex to it's parent # vertex in the traversal/spanning tree. function namedgraph_dfs_parents(graph::AbstractNamedGraph, vertex; kwargs...) - ordinal_dfs_parents = dfs_parents( - ordinal_graph(graph), vertex_to_ordinal_vertex(graph, vertex); kwargs... + one_based_dfs_parents = dfs_parents( + one_based_graph(graph), vertex_to_one_based_vertex(graph, vertex); kwargs... ) # Works around issue in this `Dictionary` constructor: # https://github.com/andyferris/Dictionaries.jl/blob/v0.4.1/src/Dictionary.jl#L139-L145 @@ -27,9 +29,9 @@ function namedgraph_dfs_parents(graph::AbstractNamedGraph, vertex; kwargs...) # TODO: Raise an issue with `Dictionaries.jl`. ## vertices_graph = Indices(collect(vertices(graph))) # This makes the vertices ordered according to the parent vertices. - vertices_graph = map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_vertices(graph)) + vertices_graph = map(v -> one_based_vertex_to_vertex(graph, v), one_based_vertices(graph)) return Dictionary( - vertices_graph, map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_dfs_parents) + vertices_graph, map(v -> one_based_vertex_to_vertex(graph, v), one_based_dfs_parents) ) end # Disambiguation from Graphs.dfs_parents diff --git a/src/distances_and_capacities.jl b/src/distances_and_capacities.jl index ba4a3cd..4c5277a 100644 --- a/src/distances_and_capacities.jl +++ b/src/distances_and_capacities.jl @@ -31,32 +31,32 @@ end getindex_dist_matrix(dist_matrix, I...) = dist_matrix[I...] getindex_dist_matrix(dist_matrix::AbstractDictionary, I...) = dist_matrix[I] -function namedgraph_dist_matrix_to_ordinal_dist_matrix( +function namedgraph_dist_matrix_to_one_based_dist_matrix( graph::AbstractNamedGraph, dist_matrix ) - ordinal_dist_matrix = spzeros(valtype(dist_matrix), nv(graph), nv(graph)) + one_based_dist_matrix = spzeros(valtype(dist_matrix), nv(graph), nv(graph)) for e in edges(graph) - ordinal_e = edge_to_ordinal_edge(graph, e) - ordinal_dist_matrix[src(ordinal_e), dst(ordinal_e)] = getindex_dist_matrix( + one_based_e = edge_to_one_based_edge(graph, e) + one_based_dist_matrix[src(one_based_e), dst(one_based_e)] = getindex_dist_matrix( dist_matrix, src(e), dst(e) ) end - return ordinal_dist_matrix + return one_based_dist_matrix end -@traitfn function dist_matrix_to_ordinal_dist_matrix( +@traitfn function dist_matrix_to_one_based_dist_matrix( graph::AbstractNamedGraph::IsDirected, dist_matrix ) - return namedgraph_dist_matrix_to_ordinal_dist_matrix(graph, dist_matrix) + return namedgraph_dist_matrix_to_one_based_dist_matrix(graph, dist_matrix) end -@traitfn function dist_matrix_to_ordinal_dist_matrix( +@traitfn function dist_matrix_to_one_based_dist_matrix( graph::AbstractNamedGraph::(!IsDirected), dist_matrix ) - return _symmetrize(namedgraph_dist_matrix_to_ordinal_dist_matrix(graph, dist_matrix)) + return _symmetrize(namedgraph_dist_matrix_to_one_based_dist_matrix(graph, dist_matrix)) end -function dist_matrix_to_ordinal_dist_matrix( +function dist_matrix_to_one_based_dist_matrix( graph::AbstractNamedGraph, distmx::Graphs.DefaultDistance ) return distmx diff --git a/src/lib/GraphsExtensions/src/abstracttrees.jl b/src/lib/GraphsExtensions/src/abstracttrees.jl index e218b5e..d8150ca 100644 --- a/src/lib/GraphsExtensions/src/abstracttrees.jl +++ b/src/lib/GraphsExtensions/src/abstracttrees.jl @@ -1,20 +1,22 @@ # AbstractTreeGraph # Tree view of a graph. abstract type AbstractTreeGraph{V} <: AbstractGraph{V} end -ordinal_graph_type(type::Type{<:AbstractTreeGraph}) = not_implemented() -ordinal_graph(graph::AbstractTreeGraph) = not_implemented() +one_based_graph_type(type::Type{<:AbstractTreeGraph}) = not_implemented() +one_based_graph(graph::AbstractTreeGraph) = not_implemented() -Graphs.is_directed(type::Type{<:AbstractTreeGraph}) = is_directed(ordinal_graph_type(type)) -Graphs.edgetype(graph::AbstractTreeGraph) = edgetype(ordinal_graph(graph)) +function Graphs.is_directed(type::Type{<:AbstractTreeGraph}) + return is_directed(one_based_graph_type(type)) +end +Graphs.edgetype(graph::AbstractTreeGraph) = edgetype(one_based_graph(graph)) function Graphs.outneighbors(graph::AbstractTreeGraph, vertex) - return outneighbors(ordinal_graph(graph), vertex) + return outneighbors(one_based_graph(graph), vertex) end function Graphs.inneighbors(graph::AbstractTreeGraph, vertex) - return inneighbors(ordinal_graph(graph), vertex) + return inneighbors(one_based_graph(graph), vertex) end -Graphs.nv(graph::AbstractTreeGraph) = nv(ordinal_graph(graph)) -Graphs.ne(graph::AbstractTreeGraph) = ne(ordinal_graph(graph)) -Graphs.vertices(graph::AbstractTreeGraph) = vertices(ordinal_graph(graph)) +Graphs.nv(graph::AbstractTreeGraph) = nv(one_based_graph(graph)) +Graphs.ne(graph::AbstractTreeGraph) = ne(one_based_graph(graph)) +Graphs.vertices(graph::AbstractTreeGraph) = vertices(one_based_graph(graph)) # AbstractTrees using AbstractTrees: @@ -60,5 +62,5 @@ end @assert is_tree(g) return _TreeGraph(g) end -ordinal_graph(graph::TreeGraph) = getfield(graph, :graph) -ordinal_graph_type(type::Type{<:TreeGraph}) = fieldtype(type, :graph) +one_based_graph(graph::TreeGraph) = getfield(graph, :graph) +one_based_graph_type(type::Type{<:TreeGraph}) = fieldtype(type, :graph) diff --git a/src/lib/OrdinalIndexedDictionaries/src/OrdinalIndexedDictionaries.jl b/src/lib/OrdinalIndexedDictionaries/src/OrdinalIndexedDictionaries.jl new file mode 100644 index 0000000..b9198f1 --- /dev/null +++ b/src/lib/OrdinalIndexedDictionaries/src/OrdinalIndexedDictionaries.jl @@ -0,0 +1,73 @@ +module OrdinalIndexedDictionaries +using Dictionaries: Dictionaries, AbstractIndices, Dictionary, gettoken + +struct OrderedIndices{I} <: AbstractIndices{I} + ordered_indices::Vector{I} + index_ordinals::Dictionary{I,Int} + function OrderedIndices{I}(indices) where {I} + ordered_indices = collect(indices) + index_ordinals = Dictionary{I,Int}(copy(ordered_indices), undef) + for i in eachindex(ordered_indices) + index_ordinals[ordered_indices[i]] = i + end + return new{I}(ordered_indices, index_ordinals) + end +end +OrderedIndices(indices) = OrderedIndices{eltype(indices)}(indices) + +Base.@propagate_inbounds function Base.iterate(indices::OrderedIndices, state...) + return iterate(indices.ordered_indices, state...) +end +Base.length(indices::OrderedIndices) = length(indices.ordered_indices) + +# https://github.com/andyferris/Dictionaries.jl/tree/master?tab=readme-ov-file#implementing-the-token-interface-for-abstractindices +Dictionaries.istokenizable(indices::OrderedIndices) = true +Dictionaries.tokentype(indices::OrderedIndices) = Int +function Dictionaries.iteratetoken(indices::OrderedIndices, state...) + return Dictionaries.iteratetoken(keys(indices.index_ordinals), state...) +end +function Dictionaries.gettoken(indices::OrderedIndices, key) + return Dictionaries.gettoken(keys(indices.index_ordinals), key) +end +function Dictionaries.gettokenvalue(indices::OrderedIndices, token) + return Dictionaries.gettokenvalue(keys(indices.index_ordinals), token) +end +Dictionaries.isinsertable(indices::OrderedIndices) = true +function Dictionaries.gettoken!(indices::OrderedIndices{I}, key::I) where {I} + (hadtoken, token) = Dictionaries.gettoken!(indices.index_ordinals, key) + Dictionaries.settokenvalue!( + indices.index_ordinals, token, length(indices.ordered_indices) + ) + if !hadtoken + push!(indices.ordered_indices, key) + end + return (hadtoken, token) +end +function Dictionaries.deletetoken!(indices::OrderedIndices, token) + index = Dictionaries.gettokenvalue(keys(indices.index_ordinals), token) + ordinal = Dictionaries.gettokenvalue(indices.index_ordinals, token) + # Move the last vertex to the position of the deleted one. + indices.ordered_indices[ordinal] = last(indices.ordered_indices) + last_index = pop!(indices.ordered_indices) + Dictionaries.deletetoken!(indices.index_ordinals, token) + indices.index_ordinals[last_index] = ordinal + return indices +end + +using ..OrdinalIndexing: OrdinalSuffixedInteger, th +Base.@propagate_inbounds function Base.getindex( + indices::OrderedIndices, i::OrdinalSuffixedInteger +) + return indices.ordered_indices[Integer(i)] +end +Base.@propagate_inbounds function Base.setindex!( + indices::OrderedIndices, value, index::OrdinalSuffixedInteger +) + old_value = indices.ordered_indices[Integer(index)] + indices.ordered_indices[Integer(index)] = value + delete!(indices.index_ordinals, old_value) + set!(indices.index_ordinals, value, Integer(index)) + return indices +end +each_ordinal_index(indices::OrderedIndices) = (Base.OneTo(length(indices))) * th +end diff --git a/src/lib/OrdinalIndexedDictionaries/test/Project.toml b/src/lib/OrdinalIndexedDictionaries/test/Project.toml new file mode 100644 index 0000000..9b4efaf --- /dev/null +++ b/src/lib/OrdinalIndexedDictionaries/test/Project.toml @@ -0,0 +1,4 @@ +[deps] +Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" +NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/src/lib/OrdinalIndexedDictionaries/test/runtests.jl b/src/lib/OrdinalIndexedDictionaries/test/runtests.jl new file mode 100644 index 0000000..4634b5b --- /dev/null +++ b/src/lib/OrdinalIndexedDictionaries/test/runtests.jl @@ -0,0 +1,59 @@ +@eval module $(gensym()) +using Dictionaries: Dictionary +using NamedGraphs.OrdinalIndexedDictionaries: OrderedIndices, each_ordinal_index +using NamedGraphs.OrdinalIndexing: th +using Test: @test, @testset +@testset "OrderedIndices" begin + i = OrderedIndices(["x1", "x2", "x3", "x4"]) + @test i isa OrderedIndices{String} + @test length(i) == 4 + @test collect(i) == ["x1", "x2", "x3", "x4"] + @test eachindex(i) isa OrderedIndices{String} + @test keys(i) isa OrderedIndices{String} + @test issetequal(i, ["x1", "x2", "x3", "x4"]) + @test keys(i) == OrderedIndices(["x1", "x2", "x3", "x4"]) + @test issetequal(keys(i), ["x1", "x2", "x3", "x4"]) + @test i["x1"] == "x1" + @test i["x2"] == "x2" + @test i["x3"] == "x3" + @test i["x4"] == "x4" + @test i[1th] == "x1" + @test i[2th] == "x2" + @test i[3th] == "x3" + @test i[4th] == "x4" + + i = OrderedIndices(["x1", "x2", "x3", "x4"]) + delete!(i, "x2") + @test length(i) == 3 + @test collect(i) == ["x1", "x4", "x3"] + @test i["x1"] == "x1" + @test i["x3"] == "x3" + @test i["x4"] == "x4" + @test !("x2" ∈ i) + @test i[1th] == "x1" + @test i[2th] == "x4" + @test i[3th] == "x3" + @test i.ordered_indices == ["x1", "x4", "x3"] + @test i.index_ordinals == Dictionary(["x1", "x3", "x4"], [1, 3, 2]) + + i = OrderedIndices(["x1", "x2", "x3"]) + insert!(i, "x4") + @test length(i) == 4 + @test collect(i) == ["x1", "x2", "x3", "x4"] + @test i["x1"] == "x1" + @test i["x2"] == "x2" + @test i["x3"] == "x3" + @test i["x4"] == "x4" + @test i[1th] == "x1" + @test i[2th] == "x2" + @test i[3th] == "x3" + @test i[4th] == "x4" + + i = OrderedIndices(["x1", "x2", "x3"]) + ords = each_ordinal_index(i) + @test ords == (1:3)th + @test i[ords[1]] == "x1" + @test i[ords[2]] == "x2" + @test i[ords[3]] == "x3" +end +end diff --git a/src/lib/OrdinalIndexing/src/OrdinalIndexing.jl b/src/lib/OrdinalIndexing/src/OrdinalIndexing.jl new file mode 100644 index 0000000..b7b62ba --- /dev/null +++ b/src/lib/OrdinalIndexing/src/OrdinalIndexing.jl @@ -0,0 +1,120 @@ +module OrdinalIndexing +struct One <: Integer end +const 𝟏 = One() +Base.convert(type::Type{<:Number}, ::One) = one(type) +Base.promote_rule(type1::Type{One}, type2::Type{<:Number}) = type2 +Base.:(*)(x::One, y::One) = 𝟏 + +function Base.show(io::IO, ordinal::One) + return print(io, "𝟏") +end + +struct OrdinalSuffixedInteger{T<:Integer} <: Integer + cardinal::T + function OrdinalSuffixedInteger{T}(cardinal::Integer) where {T<:Integer} + cardinal ≥ 0 || throw(ArgumentError("ordinal must be > 0")) + return new{T}(cardinal) + end +end +function OrdinalSuffixedInteger(cardinal::Integer) + return OrdinalSuffixedInteger{typeof(cardinal)}(cardinal) +end +function OrdinalSuffixedInteger{T}(ordinal::OrdinalSuffixedInteger) where {T<:Integer} + return OrdinalSuffixedInteger{T}(cardinal(ordinal)) +end + +cardinal(ordinal::OrdinalSuffixedInteger) = getfield(ordinal, :cardinal) +function cardinal_type(ordinal_type::Type{<:OrdinalSuffixedInteger}) + return fieldtype(ordinal_type, :cardinal) +end + +const th = OrdinalSuffixedInteger(𝟏) +const st = th +const nd = th +const rd = th + +function Base.widen(ordinal_type::Type{<:OrdinalSuffixedInteger}) + return OrdinalSuffixedInteger{widen(cardinal_type(ordinal_type))} +end + +Base.Int(ordinal::OrdinalSuffixedInteger) = Int(cardinal(ordinal)) + +function Base.:(*)(a::OrdinalSuffixedInteger, b::Integer) + return OrdinalSuffixedInteger(cardinal(a) * b) +end +function Base.:(*)(a::Integer, b::OrdinalSuffixedInteger) + return OrdinalSuffixedInteger(a * cardinal(b)) +end +function Base.:(:)( + start::OrdinalSuffixedInteger{T}, stop::OrdinalSuffixedInteger{T} +) where {T<:Integer} + return UnitRange{OrdinalSuffixedInteger{T}}(start, stop) +end + +function Base.:(*)(a::OrdinalSuffixedInteger, b::OrdinalSuffixedInteger) + return (cardinal(a) * cardinal(b)) * th +end +function Base.:(+)(a::OrdinalSuffixedInteger, b::OrdinalSuffixedInteger) + return (cardinal(a) + cardinal(b)) * th +end +function Base.:(+)(a::OrdinalSuffixedInteger, b::Integer) + return a + b * th +end +function Base.:(+)(a::Integer, b::OrdinalSuffixedInteger) + return a * th + b +end +function Base.:(-)(a::OrdinalSuffixedInteger, b::OrdinalSuffixedInteger) + return (cardinal(a) - cardinal(b)) * th +end +function Base.:(-)(a::OrdinalSuffixedInteger, b::Integer) + return a - b * th +end +function Base.:(-)(a::Integer, b::OrdinalSuffixedInteger) + return a * th - b +end + +function Base.:(:)(a::Integer, b::OrdinalSuffixedInteger) + return (a * th):b +end + +function Base.:(<)(a::OrdinalSuffixedInteger, b::OrdinalSuffixedInteger) + return (cardinal(a) < cardinal(b)) +end +Base.:(<)(a::OrdinalSuffixedInteger, b::Integer) = (a < b * th) +Base.:(<)(a::Integer, b::OrdinalSuffixedInteger) = (a * th < b) +function Base.:(<=)(a::OrdinalSuffixedInteger, b::OrdinalSuffixedInteger) + return (cardinal(a) <= cardinal(b)) +end +Base.:(<=)(a::OrdinalSuffixedInteger, b::Integer) = (a <= b * th) +Base.:(<=)(a::Integer, b::OrdinalSuffixedInteger) = (a * th <= b) + +function Broadcast.broadcasted( + ::Broadcast.DefaultArrayStyle{1}, + ::typeof(*), + r::UnitRange, + t::OrdinalSuffixedInteger{One}, +) + return (first(r) * t):(last(r) * t) +end +function Broadcast.broadcasted( + ::Broadcast.DefaultArrayStyle{1}, + ::typeof(*), + r::Base.OneTo, + t::OrdinalSuffixedInteger{One}, +) + return Base.OneTo(last(r) * t) +end + +function Base.show(io::IO, ordinal::OrdinalSuffixedInteger) + n = cardinal(ordinal) + m = n % 10 + if m == 1 + return print(io, n, n == 11 ? "th" : "st") + elseif m == 2 + return print(io, n, n == 12 ? "th" : "nd") + elseif m == 3 + return print(io, n, n == 13 ? "th" : "rd") + end + return print(io, n, "th") +end +end diff --git a/src/lib/OrdinalIndexing/test/Project.toml b/src/lib/OrdinalIndexing/test/Project.toml new file mode 100644 index 0000000..295df54 --- /dev/null +++ b/src/lib/OrdinalIndexing/test/Project.toml @@ -0,0 +1,3 @@ +[deps] +Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" +NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19" diff --git a/src/lib/OrdinalIndexing/test/runtests.jl b/src/lib/OrdinalIndexing/test/runtests.jl new file mode 100644 index 0000000..0dbe71b --- /dev/null +++ b/src/lib/OrdinalIndexing/test/runtests.jl @@ -0,0 +1,53 @@ +@eval module $(gensym()) +using NamedGraphs.OrdinalIndexing: One, 𝟏 +using NamedGraphs.OrdinalIndexing: OrdinalSuffixedInteger, th +using Test: @test, @test_broken, @test_throws, @testset +@testset "OrdinalIndexing" begin + @testset "One" begin + @test One() === 𝟏 + @test One() == 1 + @test 𝟏 * 2 === 2 + @test 2 * 𝟏 === 2 + @test 2 + 𝟏 === 3 + @test 𝟏 + 2 === 3 + @test 2 - 𝟏 === 1 + @test 𝟏 - 2 === -1 + end + @testset "OrdinalSuffixedInteger" begin + @test th === OrdinalSuffixedInteger(𝟏) + @test 1th === OrdinalSuffixedInteger(1) + @test 2th === OrdinalSuffixedInteger(2) + @test_throws ArgumentError -1th + r = (2th):(4th) + @test r isa UnitRange{OrdinalSuffixedInteger{Int}} + @test r === (2:4)th + r = Base.OneTo(4th) + @test r isa Base.OneTo{OrdinalSuffixedInteger{Int}} + @test r === Base.OneTo(4)th + for r in ((1:4)th, Base.OneTo(4)th) + @test first(r) === 1th + @test step(r) === 1th + @test last(r) === 4th + @test length(r) === 4th + @test collect(r) == [1th, 2th, 3th, 4th] + end + @testset "$suffix1, $suffix2" for (suffix1, suffix2) in ((th, th), (th, 𝟏), (𝟏, th)) + @test 2suffix1 + 3suffix2 === 5th + @test 4suffix1 - 2suffix2 === 2th + @test 2suffix1 * 3suffix2 === 6th + @test 2suffix1 < 3suffix2 + @test !(2suffix1 < 2suffix2) + @test !(3suffix1 < 2suffix2) + @test !(2suffix1 > 3suffix2) + @test !(2suffix1 > 2suffix2) + @test 3suffix1 > 2suffix2 + @test 2suffix1 <= 3suffix2 + @test 2suffix1 <= 2suffix2 + @test !(3suffix1 <= 2suffix2) + @test !(2suffix1 >= 3suffix2) + @test 2suffix1 >= 2suffix2 + @test 3suffix1 >= 2suffix2 + end + end +end +end diff --git a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl index 93164b0..31ffd8f 100644 --- a/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/abstractpartitionedgraph.jl @@ -3,9 +3,9 @@ using Graphs: using ..NamedGraphs: NamedGraphs, AbstractNamedGraph, - ordinal_graph, - ordinal_vertex_to_vertex, - vertex_to_ordinal_vertex + one_based_graph, + one_based_vertex_to_vertex, + vertex_to_one_based_vertex using ..NamedGraphs.GraphsExtensions: GraphsExtensions, add_vertices!, rem_vertices! abstract type AbstractPartitionedGraph{V,PV} <: AbstractNamedGraph{V} end @@ -33,7 +33,7 @@ function Graphs.vertices( ) where {V<:AbstractPartitionVertex} return not_implemented() end -NamedGraphs.ordinal_graph_type(PG::Type{<:AbstractPartitionedGraph}) = not_implemented() +NamedGraphs.one_based_graph_type(PG::Type{<:AbstractPartitionedGraph}) = not_implemented() function GraphsExtensions.directed_graph_type(PG::Type{<:AbstractPartitionedGraph}) return not_implemented() end @@ -43,16 +43,16 @@ end #Functions for the abstract type Graphs.vertices(pg::AbstractPartitionedGraph) = vertices(unpartitioned_graph(pg)) -function NamedGraphs.ordinal_graph(pg::AbstractPartitionedGraph) - return ordinal_graph(unpartitioned_graph(pg)) +function NamedGraphs.one_based_graph(pg::AbstractPartitionedGraph) + return one_based_graph(unpartitioned_graph(pg)) end -function NamedGraphs.vertex_to_ordinal_vertex(pg::AbstractPartitionedGraph, vertex) - return vertex_to_ordinal_vertex(unpartitioned_graph(pg), vertex) +function NamedGraphs.vertex_to_one_based_vertex(pg::AbstractPartitionedGraph, vertex) + return vertex_to_one_based_vertex(unpartitioned_graph(pg), vertex) end -function NamedGraphs.ordinal_vertex_to_vertex( - pg::AbstractPartitionedGraph, ordinal_vertex::Integer +function NamedGraphs.one_based_vertex_to_vertex( + pg::AbstractPartitionedGraph, one_based_vertex::Integer ) - return ordinal_vertex_to_vertex(unpartitioned_graph(pg), ordinal_vertex) + return one_based_vertex_to_vertex(unpartitioned_graph(pg), one_based_vertex) end Graphs.edgetype(pg::AbstractPartitionedGraph) = edgetype(unpartitioned_graph(pg)) function Graphs.nv(pg::AbstractPartitionedGraph, pv::AbstractPartitionVertex) diff --git a/src/lib/PartitionedGraphs/src/partitionedgraph.jl b/src/lib/PartitionedGraphs/src/partitionedgraph.jl index 638ccb7..4240b23 100644 --- a/src/lib/PartitionedGraphs/src/partitionedgraph.jl +++ b/src/lib/PartitionedGraphs/src/partitionedgraph.jl @@ -52,7 +52,7 @@ function GraphsExtensions.partitioned_vertices(pg::PartitionedGraph) return getfield(pg, :partitioned_vertices) end which_partition(pg::PartitionedGraph) = getfield(pg, :which_partition) -NamedGraphs.ordinal_graph_type(PG::Type{<:PartitionedGraph}) = fieldtype(PG, :graph) +NamedGraphs.one_based_graph_type(PG::Type{<:PartitionedGraph}) = fieldtype(PG, :graph) function Graphs.vertices(pg::PartitionedGraph, partitionvert::PartitionVertex) return partitioned_vertices(pg)[parent(partitionvert)] end diff --git a/src/namedgraph.jl b/src/namedgraph.jl index c86a2b7..2b89f5c 100644 --- a/src/namedgraph.jl +++ b/src/namedgraph.jl @@ -15,34 +15,34 @@ using .GraphsExtensions: GraphsExtensions, vertextype, directed_graph_type, undirected_graph_type struct GenericNamedGraph{V,G<:AbstractSimpleGraph{Int}} <: AbstractNamedGraph{V} - ordinal_graph::G + one_based_graph::G ordered_vertices::Vector{V} - vertex_to_ordinal_vertex::Dictionary{V,Int} + vertex_to_one_based_vertex::Dictionary{V,Int} end # AbstractNamedGraph required interface. -ordinal_graph_type(G::Type{<:GenericNamedGraph}) = fieldtype(G, :ordinal_graph) -ordinal_graph(graph::GenericNamedGraph) = getfield(graph, :ordinal_graph) -function vertex_to_ordinal_vertex(graph::GenericNamedGraph, vertex) - return graph.vertex_to_ordinal_vertex[vertex] +one_based_graph_type(G::Type{<:GenericNamedGraph}) = fieldtype(G, :one_based_graph) +one_based_graph(graph::GenericNamedGraph) = getfield(graph, :one_based_graph) +function vertex_to_one_based_vertex(graph::GenericNamedGraph, vertex) + return graph.vertex_to_one_based_vertex[vertex] end -function ordinal_vertex_to_vertex(graph::GenericNamedGraph, ordinal_vertex::Integer) - return graph.ordered_vertices[ordinal_vertex] +function one_based_vertex_to_vertex(graph::GenericNamedGraph, one_based_vertex::Integer) + return graph.ordered_vertices[one_based_vertex] end # TODO: Decide what this should output. # Graphs.vertices(graph::GenericNamedGraph) = graph.ordered_vertices -Graphs.vertices(graph::GenericNamedGraph) = keys(graph.vertex_to_ordinal_vertex) +Graphs.vertices(graph::GenericNamedGraph) = keys(graph.vertex_to_one_based_vertex) function Graphs.add_vertex!(graph::GenericNamedGraph, vertex) if vertex ∈ vertices(graph) return false end - add_vertex!(graph.ordinal_graph) + add_vertex!(graph.one_based_graph) # Update the forward map push!(graph.ordered_vertices, vertex) # Update the reverse map - insert!(graph.vertex_to_ordinal_vertex, vertex, nv(graph.ordinal_graph)) + insert!(graph.vertex_to_one_based_vertex, vertex, nv(graph.one_based_graph)) return true end @@ -50,21 +50,21 @@ function Graphs.rem_vertex!(graph::GenericNamedGraph, vertex) if vertex ∉ vertices(graph) return false end - ordinal_vertex = graph.vertex_to_ordinal_vertex[vertex] - rem_vertex!(graph.ordinal_graph, ordinal_vertex) + one_based_vertex = graph.vertex_to_one_based_vertex[vertex] + rem_vertex!(graph.one_based_graph, one_based_vertex) # Insert the last vertex into the position of the vertex # that is being deleted, then remove the last vertex. last_vertex = last(graph.ordered_vertices) - graph.ordered_vertices[ordinal_vertex] = last_vertex + graph.ordered_vertices[one_based_vertex] = last_vertex last_vertex = pop!(graph.ordered_vertices) - graph.vertex_to_ordinal_vertex[last_vertex] = ordinal_vertex - delete!(graph.vertex_to_ordinal_vertex, vertex) + graph.vertex_to_one_based_vertex[last_vertex] = one_based_vertex + delete!(graph.vertex_to_one_based_vertex, vertex) return true end function GraphsExtensions.rename_vertices(f::Function, g::GenericNamedGraph) # TODO: Could be implemented as `set_vertices(g, f.(g.ordered_vertices))`. - return GenericNamedGraph(g.ordinal_graph, f.(g.ordered_vertices)) + return GenericNamedGraph(g.one_based_graph, f.(g.ordered_vertices)) end function GraphsExtensions.rename_vertices(f::Function, g::AbstractSimpleGraph) @@ -75,7 +75,7 @@ end function GraphsExtensions.convert_vertextype(vertextype::Type, graph::GenericNamedGraph) return GenericNamedGraph( - ordinal_graph(graph), convert(Vector{vertextype}, graph.ordered_vertices) + one_based_graph(graph), convert(Vector{vertextype}, graph.ordered_vertices) ) end @@ -103,47 +103,49 @@ end # Inner constructor function GenericNamedGraph{V,G}( - ordinal_graph::AbstractSimpleGraph, vertices::Vector{V} + one_based_graph::AbstractSimpleGraph, vertices::Vector{V} ) where {V,G} - @assert length(vertices) == nv(ordinal_graph) + @assert length(vertices) == nv(one_based_graph) # Need to copy the vertices here, otherwise the Dictionary uses a view of the vertices return GenericNamedGraph{V,G}( - ordinal_graph, vertices, Dictionary(copy(vertices), eachindex(vertices)) + one_based_graph, vertices, Dictionary(copy(vertices), eachindex(vertices)) ) end -function GenericNamedGraph{V,G}(ordinal_graph::AbstractSimpleGraph, vertices) where {V,G} - return GenericNamedGraph{V,G}(ordinal_graph, to_vertices(V, vertices)) +function GenericNamedGraph{V,G}(one_based_graph::AbstractSimpleGraph, vertices) where {V,G} + return GenericNamedGraph{V,G}(one_based_graph, to_vertices(V, vertices)) end -function GenericNamedGraph{V}(ordinal_graph::AbstractSimpleGraph, vertices) where {V} - return GenericNamedGraph{V,typeof(ordinal_graph)}(ordinal_graph, vertices) +function GenericNamedGraph{V}(one_based_graph::AbstractSimpleGraph, vertices) where {V} + return GenericNamedGraph{V,typeof(one_based_graph)}(one_based_graph, vertices) end function GenericNamedGraph{<:Any,G}( - ordinal_graph::AbstractSimpleGraph, vertices::Vector + one_based_graph::AbstractSimpleGraph, vertices::Vector ) where {G} - return GenericNamedGraph{eltype(vertices),G}(ordinal_graph, vertices) + return GenericNamedGraph{eltype(vertices),G}(one_based_graph, vertices) end -function GenericNamedGraph{<:Any,G}(ordinal_graph::AbstractSimpleGraph, vertices) where {G} - return GenericNamedGraph{<:Any,G}(ordinal_graph, to_vertices(vertices)) +function GenericNamedGraph{<:Any,G}( + one_based_graph::AbstractSimpleGraph, vertices +) where {G} + return GenericNamedGraph{<:Any,G}(one_based_graph, to_vertices(vertices)) end -function GenericNamedGraph{<:Any,G}(ordinal_graph::AbstractSimpleGraph) where {G} - return GenericNamedGraph{<:Any,G}(ordinal_graph, vertices(ordinal_graph)) +function GenericNamedGraph{<:Any,G}(one_based_graph::AbstractSimpleGraph) where {G} + return GenericNamedGraph{<:Any,G}(one_based_graph, vertices(one_based_graph)) end -function GenericNamedGraph(ordinal_graph::AbstractSimpleGraph, vertices::Vector) - return GenericNamedGraph{eltype(vertices)}(ordinal_graph, vertices) +function GenericNamedGraph(one_based_graph::AbstractSimpleGraph, vertices::Vector) + return GenericNamedGraph{eltype(vertices)}(one_based_graph, vertices) end -function GenericNamedGraph(ordinal_graph::AbstractSimpleGraph, vertices) - return GenericNamedGraph(ordinal_graph, to_vertices(vertices)) +function GenericNamedGraph(one_based_graph::AbstractSimpleGraph, vertices) + return GenericNamedGraph(one_based_graph, to_vertices(vertices)) end -function GenericNamedGraph(ordinal_graph::AbstractSimpleGraph) - return GenericNamedGraph(ordinal_graph, vertices(ordinal_graph)) +function GenericNamedGraph(one_based_graph::AbstractSimpleGraph) + return GenericNamedGraph(one_based_graph, vertices(one_based_graph)) end # @@ -189,23 +191,23 @@ GenericNamedGraph{<:Any,G}() where {G} = GenericNamedGraph{<:Any,G}(Any[]) GenericNamedGraph() = GenericNamedGraph(Any[]) # TODO: implement as: -# graph = set_ordinal_graph(graph, copy(ordinal_graph(graph))) +# graph = set_one_based_graph(graph, copy(one_based_graph(graph))) # graph = set_vertices(graph, copy(vertices(graph))) function Base.copy(graph::GenericNamedGraph) - return GenericNamedGraph(copy(graph.ordinal_graph), copy(graph.ordered_vertices)) + return GenericNamedGraph(copy(graph.one_based_graph), copy(graph.ordered_vertices)) end Graphs.edgetype(G::Type{<:GenericNamedGraph}) = NamedEdge{vertextype(G)} Graphs.edgetype(graph::GenericNamedGraph) = edgetype(typeof(graph)) function GraphsExtensions.directed_graph_type(G::Type{<:GenericNamedGraph}) - return GenericNamedGraph{vertextype(G),directed_graph_type(ordinal_graph_type(G))} + return GenericNamedGraph{vertextype(G),directed_graph_type(one_based_graph_type(G))} end function GraphsExtensions.undirected_graph_type(G::Type{<:GenericNamedGraph}) - return GenericNamedGraph{vertextype(G),undirected_graph_type(ordinal_graph_type(G))} + return GenericNamedGraph{vertextype(G),undirected_graph_type(one_based_graph_type(G))} end -Graphs.is_directed(G::Type{<:GenericNamedGraph}) = is_directed(ordinal_graph_type(G)) +Graphs.is_directed(G::Type{<:GenericNamedGraph}) = is_directed(one_based_graph_type(G)) # TODO: Implement an edgelist version function namedgraph_induced_subgraph(graph::AbstractGraph, subvertices) diff --git a/src/shortestpaths.jl b/src/shortestpaths.jl index 63e24fd..533b57e 100644 --- a/src/shortestpaths.jl +++ b/src/shortestpaths.jl @@ -24,11 +24,11 @@ function NamedDijkstraState(parents, dists, predecessors, pathcounts, closest_ve ) end -function ordinal_path_state_to_path_state( - graph::AbstractNamedGraph, ordinal_path_state::Graphs.DijkstraState +function one_based_path_state_to_path_state( + graph::AbstractNamedGraph, one_based_path_state::Graphs.DijkstraState ) - ordinal_path_state_parents = map(eachindex(ordinal_path_state.parents)) do i - pᵢ = ordinal_path_state.parents[i] + one_based_path_state_parents = map(eachindex(one_based_path_state.parents)) do i + pᵢ = one_based_path_state.parents[i] return iszero(pᵢ) ? i : pᵢ end # Works around issue in this `Dictionary` constructor: @@ -37,18 +37,19 @@ function ordinal_path_state_to_path_state( # TODO: Raise an issue with `Dictionaries.jl`. ## graph_vertices = Indices(collect(vertices(graph))) # This makes the vertices ordered according to the parent vertices. - graph_vertices = map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_vertices(graph)) + graph_vertices = map(v -> one_based_vertex_to_vertex(graph, v), one_based_vertices(graph)) return NamedDijkstraState( Dictionary( graph_vertices, - map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_path_state_parents), + map(v -> one_based_vertex_to_vertex(graph, v), one_based_path_state_parents), ), - Dictionary(graph_vertices, ordinal_path_state.dists), + Dictionary(graph_vertices, one_based_path_state.dists), map( - x -> map(v -> ordinal_vertex_to_vertex(graph, v), x), ordinal_path_state.predecessors + x -> map(v -> one_based_vertex_to_vertex(graph, v), x), + one_based_path_state.predecessors, ), - Dictionary(graph_vertices, ordinal_path_state.pathcounts), - map(v -> ordinal_vertex_to_vertex(graph, v), ordinal_path_state.closest_vertices), + Dictionary(graph_vertices, one_based_path_state.pathcounts), + map(v -> one_based_vertex_to_vertex(graph, v), one_based_path_state.closest_vertices), ) end @@ -59,14 +60,14 @@ function namedgraph_dijkstra_shortest_paths( allpaths=false, trackvertices=false, ) - ordinal_path_state = dijkstra_shortest_paths( - ordinal_graph(graph), - map(v -> vertex_to_ordinal_vertex(graph, v), srcs), - dist_matrix_to_ordinal_dist_matrix(graph, distmx); + one_based_path_state = dijkstra_shortest_paths( + one_based_graph(graph), + map(v -> vertex_to_one_based_vertex(graph, v), srcs), + dist_matrix_to_one_based_dist_matrix(graph, distmx); allpaths, trackvertices, ) - return ordinal_path_state_to_path_state(graph, ordinal_path_state) + return one_based_path_state_to_path_state(graph, one_based_path_state) end function Graphs.dijkstra_shortest_paths( diff --git a/src/steiner_tree.jl b/src/steiner_tree.jl index 8f58d10..dfd321b 100644 --- a/src/steiner_tree.jl +++ b/src/steiner_tree.jl @@ -4,12 +4,12 @@ using SimpleTraits: SimpleTraits, Not, @traitfn @traitfn function Graphs.steiner_tree( g::AbstractNamedGraph::(!IsDirected), term_vert, distmx=weights(g) ) - ordinal_tree = steiner_tree( - ordinal_graph(g), - map(v -> vertex_to_ordinal_vertex(g, v), term_vert), - dist_matrix_to_ordinal_dist_matrix(g, distmx), + one_based_tree = steiner_tree( + one_based_graph(g), + map(v -> vertex_to_one_based_vertex(g, v), term_vert), + dist_matrix_to_one_based_dist_matrix(g, distmx), ) return typeof(g)( - ordinal_tree, map(v -> ordinal_vertex_to_vertex(g, v), vertices(ordinal_tree)) + one_based_tree, map(v -> one_based_vertex_to_vertex(g, v), vertices(one_based_tree)) ) end diff --git a/test/Project.toml b/test/Project.toml index e96a9f3..e1ba9e3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,4 +1,5 @@ [deps] +AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" GraphsFlows = "06909019-6f44-4949-96fc-b9d9aaa02889" diff --git a/test/test_abstractnamedgraph.jl b/test/test_abstractnamedgraph.jl index f594a9d..32b1234 100644 --- a/test/test_abstractnamedgraph.jl +++ b/test/test_abstractnamedgraph.jl @@ -18,7 +18,7 @@ using Test: @test, @testset add_edge!(ng2, "A" => "C") add_edge!(ng2, "B" => "D") add_edge!(ng2, "C" => "D") - @test NamedGraphs.ordinal_graph(ng1) != NamedGraphs.ordinal_graph(ng2) + @test NamedGraphs.one_based_graph(ng1) != NamedGraphs.one_based_graph(ng2) @test ng1 == ng2 rem_edge!(ng2, "B" => "A") @test ng1 != ng2 @@ -32,7 +32,7 @@ using Test: @test, @testset add_edge!(ndg2, ("X", 1) => ("Y", 1)) add_edge!(ndg2, ("X", 2) => ("Y", 2)) add_edge!(ndg2, ("Y", 1) => ("Y", 2)) - @test NamedGraphs.ordinal_graph(ndg1) != NamedGraphs.ordinal_graph(ndg2) + @test NamedGraphs.one_based_graph(ndg1) != NamedGraphs.one_based_graph(ndg2) @test ndg1 == ndg2 rem_edge!(ndg2, ("Y", 1) => ("X", 1)) @test ndg1 != ndg2 @@ -45,7 +45,7 @@ using Test: @test, @testset add_edge!(nddg2, ("X", 1) => ("Y", 1)) add_edge!(nddg2, ("X", 2) => ("Y", 2)) add_edge!(nddg2, ("Y", 1) => ("Y", 2)) - @test NamedGraphs.ordinal_graph(nddg1) != NamedGraphs.ordinal_graph(nddg2) + @test NamedGraphs.one_based_graph(nddg1) != NamedGraphs.one_based_graph(nddg2) @test nddg1 == nddg2 rem_edge!(nddg2, ("X", 1) => ("Y", 1)) add_edge!(nddg2, ("Y", 1) => ("X", 1)) diff --git a/test/test_libs.jl b/test/test_libs.jl new file mode 100644 index 0000000..4605e94 --- /dev/null +++ b/test/test_libs.jl @@ -0,0 +1,19 @@ +@eval module $(gensym()) +using NamedGraphs: NamedGraphs +using Test: @testset +libs = [ + #:GraphGenerators, + :GraphsExtensions, + #:Keys, + #:NamedGraphGenerators, + :OrdinalIndexedDictionaries, + :OrdinalIndexing, + #:PartitionedGraphs, + #:SimilarType, +] +@testset "Test lib $lib" for lib in libs + path = joinpath(pkgdir(NamedGraphs), "src", "lib", String(lib), "test", "runtests.jl") + println("Runnint lib test $path") + include(path) +end +end diff --git a/test/test_multidimgraph.jl b/test/test_multidimgraph.jl index 25d00fc..9e83b3f 100644 --- a/test/test_multidimgraph.jl +++ b/test/test_multidimgraph.jl @@ -5,10 +5,10 @@ using NamedGraphs.GraphsExtensions: ⊔, disjoint_union, subgraph using Test: @test, @testset @testset "NamedGraph" begin - ordinal_graph = grid((2, 2)) + one_based_graph = grid((2, 2)) vertices = [("X", 1), ("X", 2), ("Y", 1), ("Y", 2)] - g = NamedGraph(ordinal_graph, vertices) + g = NamedGraph(one_based_graph, vertices) @test has_vertex(g, ("X", 1)) @test has_edge(g, ("X", 1) => ("X", 2)) @@ -91,7 +91,7 @@ using Test: @test, @testset end @testset "NamedGraph add vertices" begin - ordinal_graph = grid((2, 2)) + one_based_graph = grid((2, 2)) vertices = [("X", 1), ("X", 2), ("Y", 1), ("Y", 2)] g = NamedGraph() add_vertex!(g, ("X", 1))