Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "DataGraphs"
uuid = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a"
version = "0.3.17"
version = "0.4.0"
authors = ["Matthew Fishman <mfishman@flatironinstitute.org> and contributors"]

[workspace]
Expand All @@ -22,6 +22,6 @@ DataGraphsGraphsFlowsExt = "GraphsFlows"
Dictionaries = "0.4"
Graphs = "1"
GraphsFlows = "0.1.1"
NamedGraphs = "0.10"
NamedGraphs = "0.11"
SimpleTraits = "0.9"
julia = "1.7"
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
path = ".."

[compat]
DataGraphs = "0.3"
DataGraphs = "0.4"
Documenter = "1.10"
ITensorFormatter = "0.2.27"
Literate = "2.20.1"
4 changes: 2 additions & 2 deletions examples/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19"
path = ".."

[compat]
DataGraphs = "0.3"
DataGraphs = "0.4"
Graphs = "1.12"
NamedGraphs = "0.10"
NamedGraphs = "0.11, 0.10"
15 changes: 13 additions & 2 deletions ext/DataGraphsGraphsFlowsExt/DataGraphsGraphsFlowsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ module DataGraphsGraphsFlowsExt
using DataGraphs: AbstractDataGraph, underlying_graph
using GraphsFlows: GraphsFlows

function GraphsFlows.mincut(graph::AbstractDataGraph, args...; kwargs...)
return GraphsFlows.mincut(underlying_graph(graph), args...; kwargs...)
function GraphsFlows.mincut(
graph::AbstractDataGraph,
source_vertex,
target_vertex;
kwargs...
)
return GraphsFlows.mincut(
underlying_graph(graph),
source_vertex,
target_vertex;
kwargs...
)
end

end
167 changes: 153 additions & 14 deletions src/abstractdatagraph.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
using Dictionaries: Indices, set!, unset!
using Graphs: Graphs, AbstractEdge, IsDirected, a_star, add_edge!, add_vertex!, edges, ne,
nv, steiner_tree, vertices
using Graphs: Graphs, AbstractEdge, IsDirected, a_star, add_edge!, add_vertex!, edges,
indegree, ne, nv, outdegree, steiner_tree, vertices
using NamedGraphs.GraphsExtensions: GraphsExtensions, add_vertices!, arrange_edge,
incident_edges, is_edge_arranged, similar_graph, vertextype
using NamedGraphs.OrdinalIndexing: OrdinalSuffixedInteger
using NamedGraphs.SimilarType: similar_type
using NamedGraphs: NamedGraphs, AbstractEdges, AbstractNamedEdge, AbstractNamedGraph,
AbstractVertices, position_graph_type
AbstractVertices, NamedGraph, position_graph_type
using SimpleTraits: SimpleTraits, @traitfn, Not

is_underlying_graph(::Type{<:AbstractNamedGraph}) = true

abstract type AbstractDataGraph{V, VD, ED} <: AbstractNamedGraph{V} end

vertex_data_type(::Type{<:AbstractGraph}) = Any
Expand Down Expand Up @@ -104,8 +102,153 @@ GraphsExtensions.directed_graph_type(::AbstractDataGraph) = not_implemented()
GraphsExtensions.undirected_graph_type(::AbstractDataGraph) = not_implemented()

# Thase canot be implemented abstractly.
function GraphsExtensions.convert_vertextype(vertextype::Type, graph::AbstractDataGraph)
return not_implemented()
GraphsExtensions.convert_vertextype(::Type, ::AbstractDataGraph) = not_implemented()

# =================================== `similar_graph` ==================================== #

# Construct a similar `AbstractDataGraph` with `vertices` and `edges`.
function GraphsExtensions.similar_graph(
graph::AbstractDataGraph,
vertices,
edges
)
new_underlying_graph = similar_graph(underlying_graph(graph), vertices, edges)
return similar_graph(graph, new_underlying_graph)
end

# Construct `graph_type` with `vertices` and `edges`.
function GraphsExtensions.similar_graph(
graph_type::Type{<:AbstractDataGraph},
vertices,
edges
)
underlying_graph = similar_graph(underlying_graph_type(graph_type), vertices, edges)
return similar_graph(graph_type, underlying_graph)
end

