diff --git a/GNNGraphs/docs/build/.documenter-siteinfo.json b/GNNGraphs/docs/build/.documenter-siteinfo.json index 7a804fa6b..09dcd6dd0 100644 --- a/GNNGraphs/docs/build/.documenter-siteinfo.json +++ b/GNNGraphs/docs/build/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-19T11:02:41","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-19T13:45:05","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/GNNGraphs/docs/build/api/gnngraph.html b/GNNGraphs/docs/build/api/gnngraph.html index 8a667d566..025501471 100644 --- a/GNNGraphs/docs/build/api/gnngraph.html +++ b/GNNGraphs/docs/build/api/gnngraph.html @@ -1,5 +1,5 @@ -GNNGraph · GNNGraphs.jl

GNNGraph

Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods.

Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.

Index

GNNGraph type

GNNGraphs.GNNGraphType
GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])
+GNNGraph · GNNGraphs.jl

GNNGraph

Documentation page for the graph type GNNGraph provided by GNNGraphs.jl and related methods.

Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.

Index

GNNGraph type

GNNGraphs.GNNGraphType
GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])
 GNNGraph(g::GNNGraph; [ndata, edata, gdata])

A type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.

The feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.

A GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.

When constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.

A GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.

GNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.

A GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Arguments

  • data: Some data representing the graph topology. Possible type are
    • An adjacency matrix
    • An adjacency list.
    • A tuple containing the source and target vectors (COO representation)
    • A Graphs.jl' graph.
  • graph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are
    • :coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).
    • :sparse. A sparse adjacency matrix representation.
    • :dense. A dense adjacency matrix representation.
    Defaults to :coo, currently the most supported type.
  • dir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.
  • num_nodes: The number of nodes. If not specified, inferred from g. Default nothing.
  • graph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.
  • ndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.
  • edata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.
  • gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.

Examples

using GraphNeuralNetworks
 
 # Construct from adjacency list representation
@@ -35,7 +35,7 @@
 # Both source and target are vectors of length num_edges
 source, target = edge_index(g)

A GNNGraph can be sent to the GPU using e.g. Flux's gpu function:

# Send to gpu
 using Flux, CUDA
-g = g |> Flux.gpu
source
Base.copyFunction
copy(g::GNNGraph; deep=false)

Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.

source

DataStore

Base.copyFunction
copy(g::GNNGraph; deep=false)

Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.

source

DataStore

GNNGraphs.DataStoreType
DataStore([n, data])
 DataStore([n,] k1 = x1, k2 = x2, ...)

A container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.

At construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:

julia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))
 DataStore(3) with 2 elements:
   y = 3-element Vector{Float32}
@@ -79,8 +79,8 @@
 julia> ds2.a
 2-element Vector{Float64}:
  1.0
- 1.0
source

Query

GNNGraphs.adjacency_listMethod
adjacency_list(g; dir=:out)
-adjacency_list(g, nodes; dir=:out)

Return the adjacency list representation (a vector of vectors) of the graph g.

Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.

If nodes is given, return the neighborhood of the nodes in nodes only.

source
GNNGraphs.edge_indexMethod
edge_index(g::GNNGraph)

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.

s, t = edge_index(g)
source
GNNGraphs.edge_indexMethod
edge_index(g::GNNHeteroGraph, [edge_t])

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).

If edge_t is not provided, it will error if g has more than one edge type.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNGraph; edges=false)

Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNHeteroGraph, [node_t])

Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.

See also batch.

source
GNNGraphs.has_isolated_nodesMethod
has_isolated_nodes(g::GNNGraph; dir=:out)

Return true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.

source
GNNGraphs.is_bidirectedMethod
is_bidirected(g::GNNGraph)

Check if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge.

source
GNNGraphs.khop_adjFunction
khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)

Return $A^k$ where $A$ is the adjacency matrix of the graph 'g'.

source
GNNGraphs.laplacian_lambda_maxFunction
laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)

Return the largest eigenvalue of the normalized symmetric Laplacian of the graph g.

If the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.

source
GNNGraphs.normalized_laplacianFunction
normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)

Normalized Laplacian matrix of graph g.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • add_self_loops: add self-loops while calculating the matrix.
  • dir: the edge directionality considered (:out, :in, :both).
source
GNNGraphs.scaled_laplacianFunction
scaled_laplacian(g, T=Float32; dir=:out)

Scaled Laplacian matrix of graph g, defined as $\hat{L} = \frac{2}{\lambda_{max}} L - I$ where $L$ is the normalized Laplacian matrix.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • dir: the edge directionality considered (:out, :in, :both).
source
Graphs.LinAlg.adjacency_matrixFunction
adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)

Return the adjacency matrix A for the graph g.

If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.

User may specify the eltype T of the returned matrix.

If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.

source
Graphs.degreeMethod
degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)

Return a vector containing the degrees of the nodes in g.

The gradient is propagated through this function only if edge_weight is true or a vector.

Arguments

  • g: A graph.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
  • edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
source
Graphs.degreeMethod
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)

Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.

Arguments

  • g: A graph.
  • edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
source
Graphs.neighborsMethod
neighbors(g::GNNGraph, i::Integer; dir=:out)

Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.

See also outneighbors, inneighbors.

source

Transform

Query

GNNGraphs.adjacency_listMethod
adjacency_list(g; dir=:out)
+adjacency_list(g, nodes; dir=:out)

Return the adjacency list representation (a vector of vectors) of the graph g.

Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.

If nodes is given, return the neighborhood of the nodes in nodes only.

source
GNNGraphs.edge_indexMethod
edge_index(g::GNNGraph)

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.

s, t = edge_index(g)
source
GNNGraphs.edge_indexMethod
edge_index(g::GNNHeteroGraph, [edge_t])

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).

If edge_t is not provided, it will error if g has more than one edge type.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNGraph; edges=false)

Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNHeteroGraph, [node_t])

Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.

See also batch.

source
GNNGraphs.has_isolated_nodesMethod
has_isolated_nodes(g::GNNGraph; dir=:out)

Return true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.

source
GNNGraphs.is_bidirectedMethod
is_bidirected(g::GNNGraph)

Check if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge.

source
GNNGraphs.khop_adjFunction
khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)

Return $A^k$ where $A$ is the adjacency matrix of the graph 'g'.

source
GNNGraphs.laplacian_lambda_maxFunction
laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)

Return the largest eigenvalue of the normalized symmetric Laplacian of the graph g.

If the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.

source
GNNGraphs.normalized_laplacianFunction
normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)

Normalized Laplacian matrix of graph g.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • add_self_loops: add self-loops while calculating the matrix.
  • dir: the edge directionality considered (:out, :in, :both).
source
GNNGraphs.scaled_laplacianFunction
scaled_laplacian(g, T=Float32; dir=:out)

Scaled Laplacian matrix of graph g, defined as $\hat{L} = \frac{2}{\lambda_{max}} L - I$ where $L$ is the normalized Laplacian matrix.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • dir: the edge directionality considered (:out, :in, :both).
source
Graphs.LinAlg.adjacency_matrixFunction
adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)

Return the adjacency matrix A for the graph g.

If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.

User may specify the eltype T of the returned matrix.

If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.

source
Graphs.degreeMethod
degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)

Return a vector containing the degrees of the nodes in g.

The gradient is propagated through this function only if edge_weight is true or a vector.

Arguments

  • g: A graph.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
  • edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
source
Graphs.degreeMethod
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)

Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.

Arguments

  • g: A graph.
  • edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
source
Graphs.neighborsMethod
neighbors(g::GNNGraph, i::Integer; dir=:out)

Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.

See also outneighbors, inneighbors.

source

Transform

GNNGraphs.add_edgesMethod
add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])
 add_edges(g::GNNGraph, (s, t); [edata])
 add_edges(g::GNNGraph, (s, t, w); [edata])

Add to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.

If the s or t contain nodes that are not already present in the graph, they are added to the graph as well.

Examples

julia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];
 
@@ -102,12 +102,12 @@
 julia> add_edges(g, [1,2], [2,3])
 GNNGraph:
     num_nodes: 3
-    num_edges: 2
source
GNNGraphs.add_edgesMethod
add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])
 add_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])
-add_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])

Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).

If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.

source
GNNGraphs.add_nodesMethod
add_nodes(g::GNNGraph, n; [ndata])

Add n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNGraph)

Return a graph with the same features as g but also adding edges connecting the nodes to themselves.

Nodes with already existing self-loops will obtain a second self-loop.

If the graphs has edge weights, the new edges will have weight 1.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNHeteroGraph, edge_t::EType)
-add_self_loops(g::GNNHeteroGraph)

If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.

Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.

If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.

If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.

If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.

source
GNNGraphs.getgraphMethod
getgraph(g::GNNGraph, i; nmap=false)

Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.

If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.

source
GNNGraphs.negative_sampleMethod
negative_sample(g::GNNGraph; 
+add_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])

Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).

If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.

source
GNNGraphs.add_nodesMethod
add_nodes(g::GNNGraph, n; [ndata])

Add n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNGraph)

Return a graph with the same features as g but also adding edges connecting the nodes to themselves.

Nodes with already existing self-loops will obtain a second self-loop.

If the graphs has edge weights, the new edges will have weight 1.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNHeteroGraph, edge_t::EType)
+add_self_loops(g::GNNHeteroGraph)

If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.

Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.

If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.

If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.

If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.

source
GNNGraphs.getgraphMethod
getgraph(g::GNNGraph, i; nmap=false)

Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.

If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.

source
GNNGraphs.negative_sampleMethod
negative_sample(g::GNNGraph; 
                 num_neg_edges = g.num_edges, 
-                bidirected = is_bidirected(g))

Return a graph containing random negative edges (i.e. non-edges) from graph g as edges.

If bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph.

See also is_bidirected.

source
GNNGraphs.perturb_edgesMethod
perturb_edges([rng], g::GNNGraph, perturb_ratio)

Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.

The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.

Arguments

  • g::GNNGraph: The graph to be perturbed.
  • perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
  • rng: An optionalrandom number generator to ensure reproducible results.

Examples

julia> g = GNNGraph((s, t, w))
+                bidirected = is_bidirected(g))

Return a graph containing random negative edges (i.e. non-edges) from graph g as edges.

If bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph.

See also is_bidirected.

source
GNNGraphs.perturb_edgesMethod
perturb_edges([rng], g::GNNGraph, perturb_ratio)

Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.

The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.

Arguments

  • g::GNNGraph: The graph to be perturbed.
  • perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
  • rng: An optionalrandom number generator to ensure reproducible results.

Examples

julia> g = GNNGraph((s, t, w))
 GNNGraph:
   num_nodes: 4
   num_edges: 5
@@ -115,7 +115,7 @@
 julia> perturbed_g = perturb_edges(g, 0.2)
 GNNGraph:
   num_nodes: 4
-  num_edges: 6
source
GNNGraphs.ppr_diffusionMethod
ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph

Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web

The function performs the following steps:

  1. Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
  2. Normalizes A to ensure each column sums to 1, representing transition probabilities.
  3. Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
  4. Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.

Arguments

  • g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
  • alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.

Returns

  • A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
source
GNNGraphs.rand_edge_splitMethod
rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2

Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.

If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.

rand_edge_split is tipically used to create train/test splits in link prediction tasks.

source
GNNGraphs.ppr_diffusionMethod
ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph

Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web

The function performs the following steps:

  1. Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
  2. Normalizes A to ensure each column sums to 1, representing transition probabilities.
  3. Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
  4. Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.

Arguments

  • g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
  • alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.

Returns

  • A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
source
GNNGraphs.rand_edge_splitMethod
rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2

Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.

If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.

rand_edge_split is tipically used to create train/test splits in link prediction tasks.

source
GNNGraphs.remove_edgesMethod
remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})
 remove_edges(g::GNNGraph, p=0.5)

Remove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.

Arguments

  • g: The input graph from which edges will be removed.
  • edges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.
  • p: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.

Returns

A new GNNGraph with the specified edges removed.

Example

julia> using GraphNeuralNetworks
 
 # Construct a GNNGraph
@@ -138,7 +138,7 @@
 julia> g_new
 GNNGraph:
   num_nodes: 3
-  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, p)

Returns a new graph obtained by dropping nodes from g with independent probabilities p.

Examples

julia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])
+  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, p)

Returns a new graph obtained by dropping nodes from g with independent probabilities p.

Examples

julia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])
 GNNGraph:
   num_nodes: 4
   num_edges: 6
@@ -146,7 +146,7 @@
 julia> g_new = remove_nodes(g, 0.5)
 GNNGraph:
   num_nodes: 2
-  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)

Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.

Arguments

  • g: The input graph from which nodes (and their edges) will be removed.
  • nodes_to_remove: Vector of node indices to be removed.

Returns

A new GNNGraph with the specified nodes and all edges associated with these nodes removed.

Example

using GraphNeuralNetworks
+  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)

Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.

Arguments

  • g: The input graph from which nodes (and their edges) will be removed.
  • nodes_to_remove: Vector of node indices to be removed.

Returns

A new GNNGraph with the specified nodes and all edges associated with these nodes removed.

Example

using GraphNeuralNetworks
 
 g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])
 
@@ -154,7 +154,7 @@
 g_new = remove_nodes(g, [2, 3])
 
 # g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.
-println(g_new)
source
GNNGraphs.to_bidirectedMethod
to_bidirected(g)

Adds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph.

See also is_bidirected.

Examples

julia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];
 
 julia> w = [1.0, 2.0, 3.0, 4.0, 5.0];
 
@@ -195,7 +195,7 @@
  20.0
  35.0
  35.0
- 50.0
source
GNNGraphs.to_unidirectedMethod
to_unidirected(g::GNNGraph)

Return a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.

source
MLUtils.batchMethod
batch(gs::Vector{<:GNNGraph})

Batch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.

Equivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.

Examples

julia> g1 = rand_graph(4, 6, ndata=ones(8, 4))
+ 50.0
source
GNNGraphs.to_unidirectedMethod
to_unidirected(g::GNNGraph)

Return a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.

source
MLUtils.batchMethod
batch(gs::Vector{<:GNNGraph})

Batch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.

Equivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.

Examples

julia> g1 = rand_graph(4, 6, ndata=ones(8, 4))
 GNNGraph:
     num_nodes = 4
     num_edges = 6
@@ -226,7 +226,7 @@
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
- 1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
source
MLUtils.unbatchMethod
unbatch(g::GNNGraph)

Opposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.

See also MLUtils.batch and getgraph.

Examples

julia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])
+ 1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
source
MLUtils.unbatchMethod
unbatch(g::GNNGraph)

Opposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.

See also MLUtils.batch and getgraph.

Examples

julia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])
 GNNGraph:
     num_nodes = 19
     num_edges = 16
@@ -244,8 +244,8 @@
 
  GNNGraph:
     num_nodes = 4
-    num_edges = 2
source

Utils

GNNGraphs.sort_edge_indexFunction
sort_edge_index(ei::Tuple) -> u', v'
-sort_edge_index(u, v) -> u', v'

Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.

source
GNNGraphs.color_refinementFunction
color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters

The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.

At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.

math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`

This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.

Arguments

  • g::GNNGraph: The graph to color.
  • x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.

Returns

  • x::AbstractVector{<:Integer}: The final coloring.
  • num_colors::Int: The number of colors used.
  • niters::Int: The number of iterations until convergence.
source

Generate

Utils

GNNGraphs.sort_edge_indexFunction
sort_edge_index(ei::Tuple) -> u', v'
+sort_edge_index(u, v) -> u', v'

Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.

source
GNNGraphs.color_refinementFunction
color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters

The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.

At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.

math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`

This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.

Arguments

  • g::GNNGraph: The graph to color.
  • x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.

Returns

  • x::AbstractVector{<:Integer}: The final coloring.
  • num_colors::Int: The number of colors used.
  • niters::Int: The number of iterations until convergence.
source

Generate

GNNGraphs.knn_graphMethod
knn_graph(points::AbstractMatrix, 
           k::Int; 
           graph_indicator = nothing,
           self_loops = false, 
@@ -266,7 +266,7 @@
     num_nodes = 10
     num_edges = 30
     num_graphs = 2
-
source
GNNGraphs.rand_bipartite_heterographMethod
rand_bipartite_heterograph([rng,] 
                            (n1, n2), (m12, m21); 
                            bidirected = true, 
                            node_t = (:A, :B), 
@@ -300,7 +300,7 @@
 julia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)
 GNNHeteroGraph:
   num_nodes: Dict(:item => 15, :user => 10)
-  num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)
source
GNNGraphs.rand_graphMethod
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)

Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.

If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.

A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.

Pass a random number generator as the first argument to make the generation reproducible.

Additional keyword arguments will be passed to the GNNGraph constructor.

Examples

julia> g = rand_graph(5, 4, bidirected=false)
+  num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)
source
GNNGraphs.rand_graphMethod
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)

Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.

If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.

A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.

Pass a random number generator as the first argument to make the generation reproducible.

Additional keyword arguments will be passed to the GNNGraph constructor.

Examples

julia> g = rand_graph(5, 4, bidirected=false)
 GNNGraph:
     num_nodes = 5
     num_edges = 4
@@ -318,11 +318,11 @@
 
 # Each edge has a reverse
 julia> edge_index(g)
-([1, 3, 3, 4], [3, 4, 1, 3])
source
GNNGraphs.rand_heterographFunction
rand_heterograph([rng,] n, m; bidirected=false, kws...)

Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.

Pass a random number generator as a first argument to make the generation reproducible.

Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.

Additional keyword arguments will be passed to the GNNHeteroGraph constructor.

Examples

julia> g = rand_heterograph((:user => 10, :movie => 20),
+([1, 3, 3, 4], [3, 4, 1, 3])
source
GNNGraphs.rand_heterographFunction
rand_heterograph([rng,] n, m; bidirected=false, kws...)

Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.

Pass a random number generator as a first argument to make the generation reproducible.

Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.

Additional keyword arguments will be passed to the GNNHeteroGraph constructor.

Examples

julia> g = rand_heterograph((:user => 10, :movie => 20),
                             (:user, :rate, :movie) => 30)
 GNNHeteroGraph:
   num_nodes: (:user => 10, :movie => 20)         
-  num_edges: ((:user, :rate, :movie) => 30,)
source

Operators

Base.intersectFunction

" intersect(g1::GNNGraph, g2::GNNGraph)

Intersect two graphs by keeping only the common edges.

source

Sampling

GNNGraphs.sample_neighborsFunction
sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)

Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.

The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.

Arguments

  • g. The graph.
  • nodes. A list of node IDs to sample neighbors from.
  • K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
  • dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
  • replace. If true, sample with replacement.
  • dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.

Examples

julia> g = rand_graph(20, 100)
+  num_edges: ((:user, :rate, :movie) => 30,)
source

Operators

Base.intersectFunction

" intersect(g1::GNNGraph, g2::GNNGraph)

Intersect two graphs by keeping only the common edges.

source

Sampling

GNNGraphs.sample_neighborsFunction
sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)

Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.

The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.

Arguments

  • g. The graph.
  • nodes. A list of node IDs to sample neighbors from.
  • K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
  • dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
  • replace. If true, sample with replacement.
  • dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.

Examples

julia> g = rand_graph(20, 100)
 GNNGraph:
     num_nodes = 20
     num_edges = 100
@@ -361,4 +361,4 @@
     num_nodes = 20
     num_edges = 10
     edata:
-        EID => (10,)
source
+ EID => (10,)
source
diff --git a/GNNGraphs/docs/build/api/heterograph.html b/GNNGraphs/docs/build/api/heterograph.html index 909aa109b..485df53a5 100644 --- a/GNNGraphs/docs/build/api/heterograph.html +++ b/GNNGraphs/docs/build/api/heterograph.html @@ -1,5 +1,5 @@ -Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

GNNHeteroGraph

Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.

GNNGraphs.GNNHeteroGraphType
GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])
+Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

GNNHeteroGraph

Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.

GNNGraphs.GNNHeteroGraphType
GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])
 GNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])

A type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.

Constructor Arguments

  • data: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).
  • pairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).
  • ndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.
  • edata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.
  • gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.
  • num_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.

Fields

  • graph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.
  • num_nodes: The number of nodes for each type.
  • num_edges: The number of edges for each type.
  • ndata: Node features.
  • edata: Edge features.
  • gdata: Graph features.
  • ntypes: The node types.
  • etypes: The edge types.

Examples

julia> using GraphNeuralNetworks
 
 julia> nA, nB = 10, 20;
@@ -40,7 +40,7 @@
 julia> hg.ndata[:A].x
 2×10 Matrix{Float64}:
     0.825882  0.0797502  0.245813  0.142281  0.231253  0.685025  0.821457  0.888838  0.571347   0.53165
-    0.631286  0.316292   0.705325  0.239211  0.533007  0.249233  0.473736  0.595475  0.0623298  0.159307

See also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.

source
GNNGraphs.edge_type_subgraphMethod
edge_type_subgraph(g::GNNHeteroGraph, edge_ts)

Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.

source
Graphs.has_edgeMethod
has_edge(g::GNNHeteroGraph, edge_t, i, j)

Return true if there is an edge of type edge_t from node i to node j in g.

Examples

julia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)
+    0.631286  0.316292   0.705325  0.239211  0.533007  0.249233  0.473736  0.595475  0.0623298  0.159307

See also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.

source
GNNGraphs.edge_type_subgraphMethod
edge_type_subgraph(g::GNNHeteroGraph, edge_ts)

Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.

source
Graphs.has_edgeMethod
has_edge(g::GNNHeteroGraph, edge_t, i, j)

Return true if there is an edge of type edge_t from node i to node j in g.

Examples

julia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)
 GNNHeteroGraph:
   num_nodes: (:A => 2, :B => 2)
   num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)
@@ -49,4 +49,4 @@
 true
 
 julia> has_edge(g, (:B,:to,:A), 1, 1)
-false
source
+false
source
diff --git a/GNNGraphs/docs/build/api/temporalgraph.html b/GNNGraphs/docs/build/api/temporalgraph.html index 490b05450..c150cb0c0 100644 --- a/GNNGraphs/docs/build/api/temporalgraph.html +++ b/GNNGraphs/docs/build/api/temporalgraph.html @@ -1,5 +1,5 @@ -Temporal Graphs · GNNGraphs.jl

Temporal Graphs

TemporalSnapshotsGNNGraph

Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.

GNNGraphs.TemporalSnapshotsGNNGraphType
TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})

A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.

TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.

Constructor Arguments

  • snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.

Examples

julia> using GraphNeuralNetworks
+Temporal Graphs · GNNGraphs.jl

Temporal Graphs

TemporalSnapshotsGNNGraph

Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.

GNNGraphs.TemporalSnapshotsGNNGraphType
TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})

A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.

TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.

Constructor Arguments

  • snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10,20) for i in 1:5];
 
@@ -17,7 +17,7 @@
   num_edges: [20, 20, 20, 20, 20]
   num_snapshots: 5
   tgdata:
-        x = 4-element Vector{Float64}
source
GNNGraphs.add_snapshotMethod
add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)

Return a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.

Examples

julia> using GraphNeuralNetworks
+        x = 4-element Vector{Float64}
source
GNNGraphs.add_snapshotMethod
add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)

Return a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10, 20) for i in 1:5];
 
@@ -31,7 +31,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10, 10, 10, 10, 10]
   num_edges: [20, 20, 16, 20, 20, 20]
-  num_snapshots: 6
source
GNNGraphs.remove_snapshotMethod
remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)

Return a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];
 
@@ -45,7 +45,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10]
   num_edges: [20, 22]
-  num_snapshots: 2
source

TemporalSnapshotsGNNGraph random generators

TemporalSnapshotsGNNGraph random generators

GNNGraphs.rand_temporal_radius_graphFunction
rand_temporal_radius_graph(number_nodes::Int, 
                            number_snapshots::Int,
                            speed::AbstractFloat,
                            r::AbstractFloat;
@@ -57,7 +57,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10, 10, 10, 10]
   num_edges: [90, 90, 90, 90, 90]
-  num_snapshots: 5
source
+ num_snapshots: 5

References

Section D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks

source
diff --git a/GNNGraphs/docs/build/datasets.html b/GNNGraphs/docs/build/datasets.html index 50a18f726..374d35872 100644 --- a/GNNGraphs/docs/build/datasets.html +++ b/GNNGraphs/docs/build/datasets.html @@ -1,5 +1,5 @@ -Datasets · GNNGraphs.jl

Datasets

GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.

GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.

GNNGraphs.mldataset2gnngraphFunction
mldataset2gnngraph(dataset)

Convert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.

Examples

julia> using MLDatasets, GraphNeuralNetworks
+Datasets · GNNGraphs.jl

Datasets

GNNGraphs.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others. For graphs with static structures and temporal features, datasets such as METRLA, PEMSBAY, ChickenPox, and WindMillEnergy are available. For graphs featuring both temporal structures and temporal features, the TemporalBrains dataset is suitable.

GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.

GNNGraphs.mldataset2gnngraphFunction
mldataset2gnngraph(dataset)

Convert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.

Examples

julia> using MLDatasets, GraphNeuralNetworks
 
 julia> mldataset2gnngraph(Cora())
 GNNGraph:
@@ -10,4 +10,4 @@
         targets => 2708-element Vector{Int64}
         train_mask => 2708-element BitVector
         val_mask => 2708-element BitVector
-        test_mask => 2708-element BitVector
source
+ test_mask => 2708-element BitVector
source
diff --git a/GNNGraphs/docs/build/gnngraph.html b/GNNGraphs/docs/build/gnngraph.html index d312cacda..73ff523e4 100644 --- a/GNNGraphs/docs/build/gnngraph.html +++ b/GNNGraphs/docs/build/gnngraph.html @@ -1,5 +1,5 @@ -Working with GNNGraph · GNNGraphs.jl

Working with GNNGraph

The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.

GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Graph Creation

A GNNGraph can be created from several different data sources encoding the graph topology:

using GraphNeuralNetworks, Graphs, SparseArrays
+Static Graphs · GNNGraphs.jl

Static Graphs

The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.

GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Graph Creation

A GNNGraph can be created from several different data sources encoding the graph topology:

using GraphNeuralNetworks, Graphs, SparseArrays
 
 
 # Construct a GNNGraph from from a Graphs.jl's graph
@@ -167,4 +167,4 @@
 julia> GNNGraph(gd)
 GNNGraph:
   num_nodes: 10
-  num_edges: 20
+ num_edges: 20
diff --git a/GNNGraphs/docs/build/heterograph.html b/GNNGraphs/docs/build/heterograph.html index 4a674312b..c707f0496 100644 --- a/GNNGraphs/docs/build/heterograph.html +++ b/GNNGraphs/docs/build/heterograph.html @@ -1,5 +1,5 @@ -Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).

Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.

Creating a Heterograph

A heterograph can be created empty or by passing pairs edge_type => data to the constructor.

julia> g = GNNHeteroGraph()
+Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).

Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.

Creating a Heterograph

A heterograph can be created empty or by passing pairs edge_type => data to the constructor.

julia> g = GNNHeteroGraph()
 GNNHeteroGraph:
   num_nodes: Dict()
   num_edges: Dict()
@@ -81,4 +81,4 @@
     @assert g.num_nodes[:A] == 80
     @assert size(g.ndata[:A].x) == (3, 80)    
     # ...
-end

Graph convolutions on heterographs

See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.

+end

Graph convolutions on heterographs

See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.

diff --git a/GNNGraphs/docs/build/index.html b/GNNGraphs/docs/build/index.html index 4a0c81339..e21dd578a 100644 --- a/GNNGraphs/docs/build/index.html +++ b/GNNGraphs/docs/build/index.html @@ -1,2 +1,2 @@ -Home · GNNGraphs.jl
+Home · GNNGraphs.jl

GNNGraphs.jl

GNNGraphs.jl is a package that provides graph data structures and helper functions specifically designed for working with graph neural networks. This package allows to store not only the graph structure, but also features associated with nodes, edges, and the graph itself. It is the core foundation for the GNNlib, GraphNeuralNetworks, and GNNLux packages.

It supports three types of graphs:

  • Static graph is the basic graph type represented by GNNGraph, where each node and edge can have associated features. This type of graph is used in typical graph neural network applications, where neural networks operate on both the structure of the graph and the features stored in it. It can be used to represent a graph where the structure does not change over time, but the features of the nodes and edges can change over time.

  • Temporal graph is a graph that changes over time, and is represented by TemporalSnapshotsGNNGraph. Edges and features can change dynamically. This type of graph is useful for applications that involve tracking time-dependent relationships, such as social networks.

  • Heterogeneous graph is a graph that supports multiple types of nodes and edges, and is represented by GNNHeteroGraph. Each type can have its own properties and relationships. This is useful in scenarios with different entities and interactions, such as in citation graphs or multi-relational data.

This package depends on the package Graphs.jl.

