Skip to content

Commit a569797

Browse files
Add VertexDataGraph and EdgeDataGraph (#121)
This point of this abstract interface is to allow the partial implementation of the `Dictionaries.jl` interface, on these graph types. 1. Adds `VertexDataGraph` and `EdgeDataGraph` as concrete subtypes of `AbstractVertexDataGraph` and `AbstractEdgeDataGraph` respectively. 2. A new interface function `insert_vertex_data` that should be overloaded if a given `AbstractVertexDataGraph` graph `isinsertable`. Like wise `insert_edge_data` for `AbstractEdgeDataGraph`. 3. The three and four argument `similar_graph(::AbstractGraph, ::Type, ::Type)`, and `similar_graph(::AbstractGraph, ::Type, ::Type, vertices)` have been removed. A subtype of `AbstractVertexDataGraph` or `AbstractEdgeDataGraph` implements a stricter indexing interface, inline with the one used by `Dictionaries.jl`, that is `setindex!` strictly sets existing indices (doesn't add a vertex/edge that isn't already in the graph). One should use `insert!` to strictly add a new vertex/edge with data, and `set!` to perform an `upsert` (previous behavior of `setindex!`. Eventually, this interface will be applied to `AbstractDataGraph`, but to avoid breaking changes this is deferred until a later date. ## New Interface For a settable and insertable vertex data graph, one must define: ```Julia set_vertex_data!(graph, vertex, data) # set the vertex data (assuming the vertex exists) insert_vertex_data!(graph, vertex, data) # insert the vertex data (assuming the vertex _does not_ exist) ``` An edge data graph only needs: ```Julia set_edge_data!(graph, edge, data) # set the edge data (assuming the required edge exists) insert_edge_data!(graph, vertex, data) # insert the edge data (assuming the edge _does not_ exist) ``` --------- Co-authored-by: Matthew Fishman <mtfishman@users.noreply.github.com>
1 parent 69a86af commit a569797

13 files changed

Lines changed: 1145 additions & 55 deletions

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "DataGraphs"
22
uuid = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a"
3-
version = "0.4.2"
3+
version = "0.5.0"
44
authors = ["Matthew Fishman <mfishman@flatironinstitute.org> and contributors"]
55

66
[workspace]
@@ -25,6 +25,6 @@ Dictionaries = "0.4"
2525
Graphs = "1"
2626
GraphsFlows = "0.1.1"
2727
ITensorVisualizationBase = "0.1"
28-
NamedGraphs = "0.11.1"
28+
NamedGraphs = "0.11.4"
2929
SimpleTraits = "0.9"
3030
julia = "1.10"

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
88
path = ".."
99

1010
[compat]
11-
DataGraphs = "0.4"
11+
DataGraphs = "0.5"
1212
Documenter = "1.10"
1313
ITensorFormatter = "0.2.27"
1414
Literate = "2.20.1"

examples/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ NamedGraphs = "678767b0-92e7-4007-89e4-4527a8725b19"
77
path = ".."
88

99
[compat]
10-
DataGraphs = "0.4"
10+
DataGraphs = "0.5"
1111
Graphs = "1.12"
1212
NamedGraphs = "0.11"

src/DataGraphs.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ include("dataview.jl")
66
include("abstractdatagraph.jl")
77
include("indexing.jl")
88
include("datagraph.jl")
9+
include("abstractedgeorvertexdatagraph.jl")
10+
include("vertexdatagraph.jl")
11+
include("edgedatagraph.jl")
912
# TODO: Turn into an extension once `PartitionedGraphs` is excised.
1013
include("lib/DataGraphsPartitionedGraphsExt/src/DataGraphsPartitionedGraphsExt.jl")
1114

src/abstractdatagraph.jl

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ using NamedGraphs.GraphsExtensions: GraphsExtensions, add_edges!, add_vertices!,
66
using NamedGraphs.OrdinalIndexing: OrdinalSuffixedInteger
77
using NamedGraphs.SimilarType: similar_type
88
using NamedGraphs: NamedGraphs, AbstractEdges, AbstractNamedEdge, AbstractNamedGraph,
9-
AbstractVertices, NamedDiGraph, NamedGraph, position_graph_type, similar_graph
9+
AbstractVertices, NamedDiGraph, NamedGraph, Vertices, position_graph_type,
10+
similar_graph, subgraph_edges
1011
using SimpleTraits: SimpleTraits, @traitfn, Not
1112

13+
struct VertexEdgeDataTypes{VD, ED}
14+
vertex_data_type::VD
15+
edge_data_type::ED
16+
end
17+
1218
abstract type AbstractDataGraph{V, VD, ED} <: AbstractNamedGraph{V} end
1319

1420
vertex_data_type(::Type{<:AbstractGraph}) = Any
@@ -21,12 +27,15 @@ edge_data_type(::Type{<:AbstractDataGraph{V, VD, ED}}) where {V, VD, ED} = ED
2127
# TODO: Define for `AbstractGraph` as a `DataGraphInterface`.
2228
underlying_graph(::AbstractDataGraph) = not_implemented()
2329

30+
# `isassigned`
2431
is_vertex_assigned(::AbstractDataGraph, vertex) = not_implemented()
2532
is_edge_assigned(::AbstractDataGraph, edge) = not_implemented()
2633

34+
# `getindex`
2735
get_vertex_data(::AbstractDataGraph, vertex) = not_implemented()
2836
get_edge_data(::AbstractDataGraph, edge) = not_implemented()
2937

38+
# `setindex!`
3039
set_vertex_data!(::AbstractDataGraph, data, vertex) = not_implemented()
3140
set_edge_data!(::AbstractDataGraph, data, edge) = not_implemented()
3241

@@ -41,12 +50,6 @@ function get_edges_data(g::AbstractGraph, edges)
4150
return map(e -> getindex(g, e), Indices(edges))
4251
end
4352

44-
Graphs.has_vertex(g::AbstractDataGraph, vertex) = has_vertex(underlying_graph(g), vertex)
45-
Graphs.has_edge(g::AbstractDataGraph, edge) = has_edge(underlying_graph(g), edge)
46-
function Graphs.has_edge(g::AbstractDataGraph, edge::AbstractNamedEdge)
47-
return has_edge(underlying_graph(g), edge)
48-
end
49-
5053
vertex_data(dg::AbstractGraph) = VertexDataView(dg)
5154
edge_data(dg::AbstractGraph) = EdgeDataView(dg)
5255

@@ -57,9 +60,7 @@ function assigned_edges(graph::AbstractGraph)
5760
return Indices(filter(e -> isassigned(graph, e), edges(graph)))
5861
end
5962

60-
function Graphs.edgetype(graph::AbstractDataGraph)
61-
return Graphs.edgetype(underlying_graph(graph))
62-
end
63+
Graphs.edgetype(graph::AbstractDataGraph) = edgetype(underlying_graph(graph))
6364
function Graphs.edgetype(graph_type::Type{<:AbstractDataGraph})
6465
return edgetype(underlying_graph_type(graph_type))
6566
end
@@ -75,9 +76,38 @@ function NamedGraphs.position_graph_type(type::Type{<:AbstractDataGraph})
7576
return position_graph_type(underlying_graph_type(type))
7677
end
7778

78-
function Base.copyto!(dst_graph::AbstractDataGraph, src_graph::AbstractDataGraph)
79-
vertex_data(dst_graph) .= vertex_data(src_graph)
80-
edge_data(dst_graph) .= edge_data(src_graph)
79+
function Base.copy(graph::AbstractDataGraph)
80+
copy_graph = similar_graph(graph)
81+
# Allow copies of graphs with undefined data.
82+
copyto!(copy_graph, graph, assigned_vertices(graph))
83+
copyto!(copy_graph, graph, assigned_edges(graph))
84+
return copy_graph
85+
end
86+
87+
# Base method to specialize on.
88+
function Base.copyto!(graph_dst::AbstractDataGraph, src, keys)
89+
for key in keys
90+
graph_dst[key] = src[key]
91+
end
92+
return graph_dst
93+
end
94+
95+
function Base.copyto!(graph_dst::AbstractDataGraph, src)
96+
copyto!_datagraph(graph_dst, src)
97+
return graph_dst
98+
end
99+
100+
# To prevent method ambiguities
101+
function copyto!_datagraph(dst::AbstractDataGraph, src::AbstractDataGraph)
102+
if !issetequal(vertices(dst), vertices(src))
103+
throw(ArgumentError("destination and source graphs must have the same vertices"))
104+
end
105+
copyto!(dst, src, vertices(src))
106+
copyto!(dst, src, edges(src))
107+
return dst
108+
end
109+
function copyto!_datagraph(dst_graph::AbstractDataGraph, src)
110+
copyto!(dst_graph, src, keys(src))
81111
return dst_graph
82112
end
83113

@@ -110,8 +140,8 @@ GraphsExtensions.convert_vertextype(::Type, ::AbstractDataGraph) = not_implement
110140

111141
function Base.:(==)(dg1::AbstractDataGraph, dg2::AbstractDataGraph)
112142
underlying_graph(dg1) == underlying_graph(dg2) || return false
113-
vertex_data(dg1) == vertex_data(dg2) || return false
114-
edge_data(dg1) == edge_data(dg2) || return false
143+
assigned_vertex_data(dg1) == assigned_vertex_data(dg2) || return false
144+
assigned_edge_data(dg1) == assigned_edge_data(dg2) || return false
115145
return true
116146
end
117147

@@ -120,21 +150,19 @@ end
120150
"""
121151
similar_graph(datagraph::AbstractDataGraph, D::Type)
122152
similar_graph(datagraph::AbstractDataGraph, D::Type, vertices)
123-
similar_graph(datagraph::AbstractDataGraph, VD::Type, ED::Type)
124-
similar_graph(datagraph::AbstractDataGraph, VD::Type, ED::Type, vertices)
153+
similar_graph(datagraph::AbstractDataGraph, D::VertexEdgeDataTypes)
154+
similar_graph(datagraph::AbstractDataGraph, D::VertexEdgeDataTypes, vertices)
125155
126156
Create an uninitialized data graph, similar to the provided `datagraph`, but with vertices
127157
defined by `vertices` and a vertex and edge data type `D`. One may also provide separate
128-
vertex and edge data types `VD` and `ED`.
158+
vertex and edge data types `VD` and `ED` by using the wrapper `VertexEdgeDataTypes(VD, ED)`.
129159
If vertices are not provided, then the graph is constructed with the same vertices and edges
130160
as the input graph.
131161
"""
132-
function NamedGraphs.similar_graph(
133-
graph::AbstractDataGraph
134-
)
135-
VD = vertex_data_type(graph)
136-
ED = edge_data_type(graph)
137-
return similar_graph(graph, VD, ED)
162+
163+
NamedGraphs.similar_graph(graph::AbstractDataGraph, D::Type) = similar_datagraph(graph, D)
164+
function NamedGraphs.similar_graph(graph::AbstractDataGraph, D::VertexEdgeDataTypes)
165+
return similar_datagraph(graph, D)
138166
end
139167

140168
function NamedGraphs.similar_graph(
@@ -143,37 +171,36 @@ function NamedGraphs.similar_graph(
143171
)
144172
VD = vertex_data_type(graph)
145173
ED = edge_data_type(graph)
146-
return similar_graph(graph, VD, ED, vertices)
147-
end
148-
function NamedGraphs.similar_graph(
149-
graph::AbstractDataGraph,
150-
D::Type
151-
)
152-
return similar_graph(graph, D, D)
174+
175+
return similar_graph(graph, VertexEdgeDataTypes(VD, ED), vertices)
153176
end
154177

178+
# Base case(s) (overload these if fallback not wanted).
155179
function NamedGraphs.similar_graph(
156180
graph::AbstractDataGraph,
157181
D::Type,
158182
vertices
159183
)
160-
return similar_graph(graph, D, D, vertices)
184+
return similar_datagraph(graph, D, D, vertices)
161185
end
162-
163186
function NamedGraphs.similar_graph(
164187
graph::AbstractDataGraph,
165-
VD::Type,
166-
ED::Type
188+
D::VertexEdgeDataTypes,
189+
vertices
167190
)
168-
new_graph = similar_graph(graph, VD, ED, vertices(graph))
191+
return similar_datagraph(graph, D.vertex_data_type, D.edge_data_type, vertices)
192+
end
193+
194+
# Internal implementation functions,
195+
function similar_datagraph(graph::AbstractGraph, D)
196+
new_graph = similar_graph(graph, D, vertices(graph))
169197
add_edges!(new_graph, edges(graph))
170198

171199
return new_graph
172200
end
173201

174-
# Base case(s) (overload these if fallback not wanted).
175-
@traitfn function NamedGraphs.similar_graph(
176-
graph::AbstractDataGraph::(!IsDirected),
202+
@traitfn function similar_datagraph(
203+
graph::AbstractGraph::(!IsDirected),
177204
VD::Type,
178205
ED::Type,
179206
vertices
@@ -182,8 +209,8 @@ end
182209

183210
return DataGraph(underlying_graph; vertex_data_type = VD, edge_data_type = ED)
184211
end
185-
@traitfn function NamedGraphs.similar_graph(
186-
graph::AbstractDataGraph::IsDirected,
212+
@traitfn function similar_datagraph(
213+
graph::AbstractGraph::IsDirected,
187214
VD::Type,
188215
ED::Type,
189216
vertices

0 commit comments

Comments
 (0)