# Construct a similar `AbstractDataGraph` defined by an `underlying_graph_type` with
# `vertex_data_type` and `edge_data_type`.
function GraphsExtensions.similar_graph(
graph::AbstractDataGraph,
underlying_graph_type::Type{<:AbstractGraph},
vertex_data_type,
edge_data_type
)
underlying_graph = similar_graph(underlying_graph_type, vertices(graph), edges(graph))
return similar_graph(graph, underlying_graph, vertex_data_type, edge_data_type)
end
function GraphsExtensions.similar_graph(
graph::AbstractDataGraph,
underlying_graph_type::Type{<:AbstractGraph}
)
underlying_graph = similar_graph(underlying_graph_type, vertices(graph), edges(graph))
return similar_graph(graph, underlying_graph_type)
end

# Construct a similar `AbstractDataGraph` defined by `underlying_graph` with `vertex_data_type` and `edge_data_type`.
# To be specialized (has fallback).
"""
similar_graph(datagraph::AbstractDataGraph, graph::AbstractGraph, [VD=vertex_data_type(datagraph), ED=edge_data_type(datagraph)])
similar_graph(datagraph::AbstractDataGraph, G, [VD=vertex_data_type(datagraph), ED=edge_data_type(datagraph)])

Create an uninitialized data graph, similar to the provided `datagraph`, but with underlying
graph defined by `graph`. If instead a type `G` is given as the second argument,
then an empty underlying graph is first constructed using `graph = similar_graph(G)`.
Optionally, one may specify the vertex and edge data types, which default to those of the
provided source `datagraph`.

Custom `AbstractDataGraph` subtypes may specialize on first method (either the two or four argument version)
to choose the return type of the resulting graph, based on the arguments.
If they do not specialize on this method, then the default is
`DataGraph(graph; vertex_data_type, edge_data_type)`.
"""
function GraphsExtensions.similar_graph(
::AbstractDataGraph,
underlying_graph::AbstractGraph,
vertex_data_type,
edge_data_type
)
return DataGraph(underlying_graph; vertex_data_type, edge_data_type)
end
function GraphsExtensions.similar_graph(
graph::AbstractDataGraph,
underlying_graph::AbstractGraph
)
VD = vertex_data_type(graph)
ED = edge_data_type(graph)
return similar_graph(graph, underlying_graph, VD, ED)
end

# Construct a subtype of `graph_type` with an empty underlying_graph of type `underlying_graph_type`
# and `vertex_data_type` and `edge_data_type`.
function GraphsExtensions.similar_graph(
graph_type::Type{<:AbstractDataGraph},
underlying_graph_type::Type{<:AbstractGraph},
vertex_data_type,
edge_data_type
)
underlying_graph = similar_graph(underlying_graph_type)
return similar_graph(graph_type, underlying_graph, vertex_data_type, edge_data_type)
end
function GraphsExtensions.similar_graph(
graph_type::Type{<:AbstractDataGraph},
underlying_graph_type::Type{<:AbstractGraph}
)
underlying_graph = similar_graph(underlying_graph_type)
return similar_graph(graph_type, underlying_graph)
end

# Construct a subtype of `graph_type` defined by `underlying_graph` with `vertex_data_type` and `edge_data_type`.
# To be specialized if `graph_type` doesn't have the appropriate constructor. One can
# specialize on either the two or four argument method.
"""
similar_graph(DG::Type{<:AbstractDataGraph}, graph::AbstractGraph)
similar_graph(DG::Type{<:AbstractDataGraph}, graph::AbstractGraph, VD, ED)

similar_graph(DG::Type{<:AbstractDataGraph}, G)
similar_graph(DG::Type{<:AbstractDataGraph}, G, VD, ED)

Create an uninitialized data graph that acts like the specified data graph type
`DG`, but with underlying graph defined by `graph`.
If instead a type `G` is given as the second argument, then
an empty underlying graph is first constructed using `graph = similar_graph(G)`.
Optionally, one may also specify the vertex and edge data types of the resulting data graph.

By default, calls the constructors `DG(graph)` and `DG(graph, VD, ED)` respectively.
A given custom `AbstractDataGraph` subtype may specialize on the first two methods above
(in terms a graph `graph`) if such constructors do not exist for that subtype.
"""
function GraphsExtensions.similar_graph(
graph_type::Type{<:AbstractDataGraph},
underlying_graph::AbstractGraph,
vertex_data_type,
edge_data_type
)
return graph_type(underlying_graph, vertex_data_type, edge_data_type)
end
function GraphsExtensions.similar_graph(
graph_type::Type{<:AbstractDataGraph},
underlying_graph::AbstractGraph
)
return graph_type(underlying_graph)
end