diff --git a/GNNGraphs/docs/build/objects.inv b/GNNGraphs/docs/build/objects.inv index f75ba7ae3..d65020607 100644 Binary files a/GNNGraphs/docs/build/objects.inv and b/GNNGraphs/docs/build/objects.inv differ diff --git a/GNNGraphs/docs/build/search_index.js b/GNNGraphs/docs/build/search_index.js index e87ee7b8b..b1b65e0c9 100644 --- a/GNNGraphs/docs/build/search_index.js +++ b/GNNGraphs/docs/build/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"CurrentModule = GNNGraphs","category":"page"},{"location":"api/gnngraph.html#GNNGraph","page":"GNNGraph","title":"GNNGraph","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods. ","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.","category":"page"},{"location":"api/gnngraph.html#Index","page":"GNNGraph","title":"Index","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Order = [:type, :function]\nPages = [\"gnngraph.md\"]","category":"page"},{"location":"api/gnngraph.html#GNNGraph-type","page":"GNNGraph","title":"GNNGraph type","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraph\nBase.copy","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.GNNGraph","page":"GNNGraph","title":"GNNGraphs.GNNGraph","text":"GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])\nGNNGraph(g::GNNGraph; [ndata, edata, gdata])\n\nA type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.\n\nThe feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.\n\nA GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.\n\nWhen constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.\n\nA GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.\n\nGNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.\n\nA GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.\n\nArguments\n\ndata: Some data representing the graph topology. Possible type are\nAn adjacency matrix\nAn adjacency list.\nA tuple containing the source and target vectors (COO representation)\nA Graphs.jl' graph.\ngraph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are\n:coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).\n:sparse. A sparse adjacency matrix representation.\n:dense. A dense adjacency matrix representation.\nDefaults to :coo, currently the most supported type.\ndir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.\nnum_nodes: The number of nodes. If not specified, inferred from g. Default nothing.\ngraph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.\nndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.\nedata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.\n\nExamples\n\nusing GraphNeuralNetworks\n\n# Construct from adjacency list representation\ndata = [[2,3], [1,4,5], [1], [2,5], [2,4]]\ng = GNNGraph(data)\n\n# Number of nodes, edges, and batched graphs\ng.num_nodes # 5\ng.num_edges # 10\ng.num_graphs # 1\n\n# Same graph in COO representation\ns = [1,1,2,2,2,3,4,4,5,5]\nt = [2,3,1,4,5,3,2,5,2,4]\ng = GNNGraph(s, t)\n\n# From a Graphs' graph\ng = GNNGraph(erdos_renyi(100, 20))\n\n# Add 2 node feature arrays at creation time\ng = GNNGraph(g, ndata = (x=rand(100, g.num_nodes), y=rand(g.num_nodes)))\n\n# Add 1 edge feature array, after the graph creation\ng.edata.z = rand(16, g.num_edges)\n\n# Add node features and edge features with default names `x` and `e`\ng = GNNGraph(g, ndata = rand(100, g.num_nodes), edata = rand(16, g.num_edges))\n\ng.ndata.x # or just g.x\ng.edata.e # or just g.e\n\n# Collect edges' source and target nodes.\n# Both source and target are vectors of length num_edges\nsource, target = edge_index(g)\n\nA GNNGraph can be sent to the GPU using e.g. Flux's gpu function:\n\n# Send to gpu\nusing Flux, CUDA\ng = g |> Flux.gpu\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Base.copy","page":"GNNGraph","title":"Base.copy","text":"copy(g::GNNGraph; deep=false)\n\nCreate a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#DataStore","page":"GNNGraph","title":"DataStore","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"datastore.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.DataStore","page":"GNNGraph","title":"GNNGraphs.DataStore","text":"DataStore([n, data])\nDataStore([n,] k1 = x1, k2 = x2, ...)\n\nA container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.\n\nAt construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:\n\njulia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))\nDataStore(3) with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds = DataStore(3, Dict(:x => rand(Float32, 2, 3), :y => rand(Float32, 3))); # equivalent to above\n\njulia> ds = DataStore(3, (x = rand(Float32, 2, 3), y = rand(Float32, 30)))\nERROR: AssertionError: DataStore: data[y] has 30 observations, but n = 3\nStacktrace:\n [1] DataStore(n::Int64, data::Dict{Symbol, Any})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:54\n [2] DataStore(n::Int64, data::NamedTuple{(:x, :y), Tuple{Matrix{Float32}, Vector{Float32}}})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:73\n [3] top-level scope\n @ REPL[13]:1\n\njulia> ds = DataStore(x = randFloat32, 2, 3), y = rand(Float32, 30)) # no checks\nDataStore() with 2 elements:\n y = 30-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n y = 30-element Vector{Float64}\n x = 2×3 Matrix{Float64}\n\nThe DataStore has an interface similar to both dictionaries and named tuples. Arrays can be accessed and added using either the indexing or the property syntax:\n\njulia> ds = DataStore(x = ones(Float32, 2, 3), y = zeros(Float32, 3))\nDataStore() with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds.x # same as `ds[:x]`\n2×3 Matrix{Float32}:\n 1.0 1.0 1.0\n 1.0 1.0 1.0\n\njulia> ds.z = zeros(Float32, 3) # Add new feature array `z`. Same as `ds[:z] = rand(Float32, 3)`\n3-element Vector{Float64}:\n0.0\n0.0\n0.0\n\nThe DataStore can be iterated over, and the keys and values can be accessed using keys(ds) and values(ds). map(f, ds) applies the function f to each feature array:\n\njulia> ds = DataStore(a = zeros(2), b = zeros(2));\n\njulia> ds2 = map(x -> x .+ 1, ds)\n\njulia> ds2.a\n2-element Vector{Float64}:\n 1.0\n 1.0\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Query","page":"GNNGraph","title":"Query","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"query.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.adjacency_list-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.adjacency_list","text":"adjacency_list(g; dir=:out)\nadjacency_list(g, nodes; dir=:out)\n\nReturn the adjacency list representation (a vector of vectors) of the graph g.\n\nCalling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.\n\nIf nodes is given, return the neighborhood of the nodes in nodes only.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNGraph)\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.\n\ns, t = edge_index(g)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNHeteroGraph, [edge_t])\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).\n\nIf edge_t is not provided, it will error if g has more than one edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNGraph; edges=false)\n\nReturn a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNHeteroGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNHeteroGraph, [node_t])\n\nReturn a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.\n\nSee also batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_isolated_nodes-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_isolated_nodes","text":"has_isolated_nodes(g::GNNGraph; dir=:out)\n\nReturn true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_multi_edges-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_multi_edges","text":"has_multi_edges(g::GNNGraph)\n\nReturn true if g has any multiple edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.is_bidirected-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.is_bidirected","text":"is_bidirected(g::GNNGraph)\n\nCheck if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.khop_adj","page":"GNNGraph","title":"GNNGraphs.khop_adj","text":"khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)\n\nReturn A^k where A is the adjacency matrix of the graph 'g'.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.laplacian_lambda_max","page":"GNNGraph","title":"GNNGraphs.laplacian_lambda_max","text":"laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)\n\nReturn the largest eigenvalue of the normalized symmetric Laplacian of the graph g.\n\nIf the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.normalized_laplacian","page":"GNNGraph","title":"GNNGraphs.normalized_laplacian","text":"normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)\n\nNormalized Laplacian matrix of graph g.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\nadd_self_loops: add self-loops while calculating the matrix.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.scaled_laplacian","page":"GNNGraph","title":"GNNGraphs.scaled_laplacian","text":"scaled_laplacian(g, T=Float32; dir=:out)\n\nScaled Laplacian matrix of graph g, defined as hatL = frac2lambda_max L - I where L is the normalized Laplacian matrix.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.LinAlg.adjacency_matrix","page":"GNNGraph","title":"Graphs.LinAlg.adjacency_matrix","text":"adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)\n\nReturn the adjacency matrix A for the graph g. \n\nIf dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.\n\nUser may specify the eltype T of the returned matrix. \n\nIf weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}, Tuple{TT}, Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)\n\nReturn a vector containing the degrees of the nodes in g.\n\nThe gradient is propagated through this function only if edge_weight is true or a vector.\n\nArguments\n\ng: A graph.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.\nedge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{TT}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)\n\nReturn a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.\n\nArguments\n\ng: A graph.\nedge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.has_self_loops-Tuple{GNNGraph}","page":"GNNGraph","title":"Graphs.has_self_loops","text":"has_self_loops(g::GNNGraph)\n\nReturn true if g has any self loops.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.inneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.inneighbors","text":"inneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through incoming edges.\n\nSee also neighbors and outneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.outneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.outneighbors","text":"outneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through outgoing edges.\n\nSee also neighbors and inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Graphs.neighbors(::GNNGraph, ::Integer)","category":"page"},{"location":"api/gnngraph.html#Graphs.neighbors-Tuple{GNNGraph, Integer}","page":"GNNGraph","title":"Graphs.neighbors","text":"neighbors(g::GNNGraph, i::Integer; dir=:out)\n\nReturn the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.\n\nSee also outneighbors, inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Transform","page":"GNNGraph","title":"Transform","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"transform.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])\nadd_edges(g::GNNGraph, (s, t); [edata])\nadd_edges(g::GNNGraph, (s, t, w); [edata])\n\nAdd to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.\n\nIf the s or t contain nodes that are not already present in the graph, they are added to the graph as well.\n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = Float32[1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> add_edges(g, ([2, 3], [4, 1], [10.0, 20.0]))\nGNNGraph:\n num_nodes: 4\n num_edges: 7\n\njulia> g = GNNGraph()\nGNNGraph:\n num_nodes: 0\n num_edges: 0\n\njulia> add_edges(g, [1,2], [2,3])\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])\n\nAdd to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t). \n\nIf the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"GNNGraphs.add_nodes","text":"add_nodes(g::GNNGraph, n; [ndata])\n\nAdd n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNGraph)\n\nReturn a graph with the same features as g but also adding edges connecting the nodes to themselves.\n\nNodes with already existing self-loops will obtain a second self-loop.\n\nIf the graphs has edge weights, the new edges will have weight 1.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNHeteroGraph, edge_t::EType)\nadd_self_loops(g::GNNHeteroGraph)\n\nIf the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.\n\nNodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.\n\nIf the graph has edge weights for edges of type edge_t, the new edges will have weight 1.\n\nIf no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.\n\nIf edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.getgraph-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.getgraph","text":"getgraph(g::GNNGraph, i; nmap=false)\n\nReturn the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph. \n\nIf nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.negative_sample-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.negative_sample","text":"negative_sample(g::GNNGraph; \n num_neg_edges = g.num_edges, \n bidirected = is_bidirected(g))\n\nReturn a graph containing random negative edges (i.e. non-edges) from graph g as edges.\n\nIf bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph. \n\nSee also is_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.perturb_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.perturb_edges","text":"perturb_edges([rng], g::GNNGraph, perturb_ratio)\n\nReturn a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops. \n\nThe function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.\n\nArguments\n\ng::GNNGraph: The graph to be perturbed.\nperturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.\nrng: An optionalrandom number generator to ensure reproducible results.\n\nExamples\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> perturbed_g = perturb_edges(g, 0.2)\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.ppr_diffusion-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.ppr_diffusion","text":"ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph\n\nCalculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web\n\nThe function performs the following steps:\n\nConstructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.\nNormalizes A to ensure each column sums to 1, representing transition probabilities.\nApplies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.\nUpdates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.\n\nArguments\n\ng::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.\nalpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.\n\nReturns\n\nA new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_edge_split-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.rand_edge_split","text":"rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2\n\nRandomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.\n\nIf bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.\n\nrand_edge_split is tipically used to create train/test splits in link prediction tasks.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.random_walk_pe-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.random_walk_pe","text":"random_walk_pe(g, walk_length)\n\nReturn the random walk positional encoding from the paper Graph Neural Networks with Learnable Structural and Positional Representations of the given graph g and the length of the walk walk_length as a matrix of size (walk_length, g.num_nodes). \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector{<:Integer}}","page":"GNNGraph","title":"GNNGraphs.remove_edges","text":"remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})\nremove_edges(g::GNNGraph, p=0.5)\n\nRemove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.\n\nArguments\n\ng: The input graph from which edges will be removed.\nedges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.\np: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.\n\nReturns\n\nA new GNNGraph with the specified edges removed.\n\nExample\n\njulia> using GraphNeuralNetworks\n\n# Construct a GNNGraph\njulia> g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 3\n num_edges: 5\n \n# Remove the second edge\njulia> g_new = remove_edges(g, [2]);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 4\n\n# Remove edges with a probability of 0.5\njulia> g_new = remove_edges(g, 0.5);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_multi_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_multi_edges","text":"remove_multi_edges(g::GNNGraph; aggr=+)\n\nRemove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.\n\nSee also remove_self_loops, has_multi_edges, and to_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, p)\n\nReturns a new graph obtained by dropping nodes from g with independent probabilities p. \n\nExamples\n\njulia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\njulia> g_new = remove_nodes(g, 0.5)\nGNNGraph:\n num_nodes: 2\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)\n\nRemove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.\n\nArguments\n\ng: The input graph from which nodes (and their edges) will be removed.\nnodes_to_remove: Vector of node indices to be removed.\n\nReturns\n\nA new GNNGraph with the specified nodes and all edges associated with these nodes removed. \n\nExample\n\nusing GraphNeuralNetworks\n\ng = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\n\n# Remove nodes with indices 2 and 3, for example\ng_new = remove_nodes(g, [2, 3])\n\n# g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.\nprintln(g_new)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_self_loops","text":"remove_self_loops(g::GNNGraph)\n\nReturn a graph constructed from g where self-loops (edges from a node to itself) are removed. \n\nSee also add_self_loops and remove_multi_edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.set_edge_weight-Tuple{GNNGraph, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.set_edge_weight","text":"set_edge_weight(g::GNNGraph, w::AbstractVector)\n\nSet w as edge weights in the returned graph. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_bidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_bidirected","text":"to_bidirected(g)\n\nAdds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph. \n\nSee also is_bidirected. \n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = [1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> e = [10.0, 20.0, 30.0, 40.0, 50.0];\n\njulia> g = GNNGraph(s, t, w, edata = e)\nGNNGraph:\n num_nodes = 4\n num_edges = 5\n edata:\n e => (5,)\n\njulia> g2 = to_bidirected(g)\nGNNGraph:\n num_nodes = 4\n num_edges = 7\n edata:\n e => (7,)\n\njulia> edge_index(g2)\n([1, 2, 2, 3, 3, 4, 4], [2, 1, 3, 2, 4, 3, 4])\n\njulia> get_edge_weight(g2)\n7-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.5\n 3.5\n 5.0\n\njulia> g2.edata.e\n7-element Vector{Float64}:\n 10.0\n 10.0\n 20.0\n 20.0\n 35.0\n 35.0\n 50.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_unidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_unidirected","text":"to_unidirected(g::GNNGraph)\n\nReturn a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.batch-Tuple{AbstractVector{<:GNNGraph}}","page":"GNNGraph","title":"MLUtils.batch","text":"batch(gs::Vector{<:GNNGraph})\n\nBatch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.\n\nEquivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.\n\nExamples\n\njulia> g1 = rand_graph(4, 6, ndata=ones(8, 4))\nGNNGraph:\n num_nodes = 4\n num_edges = 6\n ndata:\n x => (8, 4)\n\njulia> g2 = rand_graph(7, 4, ndata=zeros(8, 7))\nGNNGraph:\n num_nodes = 7\n num_edges = 4\n ndata:\n x => (8, 7)\n\njulia> g12 = MLUtils.batch([g1, g2])\nGNNGraph:\n num_nodes = 11\n num_edges = 10\n num_graphs = 2\n ndata:\n x => (8, 11)\n\njulia> g12.ndata.x\n8×11 Matrix{Float64}:\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.unbatch-Union{Tuple{GNNGraph{T}}, Tuple{T}} where T<:(Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}})","page":"GNNGraph","title":"MLUtils.unbatch","text":"unbatch(g::GNNGraph)\n\nOpposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.\n\nSee also MLUtils.batch and getgraph.\n\nExamples\n\njulia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])\nGNNGraph:\n num_nodes = 19\n num_edges = 16\n num_graphs = 3\n\njulia> MLUtils.unbatch(gbatched)\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph:\n num_nodes = 5\n num_edges = 6\n\n GNNGraph:\n num_nodes = 10\n num_edges = 8\n\n GNNGraph:\n num_nodes = 4\n num_edges = 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#SparseArrays.blockdiag-Tuple{GNNGraph, Vararg{GNNGraph}}","page":"GNNGraph","title":"SparseArrays.blockdiag","text":"blockdiag(xs::GNNGraph...)\n\nEquivalent to MLUtils.batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Utils","page":"GNNGraph","title":"Utils","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraphs.sort_edge_index\nGNNGraphs.color_refinement","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sort_edge_index","page":"GNNGraph","title":"GNNGraphs.sort_edge_index","text":"sort_edge_index(ei::Tuple) -> u', v'\nsort_edge_index(u, v) -> u', v'\n\nReturn a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi. \n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.color_refinement","page":"GNNGraph","title":"GNNGraphs.color_refinement","text":"color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters\n\nThe color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.\n\nAt each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.\n\nmath x_i' = hashmap((x_i, sort([x_j for j \\in N(i)]))).`\n\nThis algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.\n\nArguments\n\ng::GNNGraph: The graph to color.\nx0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.\n\nReturns\n\nx::AbstractVector{<:Integer}: The final coloring.\nnum_colors::Int: The number of colors used.\nniters::Int: The number of iterations until convergence.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Generate","page":"GNNGraph","title":"Generate","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"generate.jl\"]\nPrivate = false\nFilter = t -> typeof(t) <: Function && t!=rand_temporal_radius_graph && t!=rand_temporal_hyperbolic_graph\n","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.knn_graph-Tuple{AbstractMatrix, Int64}","page":"GNNGraph","title":"GNNGraphs.knn_graph","text":"knn_graph(points::AbstractMatrix, \n k::Int; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a k-nearest neighbor graph where each node is linked to its k closest points. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nk: The number of neighbors considered in the kNN algorithm.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its k nearest neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the k neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, k = 10, 3;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = knn_graph(x, k)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = knn_graph(x, k; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n num_graphs = 2\n\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.radius_graph-Tuple{AbstractMatrix, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.radius_graph","text":"radius_graph(points::AbstractMatrix, \n r::AbstractFloat; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a graph where each node is linked to its neighbors within a given distance r. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nr: The radius.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, r = 10, 0.75;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = radius_graph(x, r)\nGNNGraph:\n num_nodes = 10\n num_edges = 46\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = radius_graph(x, r; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n num_graphs = 2\n\n\nReferences\n\nSection B paragraphs 1 and 2 of the paper Dynamic Hidden-Variable Network Models\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_bipartite_heterograph-Tuple{Any, Any}","page":"GNNGraph","title":"GNNGraphs.rand_bipartite_heterograph","text":"rand_bipartite_heterograph([rng,] \n (n1, n2), (m12, m21); \n bidirected = true, \n node_t = (:A, :B), \n edge_t = :to, \n kws...)\n\nConstruct an GNNHeteroGraph with random edges representing a bipartite graph. The graph will have two types of nodes, and edges will only connect nodes of different types.\n\nThe first argument is a tuple (n1, n2) specifying the number of nodes of each type. The second argument is a tuple (m12, m21) specifying the number of edges connecting nodes of type 1 to nodes of type 2 and vice versa.\n\nThe type of nodes and edges can be specified with the node_t and edge_t keyword arguments, which default to (:A, :B) and :to respectively.\n\nIf bidirected=true (default), the reverse edge of each edge will be present. In this case m12 == m21 is required.\n\nA random number generator can be passed as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nSee rand_heterograph for a more general version.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 15)\n num_edges: ((:A, :to, :B) => 20, (:B, :to, :A) => 20)\n\njulia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)\nGNNHeteroGraph:\n num_nodes: Dict(:item => 15, :user => 10)\n num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_graph-Tuple{Integer, Integer}","page":"GNNGraph","title":"GNNGraphs.rand_graph","text":"rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)\n\nGenerate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.\n\nIf bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.\n\nA vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.\n\nPass a random number generator as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> g = rand_graph(5, 4, bidirected=false)\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n\njulia> edge_index(g)\n([1, 3, 3, 4], [5, 4, 5, 2])\n\n# In the bidirected case, edge data will be duplicated on the reverse edges if needed.\njulia> g = rand_graph(5, 4, edata=rand(Float32, 16, 2))\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n edata:\n e => (16, 4)\n\n# Each edge has a reverse\njulia> edge_index(g)\n([1, 3, 3, 4], [3, 4, 1, 3])\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_heterograph","page":"GNNGraph","title":"GNNGraphs.rand_heterograph","text":"rand_heterograph([rng,] n, m; bidirected=false, kws...)\n\nConstruct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.\n\nPass a random number generator as a first argument to make the generation reproducible.\n\nSetting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nExamples\n\njulia> g = rand_heterograph((:user => 10, :movie => 20),\n (:user, :rate, :movie) => 30)\nGNNHeteroGraph:\n num_nodes: (:user => 10, :movie => 20) \n num_edges: ((:user, :rate, :movie) => 30,)\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Operators","page":"GNNGraph","title":"Operators","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"operators.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Base.intersect","category":"page"},{"location":"api/gnngraph.html#Base.intersect","page":"GNNGraph","title":"Base.intersect","text":"\" intersect(g1::GNNGraph, g2::GNNGraph)\n\nIntersect two graphs by keeping only the common edges.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Sampling","page":"GNNGraph","title":"Sampling","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"sampling.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sample_neighbors","page":"GNNGraph","title":"GNNGraphs.sample_neighbors","text":"sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)\n\nSample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.\n\nThe returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.\n\nArguments\n\ng. The graph.\nnodes. A list of node IDs to sample neighbors from.\nK. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.\ndir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).\nreplace. If true, sample with replacement.\ndropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.\n\nExamples\n\njulia> g = rand_graph(20, 100)\nGNNGraph:\n num_nodes = 20\n num_edges = 100\n\njulia> sample_neighbors(g, 2:3)\nGNNGraph:\n num_nodes = 20\n num_edges = 9\n edata:\n EID => (9,)\n\njulia> sg = sample_neighbors(g, 2:3, dropnodes=true)\nGNNGraph:\n num_nodes = 10\n num_edges = 9\n ndata:\n NID => (10,)\n edata:\n EID => (9,)\n\njulia> sg.ndata.NID\n10-element Vector{Int64}:\n 2\n 3\n 17\n 14\n 18\n 15\n 16\n 20\n 7\n 10\n\njulia> sample_neighbors(g, 2:3, 5, replace=true)\nGNNGraph:\n num_nodes = 20\n num_edges = 10\n edata:\n EID => (10,)\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.","category":"page"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Modules = [GNNGraphs]\nPages = [\"temporalsnapshotsgnngraph.jl\"]\nPrivate = false","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"GNNGraphs.TemporalSnapshotsGNNGraph","text":"TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})\n\nA type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.\n\nTemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.\n\nConstructor Arguments\n\nsnapshot: a vector of snapshots, where each snapshot must have the same number of nodes.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> tg.tgdata.x = rand(4); # add temporal graph feature\n\njulia> tg # show temporal graph with new feature\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n tgdata:\n x = 4-element Vector{Float64}\n\n\n\n\n\n","category":"type"},{"location":"api/temporalgraph.html#GNNGraphs.add_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64, GNNGraph}","page":"Temporal Graphs","title":"GNNGraphs.add_snapshot","text":"add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10, 20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#GNNGraphs.remove_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64}","page":"Temporal Graphs","title":"GNNGraphs.remove_snapshot","text":"remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph-random-generators","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph random generators","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"rand_temporal_radius_graph\nrand_temporal_hyperbolic_graph","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_radius_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_radius_graph","text":"rand_temporal_radius_graph(number_nodes::Int, \n number_snapshots::Int,\n speed::AbstractFloat,\n r::AbstractFloat;\n self_loops = false,\n dir = :in,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are randomly generated in the unit square. Two nodes are connected if their distance is less than a given radius r. Each following snapshot is obtained by applying the same construction to new positions obtained as follows. For each snapshot, the new positions of the points are determined by applying random independent displacement vectors to the previous positions. The direction of the displacement is chosen uniformly at random and its length is chosen uniformly in [0, speed]. Then the connections are recomputed. If a point happens to move outside the boundary, its position is updated as if it had bounced off the boundary.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nspeed: The speed to update the nodes.\nr: The radius of connection.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, s, r = 10, 5, 0.1, 1.5;\n\njulia> tg = rand_temporal_radius_graph(n,snaps,s,r) # complete graph at each snapshot\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [90, 90, 90, 90, 90]\n num_snapshots: 5\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_hyperbolic_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_hyperbolic_graph","text":"rand_temporal_hyperbolic_graph(number_nodes::Int, \n number_snapshots::Int;\n α::Real,\n R::Real,\n speed::Real,\n ζ::Real=1,\n self_loop = false,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are generated with a quasi-uniform distribution (depending on the parameter α) in hyperbolic space within a disk of radius R. Two nodes are connected if their hyperbolic distance is less than R. Each following snapshot is created in order to keep the same initial distribution.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nα: The parameter that controls the position of the points. If α=ζ, the points are uniformly distributed on the disk of radius R. If α>ζ, the points are more concentrated in the center of the disk. If α<ζ, the points are more concentrated at the boundary of the disk.\nR: The radius of the disk and of connection.\nspeed: The speed to update the nodes.\nζ: The parameter that controls the curvature of the disk.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, α, R, speed, ζ = 10, 5, 1.0, 4.0, 0.1, 1.0;\n\njulia> thg = rand_temporal_hyperbolic_graph(n, snaps; α, R, speed, ζ)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [44, 46, 48, 42, 38]\n num_snapshots: 5\n\nReferences\n\nSection D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks\n\n\n\n\n\n","category":"function"},{"location":"temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Temporal Graphs are graphs with time varying topologies and node features. In GraphNeuralNetworks.jl temporal graphs with fixed number of nodes over time are supported by the TemporalSnapshotsGNNGraph type.","category":"page"},{"location":"temporalgraph.html#Creating-a-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Creating a TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A temporal graph can be created by passing a list of snapshots to the constructor. Each snapshot is a GNNGraph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A new temporal graph can be created by adding or removing snapshots to an existing temporal graph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"See rand_temporal_radius_graph and rand_temporal_hyperbolic_graph for generating random temporal graphs. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> tg = rand_temporal_radius_graph(10, 3, 0.1, 0.5)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [32, 30, 34]\n num_snapshots: 3","category":"page"},{"location":"temporalgraph.html#Basic-Queries","page":"Temporal Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Basic queries are similar to those for GNNGraphs:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> tg.num_nodes # number of nodes in each snapshot\n3-element Vector{Int64}:\n 10\n 10\n 10\n\njulia> tg.num_edges # number of edges in each snapshot\n3-element Vector{Int64}:\n 20\n 14\n 22\n\njulia> tg.num_snapshots # number of snapshots\n3\n\njulia> tg.snapshots # list of snapshots\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph(10, 20) with no data\n GNNGraph(10, 14) with no data\n GNNGraph(10, 22) with no data\n\njulia> tg.snapshots[1] # first snapshot, same as tg[1]\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"temporalgraph.html#Data-Features","page":"Temporal Graphs","title":"Data Features","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> tg.tgdata.y = rand(3,1); # graph features after construction\n\njulia> tg\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n tgdata:\n y = 3×1 Matrix{Float64}\n\njulia> tg.ndata # vector of Datastore for node features\n3-element Vector{DataStore}:\n DataStore(10) with 1 element:\n x = 3×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 4×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 5×10 Matrix{Float64}\n\njulia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot\nVector{Matrix{Float64}}","category":"page"},{"location":"temporalgraph.html#Graph-convolutions-on-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Graph convolutions on TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> using GraphNeuralNetworks, Flux\n\njulia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> m = GINConv(Dense(3 => 1), 0.4);\n\njulia> output = m(tg, tg.ndata.x);\n\njulia> size(output[1])\n(1, 10)","category":"page"},{"location":"heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.","category":"page"},{"location":"heterograph.html#Creating-a-Heterograph","page":"Heterogeneous Graphs","title":"Creating a Heterograph","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"A heterograph can be created empty or by passing pairs edge_type => data to the constructor.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph()\nGNNHeteroGraph:\n num_nodes: Dict()\n num_edges: Dict()\n \njulia> g = GNNHeteroGraph((:user, :like, :actor) => ([1,2,2,3], [1,3,2,9]),\n (:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 4, (:user, :rate, :movie) => 4)\n\njulia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"New relations, possibly with new node types, can be added with the function add_edges.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = add_edges(g, (:user, :like, :actor) => ([1,2,3,3,3], [3,5,1,9,4]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 5, (:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See rand_heterograph, rand_bipartite_heterograph for generating random heterographs. ","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 10, :B => 15)\n num_edges: Dict((:A, :to, :B) => 20, (:B, :to, :A) => 20)","category":"page"},{"location":"heterograph.html#Basic-Queries","page":"Heterogeneous Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Basic queries are similar to those for homogeneous graphs:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n\njulia> g.num_nodes\nDict{Symbol, Int64} with 2 entries:\n :user => 3\n :movie => 13\n\njulia> g.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 1 entry:\n (:user, :rate, :movie) => 4\n\n# source and target node for a given relation\njulia> edge_index(g, (:user, :rate, :movie))\n([1, 1, 2, 3], [7, 13, 5, 7])\n\n# node types\njulia> g.ntypes\n2-element Vector{Symbol}:\n :user\n :movie\n\n# edge types\njulia> g.etypes\n1-element Vector{Tuple{Symbol, Symbol, Symbol}}:\n (:user, :rate, :movie)","category":"page"},{"location":"heterograph.html#Data-Features","page":"Heterogeneous Graphs","title":"Data Features","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"# equivalent to g.ndata[:user][:x] = ...\njulia> g[:user].x = rand(Float32, 64, 3);\n\njulia> g[:movie].z = rand(Float32, 64, 13);\n\n# equivalent to g.edata[(:user, :rate, :movie)][:e] = ...\njulia> g[:user, :rate, :movie].e = rand(Float32, 64, 4);\n\njulia> g\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n ndata:\n :movie => DataStore(z = [64×13 Matrix{Float32}])\n :user => DataStore(x = [64×3 Matrix{Float32}])\n edata:\n (:user, :rate, :movie) => DataStore(e = [64×4 Matrix{Float32}])","category":"page"},{"location":"heterograph.html#Batching","page":"Heterogeneous Graphs","title":"Batching","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Similarly to graphs, also heterographs can be batched together.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> gs = [rand_bipartite_heterograph((5, 10), 20) for _ in 1:32];\n\njulia> Flux.batch(gs)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 160, :B => 320)\n num_edges: Dict((:A, :to, :B) => 640, (:B, :to, :A) => 640)\n num_graphs: 32","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Batching is automatically performed by the DataLoader iterator when the collate option is set to true.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"using Flux: DataLoader\n\ndata = [rand_bipartite_heterograph((5, 10), 20, \n ndata=Dict(:A=>rand(Float32, 3, 5))) \n for _ in 1:320];\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes[:A] == 80\n @assert size(g.ndata[:A].x) == (3, 80) \n # ...\nend","category":"page"},{"location":"heterograph.html#Graph-convolutions-on-heterographs","page":"Heterogeneous Graphs","title":"Graph convolutions on heterographs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.","category":"page"},{"location":"api/heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"api/heterograph.html#GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNHeteroGraph","text":"","category":"section"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.","category":"page"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Modules = [GNNGraphs]\nPages = [\"gnnheterograph.jl\"]\nPrivate = false","category":"page"},{"location":"api/heterograph.html#GNNGraphs.GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNGraphs.GNNHeteroGraph","text":"GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])\nGNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])\n\nA type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.\n\nConstructor Arguments\n\ndata: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).\npairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).\nndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.\nedata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.\nnum_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.\n\nFields\n\ngraph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.\nnum_nodes: The number of nodes for each type.\nnum_edges: The number of edges for each type.\nndata: Node features.\nedata: Edge features.\ngdata: Graph features.\nntypes: The node types.\netypes: The edge types.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> nA, nB = 10, 20;\n\njulia> num_nodes = Dict(:A => nA, :B => nB);\n\njulia> edges1 = (rand(1:nA, 20), rand(1:nB, 20))\n([4, 8, 6, 3, 4, 7, 2, 7, 3, 2, 3, 4, 9, 4, 2, 9, 10, 1, 3, 9], [6, 4, 20, 8, 16, 7, 12, 16, 5, 4, 6, 20, 11, 19, 17, 9, 12, 2, 18, 12])\n\njulia> edges2 = (rand(1:nB, 30), rand(1:nA, 30))\n([17, 5, 2, 4, 5, 3, 8, 7, 9, 7 … 19, 8, 20, 7, 16, 2, 9, 15, 8, 13], [1, 1, 3, 1, 1, 3, 2, 7, 4, 4 … 7, 10, 6, 3, 4, 9, 1, 5, 8, 5])\n\njulia> data = ((:A, :rel1, :B) => edges1, (:B, :rel2, :A) => edges2);\n\njulia> hg = GNNHeteroGraph(data; num_nodes)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n\njulia> hg.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 2 entries:\n(:A, :rel1, :B) => 20\n(:B, :rel2, :A) => 30\n\n# Let's add some node features\njulia> ndata = Dict(:A => (x = rand(2, nA), y = rand(3, num_nodes[:A])),\n :B => rand(10, nB));\n\njulia> hg = GNNHeteroGraph(data; num_nodes, ndata)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n ndata:\n :A => (x = 2×10 Matrix{Float64}, y = 3×10 Matrix{Float64})\n :B => x = 10×20 Matrix{Float64}\n\n# Access features of nodes of type :A\njulia> hg.ndata[:A].x\n2×10 Matrix{Float64}:\n 0.825882 0.0797502 0.245813 0.142281 0.231253 0.685025 0.821457 0.888838 0.571347 0.53165\n 0.631286 0.316292 0.705325 0.239211 0.533007 0.249233 0.473736 0.595475 0.0623298 0.159307\n\nSee also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.\n\n\n\n\n\n","category":"type"},{"location":"api/heterograph.html#GNNGraphs.edge_type_subgraph-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}","page":"Heterogeneous Graphs","title":"GNNGraphs.edge_type_subgraph","text":"edge_type_subgraph(g::GNNHeteroGraph, edge_ts)\n\nReturn a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_edge_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_edge_types","text":"num_edge_types(g)\n\nReturn the number of edge types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_node_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_node_types","text":"num_node_types(g)\n\nReturn the number of node types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique node types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Graphs.has_edge(::GNNHeteroGraph, ::Tuple{Symbol, Symbol, Symbol}, ::Integer, ::Integer)","category":"page"},{"location":"api/heterograph.html#Graphs.has_edge-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, Integer, Integer}","page":"Heterogeneous Graphs","title":"Graphs.has_edge","text":"has_edge(g::GNNHeteroGraph, edge_t, i, j)\n\nReturn true if there is an edge of type edge_t from node i to node j in g.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)\nGNNHeteroGraph:\n num_nodes: (:A => 2, :B => 2)\n num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)\n\njulia> has_edge(g, (:A,:to,:B), 1, 1)\ntrue\n\njulia> has_edge(g, (:B,:to,:A), 1, 1)\nfalse\n\n\n\n\n\n","category":"method"},{"location":"gnngraph.html#Working-with-GNNGraph","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library. ","category":"page"},{"location":"gnngraph.html#Graph-Creation","page":"Working with GNNGraph","title":"Graph Creation","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"A GNNGraph can be created from several different data sources encoding the graph topology:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using GraphNeuralNetworks, Graphs, SparseArrays\n\n\n# Construct a GNNGraph from from a Graphs.jl's graph\nlg = erdos_renyi(10, 30)\ng = GNNGraph(lg)\n\n# Same as above using convenience method rand_graph\ng = rand_graph(10, 60)\n\n# From an adjacency matrix\nA = sprand(10, 10, 0.3)\ng = GNNGraph(A)\n\n# From an adjacency list\nadjlist = [[2,3], [1,3], [1,2,4], [3]]\ng = GNNGraph(adjlist)\n\n# From COO representation\nsource = [1,1,2,2,3,3,3,4]\ntarget = [2,3,1,3,1,2,4,3]\ng = GNNGraph(source, target)","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"See also the related methods Graphs.adjacency_matrix, edge_index, and adjacency_list.","category":"page"},{"location":"gnngraph.html#Basic-Queries","page":"Working with GNNGraph","title":"Basic Queries","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> source = [1,1,2,2,3,3,3,4];\n\njulia> target = [2,3,1,3,1,2,4,3];\n\njulia> g = GNNGraph(source, target)\nGNNGraph:\n num_nodes: 4\n num_edges: 8\n\n\njulia> @assert g.num_nodes == 4 # number of nodes\n\njulia> @assert g.num_edges == 8 # number of edges\n\njulia> @assert g.num_graphs == 1 # number of subgraphs (a GNNGraph can batch many graphs together)\n\njulia> is_directed(g) # a GNNGraph is always directed\ntrue\n\njulia> is_bidirected(g) # for each edge, also the reverse edge is present\ntrue\n\njulia> has_self_loops(g)\nfalse\n\njulia> has_multi_edges(g) \nfalse","category":"page"},{"location":"gnngraph.html#Data-Features","page":"Working with GNNGraph","title":"Data Features","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"One or more arrays can be associated to nodes, edges, and (sub)graphs of a GNNGraph. They will be stored in the fields g.ndata, g.edata, and g.gdata respectively.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The data fields are DataStore objects. DataStores conveniently offer an interface similar to both dictionaries and named tuples. Similarly to dictionaries, DataStores support addition of new features after creation time.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The array contained in the datastores have last dimension equal to num_nodes (in ndata), num_edges (in edata), or num_graphs (in gdata) respectively.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"# Create a graph with a single feature array `x` associated to nodes\ng = rand_graph(10, 60, ndata = (; x = rand(Float32, 32, 10)))\n\ng.ndata.x # access the features\n\n# Equivalent definition passing directly the array\ng = rand_graph(10, 60, ndata = rand(Float32, 32, 10))\n\ng.ndata.x # `:x` is the default name for node features\n\ng.ndata.z = rand(Float32, 3, 10) # add new feature array `z`\n\n# For convenience, we can access the features through the shortcut\ng.x \n\n# You can have multiple feature arrays\ng = rand_graph(10, 60, ndata = (; x=rand(Float32, 32, 10), y=rand(Float32, 10)))\n\ng.ndata.y, g.ndata.x # or g.x, g.y\n\n# Attach an array with edge features.\n# Since `GNNGraph`s are directed, the number of edges\n# will be double that of the original Graphs' undirected graph.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 60))\n@assert g.num_edges == 60\n\ng.edata.e # or g.e\n\n# If we pass only half of the edge features, they will be copied\n# on the reversed edges.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 30))\n\n\n# Create a new graph from previous one, inheriting edge data\n# but replacing node data\ng′ = GNNGraph(g, ndata =(; z = ones(Float32, 16, 10)))\n\ng′.z\ng′.e","category":"page"},{"location":"gnngraph.html#Edge-weights","page":"Working with GNNGraph","title":"Edge weights","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"It is common to denote scalar edge features as edge weights. The GNNGraph has specific support for edge weights: they can be stored as part of internal representations of the graph (COO or adjacency matrix). Some graph convolutional layers, most notably the GCNConv, can use the edge weights to perform weighted sums over the nodes' neighborhoods.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> source = [1, 1, 2, 2, 3, 3];\n\njulia> target = [2, 3, 1, 3, 1, 2];\n\njulia> weight = [1.0, 0.5, 2.1, 2.3, 4, 4.1];\n\njulia> g = GNNGraph(source, target, weight)\nGNNGraph:\n num_nodes: 3\n num_edges: 6\n\njulia> get_edge_weight(g)\n6-element Vector{Float64}:\n 1.0\n 0.5\n 2.1\n 2.3\n 4.0\n 4.1","category":"page"},{"location":"gnngraph.html#Batches-and-Subgraphs","page":"Working with GNNGraph","title":"Batches and Subgraphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Multiple GNNGraphs can be batched together into a single graph that contains the total number of the original nodes and where the original graphs are disjoint subgraphs.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using Flux\nusing Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:160]\ngall = Flux.batch(data)\n\n# gall is a GNNGraph containing many graphs\n@assert gall.num_graphs == 160 \n@assert gall.num_nodes == 1600 # 10 nodes x 160 graphs\n@assert gall.num_edges == 4800 # 30 undirected edges x 160 graphs\n\n# Let's create a mini-batch from gall\ng23 = getgraph(gall, 2:3)\n@assert g23.num_graphs == 2\n@assert g23.num_nodes == 20 # 10 nodes x 2 graphs\n@assert g23.num_edges == 60 # 30 undirected edges X 2 graphs\n\n# We can pass a GNNGraph to Flux's DataLoader\ntrain_loader = DataLoader(gall, batchsize=16, shuffle=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend\n\n# Access the nodes' graph memberships \ngraph_indicator(gall)","category":"page"},{"location":"gnngraph.html#DataLoader-and-mini-batch-iteration","page":"Working with GNNGraph","title":"DataLoader and mini-batch iteration","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"While constructing a batched graph and passing it to the DataLoader is always an option for mini-batch iteration, the recommended way for better performance is to pass an array of graphs directly and set the collate option to true:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:320]\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend","category":"page"},{"location":"gnngraph.html#Graph-Manipulation","page":"Working with GNNGraph","title":"Graph Manipulation","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"g′ = add_self_loops(g)\ng′ = remove_self_loops(g)\ng′ = add_edges(g, [1, 2], [2, 3]) # add edges 1->2 and 2->3","category":"page"},{"location":"gnngraph.html#GPU-movement","page":"Working with GNNGraph","title":"GPU movement","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Move a GNNGraph to a CUDA device using Flux.gpu method. ","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using CUDA, Flux\n\ng_gpu = g |> Flux.gpu","category":"page"},{"location":"gnngraph.html#Integration-with-Graphs.jl","page":"Working with GNNGraph","title":"Integration with Graphs.jl","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Since GNNGraph <: Graphs.AbstractGraph, we can use any functionality from Graphs.jl for querying and analyzing the graph structure. Moreover, a GNNGraph can be easily constructed from a Graphs.Graph or a Graphs.DiGraph:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> import Graphs\n\njulia> using GraphNeuralNetworks\n\n# A Graphs.jl undirected graph\njulia> gu = Graphs.erdos_renyi(10, 20) \n{10, 20} undirected simple Int64 graph\n\n# Since GNNGraphs are undirected, the edges are doubled when converting \n# to GNNGraph\njulia> GNNGraph(gu)\nGNNGraph:\n num_nodes: 10\n num_edges: 40\n\n# A Graphs.jl directed graph\njulia> gd = Graphs.erdos_renyi(10, 20, is_directed=true)\n{10, 20} directed simple Int64 graph\n\njulia> GNNGraph(gd)\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"index.html#Write-introduction-GNNGraphs","page":"Home","title":"Write introduction GNNGraphs","text":"","category":"section"},{"location":"datasets.html#Datasets","page":"Datasets","title":"Datasets","text":"","category":"section"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"mldataset2gnngraph","category":"page"},{"location":"datasets.html#GNNGraphs.mldataset2gnngraph","page":"Datasets","title":"GNNGraphs.mldataset2gnngraph","text":"mldataset2gnngraph(dataset)\n\nConvert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.\n\nExamples\n\njulia> using MLDatasets, GraphNeuralNetworks\n\njulia> mldataset2gnngraph(Cora())\nGNNGraph:\n num_nodes = 2708\n num_edges = 10556\n ndata:\n features => 1433×2708 Matrix{Float32}\n targets => 2708-element Vector{Int64}\n train_mask => 2708-element BitVector\n val_mask => 2708-element BitVector\n test_mask => 2708-element BitVector\n\n\n\n\n\n","category":"function"}] +[{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"CurrentModule = GNNGraphs","category":"page"},{"location":"api/gnngraph.html#GNNGraph","page":"GNNGraph","title":"GNNGraph","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Documentation page for the graph type GNNGraph provided by GNNGraphs.jl and related methods. ","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.","category":"page"},{"location":"api/gnngraph.html#Index","page":"GNNGraph","title":"Index","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Order = [:type, :function]\nPages = [\"gnngraph.md\"]","category":"page"},{"location":"api/gnngraph.html#GNNGraph-type","page":"GNNGraph","title":"GNNGraph type","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraph\nBase.copy","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.GNNGraph","page":"GNNGraph","title":"GNNGraphs.GNNGraph","text":"GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])\nGNNGraph(g::GNNGraph; [ndata, edata, gdata])\n\nA type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.\n\nThe feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.\n\nA GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.\n\nWhen constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.\n\nA GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.\n\nGNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.\n\nA GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.\n\nArguments\n\ndata: Some data representing the graph topology. Possible type are\nAn adjacency matrix\nAn adjacency list.\nA tuple containing the source and target vectors (COO representation)\nA Graphs.jl' graph.\ngraph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are\n:coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).\n:sparse. A sparse adjacency matrix representation.\n:dense. A dense adjacency matrix representation.\nDefaults to :coo, currently the most supported type.\ndir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.\nnum_nodes: The number of nodes. If not specified, inferred from g. Default nothing.\ngraph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.\nndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.\nedata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.\n\nExamples\n\nusing GraphNeuralNetworks\n\n# Construct from adjacency list representation\ndata = [[2,3], [1,4,5], [1], [2,5], [2,4]]\ng = GNNGraph(data)\n\n# Number of nodes, edges, and batched graphs\ng.num_nodes # 5\ng.num_edges # 10\ng.num_graphs # 1\n\n# Same graph in COO representation\ns = [1,1,2,2,2,3,4,4,5,5]\nt = [2,3,1,4,5,3,2,5,2,4]\ng = GNNGraph(s, t)\n\n# From a Graphs' graph\ng = GNNGraph(erdos_renyi(100, 20))\n\n# Add 2 node feature arrays at creation time\ng = GNNGraph(g, ndata = (x=rand(100, g.num_nodes), y=rand(g.num_nodes)))\n\n# Add 1 edge feature array, after the graph creation\ng.edata.z = rand(16, g.num_edges)\n\n# Add node features and edge features with default names `x` and `e`\ng = GNNGraph(g, ndata = rand(100, g.num_nodes), edata = rand(16, g.num_edges))\n\ng.ndata.x # or just g.x\ng.edata.e # or just g.e\n\n# Collect edges' source and target nodes.\n# Both source and target are vectors of length num_edges\nsource, target = edge_index(g)\n\nA GNNGraph can be sent to the GPU using e.g. Flux's gpu function:\n\n# Send to gpu\nusing Flux, CUDA\ng = g |> Flux.gpu\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Base.copy","page":"GNNGraph","title":"Base.copy","text":"copy(g::GNNGraph; deep=false)\n\nCreate a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#DataStore","page":"GNNGraph","title":"DataStore","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"datastore.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.DataStore","page":"GNNGraph","title":"GNNGraphs.DataStore","text":"DataStore([n, data])\nDataStore([n,] k1 = x1, k2 = x2, ...)\n\nA container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.\n\nAt construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:\n\njulia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))\nDataStore(3) with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds = DataStore(3, Dict(:x => rand(Float32, 2, 3), :y => rand(Float32, 3))); # equivalent to above\n\njulia> ds = DataStore(3, (x = rand(Float32, 2, 3), y = rand(Float32, 30)))\nERROR: AssertionError: DataStore: data[y] has 30 observations, but n = 3\nStacktrace:\n [1] DataStore(n::Int64, data::Dict{Symbol, Any})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:54\n [2] DataStore(n::Int64, data::NamedTuple{(:x, :y), Tuple{Matrix{Float32}, Vector{Float32}}})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:73\n [3] top-level scope\n @ REPL[13]:1\n\njulia> ds = DataStore(x = randFloat32, 2, 3), y = rand(Float32, 30)) # no checks\nDataStore() with 2 elements:\n y = 30-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n y = 30-element Vector{Float64}\n x = 2×3 Matrix{Float64}\n\nThe DataStore has an interface similar to both dictionaries and named tuples. Arrays can be accessed and added using either the indexing or the property syntax:\n\njulia> ds = DataStore(x = ones(Float32, 2, 3), y = zeros(Float32, 3))\nDataStore() with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds.x # same as `ds[:x]`\n2×3 Matrix{Float32}:\n 1.0 1.0 1.0\n 1.0 1.0 1.0\n\njulia> ds.z = zeros(Float32, 3) # Add new feature array `z`. Same as `ds[:z] = rand(Float32, 3)`\n3-element Vector{Float64}:\n0.0\n0.0\n0.0\n\nThe DataStore can be iterated over, and the keys and values can be accessed using keys(ds) and values(ds). map(f, ds) applies the function f to each feature array:\n\njulia> ds = DataStore(a = zeros(2), b = zeros(2));\n\njulia> ds2 = map(x -> x .+ 1, ds)\n\njulia> ds2.a\n2-element Vector{Float64}:\n 1.0\n 1.0\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Query","page":"GNNGraph","title":"Query","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"query.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.adjacency_list-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.adjacency_list","text":"adjacency_list(g; dir=:out)\nadjacency_list(g, nodes; dir=:out)\n\nReturn the adjacency list representation (a vector of vectors) of the graph g.\n\nCalling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.\n\nIf nodes is given, return the neighborhood of the nodes in nodes only.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNGraph)\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.\n\ns, t = edge_index(g)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNHeteroGraph, [edge_t])\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).\n\nIf edge_t is not provided, it will error if g has more than one edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNGraph; edges=false)\n\nReturn a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNHeteroGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNHeteroGraph, [node_t])\n\nReturn a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.\n\nSee also batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_isolated_nodes-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_isolated_nodes","text":"has_isolated_nodes(g::GNNGraph; dir=:out)\n\nReturn true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_multi_edges-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_multi_edges","text":"has_multi_edges(g::GNNGraph)\n\nReturn true if g has any multiple edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.is_bidirected-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.is_bidirected","text":"is_bidirected(g::GNNGraph)\n\nCheck if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.khop_adj","page":"GNNGraph","title":"GNNGraphs.khop_adj","text":"khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)\n\nReturn A^k where A is the adjacency matrix of the graph 'g'.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.laplacian_lambda_max","page":"GNNGraph","title":"GNNGraphs.laplacian_lambda_max","text":"laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)\n\nReturn the largest eigenvalue of the normalized symmetric Laplacian of the graph g.\n\nIf the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.normalized_laplacian","page":"GNNGraph","title":"GNNGraphs.normalized_laplacian","text":"normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)\n\nNormalized Laplacian matrix of graph g.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\nadd_self_loops: add self-loops while calculating the matrix.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.scaled_laplacian","page":"GNNGraph","title":"GNNGraphs.scaled_laplacian","text":"scaled_laplacian(g, T=Float32; dir=:out)\n\nScaled Laplacian matrix of graph g, defined as hatL = frac2lambda_max L - I where L is the normalized Laplacian matrix.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.LinAlg.adjacency_matrix","page":"GNNGraph","title":"Graphs.LinAlg.adjacency_matrix","text":"adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)\n\nReturn the adjacency matrix A for the graph g. \n\nIf dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.\n\nUser may specify the eltype T of the returned matrix. \n\nIf weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}, Tuple{TT}, Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)\n\nReturn a vector containing the degrees of the nodes in g.\n\nThe gradient is propagated through this function only if edge_weight is true or a vector.\n\nArguments\n\ng: A graph.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.\nedge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{TT}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)\n\nReturn a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.\n\nArguments\n\ng: A graph.\nedge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.has_self_loops-Tuple{GNNGraph}","page":"GNNGraph","title":"Graphs.has_self_loops","text":"has_self_loops(g::GNNGraph)\n\nReturn true if g has any self loops.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.inneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.inneighbors","text":"inneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through incoming edges.\n\nSee also neighbors and outneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.outneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.outneighbors","text":"outneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through outgoing edges.\n\nSee also neighbors and inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Graphs.neighbors(::GNNGraph, ::Integer)","category":"page"},{"location":"api/gnngraph.html#Graphs.neighbors-Tuple{GNNGraph, Integer}","page":"GNNGraph","title":"Graphs.neighbors","text":"neighbors(g::GNNGraph, i::Integer; dir=:out)\n\nReturn the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.\n\nSee also outneighbors, inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Transform","page":"GNNGraph","title":"Transform","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"transform.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])\nadd_edges(g::GNNGraph, (s, t); [edata])\nadd_edges(g::GNNGraph, (s, t, w); [edata])\n\nAdd to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.\n\nIf the s or t contain nodes that are not already present in the graph, they are added to the graph as well.\n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = Float32[1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> add_edges(g, ([2, 3], [4, 1], [10.0, 20.0]))\nGNNGraph:\n num_nodes: 4\n num_edges: 7\n\njulia> g = GNNGraph()\nGNNGraph:\n num_nodes: 0\n num_edges: 0\n\njulia> add_edges(g, [1,2], [2,3])\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])\n\nAdd to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t). \n\nIf the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"GNNGraphs.add_nodes","text":"add_nodes(g::GNNGraph, n; [ndata])\n\nAdd n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNGraph)\n\nReturn a graph with the same features as g but also adding edges connecting the nodes to themselves.\n\nNodes with already existing self-loops will obtain a second self-loop.\n\nIf the graphs has edge weights, the new edges will have weight 1.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNHeteroGraph, edge_t::EType)\nadd_self_loops(g::GNNHeteroGraph)\n\nIf the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.\n\nNodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.\n\nIf the graph has edge weights for edges of type edge_t, the new edges will have weight 1.\n\nIf no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.\n\nIf edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.getgraph-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.getgraph","text":"getgraph(g::GNNGraph, i; nmap=false)\n\nReturn the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph. \n\nIf nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.negative_sample-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.negative_sample","text":"negative_sample(g::GNNGraph; \n num_neg_edges = g.num_edges, \n bidirected = is_bidirected(g))\n\nReturn a graph containing random negative edges (i.e. non-edges) from graph g as edges.\n\nIf bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph. \n\nSee also is_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.perturb_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.perturb_edges","text":"perturb_edges([rng], g::GNNGraph, perturb_ratio)\n\nReturn a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops. \n\nThe function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.\n\nArguments\n\ng::GNNGraph: The graph to be perturbed.\nperturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.\nrng: An optionalrandom number generator to ensure reproducible results.\n\nExamples\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> perturbed_g = perturb_edges(g, 0.2)\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.ppr_diffusion-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.ppr_diffusion","text":"ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph\n\nCalculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web\n\nThe function performs the following steps:\n\nConstructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.\nNormalizes A to ensure each column sums to 1, representing transition probabilities.\nApplies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.\nUpdates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.\n\nArguments\n\ng::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.\nalpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.\n\nReturns\n\nA new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_edge_split-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.rand_edge_split","text":"rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2\n\nRandomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.\n\nIf bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.\n\nrand_edge_split is tipically used to create train/test splits in link prediction tasks.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.random_walk_pe-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.random_walk_pe","text":"random_walk_pe(g, walk_length)\n\nReturn the random walk positional encoding from the paper Graph Neural Networks with Learnable Structural and Positional Representations of the given graph g and the length of the walk walk_length as a matrix of size (walk_length, g.num_nodes). \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector{<:Integer}}","page":"GNNGraph","title":"GNNGraphs.remove_edges","text":"remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})\nremove_edges(g::GNNGraph, p=0.5)\n\nRemove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.\n\nArguments\n\ng: The input graph from which edges will be removed.\nedges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.\np: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.\n\nReturns\n\nA new GNNGraph with the specified edges removed.\n\nExample\n\njulia> using GraphNeuralNetworks\n\n# Construct a GNNGraph\njulia> g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 3\n num_edges: 5\n \n# Remove the second edge\njulia> g_new = remove_edges(g, [2]);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 4\n\n# Remove edges with a probability of 0.5\njulia> g_new = remove_edges(g, 0.5);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_multi_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_multi_edges","text":"remove_multi_edges(g::GNNGraph; aggr=+)\n\nRemove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.\n\nSee also remove_self_loops, has_multi_edges, and to_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, p)\n\nReturns a new graph obtained by dropping nodes from g with independent probabilities p. \n\nExamples\n\njulia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\njulia> g_new = remove_nodes(g, 0.5)\nGNNGraph:\n num_nodes: 2\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)\n\nRemove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.\n\nArguments\n\ng: The input graph from which nodes (and their edges) will be removed.\nnodes_to_remove: Vector of node indices to be removed.\n\nReturns\n\nA new GNNGraph with the specified nodes and all edges associated with these nodes removed. \n\nExample\n\nusing GraphNeuralNetworks\n\ng = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\n\n# Remove nodes with indices 2 and 3, for example\ng_new = remove_nodes(g, [2, 3])\n\n# g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.\nprintln(g_new)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_self_loops","text":"remove_self_loops(g::GNNGraph)\n\nReturn a graph constructed from g where self-loops (edges from a node to itself) are removed. \n\nSee also add_self_loops and remove_multi_edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.set_edge_weight-Tuple{GNNGraph, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.set_edge_weight","text":"set_edge_weight(g::GNNGraph, w::AbstractVector)\n\nSet w as edge weights in the returned graph. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_bidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_bidirected","text":"to_bidirected(g)\n\nAdds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph. \n\nSee also is_bidirected. \n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = [1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> e = [10.0, 20.0, 30.0, 40.0, 50.0];\n\njulia> g = GNNGraph(s, t, w, edata = e)\nGNNGraph:\n num_nodes = 4\n num_edges = 5\n edata:\n e => (5,)\n\njulia> g2 = to_bidirected(g)\nGNNGraph:\n num_nodes = 4\n num_edges = 7\n edata:\n e => (7,)\n\njulia> edge_index(g2)\n([1, 2, 2, 3, 3, 4, 4], [2, 1, 3, 2, 4, 3, 4])\n\njulia> get_edge_weight(g2)\n7-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.5\n 3.5\n 5.0\n\njulia> g2.edata.e\n7-element Vector{Float64}:\n 10.0\n 10.0\n 20.0\n 20.0\n 35.0\n 35.0\n 50.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_unidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_unidirected","text":"to_unidirected(g::GNNGraph)\n\nReturn a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.batch-Tuple{AbstractVector{<:GNNGraph}}","page":"GNNGraph","title":"MLUtils.batch","text":"batch(gs::Vector{<:GNNGraph})\n\nBatch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.\n\nEquivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.\n\nExamples\n\njulia> g1 = rand_graph(4, 6, ndata=ones(8, 4))\nGNNGraph:\n num_nodes = 4\n num_edges = 6\n ndata:\n x => (8, 4)\n\njulia> g2 = rand_graph(7, 4, ndata=zeros(8, 7))\nGNNGraph:\n num_nodes = 7\n num_edges = 4\n ndata:\n x => (8, 7)\n\njulia> g12 = MLUtils.batch([g1, g2])\nGNNGraph:\n num_nodes = 11\n num_edges = 10\n num_graphs = 2\n ndata:\n x => (8, 11)\n\njulia> g12.ndata.x\n8×11 Matrix{Float64}:\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.unbatch-Union{Tuple{GNNGraph{T}}, Tuple{T}} where T<:(Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}})","page":"GNNGraph","title":"MLUtils.unbatch","text":"unbatch(g::GNNGraph)\n\nOpposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.\n\nSee also MLUtils.batch and getgraph.\n\nExamples\n\njulia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])\nGNNGraph:\n num_nodes = 19\n num_edges = 16\n num_graphs = 3\n\njulia> MLUtils.unbatch(gbatched)\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph:\n num_nodes = 5\n num_edges = 6\n\n GNNGraph:\n num_nodes = 10\n num_edges = 8\n\n GNNGraph:\n num_nodes = 4\n num_edges = 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#SparseArrays.blockdiag-Tuple{GNNGraph, Vararg{GNNGraph}}","page":"GNNGraph","title":"SparseArrays.blockdiag","text":"blockdiag(xs::GNNGraph...)\n\nEquivalent to MLUtils.batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Utils","page":"GNNGraph","title":"Utils","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraphs.sort_edge_index\nGNNGraphs.color_refinement","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sort_edge_index","page":"GNNGraph","title":"GNNGraphs.sort_edge_index","text":"sort_edge_index(ei::Tuple) -> u', v'\nsort_edge_index(u, v) -> u', v'\n\nReturn a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi. \n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.color_refinement","page":"GNNGraph","title":"GNNGraphs.color_refinement","text":"color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters\n\nThe color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.\n\nAt each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.\n\nmath x_i' = hashmap((x_i, sort([x_j for j \\in N(i)]))).`\n\nThis algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.\n\nArguments\n\ng::GNNGraph: The graph to color.\nx0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.\n\nReturns\n\nx::AbstractVector{<:Integer}: The final coloring.\nnum_colors::Int: The number of colors used.\nniters::Int: The number of iterations until convergence.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Generate","page":"GNNGraph","title":"Generate","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"generate.jl\"]\nPrivate = false\nFilter = t -> typeof(t) <: Function && t!=rand_temporal_radius_graph && t!=rand_temporal_hyperbolic_graph\n","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.knn_graph-Tuple{AbstractMatrix, Int64}","page":"GNNGraph","title":"GNNGraphs.knn_graph","text":"knn_graph(points::AbstractMatrix, \n k::Int; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a k-nearest neighbor graph where each node is linked to its k closest points. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nk: The number of neighbors considered in the kNN algorithm.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its k nearest neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the k neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, k = 10, 3;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = knn_graph(x, k)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = knn_graph(x, k; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n num_graphs = 2\n\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.radius_graph-Tuple{AbstractMatrix, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.radius_graph","text":"radius_graph(points::AbstractMatrix, \n r::AbstractFloat; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a graph where each node is linked to its neighbors within a given distance r. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nr: The radius.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, r = 10, 0.75;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = radius_graph(x, r)\nGNNGraph:\n num_nodes = 10\n num_edges = 46\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = radius_graph(x, r; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n num_graphs = 2\n\n\nReferences\n\nSection B paragraphs 1 and 2 of the paper Dynamic Hidden-Variable Network Models\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_bipartite_heterograph-Tuple{Any, Any}","page":"GNNGraph","title":"GNNGraphs.rand_bipartite_heterograph","text":"rand_bipartite_heterograph([rng,] \n (n1, n2), (m12, m21); \n bidirected = true, \n node_t = (:A, :B), \n edge_t = :to, \n kws...)\n\nConstruct an GNNHeteroGraph with random edges representing a bipartite graph. The graph will have two types of nodes, and edges will only connect nodes of different types.\n\nThe first argument is a tuple (n1, n2) specifying the number of nodes of each type. The second argument is a tuple (m12, m21) specifying the number of edges connecting nodes of type 1 to nodes of type 2 and vice versa.\n\nThe type of nodes and edges can be specified with the node_t and edge_t keyword arguments, which default to (:A, :B) and :to respectively.\n\nIf bidirected=true (default), the reverse edge of each edge will be present. In this case m12 == m21 is required.\n\nA random number generator can be passed as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nSee rand_heterograph for a more general version.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 15)\n num_edges: ((:A, :to, :B) => 20, (:B, :to, :A) => 20)\n\njulia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)\nGNNHeteroGraph:\n num_nodes: Dict(:item => 15, :user => 10)\n num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_graph-Tuple{Integer, Integer}","page":"GNNGraph","title":"GNNGraphs.rand_graph","text":"rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)\n\nGenerate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.\n\nIf bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.\n\nA vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.\n\nPass a random number generator as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> g = rand_graph(5, 4, bidirected=false)\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n\njulia> edge_index(g)\n([1, 3, 3, 4], [5, 4, 5, 2])\n\n# In the bidirected case, edge data will be duplicated on the reverse edges if needed.\njulia> g = rand_graph(5, 4, edata=rand(Float32, 16, 2))\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n edata:\n e => (16, 4)\n\n# Each edge has a reverse\njulia> edge_index(g)\n([1, 3, 3, 4], [3, 4, 1, 3])\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_heterograph","page":"GNNGraph","title":"GNNGraphs.rand_heterograph","text":"rand_heterograph([rng,] n, m; bidirected=false, kws...)\n\nConstruct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.\n\nPass a random number generator as a first argument to make the generation reproducible.\n\nSetting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nExamples\n\njulia> g = rand_heterograph((:user => 10, :movie => 20),\n (:user, :rate, :movie) => 30)\nGNNHeteroGraph:\n num_nodes: (:user => 10, :movie => 20) \n num_edges: ((:user, :rate, :movie) => 30,)\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Operators","page":"GNNGraph","title":"Operators","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"operators.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Base.intersect","category":"page"},{"location":"api/gnngraph.html#Base.intersect","page":"GNNGraph","title":"Base.intersect","text":"\" intersect(g1::GNNGraph, g2::GNNGraph)\n\nIntersect two graphs by keeping only the common edges.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Sampling","page":"GNNGraph","title":"Sampling","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"sampling.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sample_neighbors","page":"GNNGraph","title":"GNNGraphs.sample_neighbors","text":"sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)\n\nSample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.\n\nThe returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.\n\nArguments\n\ng. The graph.\nnodes. A list of node IDs to sample neighbors from.\nK. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.\ndir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).\nreplace. If true, sample with replacement.\ndropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.\n\nExamples\n\njulia> g = rand_graph(20, 100)\nGNNGraph:\n num_nodes = 20\n num_edges = 100\n\njulia> sample_neighbors(g, 2:3)\nGNNGraph:\n num_nodes = 20\n num_edges = 9\n edata:\n EID => (9,)\n\njulia> sg = sample_neighbors(g, 2:3, dropnodes=true)\nGNNGraph:\n num_nodes = 10\n num_edges = 9\n ndata:\n NID => (10,)\n edata:\n EID => (9,)\n\njulia> sg.ndata.NID\n10-element Vector{Int64}:\n 2\n 3\n 17\n 14\n 18\n 15\n 16\n 20\n 7\n 10\n\njulia> sample_neighbors(g, 2:3, 5, replace=true)\nGNNGraph:\n num_nodes = 20\n num_edges = 10\n edata:\n EID => (10,)\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.","category":"page"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Modules = [GNNGraphs]\nPages = [\"temporalsnapshotsgnngraph.jl\"]\nPrivate = false","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"GNNGraphs.TemporalSnapshotsGNNGraph","text":"TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})\n\nA type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.\n\nTemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.\n\nConstructor Arguments\n\nsnapshot: a vector of snapshots, where each snapshot must have the same number of nodes.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> tg.tgdata.x = rand(4); # add temporal graph feature\n\njulia> tg # show temporal graph with new feature\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n tgdata:\n x = 4-element Vector{Float64}\n\n\n\n\n\n","category":"type"},{"location":"api/temporalgraph.html#GNNGraphs.add_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64, GNNGraph}","page":"Temporal Graphs","title":"GNNGraphs.add_snapshot","text":"add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10, 20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#GNNGraphs.remove_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64}","page":"Temporal Graphs","title":"GNNGraphs.remove_snapshot","text":"remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph-random-generators","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph random generators","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"rand_temporal_radius_graph\nrand_temporal_hyperbolic_graph","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_radius_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_radius_graph","text":"rand_temporal_radius_graph(number_nodes::Int, \n number_snapshots::Int,\n speed::AbstractFloat,\n r::AbstractFloat;\n self_loops = false,\n dir = :in,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are randomly generated in the unit square. Two nodes are connected if their distance is less than a given radius r. Each following snapshot is obtained by applying the same construction to new positions obtained as follows. For each snapshot, the new positions of the points are determined by applying random independent displacement vectors to the previous positions. The direction of the displacement is chosen uniformly at random and its length is chosen uniformly in [0, speed]. Then the connections are recomputed. If a point happens to move outside the boundary, its position is updated as if it had bounced off the boundary.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nspeed: The speed to update the nodes.\nr: The radius of connection.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, s, r = 10, 5, 0.1, 1.5;\n\njulia> tg = rand_temporal_radius_graph(n,snaps,s,r) # complete graph at each snapshot\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [90, 90, 90, 90, 90]\n num_snapshots: 5\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_hyperbolic_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_hyperbolic_graph","text":"rand_temporal_hyperbolic_graph(number_nodes::Int, \n number_snapshots::Int;\n α::Real,\n R::Real,\n speed::Real,\n ζ::Real=1,\n self_loop = false,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are generated with a quasi-uniform distribution (depending on the parameter α) in hyperbolic space within a disk of radius R. Two nodes are connected if their hyperbolic distance is less than R. Each following snapshot is created in order to keep the same initial distribution.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nα: The parameter that controls the position of the points. If α=ζ, the points are uniformly distributed on the disk of radius R. If α>ζ, the points are more concentrated in the center of the disk. If α<ζ, the points are more concentrated at the boundary of the disk.\nR: The radius of the disk and of connection.\nspeed: The speed to update the nodes.\nζ: The parameter that controls the curvature of the disk.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, α, R, speed, ζ = 10, 5, 1.0, 4.0, 0.1, 1.0;\n\njulia> thg = rand_temporal_hyperbolic_graph(n, snaps; α, R, speed, ζ)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [44, 46, 48, 42, 38]\n num_snapshots: 5\n\nReferences\n\nSection D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks\n\n\n\n\n\n","category":"function"},{"location":"temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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.","category":"page"},{"location":"temporalgraph.html#Creating-a-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Creating a TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A temporal graph can be created by passing a list of snapshots to the constructor. Each snapshot is a GNNGraph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A new temporal graph can be created by adding or removing snapshots to an existing temporal graph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"See rand_temporal_radius_graph and rand_temporal_hyperbolic_graph for generating random temporal graphs. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> tg = rand_temporal_radius_graph(10, 3, 0.1, 0.5)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [32, 30, 34]\n num_snapshots: 3","category":"page"},{"location":"temporalgraph.html#Basic-Queries","page":"Temporal Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Basic queries are similar to those for GNNGraphs:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> tg.num_nodes # number of nodes in each snapshot\n3-element Vector{Int64}:\n 10\n 10\n 10\n\njulia> tg.num_edges # number of edges in each snapshot\n3-element Vector{Int64}:\n 20\n 14\n 22\n\njulia> tg.num_snapshots # number of snapshots\n3\n\njulia> tg.snapshots # list of snapshots\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph(10, 20) with no data\n GNNGraph(10, 14) with no data\n GNNGraph(10, 22) with no data\n\njulia> tg.snapshots[1] # first snapshot, same as tg[1]\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"temporalgraph.html#Data-Features","page":"Temporal Graphs","title":"Data Features","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> tg.tgdata.y = rand(3,1); # graph features after construction\n\njulia> tg\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n tgdata:\n y = 3×1 Matrix{Float64}\n\njulia> tg.ndata # vector of Datastore for node features\n3-element Vector{DataStore}:\n DataStore(10) with 1 element:\n x = 3×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 4×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 5×10 Matrix{Float64}\n\njulia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot\nVector{Matrix{Float64}}","category":"page"},{"location":"temporalgraph.html#Graph-convolutions-on-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Graph convolutions on TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> using GraphNeuralNetworks, Flux\n\njulia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> m = GINConv(Dense(3 => 1), 0.4);\n\njulia> output = m(tg, tg.ndata.x);\n\njulia> size(output[1])\n(1, 10)","category":"page"},{"location":"heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.","category":"page"},{"location":"heterograph.html#Creating-a-Heterograph","page":"Heterogeneous Graphs","title":"Creating a Heterograph","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"A heterograph can be created empty or by passing pairs edge_type => data to the constructor.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph()\nGNNHeteroGraph:\n num_nodes: Dict()\n num_edges: Dict()\n \njulia> g = GNNHeteroGraph((:user, :like, :actor) => ([1,2,2,3], [1,3,2,9]),\n (:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 4, (:user, :rate, :movie) => 4)\n\njulia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"New relations, possibly with new node types, can be added with the function add_edges.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = add_edges(g, (:user, :like, :actor) => ([1,2,3,3,3], [3,5,1,9,4]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 5, (:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See rand_heterograph, rand_bipartite_heterograph for generating random heterographs. ","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 10, :B => 15)\n num_edges: Dict((:A, :to, :B) => 20, (:B, :to, :A) => 20)","category":"page"},{"location":"heterograph.html#Basic-Queries","page":"Heterogeneous Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Basic queries are similar to those for homogeneous graphs:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n\njulia> g.num_nodes\nDict{Symbol, Int64} with 2 entries:\n :user => 3\n :movie => 13\n\njulia> g.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 1 entry:\n (:user, :rate, :movie) => 4\n\n# source and target node for a given relation\njulia> edge_index(g, (:user, :rate, :movie))\n([1, 1, 2, 3], [7, 13, 5, 7])\n\n# node types\njulia> g.ntypes\n2-element Vector{Symbol}:\n :user\n :movie\n\n# edge types\njulia> g.etypes\n1-element Vector{Tuple{Symbol, Symbol, Symbol}}:\n (:user, :rate, :movie)","category":"page"},{"location":"heterograph.html#Data-Features","page":"Heterogeneous Graphs","title":"Data Features","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"# equivalent to g.ndata[:user][:x] = ...\njulia> g[:user].x = rand(Float32, 64, 3);\n\njulia> g[:movie].z = rand(Float32, 64, 13);\n\n# equivalent to g.edata[(:user, :rate, :movie)][:e] = ...\njulia> g[:user, :rate, :movie].e = rand(Float32, 64, 4);\n\njulia> g\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n ndata:\n :movie => DataStore(z = [64×13 Matrix{Float32}])\n :user => DataStore(x = [64×3 Matrix{Float32}])\n edata:\n (:user, :rate, :movie) => DataStore(e = [64×4 Matrix{Float32}])","category":"page"},{"location":"heterograph.html#Batching","page":"Heterogeneous Graphs","title":"Batching","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Similarly to graphs, also heterographs can be batched together.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> gs = [rand_bipartite_heterograph((5, 10), 20) for _ in 1:32];\n\njulia> Flux.batch(gs)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 160, :B => 320)\n num_edges: Dict((:A, :to, :B) => 640, (:B, :to, :A) => 640)\n num_graphs: 32","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Batching is automatically performed by the DataLoader iterator when the collate option is set to true.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"using Flux: DataLoader\n\ndata = [rand_bipartite_heterograph((5, 10), 20, \n ndata=Dict(:A=>rand(Float32, 3, 5))) \n for _ in 1:320];\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes[:A] == 80\n @assert size(g.ndata[:A].x) == (3, 80) \n # ...\nend","category":"page"},{"location":"heterograph.html#Graph-convolutions-on-heterographs","page":"Heterogeneous Graphs","title":"Graph convolutions on heterographs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.","category":"page"},{"location":"api/heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"api/heterograph.html#GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNHeteroGraph","text":"","category":"section"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.","category":"page"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Modules = [GNNGraphs]\nPages = [\"gnnheterograph.jl\"]\nPrivate = false","category":"page"},{"location":"api/heterograph.html#GNNGraphs.GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNGraphs.GNNHeteroGraph","text":"GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])\nGNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])\n\nA type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.\n\nConstructor Arguments\n\ndata: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).\npairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).\nndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.\nedata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.\nnum_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.\n\nFields\n\ngraph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.\nnum_nodes: The number of nodes for each type.\nnum_edges: The number of edges for each type.\nndata: Node features.\nedata: Edge features.\ngdata: Graph features.\nntypes: The node types.\netypes: The edge types.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> nA, nB = 10, 20;\n\njulia> num_nodes = Dict(:A => nA, :B => nB);\n\njulia> edges1 = (rand(1:nA, 20), rand(1:nB, 20))\n([4, 8, 6, 3, 4, 7, 2, 7, 3, 2, 3, 4, 9, 4, 2, 9, 10, 1, 3, 9], [6, 4, 20, 8, 16, 7, 12, 16, 5, 4, 6, 20, 11, 19, 17, 9, 12, 2, 18, 12])\n\njulia> edges2 = (rand(1:nB, 30), rand(1:nA, 30))\n([17, 5, 2, 4, 5, 3, 8, 7, 9, 7 … 19, 8, 20, 7, 16, 2, 9, 15, 8, 13], [1, 1, 3, 1, 1, 3, 2, 7, 4, 4 … 7, 10, 6, 3, 4, 9, 1, 5, 8, 5])\n\njulia> data = ((:A, :rel1, :B) => edges1, (:B, :rel2, :A) => edges2);\n\njulia> hg = GNNHeteroGraph(data; num_nodes)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n\njulia> hg.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 2 entries:\n(:A, :rel1, :B) => 20\n(:B, :rel2, :A) => 30\n\n# Let's add some node features\njulia> ndata = Dict(:A => (x = rand(2, nA), y = rand(3, num_nodes[:A])),\n :B => rand(10, nB));\n\njulia> hg = GNNHeteroGraph(data; num_nodes, ndata)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n ndata:\n :A => (x = 2×10 Matrix{Float64}, y = 3×10 Matrix{Float64})\n :B => x = 10×20 Matrix{Float64}\n\n# Access features of nodes of type :A\njulia> hg.ndata[:A].x\n2×10 Matrix{Float64}:\n 0.825882 0.0797502 0.245813 0.142281 0.231253 0.685025 0.821457 0.888838 0.571347 0.53165\n 0.631286 0.316292 0.705325 0.239211 0.533007 0.249233 0.473736 0.595475 0.0623298 0.159307\n\nSee also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.\n\n\n\n\n\n","category":"type"},{"location":"api/heterograph.html#GNNGraphs.edge_type_subgraph-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}","page":"Heterogeneous Graphs","title":"GNNGraphs.edge_type_subgraph","text":"edge_type_subgraph(g::GNNHeteroGraph, edge_ts)\n\nReturn a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_edge_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_edge_types","text":"num_edge_types(g)\n\nReturn the number of edge types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_node_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_node_types","text":"num_node_types(g)\n\nReturn the number of node types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique node types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Graphs.has_edge(::GNNHeteroGraph, ::Tuple{Symbol, Symbol, Symbol}, ::Integer, ::Integer)","category":"page"},{"location":"api/heterograph.html#Graphs.has_edge-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, Integer, Integer}","page":"Heterogeneous Graphs","title":"Graphs.has_edge","text":"has_edge(g::GNNHeteroGraph, edge_t, i, j)\n\nReturn true if there is an edge of type edge_t from node i to node j in g.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)\nGNNHeteroGraph:\n num_nodes: (:A => 2, :B => 2)\n num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)\n\njulia> has_edge(g, (:A,:to,:B), 1, 1)\ntrue\n\njulia> has_edge(g, (:B,:to,:A), 1, 1)\nfalse\n\n\n\n\n\n","category":"method"},{"location":"gnngraph.html#Static-Graphs","page":"Static Graphs","title":"Static Graphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library. ","category":"page"},{"location":"gnngraph.html#Graph-Creation","page":"Static Graphs","title":"Graph Creation","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"A GNNGraph can be created from several different data sources encoding the graph topology:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using GraphNeuralNetworks, Graphs, SparseArrays\n\n\n# Construct a GNNGraph from from a Graphs.jl's graph\nlg = erdos_renyi(10, 30)\ng = GNNGraph(lg)\n\n# Same as above using convenience method rand_graph\ng = rand_graph(10, 60)\n\n# From an adjacency matrix\nA = sprand(10, 10, 0.3)\ng = GNNGraph(A)\n\n# From an adjacency list\nadjlist = [[2,3], [1,3], [1,2,4], [3]]\ng = GNNGraph(adjlist)\n\n# From COO representation\nsource = [1,1,2,2,3,3,3,4]\ntarget = [2,3,1,3,1,2,4,3]\ng = GNNGraph(source, target)","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"See also the related methods Graphs.adjacency_matrix, edge_index, and adjacency_list.","category":"page"},{"location":"gnngraph.html#Basic-Queries","page":"Static Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> source = [1,1,2,2,3,3,3,4];\n\njulia> target = [2,3,1,3,1,2,4,3];\n\njulia> g = GNNGraph(source, target)\nGNNGraph:\n num_nodes: 4\n num_edges: 8\n\n\njulia> @assert g.num_nodes == 4 # number of nodes\n\njulia> @assert g.num_edges == 8 # number of edges\n\njulia> @assert g.num_graphs == 1 # number of subgraphs (a GNNGraph can batch many graphs together)\n\njulia> is_directed(g) # a GNNGraph is always directed\ntrue\n\njulia> is_bidirected(g) # for each edge, also the reverse edge is present\ntrue\n\njulia> has_self_loops(g)\nfalse\n\njulia> has_multi_edges(g) \nfalse","category":"page"},{"location":"gnngraph.html#Data-Features","page":"Static Graphs","title":"Data Features","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"One or more arrays can be associated to nodes, edges, and (sub)graphs of a GNNGraph. They will be stored in the fields g.ndata, g.edata, and g.gdata respectively.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The data fields are DataStore objects. DataStores conveniently offer an interface similar to both dictionaries and named tuples. Similarly to dictionaries, DataStores support addition of new features after creation time.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The array contained in the datastores have last dimension equal to num_nodes (in ndata), num_edges (in edata), or num_graphs (in gdata) respectively.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"# Create a graph with a single feature array `x` associated to nodes\ng = rand_graph(10, 60, ndata = (; x = rand(Float32, 32, 10)))\n\ng.ndata.x # access the features\n\n# Equivalent definition passing directly the array\ng = rand_graph(10, 60, ndata = rand(Float32, 32, 10))\n\ng.ndata.x # `:x` is the default name for node features\n\ng.ndata.z = rand(Float32, 3, 10) # add new feature array `z`\n\n# For convenience, we can access the features through the shortcut\ng.x \n\n# You can have multiple feature arrays\ng = rand_graph(10, 60, ndata = (; x=rand(Float32, 32, 10), y=rand(Float32, 10)))\n\ng.ndata.y, g.ndata.x # or g.x, g.y\n\n# Attach an array with edge features.\n# Since `GNNGraph`s are directed, the number of edges\n# will be double that of the original Graphs' undirected graph.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 60))\n@assert g.num_edges == 60\n\ng.edata.e # or g.e\n\n# If we pass only half of the edge features, they will be copied\n# on the reversed edges.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 30))\n\n\n# Create a new graph from previous one, inheriting edge data\n# but replacing node data\ng′ = GNNGraph(g, ndata =(; z = ones(Float32, 16, 10)))\n\ng′.z\ng′.e","category":"page"},{"location":"gnngraph.html#Edge-weights","page":"Static Graphs","title":"Edge weights","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"It is common to denote scalar edge features as edge weights. The GNNGraph has specific support for edge weights: they can be stored as part of internal representations of the graph (COO or adjacency matrix). Some graph convolutional layers, most notably the GCNConv, can use the edge weights to perform weighted sums over the nodes' neighborhoods.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> source = [1, 1, 2, 2, 3, 3];\n\njulia> target = [2, 3, 1, 3, 1, 2];\n\njulia> weight = [1.0, 0.5, 2.1, 2.3, 4, 4.1];\n\njulia> g = GNNGraph(source, target, weight)\nGNNGraph:\n num_nodes: 3\n num_edges: 6\n\njulia> get_edge_weight(g)\n6-element Vector{Float64}:\n 1.0\n 0.5\n 2.1\n 2.3\n 4.0\n 4.1","category":"page"},{"location":"gnngraph.html#Batches-and-Subgraphs","page":"Static Graphs","title":"Batches and Subgraphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Multiple GNNGraphs can be batched together into a single graph that contains the total number of the original nodes and where the original graphs are disjoint subgraphs.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using Flux\nusing Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:160]\ngall = Flux.batch(data)\n\n# gall is a GNNGraph containing many graphs\n@assert gall.num_graphs == 160 \n@assert gall.num_nodes == 1600 # 10 nodes x 160 graphs\n@assert gall.num_edges == 4800 # 30 undirected edges x 160 graphs\n\n# Let's create a mini-batch from gall\ng23 = getgraph(gall, 2:3)\n@assert g23.num_graphs == 2\n@assert g23.num_nodes == 20 # 10 nodes x 2 graphs\n@assert g23.num_edges == 60 # 30 undirected edges X 2 graphs\n\n# We can pass a GNNGraph to Flux's DataLoader\ntrain_loader = DataLoader(gall, batchsize=16, shuffle=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend\n\n# Access the nodes' graph memberships \ngraph_indicator(gall)","category":"page"},{"location":"gnngraph.html#DataLoader-and-mini-batch-iteration","page":"Static Graphs","title":"DataLoader and mini-batch iteration","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"While constructing a batched graph and passing it to the DataLoader is always an option for mini-batch iteration, the recommended way for better performance is to pass an array of graphs directly and set the collate option to true:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:320]\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend","category":"page"},{"location":"gnngraph.html#Graph-Manipulation","page":"Static Graphs","title":"Graph Manipulation","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"g′ = add_self_loops(g)\ng′ = remove_self_loops(g)\ng′ = add_edges(g, [1, 2], [2, 3]) # add edges 1->2 and 2->3","category":"page"},{"location":"gnngraph.html#GPU-movement","page":"Static Graphs","title":"GPU movement","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Move a GNNGraph to a CUDA device using Flux.gpu method. ","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using CUDA, Flux\n\ng_gpu = g |> Flux.gpu","category":"page"},{"location":"gnngraph.html#Integration-with-Graphs.jl","page":"Static Graphs","title":"Integration with Graphs.jl","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Since GNNGraph <: Graphs.AbstractGraph, we can use any functionality from Graphs.jl for querying and analyzing the graph structure. Moreover, a GNNGraph can be easily constructed from a Graphs.Graph or a Graphs.DiGraph:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> import Graphs\n\njulia> using GraphNeuralNetworks\n\n# A Graphs.jl undirected graph\njulia> gu = Graphs.erdos_renyi(10, 20) \n{10, 20} undirected simple Int64 graph\n\n# Since GNNGraphs are undirected, the edges are doubled when converting \n# to GNNGraph\njulia> GNNGraph(gu)\nGNNGraph:\n num_nodes: 10\n num_edges: 40\n\n# A Graphs.jl directed graph\njulia> gd = Graphs.erdos_renyi(10, 20, is_directed=true)\n{10, 20} directed simple Int64 graph\n\njulia> GNNGraph(gd)\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"index.html#GNNGraphs.jl","page":"Home","title":"GNNGraphs.jl","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"GNNGraphs.jl is a package that provides graph data structures and helper functions specifically designed for working with graph neural networks. This package allows to store not only the graph structure, but also features associated with nodes, edges, and the graph itself. It is the core foundation for the GNNlib, GraphNeuralNetworks, and GNNLux packages.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"It supports three types of graphs: ","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"Static graph is the basic graph type represented by GNNGraph, where each node and edge can have associated features. This type of graph is used in typical graph neural network applications, where neural networks operate on both the structure of the graph and the features stored in it. It can be used to represent a graph where the structure does not change over time, but the features of the nodes and edges can change over time.\nTemporal graph is a graph that changes over time, and is represented by TemporalSnapshotsGNNGraph. Edges and features can change dynamically. This type of graph is useful for applications that involve tracking time-dependent relationships, such as social networks.\nHeterogeneous graph is a graph that supports multiple types of nodes and edges, and is represented by GNNHeteroGraph. Each type can have its own properties and relationships. This is useful in scenarios with different entities and interactions, such as in citation graphs or multi-relational data.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"This package depends on the package Graphs.jl.","category":"page"},{"location":"datasets.html#Datasets","page":"Datasets","title":"Datasets","text":"","category":"section"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GNNGraphs.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others. For graphs with static structures and temporal features, datasets such as METRLA, PEMSBAY, ChickenPox, and WindMillEnergy are available. For graphs featuring both temporal structures and temporal features, the TemporalBrains dataset is suitable.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"mldataset2gnngraph","category":"page"},{"location":"datasets.html#GNNGraphs.mldataset2gnngraph","page":"Datasets","title":"GNNGraphs.mldataset2gnngraph","text":"mldataset2gnngraph(dataset)\n\nConvert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.\n\nExamples\n\njulia> using MLDatasets, GraphNeuralNetworks\n\njulia> mldataset2gnngraph(Cora())\nGNNGraph:\n num_nodes = 2708\n num_edges = 10556\n ndata:\n features => 1433×2708 Matrix{Float32}\n targets => 2708-element Vector{Int64}\n train_mask => 2708-element BitVector\n val_mask => 2708-element BitVector\n test_mask => 2708-element BitVector\n\n\n\n\n\n","category":"function"}] } diff --git a/GNNGraphs/docs/build/temporalgraph.html b/GNNGraphs/docs/build/temporalgraph.html index 2531a812d..c07c730a2 100644 --- a/GNNGraphs/docs/build/temporalgraph.html +++ b/GNNGraphs/docs/build/temporalgraph.html @@ -1,5 +1,5 @@ -Temporal Graphs · GNNGraphs.jl

