Skip to content

Commit 751de99

Browse files
jpsamaroopszufe
andcommitted
Add DaggerGraphs subpackage
Co-authored-by: pszufe <[email protected]>
1 parent f21e841 commit 751de99

File tree

10 files changed

+2108
-0
lines changed

10 files changed

+2108
-0
lines changed

lib/DaggerGraphs/Project.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name = "DaggerGraphs"
2+
uuid = "304567ff-242f-4479-af00-6fcdcd11a1dd"
3+
authors = ["Julian P Samaroo <[email protected]>", "pszufe <[email protected]>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
Dagger = "d58978e5-989f-55fb-8d15-ea34adc7bf54"
8+
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
9+
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
10+
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
11+
LRUCache = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637"
12+
MemPool = "f9f48841-c794-520a-933b-121f7ba6ed94"
13+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
14+
ScopedValues = "7e506255-f358-4e82-b7e4-beb19740aa63"
15+
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
16+
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
17+
18+
[compat]
19+
Dagger = "0.18"
20+
Graphs = "1"
21+
OffsetArrays = "1"
22+
Tables = "1"
23+
julia = "1"

lib/DaggerGraphs/src/DaggerGraphs.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module DaggerGraphs
2+
3+
using Dagger
4+
import Dagger: Chunk, LockedObject, @safe_lock1
5+
using Distributed
6+
using Graphs
7+
import OffsetArrays: OffsetArray
8+
import Tables
9+
using ScopedValues
10+
using LRUCache
11+
12+
export DGraph
13+
14+
include("dgraph.jl")
15+
include("adjlist.jl")
16+
include("edgeiter.jl")
17+
include("operations.jl")
18+
include("io.jl")
19+
include("tables.jl")
20+
21+
end # module DaggerGraphs

lib/DaggerGraphs/src/adjlist.jl

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
## Adjacency list storage
2+
3+
abstract type AbstractAdjListStorage{T,D} end
4+
Base.IteratorSize(::Type{<:AbstractAdjListStorage}) = Base.HasLength()
5+
Base.IteratorEltype(::Type{<:AbstractAdjListStorage}) = Base.HasEltype()
6+
Base.eltype(::Type{<:AbstractAdjListStorage{T}}) where T = Edge{T}
7+
function add_edges!(adjlist::AbstractAdjListStorage, edges; all::Bool=true)
8+
count = 0
9+
for edge in edges
10+
if add_edge!(adjlist, edge)
11+
count += 1
12+
elseif all
13+
return count
14+
end
15+
end
16+
return count
17+
end
18+
19+
# Storage matching Graphs.SimpleGraph for high edge counts
20+
struct SimpleAdjListStorage{T,D} <: AbstractAdjListStorage{T,D}
21+
fadjlist::Vector{Vector{T}}
22+
badjlist::Vector{Vector{T}}
23+
end
24+
SimpleAdjListStorage{T,D}() where {T,D} =
25+
SimpleAdjListStorage{T,D}(Vector{Vector{T}}(),
26+
Vector{Vector{T}}())
27+
Base.copy(adjlist::SimpleAdjListStorage{T,D}) where {T,D} =
28+
SimpleAdjListStorage{T,D}(copy(adjlist.fadjlist),
29+
copy(adjlist.badjlist))
30+
Base.length(adjlist::SimpleAdjListStorage) =
31+
sum(length, adjlist.fadjlist; init=0)
32+
function Base.iterate(adjlist::SimpleAdjListStorage{T}) where T
33+
idx = findfirst(x->!isempty(x), adjlist.fadjlist)
34+
if idx === nothing
35+
return nothing
36+
end
37+
edge_idx = something(findfirst(x->!isempty(x), adjlist.fadjlist[idx]))
38+
state = (T(idx), T(edge_idx))
39+
return Base.iterate(adjlist, state)
40+
end
41+
function Base.iterate(adjlist::SimpleAdjListStorage{T}, state::Tuple{T,T}) where T
42+
src, dst = state
43+
if src > length(adjlist.fadjlist)
44+
return nothing
45+
elseif dst > length(adjlist.fadjlist[src])
46+
src += one(T)
47+
dst = one(T)
48+
head = src
49+
src = findfirst(x->!isempty(x), @view(adjlist.fadjlist[head:end]))
50+
if src === nothing
51+
return nothing
52+
end
53+
src = T(src)
54+
# Shift by offset from @view
55+
src += head - one(T)
56+
end
57+
value = (src, adjlist.fadjlist[src][dst])
58+
dst += one(T)
59+
return (Edge(value), (src, dst))
60+
end
61+
function Graphs.add_edge!(adjlist::SimpleAdjListStorage{T,D}, edge) where {T,D}
62+
src, dst = Tuple(edge)
63+
if !D
64+
src, dst = minmax(src, dst)
65+
end
66+
67+
has_edge(adjlist, edge) && return false
68+
69+
# If necessary, allocate more inner vectors
70+
nv = max(src, dst)
71+
if nv > length(adjlist.fadjlist)
72+
#= FIXME: Resize more efficiently, and use undef elements
73+
resize!(adjlist.fadjlist, nv)
74+
if D
75+
resize!(adjlist.badjlist, nv)
76+
end
77+
isassigned(adjlist.fadjlist, src) || (adjlist.fadjlist[src] = Vector{T}())
78+
isassigned(adjlist.fadjlist, dst) || (adjlist.fadjlist[dst] = Vector{T}())
79+
if D
80+
isassigned(adjlist.badjlist, src) || (adjlist.badjlist[src] = Vector{T}())
81+
isassigned(adjlist.badjlist, dst) || (adjlist.badjlist[dst] = Vector{T}())
82+
end
83+
=#
84+
idx = length(adjlist.fadjlist)+1
85+
for _ in idx:nv
86+
push!(adjlist.fadjlist, Vector{T}())
87+
if D
88+
push!(adjlist.badjlist, Vector{T}())
89+
end
90+
end
91+
end
92+
93+
# Add edges
94+
if D
95+
# Directed graphs have only forward edges
96+
push!(adjlist.fadjlist[src], dst)
97+
push!(adjlist.badjlist[dst], src)
98+
else
99+
# Undirected graphs have both forward and backward edges
100+
push!(adjlist.fadjlist[src], dst)
101+
push!(adjlist.fadjlist[dst], src)
102+
end
103+
104+
return true
105+
end
106+
function Graphs.has_edge(adjlist::SimpleAdjListStorage{T,D}, edge) where {T,D}
107+
src, dst = Tuple(edge)
108+
if !D
109+
src, dst = (min(src, dst), max(src, dst))
110+
end
111+
if length(adjlist.fadjlist) >= src && dst in adjlist.fadjlist[src]
112+
return true
113+
end
114+
return false
115+
end
116+
117+
# Storage for sparse background graphs
118+
struct SparseAdjListStorage{T,D} <: AbstractAdjListStorage{T,D}
119+
adjlist::Vector{Tuple{T,T}}
120+
end
121+
SparseAdjListStorage{T,D}() where {T,D} =
122+
SparseAdjListStorage{T,D}(Vector{Tuple{T,T}}())
123+
Base.copy(adjlist::SparseAdjListStorage{T,D}) where {T,D} =
124+
SparseAdjListStorage{T,D}(copy(adjlist.adjlist))
125+
Base.length(adjlist::SparseAdjListStorage) = length(adjlist.adjlist)
126+
function Base.iterate(adjlist::SparseAdjListStorage{T}, state=one(T)) where T
127+
if state > length(adjlist.adjlist)
128+
return nothing
129+
end
130+
value = adjlist.adjlist[state]
131+
return (Edge(value), state+one(T))
132+
end
133+
function Graphs.add_edge!(adjlist::SparseAdjListStorage, edge)
134+
if findfirst(==(Tuple(edge)), adjlist.adjlist) !== nothing
135+
return false
136+
end
137+
push!(adjlist.adjlist, Tuple(edge))
138+
return true
139+
end
140+
function add_edges!(adjlist::SparseAdjListStorage, edges; all::Bool=true)
141+
# FIXME: Account for non-directedness
142+
edge_set = Set(map(Tuple, edges))
143+
for edge in adjlist.adjlist
144+
if edge in edge_set
145+
if all
146+
return 0
147+
else
148+
pop!(edge_set, edge)
149+
end
150+
end
151+
end
152+
append!(adjlist.adjlist, collect(edge_set))
153+
return length(edge_set)
154+
end
155+
function Graphs.has_edge(adjlist::SparseAdjListStorage{T,D}, edge) where {T,D}
156+
src, dst = Tuple(edge)
157+
if !D
158+
src, dst = (min(src, dst), max(src, dst))
159+
end
160+
return findfirst(x->x==(src, dst), adjlist.adjlist) !== nothing
161+
end
162+
163+
## Adjacency list implementation
164+
165+
struct AdjList{T,D,A<:AbstractAdjListStorage{T,D}}
166+
data::A
167+
end
168+
AdjList{T,D}(adjlist::AbstractAdjListStorage{T,D}) where {T,D} =
169+
AdjList{T,D,typeof(adjlist)}(adjlist)
170+
#AdjList{T,D}() where {T,D} = AdjList{T,D}(SimpleAdjListStorage{T,D}())
171+
AdjList{T,D}() where {T,D} = AdjList{T,D}(SparseAdjListStorage{T,D}())
172+
AdjList() = AdjList{Int,true}()
173+
Base.copy(adj::AdjList{T,D,A}) where {T,D,A} = AdjList{T,D,A}(copy(adj.data))
174+
Graphs.ne(adj::AdjList) = length(adj.data) # TODO: Use ne()
175+
Graphs.has_edge(adj::AdjList{T}, src::Integer, dst::Integer) where T =
176+
has_edge(adj.data, Edge{T}(src, dst))
177+
Graphs.has_edge(adj::AdjList{T,D}, edge) where {T,D} = has_edge(adj.data, edge)
178+
Graphs.add_edge!(adj::AdjList{T}, src::Integer, dst::Integer) where T =
179+
add_edge!(adj, Edge{T}(src, dst))
180+
Graphs.add_edge!(adj::AdjList, edge) = add_edge!(adj.data, edge)
181+
add_edges!(adj::AdjList, edges; all::Bool=true) = add_edges!(adj.data, edges; all)
182+
Graphs.edges(adj::AdjList) = copy(adj.data)
183+
function Graphs.inneighbors(adj::AdjList{T,D}, v::Integer) where {T,D}
184+
neighbors = Int[]
185+
for edge in adj.data
186+
src, dst = Tuple(edge)
187+
if dst == v
188+
push!(neighbors, src)
189+
elseif !D && src == v
190+
push!(neighbors, dst)
191+
end
192+
end
193+
sort!(neighbors)
194+
unique!(neighbors)
195+
return neighbors
196+
end
197+
function Graphs.inneighbors(adj::AdjList{T,D,SimpleAdjListStorage{T,D}}, v::Integer) where {T,D}
198+
if D
199+
return length(adj.data.badjlist) >= v ? copy(adj.data.badjlist[v]) : T[]
200+
else
201+
if length(adj.data.fadjlist) >= v
202+
neighbors = copy(adj.data.fadjlist[v])
203+
sort!(neighbors)
204+
unique!(neighbors)
205+
return neighbors
206+
else
207+
return T[]
208+
end
209+
end
210+
end
211+
function Graphs.outneighbors(adj::AdjList{T,D}, v::Integer) where {T,D}
212+
neighbors = Int[]
213+
for edge in adj.data
214+
src, dst = Tuple(edge)
215+
if src == v
216+
push!(neighbors, dst)
217+
elseif !D && dst == v
218+
push!(neighbors, src)
219+
end
220+
end
221+
sort!(neighbors)
222+
unique!(neighbors)
223+
return neighbors
224+
end
225+
function Graphs.outneighbors(adj::AdjList{T,SimpleAdjListStorage{T,D}}, v::Integer) where {T,D}
226+
if D
227+
return length(adj.data.fadjlist) >= v ? copy(adj.data.fadjlist[v]) : T[]
228+
else
229+
if length(adj.data.fadjlist) >= v
230+
neighbors = copy(adj.data.fadjlist[v])
231+
sort!(neighbors)
232+
unique!(neighbors)
233+
return neighbors
234+
else
235+
return T[]
236+
end
237+
end
238+
end

0 commit comments

Comments
 (0)