# Set the underlying graph of a data graph, preserving data. Graphs must match.
function set_underlying_graph(datagraph::AbstractDataGraph, graph::AbstractGraph)
if vertices(datagraph) != vertices(graph) || edges(datagraph) != edges(graph)
throw(
ArgumentError(
"New underlying graph must have the same vertices and edges as the data graph"
)
)
end

new_datagraph = similar_graph(datagraph, graph)

vertex_data(new_datagraph) .= vertex_data(datagraph)
edge_data(new_datagraph) .= edge_data(datagraph)

return new_datagraph
end

# Fix for ambiguity error with `AbstractGraph` version
Expand Down Expand Up @@ -157,7 +300,7 @@ function reverse_data_direction(graph::AbstractDataGraph, edge::AbstractEdge, da
end

@traitfn function GraphsExtensions.directed_graph(graph::AbstractDataGraph::(!IsDirected))
digraph = directed_graph(typeof(graph))(directed_graph(underlying_graph(graph)))
digraph = similar_graph(graph, directed_graph(underlying_graph(graph)))
for v in vertices(graph)
# TODO: Only loop over `keys(vertex_data(graph))`
if isassigned(graph, v)
Expand All @@ -178,12 +321,9 @@ end
end

function GraphsExtensions.rename_vertices(f::Function, graph::AbstractDataGraph)

# Uses the two-argument `similar_graph` method so the new graph has correct vertex type
renamed_vertices = map(f, vertices(graph))
renamed_graph = similar_graph(graph, eltype(renamed_vertices))

add_vertices!(renamed_graph, renamed_vertices)
renamed_graph = similar_graph(graph, renamed_vertices)

for vertex in vertices(graph)
if isassigned(graph, vertex)
Expand All @@ -203,9 +343,8 @@ function GraphsExtensions.rename_vertices(f::Function, graph::AbstractDataGraph)
end

function Base.reverse(graph::AbstractDataGraph)
reversed_graph = similar_graph(graph)
reversed_graph = similar_graph(graph, vertices(graph))
for v in vertices(graph)
add_vertex!(reversed_graph, v)
if isassigned(graph, v)
reversed_graph[v] = graph[v]
end
Expand Down
39 changes: 24 additions & 15 deletions src/datagraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,37 @@ edge_data_type(G::Type{<:DataGraph}) = eltype(fieldtype(G, :edge_data))

# Extras

function GraphsExtensions.similar_graph(T::Type{<:DataGraph})
similar_underlying_graph = similar_graph(underlying_graph_type(T))
return T(similar_underlying_graph)
# Overwrite the `AbstractDataGraph` fallback (even though they coincide for `DataGraph`)
function GraphsExtensions.similar_graph(
::DataGraph,
underlying_graph::AbstractGraph,
vertex_data_type,
edge_data_type
)
return similar_graph(DataGraph, underlying_graph, vertex_data_type, edge_data_type)
end
function GraphsExtensions.similar_graph(dg::DataGraph, underlying_graph::AbstractGraph)
return DataGraph(
underlying_graph;
vertex_data_type = vertex_data_type(dg),
edge_data_type = edge_data_type(dg)

# Constructor method needs overwritten.
function GraphsExtensions.similar_graph(
T::Type{<:DataGraph},
underlying_graph::AbstractGraph,
vertex_data_type = vertex_data_type(T),
edge_data_type = edge_data_type(T)
)
return T(underlying_graph; vertex_data_type, edge_data_type)
end

function Base.copy(graph::DataGraph)
# Need to manually copy the keys of Dictionaries, see:
# https://github.com/andyferris/Dictionaries.jl/issues/98
return _DataGraph(
copy(underlying_graph(graph)), copy(vertex_data(graph)), copy(edge_data(graph))
copy(graph.underlying_graph), copy(graph.vertex_data), copy(graph.edge_data)
)
end

function DataGraph{V}(
underlying_graph::AbstractGraph; vertex_data_type::Type = Any,
underlying_graph::AbstractGraph;
vertex_data_type::Type = Any,
edge_data_type::Type = Any
) where {V}
converted_underlying_graph = convert_vertextype(V, underlying_graph)
Expand Down Expand Up @@ -107,12 +116,12 @@ DataGraph{V}(graph::DataGraph{V}) where {V} = copy(graph)
function DataGraph{V}(graph::DataGraph) where {V}
# TODO: Make sure this properly copies
converted_underlying_graph = convert_vertextype(V, underlying_graph(graph))
converted_vertex_data = Dictionary{V}(vertex_data(graph))
# This doesn't convert properly.
# converted_edge_data = Dictionary{edgetype(converted_underlying_graph)}(edge_data(graph))
converted_vertex_data = Dictionary{V}(assigned_vertex_data(graph))

old_edge_data = assigned_edge_data(graph)
converted_edge_data = Dictionary(
edgetype(converted_underlying_graph).(keys(edge_data(graph))),
values(edge_data(graph))
edgetype(converted_underlying_graph).(keys(old_edge_data)),
collect(old_edge_data)
)
return _DataGraph(
converted_underlying_graph,
Expand Down
12 changes: 5 additions & 7 deletions src/dataview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,15 @@ function Base.isassigned(view::EdgeDataView, key::Pair)
end

Base.getindex(view::VertexOrEdgeDataView{K}, key::K) where {K} = _getindex(view, key)
function Base.getindex(view::VertexOrEdgeDataView, key)
return _getindex(view, to_graph_index(view.graph, key))
end
Base.getindex(view::VertexOrEdgeDataView, key) = _getindex(view, key)

function _getindex(view::VertexDataView, key)
key in keys(view) || throw(IndexError("VertexDataView does not contain index: $key"))
return get_vertex_data(view.graph, key)
isassigned(view, key) || throw(IndexError("VertexDataView does not contain index $key"))
return getindex(view.graph, key)
end
function _getindex(view::EdgeDataView, key)
key in keys(view) || throw(IndexError("EdgeDataView does not contain index: $key"))
return get_edge_data(view.graph, key)
isassigned(view, key) || throw(IndexError("EdgeDataView does not contain index $key"))
return getindex(view.graph, key)
end

# Support indexing with `Indices`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module DataGraphsPartitionedGraphsExt
using ..DataGraphs: AbstractDataGraph, DataGraph, DataGraphs, _DataGraph, _getindex,
edge_data, edgetype, get_edge_data, get_edges_data, get_index_data, get_vertex_data,
get_vertices_data, is_edge_assigned, is_graph_index_assigned, is_vertex_assigned,
set_edge_data!, set_edges_data!, set_index_data!, set_vertex_data!, set_vertices_data!,
underlying_graph, vertex_data
using ..DataGraphs: AbstractDataGraph, DataGraph, DataGraphs, IsUnderlyingGraph, _DataGraph,
_getindex, edge_data, edgetype, get_edge_data, get_edges_data, get_index_data,
get_vertex_data, get_vertices_data, is_edge_assigned, is_graph_index_assigned,
is_underlying_graph, is_vertex_assigned, set_edge_data!, set_edges_data!,
set_index_data!, set_vertex_data!, set_vertices_data!, underlying_graph, vertex_data
using Dictionaries: Dictionary, IndexError, Indices
using Graphs: Graphs, AbstractEdge, AbstractGraph, edges, vertices
using NamedGraphs.GraphsExtensions:
Expand All @@ -14,10 +14,11 @@ using NamedGraphs.PartitionedGraphs: AbstractPartitionedGraph, PartitionedGraph,
QuotientVertexSlice, QuotientVertexVertex, QuotientVertexVertices, QuotientVertices,
QuotientVerticesVertices, QuotientView, departition, has_quotientedge,
has_quotientvertex, parent_graph_type, partitioned_vertices, partitionedgraph,
quotient_graph, quotient_graph_vertextype, quotientedges, quotientvertex,
quotientvertices, unpartitioned_graph
quotient_graph, quotient_graph_type, quotientedges, quotientvertex, quotientvertices,
unpartitioned_graph
using NamedGraphs:
NamedGraphs, Edges, Vertices, get_graph_index, to_edges, to_graph_index, to_vertices
using SimpleTraits: SimpleTraits, @traitfn, Not

# ======================== DataGraphs interface for QuotientView ========================= #

Expand Down Expand Up @@ -50,7 +51,14 @@ function DataGraphs.set_edge_data!(qv::QuotientView, val, e)
return qv
end

DataGraphs.underlying_graph(qv::QuotientView) = underlying_graph(copy(qv))
function DataGraphs.is_underlying_graph(qv::Type{<:QuotientView})
return is_underlying_graph(quotient_graph_type(qv))
end

@traitfn DataGraphs.underlying_graph(qv::QuotientView::IsUnderlyingGraph) = copy(qv)
@traitfn function DataGraphs.underlying_graph(qv::QuotientView::(!IsUnderlyingGraph))
return underlying_graph(copy(qv))
end

function Base.isassigned(qv::QuotientView, ind)
return DataGraphs.isassigned_datagraph(qv, to_graph_index(qv, ind))
Expand Down
Loading