Temporal Graphs

Temporal Graphs are graphs with time varying topologies and node features. In GraphNeuralNetworks.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];
+Temporal Graphs · GNNGraphs.jl

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:
@@ -81,7 +81,7 @@
   x = 5×10 Matrix{Float64}
 
 julia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot
-Vector{Matrix{Float64}}

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 GraphNeuralNetworks, Flux
+Vector{Matrix{Float64}}

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 GraphNeuralNetworks, Flux
 
 julia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];
 
@@ -92,4 +92,4 @@
 julia> output = m(tg, tg.ndata.x);
 
 julia> size(output[1])
-(1, 10)
+(1, 10)
diff --git a/GNNGraphs/docs/src/api/gnngraph.md b/GNNGraphs/docs/src/api/gnngraph.md index de6fc1872..b39dec18f 100644 --- a/GNNGraphs/docs/src/api/gnngraph.md +++ b/GNNGraphs/docs/src/api/gnngraph.md @@ -4,7 +4,7 @@ CurrentModule = GNNGraphs # GNNGraph -Documentation page for the graph type `GNNGraph` provided by GraphNeuralNetworks.jl and related methods. +Documentation page for the graph type `GNNGraph` provided by GNNGraphs.jl and related methods. Besides the methods documented here, one can rely on the large set of functionalities given by [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl) thanks to the fact diff --git a/GNNGraphs/docs/src/datasets.md b/GNNGraphs/docs/src/datasets.md index c134afe5a..01433a333 100644 --- a/GNNGraphs/docs/src/datasets.md +++ b/GNNGraphs/docs/src/datasets.md @@ -1,6 +1,7 @@ # Datasets -GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the [examples in the GraphNeuralNetworks.jl repository](https://github.com/CarloLucibello/GraphNeuralNetworks.jl/tree/master/examples) make use of the [MLDatasets.jl](https://github.com/JuliaML/MLDatasets.jl) package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and [many others](https://juliaml.github.io/MLDatasets.jl/dev/datasets/graphs/). +GNNGraphs.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the [examples in the GraphNeuralNetworks.jl repository](https://github.com/CarloLucibello/GraphNeuralNetworks.jl/tree/master/examples) make use of the [MLDatasets.jl](https://github.com/JuliaML/MLDatasets.jl) package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and [many others](https://juliaml.github.io/MLDatasets.jl/dev/datasets/graphs/). +For graphs with static structures and temporal features, datasets such as METRLA, PEMSBAY, ChickenPox, and WindMillEnergy are available. For graphs featuring both temporal structures and temporal features, the TemporalBrains dataset is suitable. GraphNeuralNetworks.jl provides the [`mldataset2gnngraph`](@ref) method for interfacing with MLDatasets.jl. diff --git a/GNNGraphs/docs/src/gnngraph.md b/GNNGraphs/docs/src/gnngraph.md index cfa3a2008..50b5c5ed0 100644 --- a/GNNGraphs/docs/src/gnngraph.md +++ b/GNNGraphs/docs/src/gnngraph.md @@ -1,4 +1,4 @@ -# Working with GNNGraph +# Static Graphs The fundamental graph type in GraphNeuralNetworks.jl is the [`GNNGraph`](@ref). A GNNGraph `g` is a directed graph with nodes labeled from 1 to `g.num_nodes`. diff --git a/GNNGraphs/docs/src/index.md b/GNNGraphs/docs/src/index.md index 790767ed5..94f6c69a3 100644 --- a/GNNGraphs/docs/src/index.md +++ b/GNNGraphs/docs/src/index.md @@ -1 +1,13 @@ -# Write introduction GNNGraphs \ No newline at end of file +# GNNGraphs.jl + +GNNGraphs.jl is a package that provides graph data structures and helper functions specifically designed for working with graph neural networks. This package allows to store not only the graph structure, but also features associated with nodes, edges, and the graph itself. It is the core foundation for the GNNlib, GraphNeuralNetworks, and GNNLux packages. + +It supports three types of graphs: + +- **Static graph** is the basic graph type represented by [`GNNGraph`](@ref), where each node and edge can have associated features. This type of graph is used in typical graph neural network applications, where neural networks operate on both the structure of the graph and the features stored in it. It can be used to represent a graph where the structure does not change over time, but the features of the nodes and edges can change over time. + +- **Temporal graph** is a graph that changes over time, and is represented by [`TemporalSnapshotsGNNGraph`](@ref). Edges and features can change dynamically. This type of graph is useful for applications that involve tracking time-dependent relationships, such as social networks. + +- **Heterogeneous graph** is a graph that supports multiple types of nodes and edges, and is represented by [`GNNHeteroGraph`](@ref). Each type can have its own properties and relationships. This is useful in scenarios with different entities and interactions, such as in citation graphs or multi-relational data. + +This package depends on the package [Graphs.jl] (https://github.com/JuliaGraphs/Graphs.jl). \ No newline at end of file diff --git a/GNNGraphs/docs/src/temporalgraph.md b/GNNGraphs/docs/src/temporalgraph.md index 7a43d794a..71af5b4ee 100644 --- a/GNNGraphs/docs/src/temporalgraph.md +++ b/GNNGraphs/docs/src/temporalgraph.md @@ -1,6 +1,6 @@ # Temporal Graphs -Temporal Graphs are graphs with time varying topologies and node features. In GraphNeuralNetworks.jl temporal graphs with fixed number of nodes over time are supported by the [`TemporalSnapshotsGNNGraph`](@ref) type. +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`](@ref) type. ## Creating a TemporalSnapshotsGNNGraph @@ -124,7 +124,7 @@ Vector{Matrix{Float64}} ## 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`. +A graph convolutional layer can be applied to each snapshot independently, in the next example we apply a [`GINConv`](@ref) layer to each snapshot of a `TemporalSnapshotsGNNGraph`. ```jldoctest julia> using GraphNeuralNetworks, Flux diff --git a/multidocs/build/gnngraphs/.documenter-siteinfo.json b/multidocs/build/gnngraphs/.documenter-siteinfo.json index 5f6d525d7..09dcd6dd0 100644 --- a/multidocs/build/gnngraphs/.documenter-siteinfo.json +++ b/multidocs/build/gnngraphs/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-18T10:53:37","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-19T13:45:05","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/multidocs/build/gnngraphs/api/gnngraph.html b/multidocs/build/gnngraphs/api/gnngraph.html index 92f19cb59..40a529292 100644 --- a/multidocs/build/gnngraphs/api/gnngraph.html +++ b/multidocs/build/gnngraphs/api/gnngraph.html @@ -1,4 +1,4 @@ -GNNGraph · GNNGraphs.jl

