Skip to content

Commit 07d60a0

Browse files
committed
initial graph properties API support
1 parent a41fa39 commit 07d60a0

File tree

7 files changed

+121
-0
lines changed

7 files changed

+121
-0
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ This gives users the option of reusing memory and improving performance.
7070

7171
- If the algorithm was presented in a paper, include a reference to the paper (_e.g._, a proper academic citation along with an eprint link).
7272

73+
- When implementing a new graph invariant, just add a method to `graph_property`, instead of exporting a new function. If necessary, also add the property to GraphProperties.jl.
74+
7375
## Git(Hub) usage
7476

7577
### Getting started on a package contribution

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ version = "1.13.1"
66
ArnoldiMethod = "ec485272-7323-5ecc-a04f-4719b315124d"
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
88
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
9+
GraphProperties = "bbdf290f-6e15-4dc1-adeb-6e1d1446781e"
910
Inflate = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
1011
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1112
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
@@ -18,6 +19,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1819
ArnoldiMethod = "0.4"
1920
Distributed = "1"
2021
DataStructures = "0.18, 0.19"
22+
GraphProperties = "1"
2123
Inflate = "0.1.3"
2224
LinearAlgebra = "1"
2325
Random = "1"

src/Graphs.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import Base:
6969
Pair,
7070
Tuple,
7171
zero
72+
using GraphProperties: GraphProperties, GraphProperty
7273

7374
export
7475
# Interface
@@ -434,6 +435,9 @@ export
434435
# vertexcover
435436
vertex_cover,
436437

438+
# graphproperties
439+
graph_property,
440+
437441
# longestpaths
438442
dag_longest_path
439443

@@ -548,6 +552,7 @@ include("biconnectivity/biconnect.jl")
548552
include("biconnectivity/bridge.jl")
549553
include("graphcut/normalized_cut.jl")
550554
include("graphcut/karger_min_cut.jl")
555+
include("graphproperties.jl")
551556
include("dominatingset/degree_dom_set.jl")
552557
include("dominatingset/minimal_dom_set.jl")
553558
include("independentset/degree_ind_set.jl")

src/graphproperties.jl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
graph_property(graph::AbstractGraph, property_specification::GraphProperty{T}, [options = nothing])::Union{Nothing,Some{<:T}}
3+
4+
Get the graph property specified by `property_specification` of the graph `graph`.
5+
6+
Only some properties are implemented currently.
7+
8+
A `nothing` return value may be returned in some cases, such as when a time limit specified in `options` was reached.
9+
10+
Third-party packages may add methods. Only add three-argument methods, and only if you own the third argument, `options`.
11+
"""
12+
function graph_property end
13+
14+
function graph_property(graph::AbstractGraph, prop_spec::GraphProperty)
15+
return graph_property(graph, prop_spec, nothing)
16+
end
17+
18+
function graph_property(graph::AbstractGraph, ::GraphProperties.NumberOfVertices, ::Nothing)
19+
return Some(nv(graph))
20+
end
21+
22+
function graph_property(graph::AbstractGraph, ::GraphProperties.DegreeSequence, ::Nothing)
23+
if is_directed(graph)
24+
throw(ArgumentError("expected undirected graph"))
25+
end
26+
return Some(sort(degree(graph)))
27+
end
28+
29+
function graph_property(graph::AbstractGraph, ::GraphProperties.NumberOfEdges, ::Nothing)
30+
if is_directed(graph)
31+
throw(ArgumentError("expected undirected graph"))
32+
end
33+
return Some(ne(graph))
34+
end
35+
36+
function graph_property(graph::AbstractGraph, ::GraphProperties.NumberOfArcs, ::Nothing)
37+
if !is_directed(graph)
38+
throw(ArgumentError("expected directed graph"))
39+
end
40+
return Some(ne(graph))
41+
end
42+
43+
function graph_property(
44+
graph::AbstractGraph, ::GraphProperties.NumberOfConnectedComponents, ::Nothing
45+
)
46+
if is_directed(graph)
47+
throw(ArgumentError("expected undirected graph"))
48+
end
49+
# TODO: performance: avoid allocating the components
50+
return Some(length(connected_components(graph)))
51+
end
52+
53+
function graph_property(
54+
graph::AbstractGraph, ::GraphProperties.NumberOfWeaklyConnectedComponents, ::Nothing
55+
)
56+
if !is_directed(graph)
57+
throw(ArgumentError("expected directed graph"))
58+
end
59+
# TODO: performance: avoid allocating the components
60+
return Some(length(weakly_connected_components(graph)))
61+
end
62+
63+
function graph_property(
64+
graph::AbstractGraph, ::GraphProperties.NumberOfStronglyConnectedComponents, ::Nothing
65+
)
66+
if !is_directed(graph)
67+
throw(ArgumentError("expected directed graph"))
68+
end
69+
# TODO: performance: avoid allocating the components
70+
return Some(length(strongly_connected_components(graph)))
71+
end

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
66
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
77
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
88
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
9+
GraphProperties = "bbdf290f-6e15-4dc1-adeb-6e1d1446781e"
910
Inflate = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
1011
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
1112
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"

test/graphproperties.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@testset "graph properties" begin
2+
undirected_graph = ladder_graph(5)
3+
directed_graph = wheel_digraph(5)
4+
@testset "properties without parameter" begin
5+
properties_undirected = (
6+
GraphProperties.NumberOfVertices,
7+
GraphProperties.DegreeSequence,
8+
GraphProperties.NumberOfEdges,
9+
GraphProperties.NumberOfConnectedComponents,
10+
)
11+
properties_directed = (
12+
GraphProperties.NumberOfVertices,
13+
GraphProperties.NumberOfArcs,
14+
GraphProperties.NumberOfWeaklyConnectedComponents,
15+
GraphProperties.NumberOfStronglyConnectedComponents,
16+
)
17+
@testset "undirected" begin
18+
for options in ((), (nothing,))
19+
for property in properties_undirected
20+
prop = property()
21+
@test ((@inferred graph_property(undirected_graph, prop, options...)); true)
22+
@test something(graph_property(undirected_graph, prop, options...)) isa
23+
graph_property_type(prop)
24+
end
25+
end
26+
end
27+
@testset "directed" begin
28+
for options in ((), (nothing,))
29+
for property in properties_directed
30+
prop = property()
31+
@test ((@inferred graph_property(directed_graph, prop, options...)); true)
32+
@test something(graph_property(directed_graph, prop, options...)) isa
33+
graph_property_type(prop)
34+
end
35+
end
36+
end
37+
end
38+
end

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ using Statistics: mean, std
1616
using StableRNGs
1717
using Pkg
1818
using Unitful
19+
using GraphProperties: GraphProperties, graph_property_type
1920

2021
const testdir = dirname(@__FILE__)
2122
const KMf = typeof(u"1.0km")
@@ -80,6 +81,7 @@ tests = [
8081
"interface",
8182
"core",
8283
"operators",
84+
"graphproperties",
8385
"degeneracy",
8486
"distance",
8587
"digraph/transitivity",

0 commit comments

Comments
 (0)