Temporal Graphs

Temporal Graphs are graphs with time varying topologies and features. In GNNGraphs.jl, temporal graphs with fixed number of nodes over time are supported by the TemporalSnapshotsGNNGraph type.

Creating a TemporalSnapshotsGNNGraph

A temporal graph can be created by passing a list of snapshots to the constructor. Each snapshot is a GNNGraph.

julia> snapshots = [rand_graph(10,20) for i in 1:5];

julia> tg = TemporalSnapshotsGNNGraph(snapshots)
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10, 10, 10]
  num_edges: [20, 20, 20, 20, 20]
  num_snapshots: 5

A new temporal graph can be created by adding or removing snapshots to an existing temporal graph.

julia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10, 10, 10, 10]
  num_edges: [20, 20, 16, 20, 20, 20]
  num_snapshots: 6
julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];

julia> tg = TemporalSnapshotsGNNGraph(snapshots)
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10]
  num_edges: [20, 14, 22]
  num_snapshots: 3

julia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10]
  num_edges: [20, 22]
  num_snapshots: 2

See rand_temporal_radius_graph and rand_temporal_hyperbolic_graph for generating random temporal graphs.

julia> tg = rand_temporal_radius_graph(10, 3, 0.1, 0.5)
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10]
  num_edges: [32, 30, 34]
  num_snapshots: 3

Basic Queries

Basic queries are similar to those for GNNGraphs:

julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];

julia> tg = TemporalSnapshotsGNNGraph(snapshots)
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10]
  num_edges: [20, 14, 22]
  num_snapshots: 3

julia> tg.num_nodes         # number of nodes in each snapshot
3-element Vector{Int64}:
 10
 10
 10

julia> tg.num_edges         # number of edges in each snapshot
3-element Vector{Int64}:
 20
 14
 22

julia> tg.num_snapshots     # number of snapshots
3

julia> tg.snapshots         # list of snapshots
3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:
 GNNGraph(10, 20) with no data
 GNNGraph(10, 14) with no data
 GNNGraph(10, 22) with no data

julia> tg.snapshots[1]      # first snapshot, same as tg[1]
GNNGraph:
  num_nodes: 10
  num_edges: 20

Data Features

A temporal graph can store global feature for the entire time series in the tgdata filed. Also, each snapshot can store node, edge, and graph features in the ndata, edata, and gdata fields, respectively.

julia> snapshots = [rand_graph(10,20; ndata = rand(3,10)), rand_graph(10,14; ndata = rand(4,10)), rand_graph(10,22; ndata = rand(5,10))]; # node features at construction time

julia> tg = TemporalSnapshotsGNNGraph(snapshots);

julia> tg.tgdata.y = rand(3,1); # add global features after construction

julia> tg
TemporalSnapshotsGNNGraph:
  num_nodes: [10, 10, 10]
  num_edges: [20, 14, 22]
  num_snapshots: 3
  tgdata:
        y = 3×1 Matrix{Float64}

julia> tg.ndata # vector of DataStore containing node features for each snapshot
3-element Vector{DataStore}:
 DataStore(10) with 1 element:
  x = 3×10 Matrix{Float64}
 DataStore(10) with 1 element:
  x = 4×10 Matrix{Float64}
 DataStore(10) with 1 element:
  x = 5×10 Matrix{Float64}

julia> [ds.x for ds in tg.ndata]; # vector containing the x feature of each snapshot

julia> [g.x for g in tg.snapshots]; # same vector as above, now accessing 
                                   # the x feature directly from the snapshots

Graph convolutions on TemporalSnapshotsGNNGraph

A graph convolutional layer can be applied to each snapshot independently, in the next example we apply a GINConv layer to each snapshot of a TemporalSnapshotsGNNGraph.

julia> using GNNGraphs, Flux

julia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];

julia> tg = TemporalSnapshotsGNNGraph(snapshots);

julia> m = GINConv(Dense(3 => 1), 0.4);

julia> output = m(tg, tg.ndata.x);

julia> size(output[1])
(1, 10)