GNNGraph

Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods.

Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.

Index

GNNGraph type

GNNGraphs.GNNGraphType
GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])
+GNNGraph · GNNGraphs.jl

GNNGraph

Documentation page for the graph type GNNGraph provided by GNNGraphs.jl and related methods.

Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.

Index

GNNGraph type

GNNGraphs.GNNGraphType
GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])
 GNNGraph(g::GNNGraph; [ndata, edata, gdata])

A type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.

The feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.

A GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.

When constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.

A GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.

GNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.

A GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Arguments

  • data: Some data representing the graph topology. Possible type are
    • An adjacency matrix
    • An adjacency list.
    • A tuple containing the source and target vectors (COO representation)
    • A Graphs.jl' graph.
  • graph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are
    • :coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).
    • :sparse. A sparse adjacency matrix representation.
    • :dense. A dense adjacency matrix representation.
    Defaults to :coo, currently the most supported type.
  • dir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.
  • num_nodes: The number of nodes. If not specified, inferred from g. Default nothing.
  • graph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.
  • ndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.
  • edata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.
  • gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.

Examples

using GraphNeuralNetworks
 
 # Construct from adjacency list representation
@@ -34,7 +34,7 @@
 # Both source and target are vectors of length num_edges
 source, target = edge_index(g)

A GNNGraph can be sent to the GPU using e.g. Flux's gpu function:

# Send to gpu
 using Flux, CUDA
-g = g |> Flux.gpu
source
Base.copyFunction
copy(g::GNNGraph; deep=false)

Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.

source

DataStore

Base.copyFunction
copy(g::GNNGraph; deep=false)

Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.

source

DataStore

GNNGraphs.DataStoreType
DataStore([n, data])
 DataStore([n,] k1 = x1, k2 = x2, ...)

A container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.

At construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:

julia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))
 DataStore(3) with 2 elements:
   y = 3-element Vector{Float32}
@@ -78,8 +78,8 @@
 julia> ds2.a
 2-element Vector{Float64}:
  1.0
- 1.0
source

Query

GNNGraphs.adjacency_listMethod
adjacency_list(g; dir=:out)
-adjacency_list(g, nodes; dir=:out)

Return the adjacency list representation (a vector of vectors) of the graph g.

Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.

If nodes is given, return the neighborhood of the nodes in nodes only.

source
GNNGraphs.edge_indexMethod
edge_index(g::GNNGraph)

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.

s, t = edge_index(g)
source
GNNGraphs.edge_indexMethod
edge_index(g::GNNHeteroGraph, [edge_t])

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).

If edge_t is not provided, it will error if g has more than one edge type.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNGraph; edges=false)

Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNHeteroGraph, [node_t])

Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.

See also batch.

source
GNNGraphs.has_isolated_nodesMethod
has_isolated_nodes(g::GNNGraph; dir=:out)

Return true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.

source
GNNGraphs.is_bidirectedMethod
is_bidirected(g::GNNGraph)

Check if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge.

source
GNNGraphs.khop_adjFunction
khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)

Return $A^k$ where $A$ is the adjacency matrix of the graph 'g'.

source
GNNGraphs.laplacian_lambda_maxFunction
laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)

Return the largest eigenvalue of the normalized symmetric Laplacian of the graph g.

If the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.

source
GNNGraphs.normalized_laplacianFunction
normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)

Normalized Laplacian matrix of graph g.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • add_self_loops: add self-loops while calculating the matrix.
  • dir: the edge directionality considered (:out, :in, :both).
source
GNNGraphs.scaled_laplacianFunction
scaled_laplacian(g, T=Float32; dir=:out)

Scaled Laplacian matrix of graph g, defined as $\hat{L} = \frac{2}{\lambda_{max}} L - I$ where $L$ is the normalized Laplacian matrix.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • dir: the edge directionality considered (:out, :in, :both).
source
Graphs.LinAlg.adjacency_matrixFunction
adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)

Return the adjacency matrix A for the graph g.

If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.

User may specify the eltype T of the returned matrix.

If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.

source
Graphs.degreeMethod
degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)

Return a vector containing the degrees of the nodes in g.

The gradient is propagated through this function only if edge_weight is true or a vector.

Arguments

  • g: A graph.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
  • edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
source
Graphs.degreeMethod
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)

Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.

Arguments

  • g: A graph.
  • edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
source
Graphs.neighborsMethod
neighbors(g::GNNGraph, i::Integer; dir=:out)

Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.

See also outneighbors, inneighbors.

source

Transform

Query

GNNGraphs.adjacency_listMethod
adjacency_list(g; dir=:out)
+adjacency_list(g, nodes; dir=:out)

Return the adjacency list representation (a vector of vectors) of the graph g.

Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.

If nodes is given, return the neighborhood of the nodes in nodes only.

source
GNNGraphs.edge_indexMethod
edge_index(g::GNNGraph)

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.

s, t = edge_index(g)
source
GNNGraphs.edge_indexMethod
edge_index(g::GNNHeteroGraph, [edge_t])

Return a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).

If edge_t is not provided, it will error if g has more than one edge type.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNGraph; edges=false)

Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.

source
GNNGraphs.graph_indicatorMethod
graph_indicator(g::GNNHeteroGraph, [node_t])

Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.

See also batch.

source
GNNGraphs.has_isolated_nodesMethod
has_isolated_nodes(g::GNNGraph; dir=:out)

Return true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.

source
GNNGraphs.is_bidirectedMethod
is_bidirected(g::GNNGraph)

Check if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge.

source
GNNGraphs.khop_adjFunction
khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)

Return $A^k$ where $A$ is the adjacency matrix of the graph 'g'.

source
GNNGraphs.laplacian_lambda_maxFunction
laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)

Return the largest eigenvalue of the normalized symmetric Laplacian of the graph g.

If the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.

source
GNNGraphs.normalized_laplacianFunction
normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)

Normalized Laplacian matrix of graph g.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • add_self_loops: add self-loops while calculating the matrix.
  • dir: the edge directionality considered (:out, :in, :both).
source
GNNGraphs.scaled_laplacianFunction
scaled_laplacian(g, T=Float32; dir=:out)

Scaled Laplacian matrix of graph g, defined as $\hat{L} = \frac{2}{\lambda_{max}} L - I$ where $L$ is the normalized Laplacian matrix.

Arguments

  • g: A GNNGraph.
  • T: result element type.
  • dir: the edge directionality considered (:out, :in, :both).
source
Graphs.LinAlg.adjacency_matrixFunction
adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)

Return the adjacency matrix A for the graph g.

If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.

User may specify the eltype T of the returned matrix.

If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.

source
Graphs.degreeMethod
degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)

Return a vector containing the degrees of the nodes in g.

The gradient is propagated through this function only if edge_weight is true or a vector.

Arguments

  • g: A graph.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
  • edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
source
Graphs.degreeMethod
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)

Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.

Arguments

  • g: A graph.
  • edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
  • T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
  • dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
source
Graphs.neighborsMethod
neighbors(g::GNNGraph, i::Integer; dir=:out)

Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.

See also outneighbors, inneighbors.

source

Transform

GNNGraphs.add_edgesMethod
add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])
 add_edges(g::GNNGraph, (s, t); [edata])
 add_edges(g::GNNGraph, (s, t, w); [edata])

Add to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.

If the s or t contain nodes that are not already present in the graph, they are added to the graph as well.

Examples

julia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];
 
@@ -101,12 +101,12 @@
 julia> add_edges(g, [1,2], [2,3])
 GNNGraph:
     num_nodes: 3
-    num_edges: 2
source
GNNGraphs.add_edgesMethod
add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])
 add_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])
-add_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])

Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).

If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.

source
GNNGraphs.add_nodesMethod
add_nodes(g::GNNGraph, n; [ndata])

Add n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNGraph)

Return a graph with the same features as g but also adding edges connecting the nodes to themselves.

Nodes with already existing self-loops will obtain a second self-loop.

If the graphs has edge weights, the new edges will have weight 1.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNHeteroGraph, edge_t::EType)
-add_self_loops(g::GNNHeteroGraph)

If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.

Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.

If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.

If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.

If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.

source
GNNGraphs.getgraphMethod
getgraph(g::GNNGraph, i; nmap=false)

Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.

If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.

source
GNNGraphs.negative_sampleMethod
negative_sample(g::GNNGraph; 
+add_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])

Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).

If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.

source
GNNGraphs.add_nodesMethod
add_nodes(g::GNNGraph, n; [ndata])

Add n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNGraph)

Return a graph with the same features as g but also adding edges connecting the nodes to themselves.

Nodes with already existing self-loops will obtain a second self-loop.

If the graphs has edge weights, the new edges will have weight 1.

source
GNNGraphs.add_self_loopsMethod
add_self_loops(g::GNNHeteroGraph, edge_t::EType)
+add_self_loops(g::GNNHeteroGraph)

If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.

Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.

If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.

If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.

If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.

source
GNNGraphs.getgraphMethod
getgraph(g::GNNGraph, i; nmap=false)

Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.

If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.

source
GNNGraphs.negative_sampleMethod
negative_sample(g::GNNGraph; 
                 num_neg_edges = g.num_edges, 
-                bidirected = is_bidirected(g))

Return a graph containing random negative edges (i.e. non-edges) from graph g as edges.

If bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph.

See also is_bidirected.

source
GNNGraphs.perturb_edgesMethod
perturb_edges([rng], g::GNNGraph, perturb_ratio)

Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.

The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.

Arguments

  • g::GNNGraph: The graph to be perturbed.
  • perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
  • rng: An optionalrandom number generator to ensure reproducible results.

Examples

julia> g = GNNGraph((s, t, w))
+                bidirected = is_bidirected(g))

Return a graph containing random negative edges (i.e. non-edges) from graph g as edges.

If bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph.

See also is_bidirected.

source
GNNGraphs.perturb_edgesMethod
perturb_edges([rng], g::GNNGraph, perturb_ratio)

Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.

The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.

Arguments

  • g::GNNGraph: The graph to be perturbed.
  • perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
  • rng: An optionalrandom number generator to ensure reproducible results.

Examples

julia> g = GNNGraph((s, t, w))
 GNNGraph:
   num_nodes: 4
   num_edges: 5
@@ -114,7 +114,7 @@
 julia> perturbed_g = perturb_edges(g, 0.2)
 GNNGraph:
   num_nodes: 4
-  num_edges: 6
source
GNNGraphs.ppr_diffusionMethod
ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph

Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web

The function performs the following steps:

  1. Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
  2. Normalizes A to ensure each column sums to 1, representing transition probabilities.
  3. Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
  4. Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.

Arguments

  • g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
  • alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.

Returns

  • A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
source
GNNGraphs.rand_edge_splitMethod
rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2

Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.

If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.

rand_edge_split is tipically used to create train/test splits in link prediction tasks.

source
GNNGraphs.ppr_diffusionMethod
ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph

Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web

The function performs the following steps:

  1. Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
  2. Normalizes A to ensure each column sums to 1, representing transition probabilities.
  3. Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
  4. Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.

Arguments

  • g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
  • alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.

Returns

  • A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
source
GNNGraphs.rand_edge_splitMethod
rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2

Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.

If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.

rand_edge_split is tipically used to create train/test splits in link prediction tasks.

source
GNNGraphs.remove_edgesMethod
remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})
 remove_edges(g::GNNGraph, p=0.5)

Remove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.

Arguments

  • g: The input graph from which edges will be removed.
  • edges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.
  • p: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.

Returns

A new GNNGraph with the specified edges removed.

Example

julia> using GraphNeuralNetworks
 
 # Construct a GNNGraph
@@ -137,7 +137,7 @@
 julia> g_new
 GNNGraph:
   num_nodes: 3
-  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, p)

Returns a new graph obtained by dropping nodes from g with independent probabilities p.

Examples

julia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])
+  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, p)

Returns a new graph obtained by dropping nodes from g with independent probabilities p.

Examples

julia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])
 GNNGraph:
   num_nodes: 4
   num_edges: 6
@@ -145,7 +145,7 @@
 julia> g_new = remove_nodes(g, 0.5)
 GNNGraph:
   num_nodes: 2
-  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)

Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.

Arguments

  • g: The input graph from which nodes (and their edges) will be removed.
  • nodes_to_remove: Vector of node indices to be removed.

Returns

A new GNNGraph with the specified nodes and all edges associated with these nodes removed.

Example

using GraphNeuralNetworks
+  num_edges: 2
source
GNNGraphs.remove_nodesMethod
remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)

Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.

Arguments

  • g: The input graph from which nodes (and their edges) will be removed.
  • nodes_to_remove: Vector of node indices to be removed.

Returns

A new GNNGraph with the specified nodes and all edges associated with these nodes removed.

Example

using GraphNeuralNetworks
 
 g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])
 
@@ -153,7 +153,7 @@
 g_new = remove_nodes(g, [2, 3])
 
 # g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.
-println(g_new)
source
GNNGraphs.to_bidirectedMethod
to_bidirected(g)

Adds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph.

See also is_bidirected.

Examples

julia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];
 
 julia> w = [1.0, 2.0, 3.0, 4.0, 5.0];
 
@@ -194,7 +194,7 @@
  20.0
  35.0
  35.0
- 50.0
source
GNNGraphs.to_unidirectedMethod
to_unidirected(g::GNNGraph)

Return a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.

source
MLUtils.batchMethod
batch(gs::Vector{<:GNNGraph})

Batch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.

Equivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.

Examples

julia> g1 = rand_graph(4, 6, ndata=ones(8, 4))
+ 50.0
source
GNNGraphs.to_unidirectedMethod
to_unidirected(g::GNNGraph)

Return a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.

source
MLUtils.batchMethod
batch(gs::Vector{<:GNNGraph})

Batch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.

Equivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.

Examples

julia> g1 = rand_graph(4, 6, ndata=ones(8, 4))
 GNNGraph:
     num_nodes = 4
     num_edges = 6
@@ -225,7 +225,7 @@
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
  1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
- 1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
source
MLUtils.unbatchMethod
unbatch(g::GNNGraph)

Opposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.

See also MLUtils.batch and getgraph.

Examples

julia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])
+ 1.0  1.0  1.0  1.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
source
MLUtils.unbatchMethod
unbatch(g::GNNGraph)

Opposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.

See also MLUtils.batch and getgraph.

Examples

julia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])
 GNNGraph:
     num_nodes = 19
     num_edges = 16
@@ -243,8 +243,8 @@
 
  GNNGraph:
     num_nodes = 4
-    num_edges = 2
source

Utils

GNNGraphs.sort_edge_indexFunction
sort_edge_index(ei::Tuple) -> u', v'
-sort_edge_index(u, v) -> u', v'

Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.

source
GNNGraphs.color_refinementFunction
color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters

The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.

At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.

math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`

This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.

Arguments

  • g::GNNGraph: The graph to color.
  • x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.

Returns

  • x::AbstractVector{<:Integer}: The final coloring.
  • num_colors::Int: The number of colors used.
  • niters::Int: The number of iterations until convergence.
source

Generate

Utils

GNNGraphs.sort_edge_indexFunction
sort_edge_index(ei::Tuple) -> u', v'
+sort_edge_index(u, v) -> u', v'

Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.

source
GNNGraphs.color_refinementFunction
color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters

The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.

At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.

math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`

This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.

Arguments

  • g::GNNGraph: The graph to color.
  • x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.

Returns

  • x::AbstractVector{<:Integer}: The final coloring.
  • num_colors::Int: The number of colors used.
  • niters::Int: The number of iterations until convergence.
source

Generate

GNNGraphs.knn_graphMethod
knn_graph(points::AbstractMatrix, 
           k::Int; 
           graph_indicator = nothing,
           self_loops = false, 
@@ -265,7 +265,7 @@
     num_nodes = 10
     num_edges = 30
     num_graphs = 2
-
source
GNNGraphs.rand_bipartite_heterographMethod
rand_bipartite_heterograph([rng,] 
                            (n1, n2), (m12, m21); 
                            bidirected = true, 
                            node_t = (:A, :B), 
@@ -299,7 +299,7 @@
 julia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)
 GNNHeteroGraph:
   num_nodes: Dict(:item => 15, :user => 10)
-  num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)
source
GNNGraphs.rand_graphMethod
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)

Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.

If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.

A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.

Pass a random number generator as the first argument to make the generation reproducible.

Additional keyword arguments will be passed to the GNNGraph constructor.

Examples

julia> g = rand_graph(5, 4, bidirected=false)
+  num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)
source
GNNGraphs.rand_graphMethod
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)

Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.

If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.

A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.

Pass a random number generator as the first argument to make the generation reproducible.

Additional keyword arguments will be passed to the GNNGraph constructor.

Examples

julia> g = rand_graph(5, 4, bidirected=false)
 GNNGraph:
     num_nodes = 5
     num_edges = 4
@@ -317,11 +317,11 @@
 
 # Each edge has a reverse
 julia> edge_index(g)
-([1, 3, 3, 4], [3, 4, 1, 3])
source
GNNGraphs.rand_heterographFunction
rand_heterograph([rng,] n, m; bidirected=false, kws...)

Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.

Pass a random number generator as a first argument to make the generation reproducible.

Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.

Additional keyword arguments will be passed to the GNNHeteroGraph constructor.

Examples

julia> g = rand_heterograph((:user => 10, :movie => 20),
+([1, 3, 3, 4], [3, 4, 1, 3])
source
GNNGraphs.rand_heterographFunction
rand_heterograph([rng,] n, m; bidirected=false, kws...)

Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.

Pass a random number generator as a first argument to make the generation reproducible.

Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.

Additional keyword arguments will be passed to the GNNHeteroGraph constructor.

Examples

julia> g = rand_heterograph((:user => 10, :movie => 20),
                             (:user, :rate, :movie) => 30)
 GNNHeteroGraph:
   num_nodes: (:user => 10, :movie => 20)         
-  num_edges: ((:user, :rate, :movie) => 30,)
source

Operators

Base.intersectFunction

" intersect(g1::GNNGraph, g2::GNNGraph)

Intersect two graphs by keeping only the common edges.

source

Sampling

GNNGraphs.sample_neighborsFunction
sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)

Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.

The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.

Arguments

  • g. The graph.
  • nodes. A list of node IDs to sample neighbors from.
  • K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
  • dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
  • replace. If true, sample with replacement.
  • dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.

Examples

julia> g = rand_graph(20, 100)
+  num_edges: ((:user, :rate, :movie) => 30,)
source

Operators

Base.intersectFunction

" intersect(g1::GNNGraph, g2::GNNGraph)

Intersect two graphs by keeping only the common edges.

source

Sampling

GNNGraphs.sample_neighborsFunction
sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)

Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.

The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.

Arguments

  • g. The graph.
  • nodes. A list of node IDs to sample neighbors from.
  • K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
  • dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
  • replace. If true, sample with replacement.
  • dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.

Examples

julia> g = rand_graph(20, 100)
 GNNGraph:
     num_nodes = 20
     num_edges = 100
@@ -360,4 +360,4 @@
     num_nodes = 20
     num_edges = 10
     edata:
-        EID => (10,)
source
\ No newline at end of file + EID => (10,)
source
\ No newline at end of file diff --git a/multidocs/build/gnngraphs/api/heterograph.html b/multidocs/build/gnngraphs/api/heterograph.html index 39b123a10..a91978721 100644 --- a/multidocs/build/gnngraphs/api/heterograph.html +++ b/multidocs/build/gnngraphs/api/heterograph.html @@ -1,4 +1,4 @@ -Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

GNNHeteroGraph

Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.

GNNGraphs.GNNHeteroGraphType
GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])
+Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

GNNHeteroGraph

Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.

GNNGraphs.GNNHeteroGraphType
GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])
 GNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])

A type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.

Constructor Arguments

  • data: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).
  • pairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).
  • ndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.
  • edata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.
  • gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.
  • num_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.

Fields

  • graph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.
  • num_nodes: The number of nodes for each type.
  • num_edges: The number of edges for each type.
  • ndata: Node features.
  • edata: Edge features.
  • gdata: Graph features.
  • ntypes: The node types.
  • etypes: The edge types.

Examples

julia> using GraphNeuralNetworks
 
 julia> nA, nB = 10, 20;
@@ -39,7 +39,7 @@
 julia> hg.ndata[:A].x
 2×10 Matrix{Float64}:
     0.825882  0.0797502  0.245813  0.142281  0.231253  0.685025  0.821457  0.888838  0.571347   0.53165
-    0.631286  0.316292   0.705325  0.239211  0.533007  0.249233  0.473736  0.595475  0.0623298  0.159307

See also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.

source
GNNGraphs.edge_type_subgraphMethod
edge_type_subgraph(g::GNNHeteroGraph, edge_ts)

Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.

source
Graphs.has_edgeMethod
has_edge(g::GNNHeteroGraph, edge_t, i, j)

Return true if there is an edge of type edge_t from node i to node j in g.

Examples

julia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)
+    0.631286  0.316292   0.705325  0.239211  0.533007  0.249233  0.473736  0.595475  0.0623298  0.159307

See also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.

source
GNNGraphs.edge_type_subgraphMethod
edge_type_subgraph(g::GNNHeteroGraph, edge_ts)

Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.

source
Graphs.has_edgeMethod
has_edge(g::GNNHeteroGraph, edge_t, i, j)

Return true if there is an edge of type edge_t from node i to node j in g.

Examples

julia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)
 GNNHeteroGraph:
   num_nodes: (:A => 2, :B => 2)
   num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)
@@ -48,4 +48,4 @@
 true
 
 julia> has_edge(g, (:B,:to,:A), 1, 1)
-false
source
\ No newline at end of file +false
source
\ No newline at end of file diff --git a/multidocs/build/gnngraphs/api/temporalgraph.html b/multidocs/build/gnngraphs/api/temporalgraph.html index b29ad4b3f..aaf93a891 100644 --- a/multidocs/build/gnngraphs/api/temporalgraph.html +++ b/multidocs/build/gnngraphs/api/temporalgraph.html @@ -1,4 +1,4 @@ -Temporal Graphs · GNNGraphs.jl

Temporal Graphs

TemporalSnapshotsGNNGraph

Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.

GNNGraphs.TemporalSnapshotsGNNGraphType
TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})

A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.

TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.

Constructor Arguments

  • snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.

Examples

julia> using GraphNeuralNetworks
+Temporal Graphs · GNNGraphs.jl

Temporal Graphs

TemporalSnapshotsGNNGraph

Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.

GNNGraphs.TemporalSnapshotsGNNGraphType
TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})

A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.

TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.

Constructor Arguments

  • snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10,20) for i in 1:5];
 
