Basics

using Graphs
using MetaGraphsNext

Creating an empty MetaGraph

We provide a convenience constructor for creating empty graphs, which looks as follows:

colors = MetaGraph(
    Graph();  # underlying graph structure
    label_type=Symbol,  # color name
    vertex_data_type=NTuple{3,Int},  # RGB code
    edge_data_type=Symbol,  # result of the addition between two colors
    graph_data="additive colors",  # tag for the whole graph
)
Meta graph based on a SimpleGraph{Int64} with vertex labels of type Symbol, vertex metadata of type Tuple{Int64, Int64, Int64}, edge metadata of type Symbol, graph metadata given by "additive colors", and default weight 1.0

The label_type argument defines how vertices will be referred to. It can be anything you want, provided that pairs of labels can be compared with <. Integer types are generally discouraged, to avoid confusion with the vertex codes used by Graphs.jl. The vertex_data_type and edge_data_type type determine what kind of data will be associated with each vertex and edge. Finally, graph_data can contain an arbitrary object associated with the graph as a whole.

If you don't care about labels at all, using the integer vertex codes as labels may be reasonable. Just keep in mind that labels do not change with vertex deletion, whereas vertex codes get decreased, so the coherence will be broken.

Modifying the graph

Modifications of graph elements and the associated metadata can always be done using setindex! (as in a dictionary) with the relevant labels.

Vertices

Use setindex! with one key to add a new vertex with the given label and metadata. If a vertex with the given label does not exist, it will be created automatically. Otherwise, the function will simply modify the metadata for the existing vertex.

colors[:red] = (255, 0, 0);
colors[:green] = (0, 255, 0);
colors[:blue] = (0, 0, 255);

Note that you cannot use labels or metadata that is incoherent with the types you specified at construction.

Edges

Use setindex! with two keys to add a new edge between the given labels and containing the given metadata. Beware that this time, nonexistent labels will throw an error.

colors[:red, :green] = :yellow;
colors[:red, :blue] = :magenta;
colors[:green, :blue] = :cyan;

Creating a non-empty MetaGraph

There is an alternative constructor which allows you to build and fill the graph in one fell swoop. Here's how it works:

graph = Graph(Edge.([(1, 2), (1, 3), (2, 3)]))
vertices_description = [:red => (255, 0, 0), :green => (0, 255, 0), :blue => (0, 0, 255)]
edges_description = [
    (:red, :green) => :yellow, (:red, :blue) => :magenta, (:green, :blue) => :cyan
]

colors2 = MetaGraph(graph, vertices_description, edges_description, "additive colors")
colors2 == colors
false

Accessing graph properties

To retrieve graph properties, we still follow a dictionary-like interface based on labels.

Existence

To check the presence of a vertex or edge, use haskey:

haskey(colors, :red)
true
haskey(colors, :black)
false
haskey(colors, :red, :green) && haskey(colors, :green, :red)
true
!haskey(colors, :red, :black)
true

Metadata

All kinds of metadata can be accessed with getindex:

colors[]
"additive colors"
colors[:blue]
(0, 0, 255)
colors[:green, :blue]
:cyan

Using vertex codes

In the absence of removal, vertex codes correspond to order of insertion in the underlying graph. They are the ones used by most algorithms in the Graphs.jl ecosystem.

code_for(colors, :red)
1
code_for(colors, :blue)
3

You can retrieve the associated labels as follows:

label_for(colors, 1)
:red
label_for(colors, 3)
:blue

Listing labels

The functions labels, edge_labels, (in/out)neighbor_labels iterate through labels the same way that vertices, edges and (in/out)neighbors iterate through codes.

collect(labels(colors))
3-element Vector{Symbol}:
 :red
 :green
 :blue
collect(edge_labels(colors))
3-element Vector{Tuple{Symbol, Symbol}}:
 (:red, :green)
 (:red, :blue)
 (:green, :blue)
collect(neighbor_labels(colors, :red))
2-element Vector{Symbol}:
 :green
 :blue

Handling weights

You can use the weight_function field to specify a function which will transform edge metadata into a weight. This weight must always have the same type as the default_weight, which is the value returned in case an edge does not exist.

weighted = MetaGraph(
    Graph();
    label_type=Symbol,
    edge_data_type=Float64,
    weight_function=ed -> ed^2,
    default_weight=Inf,
);

weighted[:alice] = nothing;
weighted[:bob] = nothing;
weighted[:charlie] = nothing;

weighted[:alice, :bob] = 2.0;
weighted[:bob, :charlie] = 3.0;
weight_matrix = Graphs.weights(weighted)
MetaWeights of size (3, 3)
default_weight(weighted)
Inf
size(weight_matrix)
(3, 3)
weight_matrix[1, 2]
4.0
weight_matrix[2, 3]
9.0
weight_matrix[1, 3]
Inf
wf = get_weight_function(weighted)
wf(4.0)
16.0

You can then use all functions from Graphs.jl that require weighted graphs (see the rest of the tutorial).


This page was generated using Literate.jl.