@@ -16,7 +16,7 @@
   num_edges: [20, 20, 20, 20, 20]
   num_snapshots: 5
   tgdata:
-        x = 4-element Vector{Float64}
source
GNNGraphs.add_snapshotMethod
add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)

Return a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.

Examples

julia> using GraphNeuralNetworks
+        x = 4-element Vector{Float64}
source
GNNGraphs.add_snapshotMethod
add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)

Return a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10, 20) for i in 1:5];
 
@@ -30,7 +30,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10, 10, 10, 10, 10]
   num_edges: [20, 20, 16, 20, 20, 20]
-  num_snapshots: 6
source
GNNGraphs.remove_snapshotMethod
remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)

Return a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.

Examples

julia> using GraphNeuralNetworks
 
 julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];
 
@@ -44,7 +44,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10]
   num_edges: [20, 22]
-  num_snapshots: 2
source

TemporalSnapshotsGNNGraph random generators

TemporalSnapshotsGNNGraph random generators

GNNGraphs.rand_temporal_radius_graphFunction
rand_temporal_radius_graph(number_nodes::Int, 
                            number_snapshots::Int,
                            speed::AbstractFloat,
                            r::AbstractFloat;
@@ -56,7 +56,7 @@
 TemporalSnapshotsGNNGraph:
   num_nodes: [10, 10, 10, 10, 10]
   num_edges: [90, 90, 90, 90, 90]
-  num_snapshots: 5
source
\ No newline at end of file + num_snapshots: 5

References

Section D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks

source
\ No newline at end of file diff --git a/multidocs/build/gnngraphs/datasets.html b/multidocs/build/gnngraphs/datasets.html index af4213641..2812ca1e9 100644 --- a/multidocs/build/gnngraphs/datasets.html +++ b/multidocs/build/gnngraphs/datasets.html @@ -1,4 +1,4 @@ -Datasets · GNNGraphs.jl

Datasets

GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.

GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.

GNNGraphs.mldataset2gnngraphFunction
mldataset2gnngraph(dataset)

Convert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.

Examples

julia> using MLDatasets, GraphNeuralNetworks
+Datasets · GNNGraphs.jl

Datasets

GNNGraphs.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others. For graphs with static structures and temporal features, datasets such as METRLA, PEMSBAY, ChickenPox, and WindMillEnergy are available. For graphs featuring both temporal structures and temporal features, the TemporalBrains dataset is suitable.

GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.

GNNGraphs.mldataset2gnngraphFunction
mldataset2gnngraph(dataset)

Convert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.

Examples

julia> using MLDatasets, GraphNeuralNetworks
 
 julia> mldataset2gnngraph(Cora())
 GNNGraph:
@@ -9,4 +9,4 @@
         targets => 2708-element Vector{Int64}
         train_mask => 2708-element BitVector
         val_mask => 2708-element BitVector
-        test_mask => 2708-element BitVector
source
\ No newline at end of file + test_mask => 2708-element BitVector
source
\ No newline at end of file diff --git a/multidocs/build/gnngraphs/gnngraph.html b/multidocs/build/gnngraphs/gnngraph.html index 1e36dbbd0..1d568c7c6 100644 --- a/multidocs/build/gnngraphs/gnngraph.html +++ b/multidocs/build/gnngraphs/gnngraph.html @@ -1,4 +1,4 @@ -Working with GNNGraph · GNNGraphs.jl

Working with GNNGraph

The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.

GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Graph Creation

A GNNGraph can be created from several different data sources encoding the graph topology:

using GraphNeuralNetworks, Graphs, SparseArrays
+Static Graphs · GNNGraphs.jl

Static Graphs

The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.

GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.

Graph Creation

A GNNGraph can be created from several different data sources encoding the graph topology:

using GraphNeuralNetworks, Graphs, SparseArrays
 
 
 # Construct a GNNGraph from from a Graphs.jl's graph
@@ -83,7 +83,7 @@
 g′ = GNNGraph(g, ndata =(; z = ones(Float32, 16, 10)))
 
 g′.z
-g′.e

Edge weights

julia> source = [1, 1, 2, 2, 3, 3];
+g′.e

Edge weights

It is common to denote scalar edge features as edge weights. The GNNGraph has specific support for edge weights: they can be stored as part of internal representations of the graph (COO or adjacency matrix). Some graph convolutional layers, most notably the GCNConv, can use the edge weights to perform weighted sums over the nodes' neighborhoods.

julia> source = [1, 1, 2, 2, 3, 3];
 
 julia> target = [2, 3, 1, 3, 1, 2];
 
@@ -166,4 +166,4 @@
 julia> GNNGraph(gd)
 GNNGraph:
   num_nodes: 10
-  num_edges: 20
\ No newline at end of file + num_edges: 20
\ No newline at end of file diff --git a/multidocs/build/gnngraphs/heterograph.html b/multidocs/build/gnngraphs/heterograph.html index fabc48c56..5c22f71d7 100644 --- a/multidocs/build/gnngraphs/heterograph.html +++ b/multidocs/build/gnngraphs/heterograph.html @@ -1,4 +1,4 @@ -Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).

Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.

Creating a Heterograph

A heterograph can be created empty or by passing pairs edge_type => data to the constructor.

julia> g = GNNHeteroGraph()
+Heterogeneous Graphs · GNNGraphs.jl

Heterogeneous Graphs

Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).

Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.

Creating a Heterograph

A heterograph can be created empty or by passing pairs edge_type => data to the constructor.

julia> g = GNNHeteroGraph()
 GNNHeteroGraph:
   num_nodes: Dict()
   num_edges: Dict()
@@ -80,4 +80,4 @@
     @assert g.num_nodes[:A] == 80
     @assert size(g.ndata[:A].x) == (3, 80)    
     # ...
-end
\ No newline at end of file +end

Graph convolutions on heterographs

See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.

\ No newline at end of file diff --git a/multidocs/build/gnngraphs/index.html b/multidocs/build/gnngraphs/index.html index c0ed64242..fb148706a 100644 --- a/multidocs/build/gnngraphs/index.html +++ b/multidocs/build/gnngraphs/index.html @@ -1 +1 @@ -Home · GNNGraphs.jl
\ No newline at end of file +Home · GNNGraphs.jl

GNNGraphs.jl

GNNGraphs.jl is a package that provides graph data structures and helper functions specifically designed for working with graph neural networks. This package allows to store not only the graph structure, but also features associated with nodes, edges, and the graph itself. It is the core foundation for the GNNlib, GraphNeuralNetworks, and GNNLux packages.

It supports three types of graphs:

  • Static graph is the basic graph type represented by GNNGraph, where each node and edge can have associated features. This type of graph is used in typical graph neural network applications, where neural networks operate on both the structure of the graph and the features stored in it. It can be used to represent a graph where the structure does not change over time, but the features of the nodes and edges can change over time.

  • Temporal graph is a graph that changes over time, and is represented by TemporalSnapshotsGNNGraph. Edges and features can change dynamically. This type of graph is useful for applications that involve tracking time-dependent relationships, such as social networks.

  • Heterogeneous graph is a graph that supports multiple types of nodes and edges, and is represented by GNNHeteroGraph. Each type can have its own properties and relationships. This is useful in scenarios with different entities and interactions, such as in citation graphs or multi-relational data.

This package depends on the package Graphs.jl.

\ No newline at end of file diff --git a/multidocs/build/gnngraphs/objects.inv b/multidocs/build/gnngraphs/objects.inv index 102183544..d65020607 100644 Binary files a/multidocs/build/gnngraphs/objects.inv and b/multidocs/build/gnngraphs/objects.inv differ diff --git a/multidocs/build/gnngraphs/search_index.js b/multidocs/build/gnngraphs/search_index.js index 7397a7796..b1b65e0c9 100644 --- a/multidocs/build/gnngraphs/search_index.js +++ b/multidocs/build/gnngraphs/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"CurrentModule = GNNGraphs","category":"page"},{"location":"api/gnngraph.html#GNNGraph","page":"GNNGraph","title":"GNNGraph","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods. ","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.","category":"page"},{"location":"api/gnngraph.html#Index","page":"GNNGraph","title":"Index","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Order = [:type, :function]\nPages = [\"gnngraph.md\"]","category":"page"},{"location":"api/gnngraph.html#GNNGraph-type","page":"GNNGraph","title":"GNNGraph type","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraph\nBase.copy","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.GNNGraph","page":"GNNGraph","title":"GNNGraphs.GNNGraph","text":"GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])\nGNNGraph(g::GNNGraph; [ndata, edata, gdata])\n\nA type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.\n\nThe feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.\n\nA GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.\n\nWhen constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.\n\nA GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.\n\nGNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.\n\nA GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.\n\nArguments\n\ndata: Some data representing the graph topology. Possible type are\nAn adjacency matrix\nAn adjacency list.\nA tuple containing the source and target vectors (COO representation)\nA Graphs.jl' graph.\ngraph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are\n:coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).\n:sparse. A sparse adjacency matrix representation.\n:dense. A dense adjacency matrix representation.\nDefaults to :coo, currently the most supported type.\ndir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.\nnum_nodes: The number of nodes. If not specified, inferred from g. Default nothing.\ngraph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.\nndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.\nedata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.\n\nExamples\n\nusing GraphNeuralNetworks\n\n# Construct from adjacency list representation\ndata = [[2,3], [1,4,5], [1], [2,5], [2,4]]\ng = GNNGraph(data)\n\n# Number of nodes, edges, and batched graphs\ng.num_nodes # 5\ng.num_edges # 10\ng.num_graphs # 1\n\n# Same graph in COO representation\ns = [1,1,2,2,2,3,4,4,5,5]\nt = [2,3,1,4,5,3,2,5,2,4]\ng = GNNGraph(s, t)\n\n# From a Graphs' graph\ng = GNNGraph(erdos_renyi(100, 20))\n\n# Add 2 node feature arrays at creation time\ng = GNNGraph(g, ndata = (x=rand(100, g.num_nodes), y=rand(g.num_nodes)))\n\n# Add 1 edge feature array, after the graph creation\ng.edata.z = rand(16, g.num_edges)\n\n# Add node features and edge features with default names `x` and `e`\ng = GNNGraph(g, ndata = rand(100, g.num_nodes), edata = rand(16, g.num_edges))\n\ng.ndata.x # or just g.x\ng.edata.e # or just g.e\n\n# Collect edges' source and target nodes.\n# Both source and target are vectors of length num_edges\nsource, target = edge_index(g)\n\nA GNNGraph can be sent to the GPU using e.g. Flux's gpu function:\n\n# Send to gpu\nusing Flux, CUDA\ng = g |> Flux.gpu\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Base.copy","page":"GNNGraph","title":"Base.copy","text":"copy(g::GNNGraph; deep=false)\n\nCreate a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#DataStore","page":"GNNGraph","title":"DataStore","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"datastore.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.DataStore","page":"GNNGraph","title":"GNNGraphs.DataStore","text":"DataStore([n, data])\nDataStore([n,] k1 = x1, k2 = x2, ...)\n\nA container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.\n\nAt construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:\n\njulia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))\nDataStore(3) with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds = DataStore(3, Dict(:x => rand(Float32, 2, 3), :y => rand(Float32, 3))); # equivalent to above\n\njulia> ds = DataStore(3, (x = rand(Float32, 2, 3), y = rand(Float32, 30)))\nERROR: AssertionError: DataStore: data[y] has 30 observations, but n = 3\nStacktrace:\n [1] DataStore(n::Int64, data::Dict{Symbol, Any})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:54\n [2] DataStore(n::Int64, data::NamedTuple{(:x, :y), Tuple{Matrix{Float32}, Vector{Float32}}})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:73\n [3] top-level scope\n @ REPL[13]:1\n\njulia> ds = DataStore(x = randFloat32, 2, 3), y = rand(Float32, 30)) # no checks\nDataStore() with 2 elements:\n y = 30-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n y = 30-element Vector{Float64}\n x = 2×3 Matrix{Float64}\n\nThe DataStore has an interface similar to both dictionaries and named tuples. Arrays can be accessed and added using either the indexing or the property syntax:\n\njulia> ds = DataStore(x = ones(Float32, 2, 3), y = zeros(Float32, 3))\nDataStore() with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds.x # same as `ds[:x]`\n2×3 Matrix{Float32}:\n 1.0 1.0 1.0\n 1.0 1.0 1.0\n\njulia> ds.z = zeros(Float32, 3) # Add new feature array `z`. Same as `ds[:z] = rand(Float32, 3)`\n3-element Vector{Float64}:\n0.0\n0.0\n0.0\n\nThe DataStore can be iterated over, and the keys and values can be accessed using keys(ds) and values(ds). map(f, ds) applies the function f to each feature array:\n\njulia> ds = DataStore(a = zeros(2), b = zeros(2));\n\njulia> ds2 = map(x -> x .+ 1, ds)\n\njulia> ds2.a\n2-element Vector{Float64}:\n 1.0\n 1.0\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Query","page":"GNNGraph","title":"Query","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"query.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.adjacency_list-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.adjacency_list","text":"adjacency_list(g; dir=:out)\nadjacency_list(g, nodes; dir=:out)\n\nReturn the adjacency list representation (a vector of vectors) of the graph g.\n\nCalling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.\n\nIf nodes is given, return the neighborhood of the nodes in nodes only.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNGraph)\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.\n\ns, t = edge_index(g)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNHeteroGraph, [edge_t])\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).\n\nIf edge_t is not provided, it will error if g has more than one edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNGraph; edges=false)\n\nReturn a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNHeteroGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNHeteroGraph, [node_t])\n\nReturn a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.\n\nSee also batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_isolated_nodes-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_isolated_nodes","text":"has_isolated_nodes(g::GNNGraph; dir=:out)\n\nReturn true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_multi_edges-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_multi_edges","text":"has_multi_edges(g::GNNGraph)\n\nReturn true if g has any multiple edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.is_bidirected-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.is_bidirected","text":"is_bidirected(g::GNNGraph)\n\nCheck if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.khop_adj","page":"GNNGraph","title":"GNNGraphs.khop_adj","text":"khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)\n\nReturn A^k where A is the adjacency matrix of the graph 'g'.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.laplacian_lambda_max","page":"GNNGraph","title":"GNNGraphs.laplacian_lambda_max","text":"laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)\n\nReturn the largest eigenvalue of the normalized symmetric Laplacian of the graph g.\n\nIf the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.normalized_laplacian","page":"GNNGraph","title":"GNNGraphs.normalized_laplacian","text":"normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)\n\nNormalized Laplacian matrix of graph g.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\nadd_self_loops: add self-loops while calculating the matrix.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.scaled_laplacian","page":"GNNGraph","title":"GNNGraphs.scaled_laplacian","text":"scaled_laplacian(g, T=Float32; dir=:out)\n\nScaled Laplacian matrix of graph g, defined as hatL = frac2lambda_max L - I where L is the normalized Laplacian matrix.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.LinAlg.adjacency_matrix","page":"GNNGraph","title":"Graphs.LinAlg.adjacency_matrix","text":"adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)\n\nReturn the adjacency matrix A for the graph g. \n\nIf dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.\n\nUser may specify the eltype T of the returned matrix. \n\nIf weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}, Tuple{TT}, Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)\n\nReturn a vector containing the degrees of the nodes in g.\n\nThe gradient is propagated through this function only if edge_weight is true or a vector.\n\nArguments\n\ng: A graph.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.\nedge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{TT}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)\n\nReturn a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.\n\nArguments\n\ng: A graph.\nedge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.has_self_loops-Tuple{GNNGraph}","page":"GNNGraph","title":"Graphs.has_self_loops","text":"has_self_loops(g::GNNGraph)\n\nReturn true if g has any self loops.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.inneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.inneighbors","text":"inneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through incoming edges.\n\nSee also neighbors and outneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.outneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.outneighbors","text":"outneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through outgoing edges.\n\nSee also neighbors and inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Graphs.neighbors(::GNNGraph, ::Integer)","category":"page"},{"location":"api/gnngraph.html#Graphs.neighbors-Tuple{GNNGraph, Integer}","page":"GNNGraph","title":"Graphs.neighbors","text":"neighbors(g::GNNGraph, i::Integer; dir=:out)\n\nReturn the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.\n\nSee also outneighbors, inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Transform","page":"GNNGraph","title":"Transform","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"transform.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])\nadd_edges(g::GNNGraph, (s, t); [edata])\nadd_edges(g::GNNGraph, (s, t, w); [edata])\n\nAdd to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.\n\nIf the s or t contain nodes that are not already present in the graph, they are added to the graph as well.\n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = Float32[1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> add_edges(g, ([2, 3], [4, 1], [10.0, 20.0]))\nGNNGraph:\n num_nodes: 4\n num_edges: 7\n\njulia> g = GNNGraph()\nGNNGraph:\n num_nodes: 0\n num_edges: 0\n\njulia> add_edges(g, [1,2], [2,3])\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])\n\nAdd to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t). \n\nIf the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"GNNGraphs.add_nodes","text":"add_nodes(g::GNNGraph, n; [ndata])\n\nAdd n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNGraph)\n\nReturn a graph with the same features as g but also adding edges connecting the nodes to themselves.\n\nNodes with already existing self-loops will obtain a second self-loop.\n\nIf the graphs has edge weights, the new edges will have weight 1.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNHeteroGraph, edge_t::EType)\nadd_self_loops(g::GNNHeteroGraph)\n\nIf the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.\n\nNodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.\n\nIf the graph has edge weights for edges of type edge_t, the new edges will have weight 1.\n\nIf no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.\n\nIf edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.getgraph-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.getgraph","text":"getgraph(g::GNNGraph, i; nmap=false)\n\nReturn the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph. \n\nIf nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.negative_sample-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.negative_sample","text":"negative_sample(g::GNNGraph; \n num_neg_edges = g.num_edges, \n bidirected = is_bidirected(g))\n\nReturn a graph containing random negative edges (i.e. non-edges) from graph g as edges.\n\nIf bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph. \n\nSee also is_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.perturb_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.perturb_edges","text":"perturb_edges([rng], g::GNNGraph, perturb_ratio)\n\nReturn a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops. \n\nThe function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.\n\nArguments\n\ng::GNNGraph: The graph to be perturbed.\nperturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.\nrng: An optionalrandom number generator to ensure reproducible results.\n\nExamples\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> perturbed_g = perturb_edges(g, 0.2)\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.ppr_diffusion-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.ppr_diffusion","text":"ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph\n\nCalculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web\n\nThe function performs the following steps:\n\nConstructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.\nNormalizes A to ensure each column sums to 1, representing transition probabilities.\nApplies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.\nUpdates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.\n\nArguments\n\ng::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.\nalpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.\n\nReturns\n\nA new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_edge_split-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.rand_edge_split","text":"rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2\n\nRandomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.\n\nIf bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.\n\nrand_edge_split is tipically used to create train/test splits in link prediction tasks.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.random_walk_pe-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.random_walk_pe","text":"random_walk_pe(g, walk_length)\n\nReturn the random walk positional encoding from the paper Graph Neural Networks with Learnable Structural and Positional Representations of the given graph g and the length of the walk walk_length as a matrix of size (walk_length, g.num_nodes). \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector{<:Integer}}","page":"GNNGraph","title":"GNNGraphs.remove_edges","text":"remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})\nremove_edges(g::GNNGraph, p=0.5)\n\nRemove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.\n\nArguments\n\ng: The input graph from which edges will be removed.\nedges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.\np: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.\n\nReturns\n\nA new GNNGraph with the specified edges removed.\n\nExample\n\njulia> using GraphNeuralNetworks\n\n# Construct a GNNGraph\njulia> g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 3\n num_edges: 5\n \n# Remove the second edge\njulia> g_new = remove_edges(g, [2]);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 4\n\n# Remove edges with a probability of 0.5\njulia> g_new = remove_edges(g, 0.5);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_multi_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_multi_edges","text":"remove_multi_edges(g::GNNGraph; aggr=+)\n\nRemove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.\n\nSee also remove_self_loops, has_multi_edges, and to_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, p)\n\nReturns a new graph obtained by dropping nodes from g with independent probabilities p. \n\nExamples\n\njulia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\njulia> g_new = remove_nodes(g, 0.5)\nGNNGraph:\n num_nodes: 2\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)\n\nRemove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.\n\nArguments\n\ng: The input graph from which nodes (and their edges) will be removed.\nnodes_to_remove: Vector of node indices to be removed.\n\nReturns\n\nA new GNNGraph with the specified nodes and all edges associated with these nodes removed. \n\nExample\n\nusing GraphNeuralNetworks\n\ng = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\n\n# Remove nodes with indices 2 and 3, for example\ng_new = remove_nodes(g, [2, 3])\n\n# g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.\nprintln(g_new)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_self_loops","text":"remove_self_loops(g::GNNGraph)\n\nReturn a graph constructed from g where self-loops (edges from a node to itself) are removed. \n\nSee also add_self_loops and remove_multi_edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.set_edge_weight-Tuple{GNNGraph, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.set_edge_weight","text":"set_edge_weight(g::GNNGraph, w::AbstractVector)\n\nSet w as edge weights in the returned graph. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_bidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_bidirected","text":"to_bidirected(g)\n\nAdds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph. \n\nSee also is_bidirected. \n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = [1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> e = [10.0, 20.0, 30.0, 40.0, 50.0];\n\njulia> g = GNNGraph(s, t, w, edata = e)\nGNNGraph:\n num_nodes = 4\n num_edges = 5\n edata:\n e => (5,)\n\njulia> g2 = to_bidirected(g)\nGNNGraph:\n num_nodes = 4\n num_edges = 7\n edata:\n e => (7,)\n\njulia> edge_index(g2)\n([1, 2, 2, 3, 3, 4, 4], [2, 1, 3, 2, 4, 3, 4])\n\njulia> get_edge_weight(g2)\n7-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.5\n 3.5\n 5.0\n\njulia> g2.edata.e\n7-element Vector{Float64}:\n 10.0\n 10.0\n 20.0\n 20.0\n 35.0\n 35.0\n 50.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_unidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_unidirected","text":"to_unidirected(g::GNNGraph)\n\nReturn a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.batch-Tuple{AbstractVector{<:GNNGraph}}","page":"GNNGraph","title":"MLUtils.batch","text":"batch(gs::Vector{<:GNNGraph})\n\nBatch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.\n\nEquivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.\n\nExamples\n\njulia> g1 = rand_graph(4, 6, ndata=ones(8, 4))\nGNNGraph:\n num_nodes = 4\n num_edges = 6\n ndata:\n x => (8, 4)\n\njulia> g2 = rand_graph(7, 4, ndata=zeros(8, 7))\nGNNGraph:\n num_nodes = 7\n num_edges = 4\n ndata:\n x => (8, 7)\n\njulia> g12 = MLUtils.batch([g1, g2])\nGNNGraph:\n num_nodes = 11\n num_edges = 10\n num_graphs = 2\n ndata:\n x => (8, 11)\n\njulia> g12.ndata.x\n8×11 Matrix{Float64}:\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.unbatch-Union{Tuple{GNNGraph{T}}, Tuple{T}} where T<:(Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}})","page":"GNNGraph","title":"MLUtils.unbatch","text":"unbatch(g::GNNGraph)\n\nOpposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.\n\nSee also MLUtils.batch and getgraph.\n\nExamples\n\njulia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])\nGNNGraph:\n num_nodes = 19\n num_edges = 16\n num_graphs = 3\n\njulia> MLUtils.unbatch(gbatched)\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph:\n num_nodes = 5\n num_edges = 6\n\n GNNGraph:\n num_nodes = 10\n num_edges = 8\n\n GNNGraph:\n num_nodes = 4\n num_edges = 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#SparseArrays.blockdiag-Tuple{GNNGraph, Vararg{GNNGraph}}","page":"GNNGraph","title":"SparseArrays.blockdiag","text":"blockdiag(xs::GNNGraph...)\n\nEquivalent to MLUtils.batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Utils","page":"GNNGraph","title":"Utils","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraphs.sort_edge_index\nGNNGraphs.color_refinement","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sort_edge_index","page":"GNNGraph","title":"GNNGraphs.sort_edge_index","text":"sort_edge_index(ei::Tuple) -> u', v'\nsort_edge_index(u, v) -> u', v'\n\nReturn a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi. \n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.color_refinement","page":"GNNGraph","title":"GNNGraphs.color_refinement","text":"color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters\n\nThe color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.\n\nAt each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.\n\nmath x_i' = hashmap((x_i, sort([x_j for j \\in N(i)]))).`\n\nThis algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.\n\nArguments\n\ng::GNNGraph: The graph to color.\nx0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.\n\nReturns\n\nx::AbstractVector{<:Integer}: The final coloring.\nnum_colors::Int: The number of colors used.\nniters::Int: The number of iterations until convergence.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Generate","page":"GNNGraph","title":"Generate","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"generate.jl\"]\nPrivate = false\nFilter = t -> typeof(t) <: Function && t!=rand_temporal_radius_graph && t!=rand_temporal_hyperbolic_graph\n","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.knn_graph-Tuple{AbstractMatrix, Int64}","page":"GNNGraph","title":"GNNGraphs.knn_graph","text":"knn_graph(points::AbstractMatrix, \n k::Int; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a k-nearest neighbor graph where each node is linked to its k closest points. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nk: The number of neighbors considered in the kNN algorithm.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its k nearest neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the k neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, k = 10, 3;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = knn_graph(x, k)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = knn_graph(x, k; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n num_graphs = 2\n\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.radius_graph-Tuple{AbstractMatrix, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.radius_graph","text":"radius_graph(points::AbstractMatrix, \n r::AbstractFloat; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a graph where each node is linked to its neighbors within a given distance r. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nr: The radius.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, r = 10, 0.75;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = radius_graph(x, r)\nGNNGraph:\n num_nodes = 10\n num_edges = 46\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = radius_graph(x, r; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n num_graphs = 2\n\n\nReferences\n\nSection B paragraphs 1 and 2 of the paper Dynamic Hidden-Variable Network Models\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_bipartite_heterograph-Tuple{Any, Any}","page":"GNNGraph","title":"GNNGraphs.rand_bipartite_heterograph","text":"rand_bipartite_heterograph([rng,] \n (n1, n2), (m12, m21); \n bidirected = true, \n node_t = (:A, :B), \n edge_t = :to, \n kws...)\n\nConstruct an GNNHeteroGraph with random edges representing a bipartite graph. The graph will have two types of nodes, and edges will only connect nodes of different types.\n\nThe first argument is a tuple (n1, n2) specifying the number of nodes of each type. The second argument is a tuple (m12, m21) specifying the number of edges connecting nodes of type 1 to nodes of type 2 and vice versa.\n\nThe type of nodes and edges can be specified with the node_t and edge_t keyword arguments, which default to (:A, :B) and :to respectively.\n\nIf bidirected=true (default), the reverse edge of each edge will be present. In this case m12 == m21 is required.\n\nA random number generator can be passed as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nSee rand_heterograph for a more general version.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 15)\n num_edges: ((:A, :to, :B) => 20, (:B, :to, :A) => 20)\n\njulia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)\nGNNHeteroGraph:\n num_nodes: Dict(:item => 15, :user => 10)\n num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_graph-Tuple{Integer, Integer}","page":"GNNGraph","title":"GNNGraphs.rand_graph","text":"rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)\n\nGenerate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.\n\nIf bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.\n\nA vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.\n\nPass a random number generator as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> g = rand_graph(5, 4, bidirected=false)\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n\njulia> edge_index(g)\n([1, 3, 3, 4], [5, 4, 5, 2])\n\n# In the bidirected case, edge data will be duplicated on the reverse edges if needed.\njulia> g = rand_graph(5, 4, edata=rand(Float32, 16, 2))\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n edata:\n e => (16, 4)\n\n# Each edge has a reverse\njulia> edge_index(g)\n([1, 3, 3, 4], [3, 4, 1, 3])\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_heterograph","page":"GNNGraph","title":"GNNGraphs.rand_heterograph","text":"rand_heterograph([rng,] n, m; bidirected=false, kws...)\n\nConstruct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.\n\nPass a random number generator as a first argument to make the generation reproducible.\n\nSetting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nExamples\n\njulia> g = rand_heterograph((:user => 10, :movie => 20),\n (:user, :rate, :movie) => 30)\nGNNHeteroGraph:\n num_nodes: (:user => 10, :movie => 20) \n num_edges: ((:user, :rate, :movie) => 30,)\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Operators","page":"GNNGraph","title":"Operators","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"operators.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Base.intersect","category":"page"},{"location":"api/gnngraph.html#Base.intersect","page":"GNNGraph","title":"Base.intersect","text":"\" intersect(g1::GNNGraph, g2::GNNGraph)\n\nIntersect two graphs by keeping only the common edges.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Sampling","page":"GNNGraph","title":"Sampling","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"sampling.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sample_neighbors","page":"GNNGraph","title":"GNNGraphs.sample_neighbors","text":"sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)\n\nSample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.\n\nThe returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.\n\nArguments\n\ng. The graph.\nnodes. A list of node IDs to sample neighbors from.\nK. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.\ndir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).\nreplace. If true, sample with replacement.\ndropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.\n\nExamples\n\njulia> g = rand_graph(20, 100)\nGNNGraph:\n num_nodes = 20\n num_edges = 100\n\njulia> sample_neighbors(g, 2:3)\nGNNGraph:\n num_nodes = 20\n num_edges = 9\n edata:\n EID => (9,)\n\njulia> sg = sample_neighbors(g, 2:3, dropnodes=true)\nGNNGraph:\n num_nodes = 10\n num_edges = 9\n ndata:\n NID => (10,)\n edata:\n EID => (9,)\n\njulia> sg.ndata.NID\n10-element Vector{Int64}:\n 2\n 3\n 17\n 14\n 18\n 15\n 16\n 20\n 7\n 10\n\njulia> sample_neighbors(g, 2:3, 5, replace=true)\nGNNGraph:\n num_nodes = 20\n num_edges = 10\n edata:\n EID => (10,)\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.","category":"page"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Modules = [GNNGraphs]\nPages = [\"temporalsnapshotsgnngraph.jl\"]\nPrivate = false","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"GNNGraphs.TemporalSnapshotsGNNGraph","text":"TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})\n\nA type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.\n\nTemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.\n\nConstructor Arguments\n\nsnapshot: a vector of snapshots, where each snapshot must have the same number of nodes.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> tg.tgdata.x = rand(4); # add temporal graph feature\n\njulia> tg # show temporal graph with new feature\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n tgdata:\n x = 4-element Vector{Float64}\n\n\n\n\n\n","category":"type"},{"location":"api/temporalgraph.html#GNNGraphs.add_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64, GNNGraph}","page":"Temporal Graphs","title":"GNNGraphs.add_snapshot","text":"add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10, 20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#GNNGraphs.remove_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64}","page":"Temporal Graphs","title":"GNNGraphs.remove_snapshot","text":"remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph-random-generators","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph random generators","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"rand_temporal_radius_graph\nrand_temporal_hyperbolic_graph","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_radius_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_radius_graph","text":"rand_temporal_radius_graph(number_nodes::Int, \n number_snapshots::Int,\n speed::AbstractFloat,\n r::AbstractFloat;\n self_loops = false,\n dir = :in,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are randomly generated in the unit square. Two nodes are connected if their distance is less than a given radius r. Each following snapshot is obtained by applying the same construction to new positions obtained as follows. For each snapshot, the new positions of the points are determined by applying random independent displacement vectors to the previous positions. The direction of the displacement is chosen uniformly at random and its length is chosen uniformly in [0, speed]. Then the connections are recomputed. If a point happens to move outside the boundary, its position is updated as if it had bounced off the boundary.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nspeed: The speed to update the nodes.\nr: The radius of connection.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, s, r = 10, 5, 0.1, 1.5;\n\njulia> tg = rand_temporal_radius_graph(n,snaps,s,r) # complete graph at each snapshot\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [90, 90, 90, 90, 90]\n num_snapshots: 5\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_hyperbolic_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_hyperbolic_graph","text":"rand_temporal_hyperbolic_graph(number_nodes::Int, \n number_snapshots::Int;\n α::Real,\n R::Real,\n speed::Real,\n ζ::Real=1,\n self_loop = false,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are generated with a quasi-uniform distribution (depending on the parameter α) in hyperbolic space within a disk of radius R. Two nodes are connected if their hyperbolic distance is less than R. Each following snapshot is created in order to keep the same initial distribution.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nα: The parameter that controls the position of the points. If α=ζ, the points are uniformly distributed on the disk of radius R. If α>ζ, the points are more concentrated in the center of the disk. If α<ζ, the points are more concentrated at the boundary of the disk.\nR: The radius of the disk and of connection.\nspeed: The speed to update the nodes.\nζ: The parameter that controls the curvature of the disk.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, α, R, speed, ζ = 10, 5, 1.0, 4.0, 0.1, 1.0;\n\njulia> thg = rand_temporal_hyperbolic_graph(n, snaps; α, R, speed, ζ)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [44, 46, 48, 42, 38]\n num_snapshots: 5\n\nReferences\n\nSection D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks\n\n\n\n\n\n","category":"function"},{"location":"temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Temporal Graphs are graphs with time varying topologies and node features. In GraphNeuralNetworks.jl temporal graphs with fixed number of nodes over time are supported by the TemporalSnapshotsGNNGraph type.","category":"page"},{"location":"temporalgraph.html#Creating-a-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Creating a TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A temporal graph can be created by passing a list of snapshots to the constructor. Each snapshot is a GNNGraph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A new temporal graph can be created by adding or removing snapshots to an existing temporal graph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"See rand_temporal_radius_graph and rand_temporal_hyperbolic_graph for generating random temporal graphs. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> tg = rand_temporal_radius_graph(10, 3, 0.1, 0.5)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [32, 30, 34]\n num_snapshots: 3","category":"page"},{"location":"temporalgraph.html#Basic-Queries","page":"Temporal Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Basic queries are similar to those for GNNGraphs:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> tg.num_nodes # number of nodes in each snapshot\n3-element Vector{Int64}:\n 10\n 10\n 10\n\njulia> tg.num_edges # number of edges in each snapshot\n3-element Vector{Int64}:\n 20\n 14\n 22\n\njulia> tg.num_snapshots # number of snapshots\n3\n\njulia> tg.snapshots # list of snapshots\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph(10, 20) with no data\n GNNGraph(10, 14) with no data\n GNNGraph(10, 22) with no data\n\njulia> tg.snapshots[1] # first snapshot, same as tg[1]\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"temporalgraph.html#Data-Features","page":"Temporal Graphs","title":"Data Features","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> tg.tgdata.y = rand(3,1); # graph features after construction\n\njulia> tg\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n tgdata:\n y = 3×1 Matrix{Float64}\n\njulia> tg.ndata # vector of Datastore for node features\n3-element Vector{DataStore}:\n DataStore(10) with 1 element:\n x = 3×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 4×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 5×10 Matrix{Float64}\n\njulia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot\nVector{Matrix{Float64}}","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> using GraphNeuralNetworks, Flux\n\njulia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> m = GINConv(Dense(3 => 1), 0.4);\n\njulia> output = m(tg, tg.ndata.x);\n\njulia> size(output[1])\n(1, 10)","category":"page"},{"location":"heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.","category":"page"},{"location":"heterograph.html#Creating-a-Heterograph","page":"Heterogeneous Graphs","title":"Creating a Heterograph","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"A heterograph can be created empty or by passing pairs edge_type => data to the constructor.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph()\nGNNHeteroGraph:\n num_nodes: Dict()\n num_edges: Dict()\n \njulia> g = GNNHeteroGraph((:user, :like, :actor) => ([1,2,2,3], [1,3,2,9]),\n (:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 4, (:user, :rate, :movie) => 4)\n\njulia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"New relations, possibly with new node types, can be added with the function add_edges.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = add_edges(g, (:user, :like, :actor) => ([1,2,3,3,3], [3,5,1,9,4]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 5, (:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See rand_heterograph, rand_bipartite_heterograph for generating random heterographs. ","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 10, :B => 15)\n num_edges: Dict((:A, :to, :B) => 20, (:B, :to, :A) => 20)","category":"page"},{"location":"heterograph.html#Basic-Queries","page":"Heterogeneous Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Basic queries are similar to those for homogeneous graphs:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n\njulia> g.num_nodes\nDict{Symbol, Int64} with 2 entries:\n :user => 3\n :movie => 13\n\njulia> g.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 1 entry:\n (:user, :rate, :movie) => 4\n\n# source and target node for a given relation\njulia> edge_index(g, (:user, :rate, :movie))\n([1, 1, 2, 3], [7, 13, 5, 7])\n\n# node types\njulia> g.ntypes\n2-element Vector{Symbol}:\n :user\n :movie\n\n# edge types\njulia> g.etypes\n1-element Vector{Tuple{Symbol, Symbol, Symbol}}:\n (:user, :rate, :movie)","category":"page"},{"location":"heterograph.html#Data-Features","page":"Heterogeneous Graphs","title":"Data Features","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"# equivalent to g.ndata[:user][:x] = ...\njulia> g[:user].x = rand(Float32, 64, 3);\n\njulia> g[:movie].z = rand(Float32, 64, 13);\n\n# equivalent to g.edata[(:user, :rate, :movie)][:e] = ...\njulia> g[:user, :rate, :movie].e = rand(Float32, 64, 4);\n\njulia> g\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n ndata:\n :movie => DataStore(z = [64×13 Matrix{Float32}])\n :user => DataStore(x = [64×3 Matrix{Float32}])\n edata:\n (:user, :rate, :movie) => DataStore(e = [64×4 Matrix{Float32}])","category":"page"},{"location":"heterograph.html#Batching","page":"Heterogeneous Graphs","title":"Batching","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Similarly to graphs, also heterographs can be batched together.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> gs = [rand_bipartite_heterograph((5, 10), 20) for _ in 1:32];\n\njulia> Flux.batch(gs)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 160, :B => 320)\n num_edges: Dict((:A, :to, :B) => 640, (:B, :to, :A) => 640)\n num_graphs: 32","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Batching is automatically performed by the DataLoader iterator when the collate option is set to true.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"using Flux: DataLoader\n\ndata = [rand_bipartite_heterograph((5, 10), 20, \n ndata=Dict(:A=>rand(Float32, 3, 5))) \n for _ in 1:320];\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes[:A] == 80\n @assert size(g.ndata[:A].x) == (3, 80) \n # ...\nend","category":"page"},{"location":"api/heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"api/heterograph.html#GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNHeteroGraph","text":"","category":"section"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.","category":"page"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Modules = [GNNGraphs]\nPages = [\"gnnheterograph.jl\"]\nPrivate = false","category":"page"},{"location":"api/heterograph.html#GNNGraphs.GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNGraphs.GNNHeteroGraph","text":"GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])\nGNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])\n\nA type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.\n\nConstructor Arguments\n\ndata: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).\npairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).\nndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.\nedata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.\nnum_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.\n\nFields\n\ngraph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.\nnum_nodes: The number of nodes for each type.\nnum_edges: The number of edges for each type.\nndata: Node features.\nedata: Edge features.\ngdata: Graph features.\nntypes: The node types.\netypes: The edge types.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> nA, nB = 10, 20;\n\njulia> num_nodes = Dict(:A => nA, :B => nB);\n\njulia> edges1 = (rand(1:nA, 20), rand(1:nB, 20))\n([4, 8, 6, 3, 4, 7, 2, 7, 3, 2, 3, 4, 9, 4, 2, 9, 10, 1, 3, 9], [6, 4, 20, 8, 16, 7, 12, 16, 5, 4, 6, 20, 11, 19, 17, 9, 12, 2, 18, 12])\n\njulia> edges2 = (rand(1:nB, 30), rand(1:nA, 30))\n([17, 5, 2, 4, 5, 3, 8, 7, 9, 7 … 19, 8, 20, 7, 16, 2, 9, 15, 8, 13], [1, 1, 3, 1, 1, 3, 2, 7, 4, 4 … 7, 10, 6, 3, 4, 9, 1, 5, 8, 5])\n\njulia> data = ((:A, :rel1, :B) => edges1, (:B, :rel2, :A) => edges2);\n\njulia> hg = GNNHeteroGraph(data; num_nodes)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n\njulia> hg.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 2 entries:\n(:A, :rel1, :B) => 20\n(:B, :rel2, :A) => 30\n\n# Let's add some node features\njulia> ndata = Dict(:A => (x = rand(2, nA), y = rand(3, num_nodes[:A])),\n :B => rand(10, nB));\n\njulia> hg = GNNHeteroGraph(data; num_nodes, ndata)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n ndata:\n :A => (x = 2×10 Matrix{Float64}, y = 3×10 Matrix{Float64})\n :B => x = 10×20 Matrix{Float64}\n\n# Access features of nodes of type :A\njulia> hg.ndata[:A].x\n2×10 Matrix{Float64}:\n 0.825882 0.0797502 0.245813 0.142281 0.231253 0.685025 0.821457 0.888838 0.571347 0.53165\n 0.631286 0.316292 0.705325 0.239211 0.533007 0.249233 0.473736 0.595475 0.0623298 0.159307\n\nSee also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.\n\n\n\n\n\n","category":"type"},{"location":"api/heterograph.html#GNNGraphs.edge_type_subgraph-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}","page":"Heterogeneous Graphs","title":"GNNGraphs.edge_type_subgraph","text":"edge_type_subgraph(g::GNNHeteroGraph, edge_ts)\n\nReturn a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_edge_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_edge_types","text":"num_edge_types(g)\n\nReturn the number of edge types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_node_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_node_types","text":"num_node_types(g)\n\nReturn the number of node types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique node types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Graphs.has_edge(::GNNHeteroGraph, ::Tuple{Symbol, Symbol, Symbol}, ::Integer, ::Integer)","category":"page"},{"location":"api/heterograph.html#Graphs.has_edge-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, Integer, Integer}","page":"Heterogeneous Graphs","title":"Graphs.has_edge","text":"has_edge(g::GNNHeteroGraph, edge_t, i, j)\n\nReturn true if there is an edge of type edge_t from node i to node j in g.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)\nGNNHeteroGraph:\n num_nodes: (:A => 2, :B => 2)\n num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)\n\njulia> has_edge(g, (:A,:to,:B), 1, 1)\ntrue\n\njulia> has_edge(g, (:B,:to,:A), 1, 1)\nfalse\n\n\n\n\n\n","category":"method"},{"location":"gnngraph.html#Working-with-GNNGraph","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library. ","category":"page"},{"location":"gnngraph.html#Graph-Creation","page":"Working with GNNGraph","title":"Graph Creation","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"A GNNGraph can be created from several different data sources encoding the graph topology:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using GraphNeuralNetworks, Graphs, SparseArrays\n\n\n# Construct a GNNGraph from from a Graphs.jl's graph\nlg = erdos_renyi(10, 30)\ng = GNNGraph(lg)\n\n# Same as above using convenience method rand_graph\ng = rand_graph(10, 60)\n\n# From an adjacency matrix\nA = sprand(10, 10, 0.3)\ng = GNNGraph(A)\n\n# From an adjacency list\nadjlist = [[2,3], [1,3], [1,2,4], [3]]\ng = GNNGraph(adjlist)\n\n# From COO representation\nsource = [1,1,2,2,3,3,3,4]\ntarget = [2,3,1,3,1,2,4,3]\ng = GNNGraph(source, target)","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"See also the related methods Graphs.adjacency_matrix, edge_index, and adjacency_list.","category":"page"},{"location":"gnngraph.html#Basic-Queries","page":"Working with GNNGraph","title":"Basic Queries","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> source = [1,1,2,2,3,3,3,4];\n\njulia> target = [2,3,1,3,1,2,4,3];\n\njulia> g = GNNGraph(source, target)\nGNNGraph:\n num_nodes: 4\n num_edges: 8\n\n\njulia> @assert g.num_nodes == 4 # number of nodes\n\njulia> @assert g.num_edges == 8 # number of edges\n\njulia> @assert g.num_graphs == 1 # number of subgraphs (a GNNGraph can batch many graphs together)\n\njulia> is_directed(g) # a GNNGraph is always directed\ntrue\n\njulia> is_bidirected(g) # for each edge, also the reverse edge is present\ntrue\n\njulia> has_self_loops(g)\nfalse\n\njulia> has_multi_edges(g) \nfalse","category":"page"},{"location":"gnngraph.html#Data-Features","page":"Working with GNNGraph","title":"Data Features","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"One or more arrays can be associated to nodes, edges, and (sub)graphs of a GNNGraph. They will be stored in the fields g.ndata, g.edata, and g.gdata respectively.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The data fields are DataStore objects. DataStores conveniently offer an interface similar to both dictionaries and named tuples. Similarly to dictionaries, DataStores support addition of new features after creation time.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"The array contained in the datastores have last dimension equal to num_nodes (in ndata), num_edges (in edata), or num_graphs (in gdata) respectively.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"# Create a graph with a single feature array `x` associated to nodes\ng = rand_graph(10, 60, ndata = (; x = rand(Float32, 32, 10)))\n\ng.ndata.x # access the features\n\n# Equivalent definition passing directly the array\ng = rand_graph(10, 60, ndata = rand(Float32, 32, 10))\n\ng.ndata.x # `:x` is the default name for node features\n\ng.ndata.z = rand(Float32, 3, 10) # add new feature array `z`\n\n# For convenience, we can access the features through the shortcut\ng.x \n\n# You can have multiple feature arrays\ng = rand_graph(10, 60, ndata = (; x=rand(Float32, 32, 10), y=rand(Float32, 10)))\n\ng.ndata.y, g.ndata.x # or g.x, g.y\n\n# Attach an array with edge features.\n# Since `GNNGraph`s are directed, the number of edges\n# will be double that of the original Graphs' undirected graph.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 60))\n@assert g.num_edges == 60\n\ng.edata.e # or g.e\n\n# If we pass only half of the edge features, they will be copied\n# on the reversed edges.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 30))\n\n\n# Create a new graph from previous one, inheriting edge data\n# but replacing node data\ng′ = GNNGraph(g, ndata =(; z = ones(Float32, 16, 10)))\n\ng′.z\ng′.e","category":"page"},{"location":"gnngraph.html#Edge-weights","page":"Working with GNNGraph","title":"Edge weights","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> source = [1, 1, 2, 2, 3, 3];\n\njulia> target = [2, 3, 1, 3, 1, 2];\n\njulia> weight = [1.0, 0.5, 2.1, 2.3, 4, 4.1];\n\njulia> g = GNNGraph(source, target, weight)\nGNNGraph:\n num_nodes: 3\n num_edges: 6\n\njulia> get_edge_weight(g)\n6-element Vector{Float64}:\n 1.0\n 0.5\n 2.1\n 2.3\n 4.0\n 4.1","category":"page"},{"location":"gnngraph.html#Batches-and-Subgraphs","page":"Working with GNNGraph","title":"Batches and Subgraphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Multiple GNNGraphs can be batched together into a single graph that contains the total number of the original nodes and where the original graphs are disjoint subgraphs.","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using Flux\nusing Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:160]\ngall = Flux.batch(data)\n\n# gall is a GNNGraph containing many graphs\n@assert gall.num_graphs == 160 \n@assert gall.num_nodes == 1600 # 10 nodes x 160 graphs\n@assert gall.num_edges == 4800 # 30 undirected edges x 160 graphs\n\n# Let's create a mini-batch from gall\ng23 = getgraph(gall, 2:3)\n@assert g23.num_graphs == 2\n@assert g23.num_nodes == 20 # 10 nodes x 2 graphs\n@assert g23.num_edges == 60 # 30 undirected edges X 2 graphs\n\n# We can pass a GNNGraph to Flux's DataLoader\ntrain_loader = DataLoader(gall, batchsize=16, shuffle=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend\n\n# Access the nodes' graph memberships \ngraph_indicator(gall)","category":"page"},{"location":"gnngraph.html#DataLoader-and-mini-batch-iteration","page":"Working with GNNGraph","title":"DataLoader and mini-batch iteration","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"While constructing a batched graph and passing it to the DataLoader is always an option for mini-batch iteration, the recommended way for better performance is to pass an array of graphs directly and set the collate option to true:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:320]\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend","category":"page"},{"location":"gnngraph.html#Graph-Manipulation","page":"Working with GNNGraph","title":"Graph Manipulation","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"g′ = add_self_loops(g)\ng′ = remove_self_loops(g)\ng′ = add_edges(g, [1, 2], [2, 3]) # add edges 1->2 and 2->3","category":"page"},{"location":"gnngraph.html#GPU-movement","page":"Working with GNNGraph","title":"GPU movement","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Move a GNNGraph to a CUDA device using Flux.gpu method. ","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"using CUDA, Flux\n\ng_gpu = g |> Flux.gpu","category":"page"},{"location":"gnngraph.html#Integration-with-Graphs.jl","page":"Working with GNNGraph","title":"Integration with Graphs.jl","text":"","category":"section"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"Since GNNGraph <: Graphs.AbstractGraph, we can use any functionality from Graphs.jl for querying and analyzing the graph structure. Moreover, a GNNGraph can be easily constructed from a Graphs.Graph or a Graphs.DiGraph:","category":"page"},{"location":"gnngraph.html","page":"Working with GNNGraph","title":"Working with GNNGraph","text":"julia> import Graphs\n\njulia> using GraphNeuralNetworks\n\n# A Graphs.jl undirected graph\njulia> gu = Graphs.erdos_renyi(10, 20) \n{10, 20} undirected simple Int64 graph\n\n# Since GNNGraphs are undirected, the edges are doubled when converting \n# to GNNGraph\njulia> GNNGraph(gu)\nGNNGraph:\n num_nodes: 10\n num_edges: 40\n\n# A Graphs.jl directed graph\njulia> gd = Graphs.erdos_renyi(10, 20, is_directed=true)\n{10, 20} directed simple Int64 graph\n\njulia> GNNGraph(gd)\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"index.html#Hello-GNNGraphs","page":"Home","title":"Hello GNNGraphs","text":"","category":"section"},{"location":"datasets.html#Datasets","page":"Datasets","title":"Datasets","text":"","category":"section"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"mldataset2gnngraph","category":"page"},{"location":"datasets.html#GNNGraphs.mldataset2gnngraph","page":"Datasets","title":"GNNGraphs.mldataset2gnngraph","text":"mldataset2gnngraph(dataset)\n\nConvert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.\n\nExamples\n\njulia> using MLDatasets, GraphNeuralNetworks\n\njulia> mldataset2gnngraph(Cora())\nGNNGraph:\n num_nodes = 2708\n num_edges = 10556\n ndata:\n features => 1433×2708 Matrix{Float32}\n targets => 2708-element Vector{Int64}\n train_mask => 2708-element BitVector\n val_mask => 2708-element BitVector\n test_mask => 2708-element BitVector\n\n\n\n\n\n","category":"function"}] +[{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"CurrentModule = GNNGraphs","category":"page"},{"location":"api/gnngraph.html#GNNGraph","page":"GNNGraph","title":"GNNGraph","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Documentation page for the graph type GNNGraph provided by GNNGraphs.jl and related methods. ","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.","category":"page"},{"location":"api/gnngraph.html#Index","page":"GNNGraph","title":"Index","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Order = [:type, :function]\nPages = [\"gnngraph.md\"]","category":"page"},{"location":"api/gnngraph.html#GNNGraph-type","page":"GNNGraph","title":"GNNGraph type","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraph\nBase.copy","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.GNNGraph","page":"GNNGraph","title":"GNNGraphs.GNNGraph","text":"GNNGraph(data; [graph_type, ndata, edata, gdata, num_nodes, graph_indicator, dir])\nGNNGraph(g::GNNGraph; [ndata, edata, gdata])\n\nA type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.\n\nThe feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.\n\nA GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.\n\nWhen constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.\n\nA GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.\n\nGNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.\n\nA GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.\n\nArguments\n\ndata: Some data representing the graph topology. Possible type are\nAn adjacency matrix\nAn adjacency list.\nA tuple containing the source and target vectors (COO representation)\nA Graphs.jl' graph.\ngraph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are\n:coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).\n:sparse. A sparse adjacency matrix representation.\n:dense. A dense adjacency matrix representation.\nDefaults to :coo, currently the most supported type.\ndir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.\nnum_nodes: The number of nodes. If not specified, inferred from g. Default nothing.\ngraph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.\nndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.\nedata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.\n\nExamples\n\nusing GraphNeuralNetworks\n\n# Construct from adjacency list representation\ndata = [[2,3], [1,4,5], [1], [2,5], [2,4]]\ng = GNNGraph(data)\n\n# Number of nodes, edges, and batched graphs\ng.num_nodes # 5\ng.num_edges # 10\ng.num_graphs # 1\n\n# Same graph in COO representation\ns = [1,1,2,2,2,3,4,4,5,5]\nt = [2,3,1,4,5,3,2,5,2,4]\ng = GNNGraph(s, t)\n\n# From a Graphs' graph\ng = GNNGraph(erdos_renyi(100, 20))\n\n# Add 2 node feature arrays at creation time\ng = GNNGraph(g, ndata = (x=rand(100, g.num_nodes), y=rand(g.num_nodes)))\n\n# Add 1 edge feature array, after the graph creation\ng.edata.z = rand(16, g.num_edges)\n\n# Add node features and edge features with default names `x` and `e`\ng = GNNGraph(g, ndata = rand(100, g.num_nodes), edata = rand(16, g.num_edges))\n\ng.ndata.x # or just g.x\ng.edata.e # or just g.e\n\n# Collect edges' source and target nodes.\n# Both source and target are vectors of length num_edges\nsource, target = edge_index(g)\n\nA GNNGraph can be sent to the GPU using e.g. Flux's gpu function:\n\n# Send to gpu\nusing Flux, CUDA\ng = g |> Flux.gpu\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Base.copy","page":"GNNGraph","title":"Base.copy","text":"copy(g::GNNGraph; deep=false)\n\nCreate a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#DataStore","page":"GNNGraph","title":"DataStore","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"datastore.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.DataStore","page":"GNNGraph","title":"GNNGraphs.DataStore","text":"DataStore([n, data])\nDataStore([n,] k1 = x1, k2 = x2, ...)\n\nA container for feature arrays. The optional argument n enforces that numobs(x) == n for each array contained in the datastore.\n\nAt construction time, the data can be provided as any iterables of pairs of symbols and arrays or as keyword arguments:\n\njulia> ds = DataStore(3, x = rand(Float32, 2, 3), y = rand(Float32, 3))\nDataStore(3) with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds = DataStore(3, Dict(:x => rand(Float32, 2, 3), :y => rand(Float32, 3))); # equivalent to above\n\njulia> ds = DataStore(3, (x = rand(Float32, 2, 3), y = rand(Float32, 30)))\nERROR: AssertionError: DataStore: data[y] has 30 observations, but n = 3\nStacktrace:\n [1] DataStore(n::Int64, data::Dict{Symbol, Any})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:54\n [2] DataStore(n::Int64, data::NamedTuple{(:x, :y), Tuple{Matrix{Float32}, Vector{Float32}}})\n @ GNNGraphs ~/.julia/dev/GNNGraphs/datastore.jl:73\n [3] top-level scope\n @ REPL[13]:1\n\njulia> ds = DataStore(x = randFloat32, 2, 3), y = rand(Float32, 30)) # no checks\nDataStore() with 2 elements:\n y = 30-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n y = 30-element Vector{Float64}\n x = 2×3 Matrix{Float64}\n\nThe DataStore has an interface similar to both dictionaries and named tuples. Arrays can be accessed and added using either the indexing or the property syntax:\n\njulia> ds = DataStore(x = ones(Float32, 2, 3), y = zeros(Float32, 3))\nDataStore() with 2 elements:\n y = 3-element Vector{Float32}\n x = 2×3 Matrix{Float32}\n\njulia> ds.x # same as `ds[:x]`\n2×3 Matrix{Float32}:\n 1.0 1.0 1.0\n 1.0 1.0 1.0\n\njulia> ds.z = zeros(Float32, 3) # Add new feature array `z`. Same as `ds[:z] = rand(Float32, 3)`\n3-element Vector{Float64}:\n0.0\n0.0\n0.0\n\nThe DataStore can be iterated over, and the keys and values can be accessed using keys(ds) and values(ds). map(f, ds) applies the function f to each feature array:\n\njulia> ds = DataStore(a = zeros(2), b = zeros(2));\n\njulia> ds2 = map(x -> x .+ 1, ds)\n\njulia> ds2.a\n2-element Vector{Float64}:\n 1.0\n 1.0\n\n\n\n\n\n","category":"type"},{"location":"api/gnngraph.html#Query","page":"GNNGraph","title":"Query","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"query.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.adjacency_list-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.adjacency_list","text":"adjacency_list(g; dir=:out)\nadjacency_list(g, nodes; dir=:out)\n\nReturn the adjacency list representation (a vector of vectors) of the graph g.\n\nCalling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.\n\nIf nodes is given, return the neighborhood of the nodes in nodes only.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNGraph)\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g.\n\ns, t = edge_index(g)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.edge_index-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.edge_index","text":"edge_index(g::GNNHeteroGraph, [edge_t])\n\nReturn a tuple containing two vectors, respectively storing the source and target nodes for each edges in g of type edge_t = (src_t, rel_t, trg_t).\n\nIf edge_t is not provided, it will error if g has more than one edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNGraph; edges=false)\n\nReturn a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.graph_indicator-Tuple{GNNHeteroGraph}","page":"GNNGraph","title":"GNNGraphs.graph_indicator","text":"graph_indicator(g::GNNHeteroGraph, [node_t])\n\nReturn a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.\n\nSee also batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_isolated_nodes-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_isolated_nodes","text":"has_isolated_nodes(g::GNNGraph; dir=:out)\n\nReturn true if the graph g contains nodes with out-degree (if dir=:out) or in-degree (if dir = :in) equal to zero.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.has_multi_edges-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.has_multi_edges","text":"has_multi_edges(g::GNNGraph)\n\nReturn true if g has any multiple edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.is_bidirected-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.is_bidirected","text":"is_bidirected(g::GNNGraph)\n\nCheck if the directed graph g essentially corresponds to an undirected graph, i.e. if for each edge it also contains the reverse edge. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.khop_adj","page":"GNNGraph","title":"GNNGraphs.khop_adj","text":"khop_adj(g::GNNGraph,k::Int,T::DataType=eltype(g); dir=:out, weighted=true)\n\nReturn A^k where A is the adjacency matrix of the graph 'g'.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.laplacian_lambda_max","page":"GNNGraph","title":"GNNGraphs.laplacian_lambda_max","text":"laplacian_lambda_max(g::GNNGraph, T=Float32; add_self_loops=false, dir=:out)\n\nReturn the largest eigenvalue of the normalized symmetric Laplacian of the graph g.\n\nIf the graph is batched from multiple graphs, return the list of the largest eigenvalue for each graph.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.normalized_laplacian","page":"GNNGraph","title":"GNNGraphs.normalized_laplacian","text":"normalized_laplacian(g, T=Float32; add_self_loops=false, dir=:out)\n\nNormalized Laplacian matrix of graph g.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\nadd_self_loops: add self-loops while calculating the matrix.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.scaled_laplacian","page":"GNNGraph","title":"GNNGraphs.scaled_laplacian","text":"scaled_laplacian(g, T=Float32; dir=:out)\n\nScaled Laplacian matrix of graph g, defined as hatL = frac2lambda_max L - I where L is the normalized Laplacian matrix.\n\nArguments\n\ng: A GNNGraph.\nT: result element type.\ndir: the edge directionality considered (:out, :in, :both).\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.LinAlg.adjacency_matrix","page":"GNNGraph","title":"Graphs.LinAlg.adjacency_matrix","text":"adjacency_matrix(g::GNNGraph, T=eltype(g); dir=:out, weighted=true)\n\nReturn the adjacency matrix A for the graph g. \n\nIf dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.\n\nUser may specify the eltype T of the returned matrix. \n\nIf weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}, Tuple{TT}, Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNGraph, T=nothing; dir=:out, edge_weight=true)\n\nReturn a vector containing the degrees of the nodes in g.\n\nThe gradient is propagated through this function only if edge_weight is true or a vector.\n\nArguments\n\ng: A graph.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.\nedge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.degree-Union{Tuple{TT}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}, Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, TT}} where TT<:Union{Nothing, Type{<:Number}}","page":"GNNGraph","title":"Graphs.degree","text":"degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)\n\nReturn a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.\n\nArguments\n\ng: A graph.\nedge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.\nT: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.\ndir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.has_self_loops-Tuple{GNNGraph}","page":"GNNGraph","title":"Graphs.has_self_loops","text":"has_self_loops(g::GNNGraph)\n\nReturn true if g has any self loops.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.inneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.inneighbors","text":"inneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through incoming edges.\n\nSee also neighbors and outneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Graphs.outneighbors-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"Graphs.outneighbors","text":"outneighbors(g::GNNGraph, i::Integer)\n\nReturn the neighbors of node i in the graph g through outgoing edges.\n\nSee also neighbors and inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Graphs.neighbors(::GNNGraph, ::Integer)","category":"page"},{"location":"api/gnngraph.html#Graphs.neighbors-Tuple{GNNGraph, Integer}","page":"GNNGraph","title":"Graphs.neighbors","text":"neighbors(g::GNNGraph, i::Integer; dir=:out)\n\nReturn the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.\n\nSee also outneighbors, inneighbors.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Transform","page":"GNNGraph","title":"Transform","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"transform.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNGraph, s::AbstractVector, t::AbstractVector; [edata])\nadd_edges(g::GNNGraph, (s, t); [edata])\nadd_edges(g::GNNGraph, (s, t, w); [edata])\n\nAdd to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.\n\nIf the s or t contain nodes that are not already present in the graph, they are added to the graph as well.\n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = Float32[1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> add_edges(g, ([2, 3], [4, 1], [10.0, 20.0]))\nGNNGraph:\n num_nodes: 4\n num_edges: 7\n\njulia> g = GNNGraph()\nGNNGraph:\n num_nodes: 0\n num_edges: 0\n\njulia> add_edges(g, [1,2], [2,3])\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_edges-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}, AbstractVector, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.add_edges","text":"add_edges(g::GNNHeteroGraph, edge_t, s, t; [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t); [edata, num_nodes])\nadd_edges(g::GNNHeteroGraph, edge_t => (s, t, w); [edata, num_nodes])\n\nAdd to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t). \n\nIf the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Integer}","page":"GNNGraph","title":"GNNGraphs.add_nodes","text":"add_nodes(g::GNNGraph, n; [ndata])\n\nAdd n new nodes to graph g. In the new graph, these nodes will have indexes from g.num_nodes + 1 to g.num_nodes + n.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNGraph)\n\nReturn a graph with the same features as g but also adding edges connecting the nodes to themselves.\n\nNodes with already existing self-loops will obtain a second self-loop.\n\nIf the graphs has edge weights, the new edges will have weight 1.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.add_self_loops-Tuple{GNNHeteroGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, Tuple{Symbol, Symbol, Symbol}}","page":"GNNGraph","title":"GNNGraphs.add_self_loops","text":"add_self_loops(g::GNNHeteroGraph, edge_t::EType)\nadd_self_loops(g::GNNHeteroGraph)\n\nIf the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.\n\nNodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.\n\nIf the graph has edge weights for edges of type edge_t, the new edges will have weight 1.\n\nIf no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.\n\nIf edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.getgraph-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.getgraph","text":"getgraph(g::GNNGraph, i; nmap=false)\n\nReturn the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph. \n\nIf nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.negative_sample-Tuple{GNNGraph}","page":"GNNGraph","title":"GNNGraphs.negative_sample","text":"negative_sample(g::GNNGraph; \n num_neg_edges = g.num_edges, \n bidirected = is_bidirected(g))\n\nReturn a graph containing random negative edges (i.e. non-edges) from graph g as edges.\n\nIf bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph. \n\nSee also is_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.perturb_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.perturb_edges","text":"perturb_edges([rng], g::GNNGraph, perturb_ratio)\n\nReturn a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops. \n\nThe function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.\n\nArguments\n\ng::GNNGraph: The graph to be perturbed.\nperturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.\nrng: An optionalrandom number generator to ensure reproducible results.\n\nExamples\n\njulia> g = GNNGraph((s, t, w))\nGNNGraph:\n num_nodes: 4\n num_edges: 5\n\njulia> perturbed_g = perturb_edges(g, 0.2)\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.ppr_diffusion-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.ppr_diffusion","text":"ppr_diffusion(g::GNNGraph{<:COO_T}, alpha =0.85f0) -> GNNGraph\n\nCalculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web\n\nThe function performs the following steps:\n\nConstructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.\nNormalizes A to ensure each column sums to 1, representing transition probabilities.\nApplies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.\nUpdates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.\n\nArguments\n\ng::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.\nalpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.\n\nReturns\n\nA new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_edge_split-Tuple{GNNGraph, Any}","page":"GNNGraph","title":"GNNGraphs.rand_edge_split","text":"rand_edge_split(g::GNNGraph, frac; bidirected=is_bidirected(g)) -> g1, g2\n\nRandomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.\n\nIf bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.\n\nrand_edge_split is tipically used to create train/test splits in link prediction tasks.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.random_walk_pe-Tuple{GNNGraph, Int64}","page":"GNNGraph","title":"GNNGraphs.random_walk_pe","text":"random_walk_pe(g, walk_length)\n\nReturn the random walk positional encoding from the paper Graph Neural Networks with Learnable Structural and Positional Representations of the given graph g and the length of the walk walk_length as a matrix of size (walk_length, g.num_nodes). \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector{<:Integer}}","page":"GNNGraph","title":"GNNGraphs.remove_edges","text":"remove_edges(g::GNNGraph, edges_to_remove::AbstractVector{<:Integer})\nremove_edges(g::GNNGraph, p=0.5)\n\nRemove specified edges from a GNNGraph, either by specifying edge indices or by randomly removing edges with a given probability.\n\nArguments\n\ng: The input graph from which edges will be removed.\nedges_to_remove: Vector of edge indices to be removed. This argument is only required for the first method.\np: Probability of removing each edge. This argument is only required for the second method and defaults to 0.5.\n\nReturns\n\nA new GNNGraph with the specified edges removed.\n\nExample\n\njulia> using GraphNeuralNetworks\n\n# Construct a GNNGraph\njulia> g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 3\n num_edges: 5\n \n# Remove the second edge\njulia> g_new = remove_edges(g, [2]);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 4\n\n# Remove edges with a probability of 0.5\njulia> g_new = remove_edges(g, 0.5);\n\njulia> g_new\nGNNGraph:\n num_nodes: 3\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_multi_edges-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_multi_edges","text":"remove_multi_edges(g::GNNGraph; aggr=+)\n\nRemove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.\n\nSee also remove_self_loops, has_multi_edges, and to_bidirected.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, p)\n\nReturns a new graph obtained by dropping nodes from g with independent probabilities p. \n\nExamples\n\njulia> g = GNNGraph([1, 1, 2, 2, 3, 4], [1, 2, 3, 1, 3, 1])\nGNNGraph:\n num_nodes: 4\n num_edges: 6\n\njulia> g_new = remove_nodes(g, 0.5)\nGNNGraph:\n num_nodes: 2\n num_edges: 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_nodes-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.remove_nodes","text":"remove_nodes(g::GNNGraph, nodes_to_remove::AbstractVector)\n\nRemove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.\n\nArguments\n\ng: The input graph from which nodes (and their edges) will be removed.\nnodes_to_remove: Vector of node indices to be removed.\n\nReturns\n\nA new GNNGraph with the specified nodes and all edges associated with these nodes removed. \n\nExample\n\nusing GraphNeuralNetworks\n\ng = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])\n\n# Remove nodes with indices 2 and 3, for example\ng_new = remove_nodes(g, [2, 3])\n\n# g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.\nprintln(g_new)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.remove_self_loops-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.remove_self_loops","text":"remove_self_loops(g::GNNGraph)\n\nReturn a graph constructed from g where self-loops (edges from a node to itself) are removed. \n\nSee also add_self_loops and remove_multi_edges.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.set_edge_weight-Tuple{GNNGraph, AbstractVector}","page":"GNNGraph","title":"GNNGraphs.set_edge_weight","text":"set_edge_weight(g::GNNGraph, w::AbstractVector)\n\nSet w as edge weights in the returned graph. \n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_bidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_bidirected","text":"to_bidirected(g)\n\nAdds a reverse edge for each edge in the graph, then calls remove_multi_edges with mean aggregation to simplify the graph. \n\nSee also is_bidirected. \n\nExamples\n\njulia> s, t = [1, 2, 3, 3, 4], [2, 3, 4, 4, 4];\n\njulia> w = [1.0, 2.0, 3.0, 4.0, 5.0];\n\njulia> e = [10.0, 20.0, 30.0, 40.0, 50.0];\n\njulia> g = GNNGraph(s, t, w, edata = e)\nGNNGraph:\n num_nodes = 4\n num_edges = 5\n edata:\n e => (5,)\n\njulia> g2 = to_bidirected(g)\nGNNGraph:\n num_nodes = 4\n num_edges = 7\n edata:\n e => (7,)\n\njulia> edge_index(g2)\n([1, 2, 2, 3, 3, 4, 4], [2, 1, 3, 2, 4, 3, 4])\n\njulia> get_edge_weight(g2)\n7-element Vector{Float64}:\n 1.0\n 1.0\n 2.0\n 2.0\n 3.5\n 3.5\n 5.0\n\njulia> g2.edata.e\n7-element Vector{Float64}:\n 10.0\n 10.0\n 20.0\n 20.0\n 35.0\n 35.0\n 50.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.to_unidirected-Tuple{GNNGraph{<:Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}}}}","page":"GNNGraph","title":"GNNGraphs.to_unidirected","text":"to_unidirected(g::GNNGraph)\n\nReturn a graph that for each multiple edge between two nodes in g keeps only an edge in one direction.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.batch-Tuple{AbstractVector{<:GNNGraph}}","page":"GNNGraph","title":"MLUtils.batch","text":"batch(gs::Vector{<:GNNGraph})\n\nBatch together multiple GNNGraphs into a single one containing the total number of original nodes and edges.\n\nEquivalent to SparseArrays.blockdiag. See also MLUtils.unbatch.\n\nExamples\n\njulia> g1 = rand_graph(4, 6, ndata=ones(8, 4))\nGNNGraph:\n num_nodes = 4\n num_edges = 6\n ndata:\n x => (8, 4)\n\njulia> g2 = rand_graph(7, 4, ndata=zeros(8, 7))\nGNNGraph:\n num_nodes = 7\n num_edges = 4\n ndata:\n x => (8, 7)\n\njulia> g12 = MLUtils.batch([g1, g2])\nGNNGraph:\n num_nodes = 11\n num_edges = 10\n num_graphs = 2\n ndata:\n x => (8, 11)\n\njulia> g12.ndata.x\n8×11 Matrix{Float64}:\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#MLUtils.unbatch-Union{Tuple{GNNGraph{T}}, Tuple{T}} where T<:(Tuple{T, T, V} where {T<:(AbstractVector{<:Integer}), V<:Union{Nothing, AbstractVector}})","page":"GNNGraph","title":"MLUtils.unbatch","text":"unbatch(g::GNNGraph)\n\nOpposite of the MLUtils.batch operation, returns an array of the individual graphs batched together in g.\n\nSee also MLUtils.batch and getgraph.\n\nExamples\n\njulia> gbatched = MLUtils.batch([rand_graph(5, 6), rand_graph(10, 8), rand_graph(4,2)])\nGNNGraph:\n num_nodes = 19\n num_edges = 16\n num_graphs = 3\n\njulia> MLUtils.unbatch(gbatched)\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph:\n num_nodes = 5\n num_edges = 6\n\n GNNGraph:\n num_nodes = 10\n num_edges = 8\n\n GNNGraph:\n num_nodes = 4\n num_edges = 2\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#SparseArrays.blockdiag-Tuple{GNNGraph, Vararg{GNNGraph}}","page":"GNNGraph","title":"SparseArrays.blockdiag","text":"blockdiag(xs::GNNGraph...)\n\nEquivalent to MLUtils.batch.\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#Utils","page":"GNNGraph","title":"Utils","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"GNNGraphs.sort_edge_index\nGNNGraphs.color_refinement","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sort_edge_index","page":"GNNGraph","title":"GNNGraphs.sort_edge_index","text":"sort_edge_index(ei::Tuple) -> u', v'\nsort_edge_index(u, v) -> u', v'\n\nReturn a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi. \n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#GNNGraphs.color_refinement","page":"GNNGraph","title":"GNNGraphs.color_refinement","text":"color_refinement(g::GNNGraph, [x0]) -> x, num_colors, niters\n\nThe color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.\n\nAt each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.\n\nmath x_i' = hashmap((x_i, sort([x_j for j \\in N(i)]))).`\n\nThis algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.\n\nArguments\n\ng::GNNGraph: The graph to color.\nx0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.\n\nReturns\n\nx::AbstractVector{<:Integer}: The final coloring.\nnum_colors::Int: The number of colors used.\nniters::Int: The number of iterations until convergence.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Generate","page":"GNNGraph","title":"Generate","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"generate.jl\"]\nPrivate = false\nFilter = t -> typeof(t) <: Function && t!=rand_temporal_radius_graph && t!=rand_temporal_hyperbolic_graph\n","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.knn_graph-Tuple{AbstractMatrix, Int64}","page":"GNNGraph","title":"GNNGraphs.knn_graph","text":"knn_graph(points::AbstractMatrix, \n k::Int; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a k-nearest neighbor graph where each node is linked to its k closest points. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nk: The number of neighbors considered in the kNN algorithm.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its k nearest neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the k neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, k = 10, 3;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = knn_graph(x, k)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = knn_graph(x, k; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 30\n num_graphs = 2\n\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.radius_graph-Tuple{AbstractMatrix, AbstractFloat}","page":"GNNGraph","title":"GNNGraphs.radius_graph","text":"radius_graph(points::AbstractMatrix, \n r::AbstractFloat; \n graph_indicator = nothing,\n self_loops = false, \n dir = :in, \n kws...)\n\nCreate a graph where each node is linked to its neighbors within a given distance r. \n\nArguments\n\npoints: A numfeatures × numnodes matrix storing the Euclidean positions of the nodes.\nr: The radius.\ngraph_indicator: Either nothing or a vector containing the graph assignment of each node, in which case the returned graph will be a batch of graphs. \nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> n, r = 10, 0.75;\n\njulia> x = rand(Float32, 3, n);\n\njulia> g = radius_graph(x, r)\nGNNGraph:\n num_nodes = 10\n num_edges = 46\n\njulia> graph_indicator = [1,1,1,1,1,2,2,2,2,2];\n\njulia> g = radius_graph(x, r; graph_indicator)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n num_graphs = 2\n\n\nReferences\n\nSection B paragraphs 1 and 2 of the paper Dynamic Hidden-Variable Network Models\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_bipartite_heterograph-Tuple{Any, Any}","page":"GNNGraph","title":"GNNGraphs.rand_bipartite_heterograph","text":"rand_bipartite_heterograph([rng,] \n (n1, n2), (m12, m21); \n bidirected = true, \n node_t = (:A, :B), \n edge_t = :to, \n kws...)\n\nConstruct an GNNHeteroGraph with random edges representing a bipartite graph. The graph will have two types of nodes, and edges will only connect nodes of different types.\n\nThe first argument is a tuple (n1, n2) specifying the number of nodes of each type. The second argument is a tuple (m12, m21) specifying the number of edges connecting nodes of type 1 to nodes of type 2 and vice versa.\n\nThe type of nodes and edges can be specified with the node_t and edge_t keyword arguments, which default to (:A, :B) and :to respectively.\n\nIf bidirected=true (default), the reverse edge of each edge will be present. In this case m12 == m21 is required.\n\nA random number generator can be passed as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nSee rand_heterograph for a more general version.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 15)\n num_edges: ((:A, :to, :B) => 20, (:B, :to, :A) => 20)\n\njulia> g = rand_bipartite_heterograph((10, 15), (20, 0), node_t=(:user, :item), edge_t=:-, bidirected=false)\nGNNHeteroGraph:\n num_nodes: Dict(:item => 15, :user => 10)\n num_edges: Dict((:item, :-, :user) => 0, (:user, :-, :item) => 20)\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_graph-Tuple{Integer, Integer}","page":"GNNGraph","title":"GNNGraphs.rand_graph","text":"rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)\n\nGenerate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.\n\nIf bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.\n\nA vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.\n\nPass a random number generator as the first argument to make the generation reproducible.\n\nAdditional keyword arguments will be passed to the GNNGraph constructor.\n\nExamples\n\njulia> g = rand_graph(5, 4, bidirected=false)\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n\njulia> edge_index(g)\n([1, 3, 3, 4], [5, 4, 5, 2])\n\n# In the bidirected case, edge data will be duplicated on the reverse edges if needed.\njulia> g = rand_graph(5, 4, edata=rand(Float32, 16, 2))\nGNNGraph:\n num_nodes = 5\n num_edges = 4\n edata:\n e => (16, 4)\n\n# Each edge has a reverse\njulia> edge_index(g)\n([1, 3, 3, 4], [3, 4, 1, 3])\n\n\n\n\n\n","category":"method"},{"location":"api/gnngraph.html#GNNGraphs.rand_heterograph","page":"GNNGraph","title":"GNNGraphs.rand_heterograph","text":"rand_heterograph([rng,] n, m; bidirected=false, kws...)\n\nConstruct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.\n\nPass a random number generator as a first argument to make the generation reproducible.\n\nSetting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.\n\nAdditional keyword arguments will be passed to the GNNHeteroGraph constructor.\n\nExamples\n\njulia> g = rand_heterograph((:user => 10, :movie => 20),\n (:user, :rate, :movie) => 30)\nGNNHeteroGraph:\n num_nodes: (:user => 10, :movie => 20) \n num_edges: ((:user, :rate, :movie) => 30,)\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Operators","page":"GNNGraph","title":"Operators","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"operators.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Base.intersect","category":"page"},{"location":"api/gnngraph.html#Base.intersect","page":"GNNGraph","title":"Base.intersect","text":"\" intersect(g1::GNNGraph, g2::GNNGraph)\n\nIntersect two graphs by keeping only the common edges.\n\n\n\n\n\n","category":"function"},{"location":"api/gnngraph.html#Sampling","page":"GNNGraph","title":"Sampling","text":"","category":"section"},{"location":"api/gnngraph.html","page":"GNNGraph","title":"GNNGraph","text":"Modules = [GNNGraphs]\nPages = [\"sampling.jl\"]\nPrivate = false","category":"page"},{"location":"api/gnngraph.html#GNNGraphs.sample_neighbors","page":"GNNGraph","title":"GNNGraphs.sample_neighbors","text":"sample_neighbors(g, nodes, K=-1; dir=:in, replace=false, dropnodes=false)\n\nSample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.\n\nThe returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.\n\nArguments\n\ng. The graph.\nnodes. A list of node IDs to sample neighbors from.\nK. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.\ndir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).\nreplace. If true, sample with replacement.\ndropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.\n\nExamples\n\njulia> g = rand_graph(20, 100)\nGNNGraph:\n num_nodes = 20\n num_edges = 100\n\njulia> sample_neighbors(g, 2:3)\nGNNGraph:\n num_nodes = 20\n num_edges = 9\n edata:\n EID => (9,)\n\njulia> sg = sample_neighbors(g, 2:3, dropnodes=true)\nGNNGraph:\n num_nodes = 10\n num_edges = 9\n ndata:\n NID => (10,)\n edata:\n EID => (9,)\n\njulia> sg.ndata.NID\n10-element Vector{Int64}:\n 2\n 3\n 17\n 14\n 18\n 15\n 16\n 20\n 7\n 10\n\njulia> sample_neighbors(g, 2:3, 5, replace=true)\nGNNGraph:\n num_nodes = 20\n num_edges = 10\n edata:\n EID => (10,)\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Documentation page for the graph type TemporalSnapshotsGNNGraph and related methods, representing time varying graphs with time varying features.","category":"page"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Modules = [GNNGraphs]\nPages = [\"temporalsnapshotsgnngraph.jl\"]\nPrivate = false","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"GNNGraphs.TemporalSnapshotsGNNGraph","text":"TemporalSnapshotsGNNGraph(snapshots::AbstractVector{<:GNNGraph})\n\nA type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.\n\nTemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.\n\nConstructor Arguments\n\nsnapshot: a vector of snapshots, where each snapshot must have the same number of nodes.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> tg.tgdata.x = rand(4); # add temporal graph feature\n\njulia> tg # show temporal graph with new feature\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n tgdata:\n x = 4-element Vector{Float64}\n\n\n\n\n\n","category":"type"},{"location":"api/temporalgraph.html#GNNGraphs.add_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64, GNNGraph}","page":"Temporal Graphs","title":"GNNGraphs.add_snapshot","text":"add_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int, g::GNNGraph)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by adding the snapshot g at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10, 20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5\n\njulia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#GNNGraphs.remove_snapshot-Tuple{TemporalSnapshotsGNNGraph, Int64}","page":"Temporal Graphs","title":"GNNGraphs.remove_snapshot","text":"remove_snapshot(tg::TemporalSnapshotsGNNGraph, t::Int)\n\nReturn a TemporalSnapshotsGNNGraph created starting from tg by removing the snapshot at time index t.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2\n\n\n\n\n\n","category":"method"},{"location":"api/temporalgraph.html#TemporalSnapshotsGNNGraph-random-generators","page":"Temporal Graphs","title":"TemporalSnapshotsGNNGraph random generators","text":"","category":"section"},{"location":"api/temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"rand_temporal_radius_graph\nrand_temporal_hyperbolic_graph","category":"page"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_radius_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_radius_graph","text":"rand_temporal_radius_graph(number_nodes::Int, \n number_snapshots::Int,\n speed::AbstractFloat,\n r::AbstractFloat;\n self_loops = false,\n dir = :in,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are randomly generated in the unit square. Two nodes are connected if their distance is less than a given radius r. Each following snapshot is obtained by applying the same construction to new positions obtained as follows. For each snapshot, the new positions of the points are determined by applying random independent displacement vectors to the previous positions. The direction of the displacement is chosen uniformly at random and its length is chosen uniformly in [0, speed]. Then the connections are recomputed. If a point happens to move outside the boundary, its position is updated as if it had bounced off the boundary.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nspeed: The speed to update the nodes.\nr: The radius of connection.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops. \ndir: The direction of the edges. If dir=:in edges go from the neighbors to the central node. If dir=:out we have the opposite direction.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, s, r = 10, 5, 0.1, 1.5;\n\njulia> tg = rand_temporal_radius_graph(n,snaps,s,r) # complete graph at each snapshot\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [90, 90, 90, 90, 90]\n num_snapshots: 5\n\n\n\n\n\n","category":"function"},{"location":"api/temporalgraph.html#GNNGraphs.rand_temporal_hyperbolic_graph","page":"Temporal Graphs","title":"GNNGraphs.rand_temporal_hyperbolic_graph","text":"rand_temporal_hyperbolic_graph(number_nodes::Int, \n number_snapshots::Int;\n α::Real,\n R::Real,\n speed::Real,\n ζ::Real=1,\n self_loop = false,\n kws...)\n\nCreate a random temporal graph given number_nodes nodes and number_snapshots snapshots. First, the positions of the nodes are generated with a quasi-uniform distribution (depending on the parameter α) in hyperbolic space within a disk of radius R. Two nodes are connected if their hyperbolic distance is less than R. Each following snapshot is created in order to keep the same initial distribution.\n\nArguments\n\nnumber_nodes: The number of nodes of each snapshot.\nnumber_snapshots: The number of snapshots.\nα: The parameter that controls the position of the points. If α=ζ, the points are uniformly distributed on the disk of radius R. If α>ζ, the points are more concentrated in the center of the disk. If α<ζ, the points are more concentrated at the boundary of the disk.\nR: The radius of the disk and of connection.\nspeed: The speed to update the nodes.\nζ: The parameter that controls the curvature of the disk.\nself_loops: If true, consider the node itself among its neighbors, in which case the graph will contain self-loops.\nkws: Further keyword arguments will be passed to the GNNGraph constructor of each snapshot.\n\nExample\n\njulia> n, snaps, α, R, speed, ζ = 10, 5, 1.0, 4.0, 0.1, 1.0;\n\njulia> thg = rand_temporal_hyperbolic_graph(n, snaps; α, R, speed, ζ)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [44, 46, 48, 42, 38]\n num_snapshots: 5\n\nReferences\n\nSection D of the paper Dynamic Hidden-Variable Network Models and the paper Hyperbolic Geometry of Complex Networks\n\n\n\n\n\n","category":"function"},{"location":"temporalgraph.html#Temporal-Graphs","page":"Temporal Graphs","title":"Temporal Graphs","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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.","category":"page"},{"location":"temporalgraph.html#Creating-a-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Creating a TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A temporal graph can be created by passing a list of snapshots to the constructor. Each snapshot is a GNNGraph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20) for i in 1:5];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10]\n num_edges: [20, 20, 20, 20, 20]\n num_snapshots: 5","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"A new temporal graph can be created by adding or removing snapshots to an existing temporal graph. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> new_tg = add_snapshot(tg, 3, rand_graph(10, 16)) # add a new snapshot at time 3\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10, 10, 10, 10]\n num_edges: [20, 20, 16, 20, 20, 20]\n num_snapshots: 6","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> new_tg = remove_snapshot(tg, 2) # remove snapshot at time 2\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10]\n num_edges: [20, 22]\n num_snapshots: 2","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"See rand_temporal_radius_graph and rand_temporal_hyperbolic_graph for generating random temporal graphs. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> tg = rand_temporal_radius_graph(10, 3, 0.1, 0.5)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [32, 30, 34]\n num_snapshots: 3","category":"page"},{"location":"temporalgraph.html#Basic-Queries","page":"Temporal Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Basic queries are similar to those for GNNGraphs:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> snapshots = [rand_graph(10,20), rand_graph(10,14), rand_graph(10,22)];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots)\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n\njulia> tg.num_nodes # number of nodes in each snapshot\n3-element Vector{Int64}:\n 10\n 10\n 10\n\njulia> tg.num_edges # number of edges in each snapshot\n3-element Vector{Int64}:\n 20\n 14\n 22\n\njulia> tg.num_snapshots # number of snapshots\n3\n\njulia> tg.snapshots # list of snapshots\n3-element Vector{GNNGraph{Tuple{Vector{Int64}, Vector{Int64}, Nothing}}}:\n GNNGraph(10, 20) with no data\n GNNGraph(10, 14) with no data\n GNNGraph(10, 22) with no data\n\njulia> tg.snapshots[1] # first snapshot, same as tg[1]\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"temporalgraph.html#Data-Features","page":"Temporal Graphs","title":"Data Features","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> tg.tgdata.y = rand(3,1); # graph features after construction\n\njulia> tg\nTemporalSnapshotsGNNGraph:\n num_nodes: [10, 10, 10]\n num_edges: [20, 14, 22]\n num_snapshots: 3\n tgdata:\n y = 3×1 Matrix{Float64}\n\njulia> tg.ndata # vector of Datastore for node features\n3-element Vector{DataStore}:\n DataStore(10) with 1 element:\n x = 3×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 4×10 Matrix{Float64}\n DataStore(10) with 1 element:\n x = 5×10 Matrix{Float64}\n\njulia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot\nVector{Matrix{Float64}}","category":"page"},{"location":"temporalgraph.html#Graph-convolutions-on-TemporalSnapshotsGNNGraph","page":"Temporal Graphs","title":"Graph convolutions on TemporalSnapshotsGNNGraph","text":"","category":"section"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"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. ","category":"page"},{"location":"temporalgraph.html","page":"Temporal Graphs","title":"Temporal Graphs","text":"julia> using GraphNeuralNetworks, Flux\n\njulia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];\n\njulia> tg = TemporalSnapshotsGNNGraph(snapshots);\n\njulia> m = GINConv(Dense(3 => 1), 0.4);\n\njulia> output = m(tg, tg.ndata.x);\n\njulia> size(output[1])\n(1, 10)","category":"page"},{"location":"heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Heterogeneous graphs (also called heterographs), are graphs where each node has a type, that we denote with symbols such as :user and :movie. Relations such as :rate or :like can connect nodes of different types. We call a triplet (source_node_type, relation_type, target_node_type) the type of a edge, e.g. (:user, :rate, :movie).","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Different node/edge types can store different groups of features and this makes heterographs a very flexible modeling tools and data containers. In GraphNeuralNetworks.jl heterographs are implemented in the type GNNHeteroGraph.","category":"page"},{"location":"heterograph.html#Creating-a-Heterograph","page":"Heterogeneous Graphs","title":"Creating a Heterograph","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"A heterograph can be created empty or by passing pairs edge_type => data to the constructor.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph()\nGNNHeteroGraph:\n num_nodes: Dict()\n num_edges: Dict()\n \njulia> g = GNNHeteroGraph((:user, :like, :actor) => ([1,2,2,3], [1,3,2,9]),\n (:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 4, (:user, :rate, :movie) => 4)\n\njulia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"New relations, possibly with new node types, can be added with the function add_edges.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = add_edges(g, (:user, :like, :actor) => ([1,2,3,3,3], [3,5,1,9,4]))\nGNNHeteroGraph:\n num_nodes: Dict(:actor => 9, :movie => 13, :user => 3)\n num_edges: Dict((:user, :like, :actor) => 5, (:user, :rate, :movie) => 4)","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See rand_heterograph, rand_bipartite_heterograph for generating random heterographs. ","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = rand_bipartite_heterograph((10, 15), 20)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 10, :B => 15)\n num_edges: Dict((:A, :to, :B) => 20, (:B, :to, :A) => 20)","category":"page"},{"location":"heterograph.html#Basic-Queries","page":"Heterogeneous Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Basic queries are similar to those for homogeneous graphs:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> g = GNNHeteroGraph((:user, :rate, :movie) => ([1,1,2,3], [7,13,5,7]))\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n\njulia> g.num_nodes\nDict{Symbol, Int64} with 2 entries:\n :user => 3\n :movie => 13\n\njulia> g.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 1 entry:\n (:user, :rate, :movie) => 4\n\n# source and target node for a given relation\njulia> edge_index(g, (:user, :rate, :movie))\n([1, 1, 2, 3], [7, 13, 5, 7])\n\n# node types\njulia> g.ntypes\n2-element Vector{Symbol}:\n :user\n :movie\n\n# edge types\njulia> g.etypes\n1-element Vector{Tuple{Symbol, Symbol, Symbol}}:\n (:user, :rate, :movie)","category":"page"},{"location":"heterograph.html#Data-Features","page":"Heterogeneous Graphs","title":"Data Features","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Node, edge, and graph features can be added at construction time or later using:","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"# equivalent to g.ndata[:user][:x] = ...\njulia> g[:user].x = rand(Float32, 64, 3);\n\njulia> g[:movie].z = rand(Float32, 64, 13);\n\n# equivalent to g.edata[(:user, :rate, :movie)][:e] = ...\njulia> g[:user, :rate, :movie].e = rand(Float32, 64, 4);\n\njulia> g\nGNNHeteroGraph:\n num_nodes: Dict(:movie => 13, :user => 3)\n num_edges: Dict((:user, :rate, :movie) => 4)\n ndata:\n :movie => DataStore(z = [64×13 Matrix{Float32}])\n :user => DataStore(x = [64×3 Matrix{Float32}])\n edata:\n (:user, :rate, :movie) => DataStore(e = [64×4 Matrix{Float32}])","category":"page"},{"location":"heterograph.html#Batching","page":"Heterogeneous Graphs","title":"Batching","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Similarly to graphs, also heterographs can be batched together.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"julia> gs = [rand_bipartite_heterograph((5, 10), 20) for _ in 1:32];\n\njulia> Flux.batch(gs)\nGNNHeteroGraph:\n num_nodes: Dict(:A => 160, :B => 320)\n num_edges: Dict((:A, :to, :B) => 640, (:B, :to, :A) => 640)\n num_graphs: 32","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Batching is automatically performed by the DataLoader iterator when the collate option is set to true.","category":"page"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"using Flux: DataLoader\n\ndata = [rand_bipartite_heterograph((5, 10), 20, \n ndata=Dict(:A=>rand(Float32, 3, 5))) \n for _ in 1:320];\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes[:A] == 80\n @assert size(g.ndata[:A].x) == (3, 80) \n # ...\nend","category":"page"},{"location":"heterograph.html#Graph-convolutions-on-heterographs","page":"Heterogeneous Graphs","title":"Graph convolutions on heterographs","text":"","category":"section"},{"location":"heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"See HeteroGraphConv for how to perform convolutions on heterogeneous graphs.","category":"page"},{"location":"api/heterograph.html#Heterogeneous-Graphs","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"","category":"section"},{"location":"api/heterograph.html#GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNHeteroGraph","text":"","category":"section"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Documentation page for the type GNNHeteroGraph representing heterogeneous graphs, where nodes and edges can have different types.","category":"page"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Modules = [GNNGraphs]\nPages = [\"gnnheterograph.jl\"]\nPrivate = false","category":"page"},{"location":"api/heterograph.html#GNNGraphs.GNNHeteroGraph","page":"Heterogeneous Graphs","title":"GNNGraphs.GNNHeteroGraph","text":"GNNHeteroGraph(data; [ndata, edata, gdata, num_nodes])\nGNNHeteroGraph(pairs...; [ndata, edata, gdata, num_nodes])\n\nA type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.\n\nConstructor Arguments\n\ndata: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).\npairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).\nndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.\nedata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.\ngdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.\nnum_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.\n\nFields\n\ngraph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.\nnum_nodes: The number of nodes for each type.\nnum_edges: The number of edges for each type.\nndata: Node features.\nedata: Edge features.\ngdata: Graph features.\nntypes: The node types.\netypes: The edge types.\n\nExamples\n\njulia> using GraphNeuralNetworks\n\njulia> nA, nB = 10, 20;\n\njulia> num_nodes = Dict(:A => nA, :B => nB);\n\njulia> edges1 = (rand(1:nA, 20), rand(1:nB, 20))\n([4, 8, 6, 3, 4, 7, 2, 7, 3, 2, 3, 4, 9, 4, 2, 9, 10, 1, 3, 9], [6, 4, 20, 8, 16, 7, 12, 16, 5, 4, 6, 20, 11, 19, 17, 9, 12, 2, 18, 12])\n\njulia> edges2 = (rand(1:nB, 30), rand(1:nA, 30))\n([17, 5, 2, 4, 5, 3, 8, 7, 9, 7 … 19, 8, 20, 7, 16, 2, 9, 15, 8, 13], [1, 1, 3, 1, 1, 3, 2, 7, 4, 4 … 7, 10, 6, 3, 4, 9, 1, 5, 8, 5])\n\njulia> data = ((:A, :rel1, :B) => edges1, (:B, :rel2, :A) => edges2);\n\njulia> hg = GNNHeteroGraph(data; num_nodes)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n\njulia> hg.num_edges\nDict{Tuple{Symbol, Symbol, Symbol}, Int64} with 2 entries:\n(:A, :rel1, :B) => 20\n(:B, :rel2, :A) => 30\n\n# Let's add some node features\njulia> ndata = Dict(:A => (x = rand(2, nA), y = rand(3, num_nodes[:A])),\n :B => rand(10, nB));\n\njulia> hg = GNNHeteroGraph(data; num_nodes, ndata)\nGNNHeteroGraph:\n num_nodes: (:A => 10, :B => 20)\n num_edges: ((:A, :rel1, :B) => 20, (:B, :rel2, :A) => 30)\n ndata:\n :A => (x = 2×10 Matrix{Float64}, y = 3×10 Matrix{Float64})\n :B => x = 10×20 Matrix{Float64}\n\n# Access features of nodes of type :A\njulia> hg.ndata[:A].x\n2×10 Matrix{Float64}:\n 0.825882 0.0797502 0.245813 0.142281 0.231253 0.685025 0.821457 0.888838 0.571347 0.53165\n 0.631286 0.316292 0.705325 0.239211 0.533007 0.249233 0.473736 0.595475 0.0623298 0.159307\n\nSee also GNNGraph for a homogeneous graph type and rand_heterograph for a function to generate random heterographs.\n\n\n\n\n\n","category":"type"},{"location":"api/heterograph.html#GNNGraphs.edge_type_subgraph-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}}","page":"Heterogeneous Graphs","title":"GNNGraphs.edge_type_subgraph","text":"edge_type_subgraph(g::GNNHeteroGraph, edge_ts)\n\nReturn a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_edge_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_edge_types","text":"num_edge_types(g)\n\nReturn the number of edge types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique edge types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html#GNNGraphs.num_node_types-Tuple{GNNGraph}","page":"Heterogeneous Graphs","title":"GNNGraphs.num_node_types","text":"num_node_types(g)\n\nReturn the number of node types in the graph. For GNNGraphs, this is always 1. For GNNHeteroGraphs, this is the number of unique node types.\n\n\n\n\n\n","category":"method"},{"location":"api/heterograph.html","page":"Heterogeneous Graphs","title":"Heterogeneous Graphs","text":"Graphs.has_edge(::GNNHeteroGraph, ::Tuple{Symbol, Symbol, Symbol}, ::Integer, ::Integer)","category":"page"},{"location":"api/heterograph.html#Graphs.has_edge-Tuple{GNNHeteroGraph, Tuple{Symbol, Symbol, Symbol}, Integer, Integer}","page":"Heterogeneous Graphs","title":"Graphs.has_edge","text":"has_edge(g::GNNHeteroGraph, edge_t, i, j)\n\nReturn true if there is an edge of type edge_t from node i to node j in g.\n\nExamples\n\njulia> g = rand_bipartite_heterograph((2, 2), (4, 0), bidirected=false)\nGNNHeteroGraph:\n num_nodes: (:A => 2, :B => 2)\n num_edges: ((:A, :to, :B) => 4, (:B, :to, :A) => 0)\n\njulia> has_edge(g, (:A,:to,:B), 1, 1)\ntrue\n\njulia> has_edge(g, (:B,:to,:A), 1, 1)\nfalse\n\n\n\n\n\n","category":"method"},{"location":"gnngraph.html#Static-Graphs","page":"Static Graphs","title":"Static Graphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The fundamental graph type in GraphNeuralNetworks.jl is the GNNGraph. A GNNGraph g is a directed graph with nodes labeled from 1 to g.num_nodes. The underlying implementation allows for efficient application of graph neural network operators, gpu movement, and storage of node/edge/graph related feature arrays.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"GNNGraph inherits from Graphs.jl's AbstractGraph, therefore it supports most functionality from that library. ","category":"page"},{"location":"gnngraph.html#Graph-Creation","page":"Static Graphs","title":"Graph Creation","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"A GNNGraph can be created from several different data sources encoding the graph topology:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using GraphNeuralNetworks, Graphs, SparseArrays\n\n\n# Construct a GNNGraph from from a Graphs.jl's graph\nlg = erdos_renyi(10, 30)\ng = GNNGraph(lg)\n\n# Same as above using convenience method rand_graph\ng = rand_graph(10, 60)\n\n# From an adjacency matrix\nA = sprand(10, 10, 0.3)\ng = GNNGraph(A)\n\n# From an adjacency list\nadjlist = [[2,3], [1,3], [1,2,4], [3]]\ng = GNNGraph(adjlist)\n\n# From COO representation\nsource = [1,1,2,2,3,3,3,4]\ntarget = [2,3,1,3,1,2,4,3]\ng = GNNGraph(source, target)","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"See also the related methods Graphs.adjacency_matrix, edge_index, and adjacency_list.","category":"page"},{"location":"gnngraph.html#Basic-Queries","page":"Static Graphs","title":"Basic Queries","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> source = [1,1,2,2,3,3,3,4];\n\njulia> target = [2,3,1,3,1,2,4,3];\n\njulia> g = GNNGraph(source, target)\nGNNGraph:\n num_nodes: 4\n num_edges: 8\n\n\njulia> @assert g.num_nodes == 4 # number of nodes\n\njulia> @assert g.num_edges == 8 # number of edges\n\njulia> @assert g.num_graphs == 1 # number of subgraphs (a GNNGraph can batch many graphs together)\n\njulia> is_directed(g) # a GNNGraph is always directed\ntrue\n\njulia> is_bidirected(g) # for each edge, also the reverse edge is present\ntrue\n\njulia> has_self_loops(g)\nfalse\n\njulia> has_multi_edges(g) \nfalse","category":"page"},{"location":"gnngraph.html#Data-Features","page":"Static Graphs","title":"Data Features","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"One or more arrays can be associated to nodes, edges, and (sub)graphs of a GNNGraph. They will be stored in the fields g.ndata, g.edata, and g.gdata respectively.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The data fields are DataStore objects. DataStores conveniently offer an interface similar to both dictionaries and named tuples. Similarly to dictionaries, DataStores support addition of new features after creation time.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"The array contained in the datastores have last dimension equal to num_nodes (in ndata), num_edges (in edata), or num_graphs (in gdata) respectively.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"# Create a graph with a single feature array `x` associated to nodes\ng = rand_graph(10, 60, ndata = (; x = rand(Float32, 32, 10)))\n\ng.ndata.x # access the features\n\n# Equivalent definition passing directly the array\ng = rand_graph(10, 60, ndata = rand(Float32, 32, 10))\n\ng.ndata.x # `:x` is the default name for node features\n\ng.ndata.z = rand(Float32, 3, 10) # add new feature array `z`\n\n# For convenience, we can access the features through the shortcut\ng.x \n\n# You can have multiple feature arrays\ng = rand_graph(10, 60, ndata = (; x=rand(Float32, 32, 10), y=rand(Float32, 10)))\n\ng.ndata.y, g.ndata.x # or g.x, g.y\n\n# Attach an array with edge features.\n# Since `GNNGraph`s are directed, the number of edges\n# will be double that of the original Graphs' undirected graph.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 60))\n@assert g.num_edges == 60\n\ng.edata.e # or g.e\n\n# If we pass only half of the edge features, they will be copied\n# on the reversed edges.\ng = GNNGraph(erdos_renyi(10, 30), edata = rand(Float32, 30))\n\n\n# Create a new graph from previous one, inheriting edge data\n# but replacing node data\ng′ = GNNGraph(g, ndata =(; z = ones(Float32, 16, 10)))\n\ng′.z\ng′.e","category":"page"},{"location":"gnngraph.html#Edge-weights","page":"Static Graphs","title":"Edge weights","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"It is common to denote scalar edge features as edge weights. The GNNGraph has specific support for edge weights: they can be stored as part of internal representations of the graph (COO or adjacency matrix). Some graph convolutional layers, most notably the GCNConv, can use the edge weights to perform weighted sums over the nodes' neighborhoods.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> source = [1, 1, 2, 2, 3, 3];\n\njulia> target = [2, 3, 1, 3, 1, 2];\n\njulia> weight = [1.0, 0.5, 2.1, 2.3, 4, 4.1];\n\njulia> g = GNNGraph(source, target, weight)\nGNNGraph:\n num_nodes: 3\n num_edges: 6\n\njulia> get_edge_weight(g)\n6-element Vector{Float64}:\n 1.0\n 0.5\n 2.1\n 2.3\n 4.0\n 4.1","category":"page"},{"location":"gnngraph.html#Batches-and-Subgraphs","page":"Static Graphs","title":"Batches and Subgraphs","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Multiple GNNGraphs can be batched together into a single graph that contains the total number of the original nodes and where the original graphs are disjoint subgraphs.","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using Flux\nusing Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:160]\ngall = Flux.batch(data)\n\n# gall is a GNNGraph containing many graphs\n@assert gall.num_graphs == 160 \n@assert gall.num_nodes == 1600 # 10 nodes x 160 graphs\n@assert gall.num_edges == 4800 # 30 undirected edges x 160 graphs\n\n# Let's create a mini-batch from gall\ng23 = getgraph(gall, 2:3)\n@assert g23.num_graphs == 2\n@assert g23.num_nodes == 20 # 10 nodes x 2 graphs\n@assert g23.num_edges == 60 # 30 undirected edges X 2 graphs\n\n# We can pass a GNNGraph to Flux's DataLoader\ntrain_loader = DataLoader(gall, batchsize=16, shuffle=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend\n\n# Access the nodes' graph memberships \ngraph_indicator(gall)","category":"page"},{"location":"gnngraph.html#DataLoader-and-mini-batch-iteration","page":"Static Graphs","title":"DataLoader and mini-batch iteration","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"While constructing a batched graph and passing it to the DataLoader is always an option for mini-batch iteration, the recommended way for better performance is to pass an array of graphs directly and set the collate option to true:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using Flux: DataLoader\n\ndata = [rand_graph(10, 30, ndata=rand(Float32, 3, 10)) for _ in 1:320]\n\ntrain_loader = DataLoader(data, batchsize=16, shuffle=true, collate=true)\n\nfor g in train_loader\n @assert g.num_graphs == 16\n @assert g.num_nodes == 160\n @assert size(g.ndata.x) = (3, 160) \n # .....\nend","category":"page"},{"location":"gnngraph.html#Graph-Manipulation","page":"Static Graphs","title":"Graph Manipulation","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"g′ = add_self_loops(g)\ng′ = remove_self_loops(g)\ng′ = add_edges(g, [1, 2], [2, 3]) # add edges 1->2 and 2->3","category":"page"},{"location":"gnngraph.html#GPU-movement","page":"Static Graphs","title":"GPU movement","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Move a GNNGraph to a CUDA device using Flux.gpu method. ","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"using CUDA, Flux\n\ng_gpu = g |> Flux.gpu","category":"page"},{"location":"gnngraph.html#Integration-with-Graphs.jl","page":"Static Graphs","title":"Integration with Graphs.jl","text":"","category":"section"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"Since GNNGraph <: Graphs.AbstractGraph, we can use any functionality from Graphs.jl for querying and analyzing the graph structure. Moreover, a GNNGraph can be easily constructed from a Graphs.Graph or a Graphs.DiGraph:","category":"page"},{"location":"gnngraph.html","page":"Static Graphs","title":"Static Graphs","text":"julia> import Graphs\n\njulia> using GraphNeuralNetworks\n\n# A Graphs.jl undirected graph\njulia> gu = Graphs.erdos_renyi(10, 20) \n{10, 20} undirected simple Int64 graph\n\n# Since GNNGraphs are undirected, the edges are doubled when converting \n# to GNNGraph\njulia> GNNGraph(gu)\nGNNGraph:\n num_nodes: 10\n num_edges: 40\n\n# A Graphs.jl directed graph\njulia> gd = Graphs.erdos_renyi(10, 20, is_directed=true)\n{10, 20} directed simple Int64 graph\n\njulia> GNNGraph(gd)\nGNNGraph:\n num_nodes: 10\n num_edges: 20","category":"page"},{"location":"index.html#GNNGraphs.jl","page":"Home","title":"GNNGraphs.jl","text":"","category":"section"},{"location":"index.html","page":"Home","title":"Home","text":"GNNGraphs.jl is a package that provides graph data structures and helper functions specifically designed for working with graph neural networks. This package allows to store not only the graph structure, but also features associated with nodes, edges, and the graph itself. It is the core foundation for the GNNlib, GraphNeuralNetworks, and GNNLux packages.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"It supports three types of graphs: ","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"Static graph is the basic graph type represented by GNNGraph, where each node and edge can have associated features. This type of graph is used in typical graph neural network applications, where neural networks operate on both the structure of the graph and the features stored in it. It can be used to represent a graph where the structure does not change over time, but the features of the nodes and edges can change over time.\nTemporal graph is a graph that changes over time, and is represented by TemporalSnapshotsGNNGraph. Edges and features can change dynamically. This type of graph is useful for applications that involve tracking time-dependent relationships, such as social networks.\nHeterogeneous graph is a graph that supports multiple types of nodes and edges, and is represented by GNNHeteroGraph. Each type can have its own properties and relationships. This is useful in scenarios with different entities and interactions, such as in citation graphs or multi-relational data.","category":"page"},{"location":"index.html","page":"Home","title":"Home","text":"This package depends on the package Graphs.jl.","category":"page"},{"location":"datasets.html#Datasets","page":"Datasets","title":"Datasets","text":"","category":"section"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GNNGraphs.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others. For graphs with static structures and temporal features, datasets such as METRLA, PEMSBAY, ChickenPox, and WindMillEnergy are available. For graphs featuring both temporal structures and temporal features, the TemporalBrains dataset is suitable.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.","category":"page"},{"location":"datasets.html","page":"Datasets","title":"Datasets","text":"mldataset2gnngraph","category":"page"},{"location":"datasets.html#GNNGraphs.mldataset2gnngraph","page":"Datasets","title":"GNNGraphs.mldataset2gnngraph","text":"mldataset2gnngraph(dataset)\n\nConvert a graph dataset from the package MLDatasets.jl into one or many GNNGraphs.\n\nExamples\n\njulia> using MLDatasets, GraphNeuralNetworks\n\njulia> mldataset2gnngraph(Cora())\nGNNGraph:\n num_nodes = 2708\n num_edges = 10556\n ndata:\n features => 1433×2708 Matrix{Float32}\n targets => 2708-element Vector{Int64}\n train_mask => 2708-element BitVector\n val_mask => 2708-element BitVector\n test_mask => 2708-element BitVector\n\n\n\n\n\n","category":"function"}] } diff --git a/multidocs/build/gnngraphs/temporalgraph.html b/multidocs/build/gnngraphs/temporalgraph.html index eaed581af..995baea6b 100644 --- a/multidocs/build/gnngraphs/temporalgraph.html +++ b/multidocs/build/gnngraphs/temporalgraph.html @@ -1,4 +1,4 @@ -Temporal Graphs · GNNGraphs.jl

Temporal Graphs

Temporal Graphs are graphs with time varying topologies and node features. In GraphNeuralNetworks.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];
+Temporal Graphs · GNNGraphs.jl

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:
@@ -80,7 +80,7 @@
   x = 5×10 Matrix{Float64}
 
 julia> typeof(tg.ndata.x) # vector containing the x feature of each snapshot
-Vector{Matrix{Float64}}
julia> using GraphNeuralNetworks, Flux
+Vector{Matrix{Float64}}

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 GraphNeuralNetworks, Flux
 
 julia> snapshots = [rand_graph(10, 20; ndata = rand(3, 10)), rand_graph(10, 14; ndata = rand(3, 10))];
 
@@ -91,4 +91,4 @@
 julia> output = m(tg, tg.ndata.x);
 
 julia> size(output[1])
-(1, 10)
\ No newline at end of file +(1, 10)
\ No newline at end of file diff --git a/multidocs/build/gnnlib/.documenter-siteinfo.json b/multidocs/build/gnnlib/.documenter-siteinfo.json index d3ba73e29..8aadfed6c 100644 --- a/multidocs/build/gnnlib/.documenter-siteinfo.json +++ b/multidocs/build/gnnlib/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-18T14:12:16","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.5","generation_timestamp":"2024-09-19T11:12:27","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/multidocs/build/gnnlib/api/messagepassing.html b/multidocs/build/gnnlib/api/messagepassing.html index 2b71ba5d6..632798fcd 100644 --- a/multidocs/build/gnnlib/api/messagepassing.html +++ b/multidocs/build/gnnlib/api/messagepassing.html @@ -1,7 +1,7 @@ Message Passing · GNNlib.jl

Message Passing

Index

Interface

GNNlib.apply_edgesFunction
apply_edges(fmsg, g; [xi, xj, e])
-apply_edges(fmsg, g, xi, xj, e=nothing)

Returns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).

The function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.

Arguments

  • g: An AbstractGNNGraph.
  • xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
  • xj: As xi, but now to be materialized on each edge's source node.
  • e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
  • fmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).

See also propagate and aggregate_neighbors.

source
GNNlib.aggregate_neighborsFunction
aggregate_neighbors(g, aggr, m)

Given a graph g, edge features m, and an aggregation operator aggr (e.g +, min, max, mean), returns the new node features

\[\mathbf{x}_i = \square_{j \in \mathcal{N}(i)} \mathbf{m}_{j\to i}\]

Neighborhood aggregation is the second step of propagate, where it comes after apply_edges.

source
GNNlib.propagateFunction
propagate(fmsg, g, aggr; [xi, xj, e])
+apply_edges(fmsg, g, xi, xj, e=nothing)

Returns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).

The function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.

Arguments

  • g: An AbstractGNNGraph.
  • xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
  • xj: As xi, but now to be materialized on each edge's source node.
  • e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
  • fmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).

See also propagate and aggregate_neighbors.

source
GNNlib.aggregate_neighborsFunction
aggregate_neighbors(g, aggr, m)

Given a graph g, edge features m, and an aggregation operator aggr (e.g +, min, max, mean), returns the new node features

\[\mathbf{x}_i = \square_{j \in \mathcal{N}(i)} \mathbf{m}_{j\to i}\]

Neighborhood aggregation is the second step of propagate, where it comes after apply_edges.

source
GNNlib.propagateFunction
propagate(fmsg, g, aggr; [xi, xj, e])
 propagate(fmsg, g, aggr xi, xj, e=nothing)

Performs message passing on graph g. Takes care of materializing the node features on each edge, applying the message function fmsg, and returning an aggregated message $\bar{\mathbf{m}}$ (depending on the return value of fmsg, an array or a named tuple of arrays with last dimension's size g.num_nodes).

It can be decomposed in two steps:

m = apply_edges(fmsg, g, xi, xj, e)
-m̄ = aggregate_neighbors(g, aggr, m)

GNN layers typically call propagate in their forward pass, providing as input f a closure.

Arguments

  • g: A GNNGraph.
  • xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
  • xj: As xj, but to be materialized on edges' sources.
  • e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
  • fmsg: A generic function that will be passed over to apply_edges. Has to take as inputs the edge-materialized xi, xj, and e (arrays or named tuples of arrays whose last dimension' size is the size of a batch of edges). Its output has to be an array or a named tuple of arrays with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).
  • aggr: Neighborhood aggregation operator. Use +, mean, max, or min.

Examples

using GraphNeuralNetworks, Flux
+m̄ = aggregate_neighbors(g, aggr, m)

GNN layers typically call propagate in their forward pass, providing as input f a closure.

Arguments

  • g: A GNNGraph.
  • xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
  • xj: As xj, but to be materialized on edges' sources.
  • e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
  • fmsg: A generic function that will be passed over to apply_edges. Has to take as inputs the edge-materialized xi, xj, and e (arrays or named tuples of arrays whose last dimension' size is the size of a batch of edges). Its output has to be an array or a named tuple of arrays with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).
  • aggr: Neighborhood aggregation operator. Use +, mean, max, or min.

Examples

using GraphNeuralNetworks, Flux
 
 struct GNNConv <: GNNLayer
     W
@@ -25,4 +25,4 @@
 end
 
 l = GNNConv(10 => 20)
-l(g, x)

See also apply_edges and aggregate_neighbors.

source

Built-in message functions

GNNlib.e_mul_xjFunction
e_mul_xj(xi, xj, e) = reshape(e, (...)) .* xj

Reshape e into broadcast compatible shape with xj (by prepending singleton dimensions) then perform broadcasted multiplication.

source
GNNlib.w_mul_xjFunction
w_mul_xj(xi, xj, w) = reshape(w, (...)) .* xj

Similar to e_mul_xj but specialized on scalar edge features (weights).

source
\ No newline at end of file +l(g, x)

See also apply_edges and aggregate_neighbors.

source

Built-in message functions

GNNlib.copy_xiFunction
copy_xi(xi, xj, e) = xi
source
GNNlib.copy_xjFunction
copy_xj(xi, xj, e) = xj
source
GNNlib.xi_dot_xjFunction
xi_dot_xj(xi, xj, e) = sum(xi .* xj, dims=1)
source
GNNlib.xi_sub_xjFunction
xi_sub_xj(xi, xj, e) = xi .- xj
source
GNNlib.xj_sub_xiFunction
xj_sub_xi(xi, xj, e) = xj .- xi
source
GNNlib.e_mul_xjFunction
e_mul_xj(xi, xj, e) = reshape(e, (...)) .* xj

Reshape e into broadcast compatible shape with xj (by prepending singleton dimensions) then perform broadcasted multiplication.

source
GNNlib.w_mul_xjFunction
w_mul_xj(xi, xj, w) = reshape(w, (...)) .* xj

Similar to e_mul_xj but specialized on scalar edge features (weights).

source
\ No newline at end of file diff --git a/multidocs/build/gnnlib/api/utils.html b/multidocs/build/gnnlib/api/utils.html index 380cee678..73aaf71c3 100644 --- a/multidocs/build/gnnlib/api/utils.html +++ b/multidocs/build/gnnlib/api/utils.html @@ -1,2 +1,2 @@ -Utils · GNNlib.jl

Utility Functions

Index

Docs

Graph-wise operations

GNNlib.reduce_nodesFunction
reduce_nodes(aggr, g, x)

For a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.

See also: reduce_edges.

source
reduce_nodes(aggr, indicator::AbstractVector, x)

Return the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.

See also graph_indicator.

source
GNNlib.reduce_edgesFunction
reduce_edges(aggr, g, e)

For a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.

source
GNNlib.broadcast_nodesFunction
broadcast_nodes(g, x)

Graph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_nodes).

source
GNNlib.broadcast_edgesFunction
broadcast_edges(g, x)

Graph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_edges).

source

Neighborhood operations

GNNlib.softmax_edge_neighborsFunction
softmax_edge_neighbors(g, e)

Softmax over each node's neighborhood of the edge features e.

\[\mathbf{e}'_{j\to i} = \frac{e^{\mathbf{e}_{j\to i}}} - {\sum_{j'\in N(i)} e^{\mathbf{e}_{j'\to i}}}.\]

source

NNlib

Primitive functions implemented in NNlib.jl:

\ No newline at end of file +Utils · GNNlib.jl

Utility Functions

Index

Docs

Graph-wise operations

GNNlib.reduce_nodesFunction
reduce_nodes(aggr, g, x)

For a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.

See also: reduce_edges.

source
reduce_nodes(aggr, indicator::AbstractVector, x)

Return the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.

See also graph_indicator.

source
GNNlib.reduce_edgesFunction
reduce_edges(aggr, g, e)

For a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.

source
GNNlib.broadcast_nodesFunction
broadcast_nodes(g, x)

Graph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_nodes).

source
GNNlib.broadcast_edgesFunction
broadcast_edges(g, x)

Graph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_edges).

source

Neighborhood operations

GNNlib.softmax_edge_neighborsFunction
softmax_edge_neighbors(g, e)

Softmax over each node's neighborhood of the edge features e.

\[\mathbf{e}'_{j\to i} = \frac{e^{\mathbf{e}_{j\to i}}} + {\sum_{j'\in N(i)} e^{\mathbf{e}_{j'\to i}}}.\]

source

NNlib

Primitive functions implemented in NNlib.jl:

\ No newline at end of file diff --git a/multidocs/build/gnnlib/index.html b/multidocs/build/gnnlib/index.html index 9ec46f339..23908965c 100644 --- a/multidocs/build/gnnlib/index.html +++ b/multidocs/build/gnnlib/index.html @@ -1 +1 @@ -Home · GNNlib.jl
\ No newline at end of file +Home · GNNlib.jl
\ No newline at end of file diff --git a/multidocs/build/gnnlib/messagepassing.html b/multidocs/build/gnnlib/messagepassing.html index 3bfd9b594..281173140 100644 --- a/multidocs/build/gnnlib/messagepassing.html +++ b/multidocs/build/gnnlib/messagepassing.html @@ -75,4 +75,4 @@ x = propagate(message, g, +, xj=x) return l.σ.(l.weight * x .+ l.bias) -end

Built-in message functions

In order to exploit optimized specializations of the propagate, it is recommended to use built-in message functions such as copy_xj whenever possible.

\ No newline at end of file +end

See the GATConv implementation here for a more complex example.

Built-in message functions

In order to exploit optimized specializations of the propagate, it is recommended to use built-in message functions such as copy_xj whenever possible.

\ No newline at end of file diff --git a/multidocs/build/gnnlib/search_index.js b/multidocs/build/gnnlib/search_index.js index b58e070f4..fa0545acc 100644 --- a/multidocs/build/gnnlib/search_index.js +++ b/multidocs/build/gnnlib/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"CurrentModule = GNNlib","category":"page"},{"location":"api/messagepassing.html#Message-Passing","page":"Message Passing","title":"Message Passing","text":"","category":"section"},{"location":"api/messagepassing.html#Index","page":"Message Passing","title":"Index","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"Order = [:type, :function]\nPages = [\"messagepassing.md\"]","category":"page"},{"location":"api/messagepassing.html#Interface","page":"Message Passing","title":"Interface","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"GNNlib.apply_edges\nGNNlib.aggregate_neighbors\nGNNlib.propagate","category":"page"},{"location":"api/messagepassing.html#GNNlib.apply_edges","page":"Message Passing","title":"GNNlib.apply_edges","text":"apply_edges(fmsg, g; [xi, xj, e])\napply_edges(fmsg, g, xi, xj, e=nothing)\n\nReturns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).\n\nThe function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.\n\nArguments\n\ng: An AbstractGNNGraph.\nxi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).\nxj: As xi, but now to be materialized on each edge's source node. \ne: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.\nfmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).\n\nSee also propagate and aggregate_neighbors.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.aggregate_neighbors","page":"Message Passing","title":"GNNlib.aggregate_neighbors","text":"aggregate_neighbors(g, aggr, m)\n\nGiven a graph g, edge features m, and an aggregation operator aggr (e.g +, min, max, mean), returns the new node features \n\nmathbfx_i = square_j in mathcalN(i) mathbfm_jto i\n\nNeighborhood aggregation is the second step of propagate, where it comes after apply_edges.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.propagate","page":"Message Passing","title":"GNNlib.propagate","text":"propagate(fmsg, g, aggr; [xi, xj, e])\npropagate(fmsg, g, aggr xi, xj, e=nothing)\n\nPerforms message passing on graph g. Takes care of materializing the node features on each edge, applying the message function fmsg, and returning an aggregated message barmathbfm (depending on the return value of fmsg, an array or a named tuple of arrays with last dimension's size g.num_nodes).\n\nIt can be decomposed in two steps:\n\nm = apply_edges(fmsg, g, xi, xj, e)\nm̄ = aggregate_neighbors(g, aggr, m)\n\nGNN layers typically call propagate in their forward pass, providing as input f a closure. \n\nArguments\n\ng: A GNNGraph.\nxi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).\nxj: As xj, but to be materialized on edges' sources. \ne: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.\nfmsg: A generic function that will be passed over to apply_edges. Has to take as inputs the edge-materialized xi, xj, and e (arrays or named tuples of arrays whose last dimension' size is the size of a batch of edges). Its output has to be an array or a named tuple of arrays with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).\naggr: Neighborhood aggregation operator. Use +, mean, max, or min. \n\nExamples\n\nusing GraphNeuralNetworks, Flux\n\nstruct GNNConv <: GNNLayer\n W\n b\n σ\nend\n\nFlux.@layer GNNConv\n\nfunction GNNConv(ch::Pair{Int,Int}, σ=identity)\n in, out = ch\n W = Flux.glorot_uniform(out, in)\n b = zeros(Float32, out)\n GNNConv(W, b, σ)\nend\n\nfunction (l::GNNConv)(g::GNNGraph, x::AbstractMatrix)\n message(xi, xj, e) = l.W * xj\n m̄ = propagate(message, g, +, xj=x)\n return l.σ.(m̄ .+ l.bias)\nend\n\nl = GNNConv(10 => 20)\nl(g, x)\n\nSee also apply_edges and aggregate_neighbors.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#Built-in-message-functions","page":"Message Passing","title":"Built-in message functions","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"GNNlib.copy_xi\nGNNlib.copy_xj\nGNNlib.xi_dot_xj\nGNNlib.xi_sub_xj\nGNNlib.xj_sub_xi\nGNNlib.e_mul_xj\nGNNlib.w_mul_xj","category":"page"},{"location":"api/messagepassing.html#GNNlib.copy_xi","page":"Message Passing","title":"GNNlib.copy_xi","text":"copy_xi(xi, xj, e) = xi\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.copy_xj","page":"Message Passing","title":"GNNlib.copy_xj","text":"copy_xj(xi, xj, e) = xj\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xi_dot_xj","page":"Message Passing","title":"GNNlib.xi_dot_xj","text":"xi_dot_xj(xi, xj, e) = sum(xi .* xj, dims=1)\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xi_sub_xj","page":"Message Passing","title":"GNNlib.xi_sub_xj","text":"xi_sub_xj(xi, xj, e) = xi .- xj\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xj_sub_xi","page":"Message Passing","title":"GNNlib.xj_sub_xi","text":"xj_sub_xi(xi, xj, e) = xj .- xi\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.e_mul_xj","page":"Message Passing","title":"GNNlib.e_mul_xj","text":"e_mul_xj(xi, xj, e) = reshape(e, (...)) .* xj\n\nReshape e into broadcast compatible shape with xj (by prepending singleton dimensions) then perform broadcasted multiplication.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.w_mul_xj","page":"Message Passing","title":"GNNlib.w_mul_xj","text":"w_mul_xj(xi, xj, w) = reshape(w, (...)) .* xj\n\nSimilar to e_mul_xj but specialized on scalar edge features (weights).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"CurrentModule = GNNlib","category":"page"},{"location":"api/utils.html#Utility-Functions","page":"Utils","title":"Utility Functions","text":"","category":"section"},{"location":"api/utils.html#Index","page":"Utils","title":"Index","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"Order = [:type, :function]\nPages = [\"utils.md\"]","category":"page"},{"location":"api/utils.html#Docs","page":"Utils","title":"Docs","text":"","category":"section"},{"location":"api/utils.html#Graph-wise-operations","page":"Utils","title":"Graph-wise operations","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"reduce_nodes\nreduce_edges\nsoftmax_nodes\nsoftmax_edges\nbroadcast_nodes\nbroadcast_edges","category":"page"},{"location":"api/utils.html#GNNlib.reduce_nodes","page":"Utils","title":"GNNlib.reduce_nodes","text":"reduce_nodes(aggr, g, x)\n\nFor a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.\n\nSee also: reduce_edges.\n\n\n\n\n\nreduce_nodes(aggr, indicator::AbstractVector, x)\n\nReturn the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.\n\nSee also graph_indicator.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.reduce_edges","page":"Utils","title":"GNNlib.reduce_edges","text":"reduce_edges(aggr, g, e)\n\nFor a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.softmax_nodes","page":"Utils","title":"GNNlib.softmax_nodes","text":"softmax_nodes(g, x)\n\nGraph-wise softmax of the node features x.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.softmax_edges","page":"Utils","title":"GNNlib.softmax_edges","text":"softmax_edges(g, e)\n\nGraph-wise softmax of the edge features e.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.broadcast_nodes","page":"Utils","title":"GNNlib.broadcast_nodes","text":"broadcast_nodes(g, x)\n\nGraph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_nodes).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.broadcast_edges","page":"Utils","title":"GNNlib.broadcast_edges","text":"broadcast_edges(g, x)\n\nGraph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_edges).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#Neighborhood-operations","page":"Utils","title":"Neighborhood operations","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"softmax_edge_neighbors","category":"page"},{"location":"api/utils.html#GNNlib.softmax_edge_neighbors","page":"Utils","title":"GNNlib.softmax_edge_neighbors","text":"softmax_edge_neighbors(g, e)\n\nSoftmax over each node's neighborhood of the edge features e.\n\nmathbfe_jto i = frace^mathbfe_jto i\n sum_jin N(i) e^mathbfe_jto i\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#NNlib","page":"Utils","title":"NNlib","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"Primitive functions implemented in NNlib.jl:","category":"page"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"gather!\ngather\nscatter!\nscatter","category":"page"},{"location":"messagepassing.html#Message-Passing","page":"Message Passing","title":"Message Passing","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"A generic message passing on graph takes the form","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"beginaligned\nmathbfm_jto i = phi(mathbfx_i mathbfx_j mathbfe_jto i) \nbarmathbfm_i = square_jin N(i) mathbfm_jto i \nmathbfx_i = gamma_x(mathbfx_i barmathbfm_i)\nmathbfe_jto i^prime = gamma_e(mathbfe_j to imathbfm_j to i)\nendaligned","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"where we refer to phi as to the message function, and to gamma_x and gamma_e as to the node update and edge update function respectively. The aggregation square is over the neighborhood N(i) of node i, and it is usually equal either to sum, to max or to a mean operation. ","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"In GraphNeuralNetworks.jl, the message passing mechanism is exposed by the propagate function. propagate takes care of materializing the node features on each edge, applying the message function, performing the aggregation, and returning barmathbfm. It is then left to the user to perform further node and edge updates, manipulating arrays of size D_node times num_nodes and D_edge times num_edges.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"propagate is composed of two steps, also available as two independent methods:","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"apply_edges materializes node features on edges and applies the message function. \naggregate_neighbors applies a reduction operator on the messages coming from the neighborhood of each node.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The whole propagation mechanism internally relies on the NNlib.gather and NNlib.scatter methods.","category":"page"},{"location":"messagepassing.html#Examples","page":"Message Passing","title":"Examples","text":"","category":"section"},{"location":"messagepassing.html#Basic-use-of-apply_edges-and-propagate","page":"Message Passing","title":"Basic use of apply_edges and propagate","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The function apply_edges can be used to broadcast node data on each edge and produce new edge data.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"julia> using GraphNeuralNetworks, Graphs, Statistics\n\njulia> g = rand_graph(10, 20)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n\njulia> x = ones(2,10);\n\njulia> z = 2ones(2,10);\n\n# Return an edge features arrays (D × num_edges)\njulia> apply_edges((xi, xj, e) -> xi .+ xj, g, xi=x, xj=z)\n2×20 Matrix{Float64}:\n 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0\n 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0\n\n# now returning a named tuple\njulia> apply_edges((xi, xj, e) -> (a=xi .+ xj, b=xi .- xj), g, xi=x, xj=z)\n(a = [3.0 3.0 … 3.0 3.0; 3.0 3.0 … 3.0 3.0], b = [-1.0 -1.0 … -1.0 -1.0; -1.0 -1.0 … -1.0 -1.0])\n\n# Here we provide a named tuple input\njulia> apply_edges((xi, xj, e) -> xi.a + xi.b .* xj, g, xi=(a=x,b=z), xj=z)\n2×20 Matrix{Float64}:\n 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0\n 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The function propagate instead performs the apply_edges operation but then also applies a reduction over each node's neighborhood (see aggregate_neighbors).","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"julia> propagate((xi, xj, e) -> xi .+ xj, g, +, xi=x, xj=z)\n2×10 Matrix{Float64}:\n 3.0 6.0 9.0 9.0 0.0 6.0 6.0 3.0 15.0 3.0\n 3.0 6.0 9.0 9.0 0.0 6.0 6.0 3.0 15.0 3.0\n\n# Previous output can be understood by looking at the degree\njulia> degree(g)\n10-element Vector{Int64}:\n 1\n 2\n 3\n 3\n 0\n 2\n 2\n 1\n 5\n 1","category":"page"},{"location":"messagepassing.html#Implementing-a-custom-Graph-Convolutional-Layer","page":"Message Passing","title":"Implementing a custom Graph Convolutional Layer","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"Let's implement a simple graph convolutional layer using the message passing framework. The convolution reads ","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"mathbfx_i = W cdot sum_j in N(i) mathbfx_j","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"We will also add a bias and an activation function.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"using Flux, Graphs, GraphNeuralNetworks\n\nstruct GCN{A<:AbstractMatrix, B, F} <: GNNLayer\n weight::A\n bias::B\n σ::F\nend\n\nFlux.@layer GCN # allow gpu movement, select trainable params etc...\n\nfunction GCN(ch::Pair{Int,Int}, σ=identity)\n in, out = ch\n W = Flux.glorot_uniform(out, in)\n b = zeros(Float32, out)\n GCN(W, b, σ)\nend\n\nfunction (l::GCN)(g::GNNGraph, x::AbstractMatrix{T}) where T\n @assert size(x, 2) == g.num_nodes\n\n # Computes messages from source/neighbour nodes (j) to target/root nodes (i).\n # The message function will have to handle matrices of size (*, num_edges).\n # In this simple case we just let the neighbor features go through.\n message(xi, xj, e) = xj \n\n # The + operator gives the sum aggregation.\n # `mean`, `max`, `min`, and `*` are other possibilities.\n x = propagate(message, g, +, xj=x) \n\n return l.σ.(l.weight * x .+ l.bias)\nend","category":"page"},{"location":"messagepassing.html#Built-in-message-functions","page":"Message Passing","title":"Built-in message functions","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"In order to exploit optimized specializations of the propagate, it is recommended to use built-in message functions such as copy_xj whenever possible. ","category":"page"},{"location":"index.html#Write-introduction-for-GNNlib","page":"Home","title":"Write introduction for GNNlib","text":"","category":"section"}] +[{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"CurrentModule = GNNlib","category":"page"},{"location":"api/messagepassing.html#Message-Passing","page":"Message Passing","title":"Message Passing","text":"","category":"section"},{"location":"api/messagepassing.html#Index","page":"Message Passing","title":"Index","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"Order = [:type, :function]\nPages = [\"messagepassing.md\"]","category":"page"},{"location":"api/messagepassing.html#Interface","page":"Message Passing","title":"Interface","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"GNNlib.apply_edges\nGNNlib.aggregate_neighbors\nGNNlib.propagate","category":"page"},{"location":"api/messagepassing.html#GNNlib.apply_edges","page":"Message Passing","title":"GNNlib.apply_edges","text":"apply_edges(fmsg, g; [xi, xj, e])\napply_edges(fmsg, g, xi, xj, e=nothing)\n\nReturns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).\n\nThe function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.\n\nArguments\n\ng: An AbstractGNNGraph.\nxi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).\nxj: As xi, but now to be materialized on each edge's source node. \ne: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.\nfmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).\n\nSee also propagate and aggregate_neighbors.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.aggregate_neighbors","page":"Message Passing","title":"GNNlib.aggregate_neighbors","text":"aggregate_neighbors(g, aggr, m)\n\nGiven a graph g, edge features m, and an aggregation operator aggr (e.g +, min, max, mean), returns the new node features \n\nmathbfx_i = square_j in mathcalN(i) mathbfm_jto i\n\nNeighborhood aggregation is the second step of propagate, where it comes after apply_edges.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.propagate","page":"Message Passing","title":"GNNlib.propagate","text":"propagate(fmsg, g, aggr; [xi, xj, e])\npropagate(fmsg, g, aggr xi, xj, e=nothing)\n\nPerforms message passing on graph g. Takes care of materializing the node features on each edge, applying the message function fmsg, and returning an aggregated message barmathbfm (depending on the return value of fmsg, an array or a named tuple of arrays with last dimension's size g.num_nodes).\n\nIt can be decomposed in two steps:\n\nm = apply_edges(fmsg, g, xi, xj, e)\nm̄ = aggregate_neighbors(g, aggr, m)\n\nGNN layers typically call propagate in their forward pass, providing as input f a closure. \n\nArguments\n\ng: A GNNGraph.\nxi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).\nxj: As xj, but to be materialized on edges' sources. \ne: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.\nfmsg: A generic function that will be passed over to apply_edges. Has to take as inputs the edge-materialized xi, xj, and e (arrays or named tuples of arrays whose last dimension' size is the size of a batch of edges). Its output has to be an array or a named tuple of arrays with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).\naggr: Neighborhood aggregation operator. Use +, mean, max, or min. \n\nExamples\n\nusing GraphNeuralNetworks, Flux\n\nstruct GNNConv <: GNNLayer\n W\n b\n σ\nend\n\nFlux.@layer GNNConv\n\nfunction GNNConv(ch::Pair{Int,Int}, σ=identity)\n in, out = ch\n W = Flux.glorot_uniform(out, in)\n b = zeros(Float32, out)\n GNNConv(W, b, σ)\nend\n\nfunction (l::GNNConv)(g::GNNGraph, x::AbstractMatrix)\n message(xi, xj, e) = l.W * xj\n m̄ = propagate(message, g, +, xj=x)\n return l.σ.(m̄ .+ l.bias)\nend\n\nl = GNNConv(10 => 20)\nl(g, x)\n\nSee also apply_edges and aggregate_neighbors.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#Built-in-message-functions","page":"Message Passing","title":"Built-in message functions","text":"","category":"section"},{"location":"api/messagepassing.html","page":"Message Passing","title":"Message Passing","text":"GNNlib.copy_xi\nGNNlib.copy_xj\nGNNlib.xi_dot_xj\nGNNlib.xi_sub_xj\nGNNlib.xj_sub_xi\nGNNlib.e_mul_xj\nGNNlib.w_mul_xj","category":"page"},{"location":"api/messagepassing.html#GNNlib.copy_xi","page":"Message Passing","title":"GNNlib.copy_xi","text":"copy_xi(xi, xj, e) = xi\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.copy_xj","page":"Message Passing","title":"GNNlib.copy_xj","text":"copy_xj(xi, xj, e) = xj\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xi_dot_xj","page":"Message Passing","title":"GNNlib.xi_dot_xj","text":"xi_dot_xj(xi, xj, e) = sum(xi .* xj, dims=1)\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xi_sub_xj","page":"Message Passing","title":"GNNlib.xi_sub_xj","text":"xi_sub_xj(xi, xj, e) = xi .- xj\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.xj_sub_xi","page":"Message Passing","title":"GNNlib.xj_sub_xi","text":"xj_sub_xi(xi, xj, e) = xj .- xi\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.e_mul_xj","page":"Message Passing","title":"GNNlib.e_mul_xj","text":"e_mul_xj(xi, xj, e) = reshape(e, (...)) .* xj\n\nReshape e into broadcast compatible shape with xj (by prepending singleton dimensions) then perform broadcasted multiplication.\n\n\n\n\n\n","category":"function"},{"location":"api/messagepassing.html#GNNlib.w_mul_xj","page":"Message Passing","title":"GNNlib.w_mul_xj","text":"w_mul_xj(xi, xj, w) = reshape(w, (...)) .* xj\n\nSimilar to e_mul_xj but specialized on scalar edge features (weights).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"CurrentModule = GNNlib","category":"page"},{"location":"api/utils.html#Utility-Functions","page":"Utils","title":"Utility Functions","text":"","category":"section"},{"location":"api/utils.html#Index","page":"Utils","title":"Index","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"Order = [:type, :function]\nPages = [\"utils.md\"]","category":"page"},{"location":"api/utils.html#Docs","page":"Utils","title":"Docs","text":"","category":"section"},{"location":"api/utils.html#Graph-wise-operations","page":"Utils","title":"Graph-wise operations","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"reduce_nodes\nreduce_edges\nsoftmax_nodes\nsoftmax_edges\nbroadcast_nodes\nbroadcast_edges","category":"page"},{"location":"api/utils.html#GNNlib.reduce_nodes","page":"Utils","title":"GNNlib.reduce_nodes","text":"reduce_nodes(aggr, g, x)\n\nFor a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.\n\nSee also: reduce_edges.\n\n\n\n\n\nreduce_nodes(aggr, indicator::AbstractVector, x)\n\nReturn the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.\n\nSee also graph_indicator.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.reduce_edges","page":"Utils","title":"GNNlib.reduce_edges","text":"reduce_edges(aggr, g, e)\n\nFor a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.softmax_nodes","page":"Utils","title":"GNNlib.softmax_nodes","text":"softmax_nodes(g, x)\n\nGraph-wise softmax of the node features x.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.softmax_edges","page":"Utils","title":"GNNlib.softmax_edges","text":"softmax_edges(g, e)\n\nGraph-wise softmax of the edge features e.\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.broadcast_nodes","page":"Utils","title":"GNNlib.broadcast_nodes","text":"broadcast_nodes(g, x)\n\nGraph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_nodes).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#GNNlib.broadcast_edges","page":"Utils","title":"GNNlib.broadcast_edges","text":"broadcast_edges(g, x)\n\nGraph-wise broadcast array x of size (*, g.num_graphs) to size (*, g.num_edges).\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#Neighborhood-operations","page":"Utils","title":"Neighborhood operations","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"softmax_edge_neighbors","category":"page"},{"location":"api/utils.html#GNNlib.softmax_edge_neighbors","page":"Utils","title":"GNNlib.softmax_edge_neighbors","text":"softmax_edge_neighbors(g, e)\n\nSoftmax over each node's neighborhood of the edge features e.\n\nmathbfe_jto i = frace^mathbfe_jto i\n sum_jin N(i) e^mathbfe_jto i\n\n\n\n\n\n","category":"function"},{"location":"api/utils.html#NNlib","page":"Utils","title":"NNlib","text":"","category":"section"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"Primitive functions implemented in NNlib.jl:","category":"page"},{"location":"api/utils.html","page":"Utils","title":"Utils","text":"gather!\ngather\nscatter!\nscatter","category":"page"},{"location":"messagepassing.html#Message-Passing","page":"Message Passing","title":"Message Passing","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"A generic message passing on graph takes the form","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"beginaligned\nmathbfm_jto i = phi(mathbfx_i mathbfx_j mathbfe_jto i) \nbarmathbfm_i = square_jin N(i) mathbfm_jto i \nmathbfx_i = gamma_x(mathbfx_i barmathbfm_i)\nmathbfe_jto i^prime = gamma_e(mathbfe_j to imathbfm_j to i)\nendaligned","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"where we refer to phi as to the message function, and to gamma_x and gamma_e as to the node update and edge update function respectively. The aggregation square is over the neighborhood N(i) of node i, and it is usually equal either to sum, to max or to a mean operation. ","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"In GraphNeuralNetworks.jl, the message passing mechanism is exposed by the propagate function. propagate takes care of materializing the node features on each edge, applying the message function, performing the aggregation, and returning barmathbfm. It is then left to the user to perform further node and edge updates, manipulating arrays of size D_node times num_nodes and D_edge times num_edges.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"propagate is composed of two steps, also available as two independent methods:","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"apply_edges materializes node features on edges and applies the message function. \naggregate_neighbors applies a reduction operator on the messages coming from the neighborhood of each node.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The whole propagation mechanism internally relies on the NNlib.gather and NNlib.scatter methods.","category":"page"},{"location":"messagepassing.html#Examples","page":"Message Passing","title":"Examples","text":"","category":"section"},{"location":"messagepassing.html#Basic-use-of-apply_edges-and-propagate","page":"Message Passing","title":"Basic use of apply_edges and propagate","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The function apply_edges can be used to broadcast node data on each edge and produce new edge data.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"julia> using GraphNeuralNetworks, Graphs, Statistics\n\njulia> g = rand_graph(10, 20)\nGNNGraph:\n num_nodes = 10\n num_edges = 20\n\njulia> x = ones(2,10);\n\njulia> z = 2ones(2,10);\n\n# Return an edge features arrays (D × num_edges)\njulia> apply_edges((xi, xj, e) -> xi .+ xj, g, xi=x, xj=z)\n2×20 Matrix{Float64}:\n 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0\n 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0 3.0\n\n# now returning a named tuple\njulia> apply_edges((xi, xj, e) -> (a=xi .+ xj, b=xi .- xj), g, xi=x, xj=z)\n(a = [3.0 3.0 … 3.0 3.0; 3.0 3.0 … 3.0 3.0], b = [-1.0 -1.0 … -1.0 -1.0; -1.0 -1.0 … -1.0 -1.0])\n\n# Here we provide a named tuple input\njulia> apply_edges((xi, xj, e) -> xi.a + xi.b .* xj, g, xi=(a=x,b=z), xj=z)\n2×20 Matrix{Float64}:\n 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0\n 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"The function propagate instead performs the apply_edges operation but then also applies a reduction over each node's neighborhood (see aggregate_neighbors).","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"julia> propagate((xi, xj, e) -> xi .+ xj, g, +, xi=x, xj=z)\n2×10 Matrix{Float64}:\n 3.0 6.0 9.0 9.0 0.0 6.0 6.0 3.0 15.0 3.0\n 3.0 6.0 9.0 9.0 0.0 6.0 6.0 3.0 15.0 3.0\n\n# Previous output can be understood by looking at the degree\njulia> degree(g)\n10-element Vector{Int64}:\n 1\n 2\n 3\n 3\n 0\n 2\n 2\n 1\n 5\n 1","category":"page"},{"location":"messagepassing.html#Implementing-a-custom-Graph-Convolutional-Layer","page":"Message Passing","title":"Implementing a custom Graph Convolutional Layer","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"Let's implement a simple graph convolutional layer using the message passing framework. The convolution reads ","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"mathbfx_i = W cdot sum_j in N(i) mathbfx_j","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"We will also add a bias and an activation function.","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"using Flux, Graphs, GraphNeuralNetworks\n\nstruct GCN{A<:AbstractMatrix, B, F} <: GNNLayer\n weight::A\n bias::B\n σ::F\nend\n\nFlux.@layer GCN # allow gpu movement, select trainable params etc...\n\nfunction GCN(ch::Pair{Int,Int}, σ=identity)\n in, out = ch\n W = Flux.glorot_uniform(out, in)\n b = zeros(Float32, out)\n GCN(W, b, σ)\nend\n\nfunction (l::GCN)(g::GNNGraph, x::AbstractMatrix{T}) where T\n @assert size(x, 2) == g.num_nodes\n\n # Computes messages from source/neighbour nodes (j) to target/root nodes (i).\n # The message function will have to handle matrices of size (*, num_edges).\n # In this simple case we just let the neighbor features go through.\n message(xi, xj, e) = xj \n\n # The + operator gives the sum aggregation.\n # `mean`, `max`, `min`, and `*` are other possibilities.\n x = propagate(message, g, +, xj=x) \n\n return l.σ.(l.weight * x .+ l.bias)\nend","category":"page"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"See the GATConv implementation here for a more complex example.","category":"page"},{"location":"messagepassing.html#Built-in-message-functions","page":"Message Passing","title":"Built-in message functions","text":"","category":"section"},{"location":"messagepassing.html","page":"Message Passing","title":"Message Passing","text":"In order to exploit optimized specializations of the propagate, it is recommended to use built-in message functions such as copy_xj whenever possible. ","category":"page"},{"location":"index.html#Write-introduction-for-GNNlib","page":"Home","title":"Write introduction for GNNlib","text":"","category":"section"}] }