Mikhail Krechetov Personal page

Shared Risk Groups.

In this short post, I want to define Shared Risk Link Groups and illustrate this with an interactive plot using Grave and Networkx.

Shared Risk Groups

Shared Risk (Resource) Group is an important concept in Network Theory. This concept may arise in different types of networks (IP, optical, MPLS). Generally, there are two networks to be considered: physical and virtual. A set of pre-computed paths in physical is in one-to-one correspondence with links of the virtual graph. If a single physical edge is broken, some subset of virtual edges also fails; this subset is called a Shared Risk Link Group.

Example from Optical Networks

A typical example I have personally worked with is Shared Risk Link Groups in optical mesh networks. Edges in optical networks correspond to fibers and paths in optical networks are called optical channels. Assume that there is a set of established optical channels; a service provider wants to satisfy network demands and route them using established optical channels.

Usually, every demand requires two (or more) paths called working and protection; if the working path fails, the protection path ensures non-disrupted information delivery. However, there is a difficult condition to be satisfied: if a single optical edge fails (and thus some set of optical channels fails), at least one of the working/protection paths should stay online for every demand.

Interactive Networkx

We will need the following imports and have Grave library installed.

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from grave import plot_network
from grave.style import use_attributes
import itertools
import random

First, we prepare some data for visualization and generate a toy optical network:

random.seed(a = 17)

graph = nx.compose(nx.cycle_graph(20), nx.random_tree(10))
pos = nx.kamada_kawai_layout(graph)
shift = 3.0

def lex(edge):
    return tuple(sorted(list(edge)))

service_num = 15
endnodes = list(itertools.combinations(graph.nodes(), 2))
endnodes = random.sample(endnodes, k = service_num)
srlg = {}
for edge in graph.edges():
    srlg[lex(edge)] = set([])

Now we generate optical channels and links of a virtual graph:

for st in endnodes:
    path = nx.shortest_path(graph, source=st[0], target=st[1])
 
    Vst = ("V"+str(st[0]), "V"+str(st[1])) 
    graph.add_edge(*Vst)
    pos[Vst[0]] = np.array([pos[st[0]][0], pos[st[0]][1] + shift])
    pos[Vst[1]] = np.array([pos[st[1]][0], pos[st[1]][1] + shift])
    
    srlg[lex(Vst)] = set([Vst])
    edges = [(path[i], path[i+1]) for i in range(len(path) - 1)]
    for edge in edges:
        srlg[lex(edge)].add(Vst)

The hilighter function is a minor update from example:

def hilighter(event):
    # if we did not hit a node, bail
    if not hasattr(event, 'edges') or not event.edges:
        return

    # pull out the graph,
    graph = event.artist.graph

    # clear any non-default color on edges

    for u, v, attributes in graph.edges.data():
        attributes.pop('color', None)

    for edge in event.edges:
        graph.edges[edge]['color'] = 'red'
        for failed_edge in srlg[lex(edge)]:
            graph.edges[failed_edge]['color'] = 'red'
    
    # update the screen
    event.artist.stale = True
    event.artist.figure.canvas.draw_idle()

The decorator below is a solution that allows passing my precomputed layout into the plot_network function.

def make_layout(pos):
    def layout(graph):
        return pos
    return layout

Result

Now we can run the code below

fig, ax = plt.subplots()
art = plot_network(graph, layout=make_layout(pos), ax=ax, node_style=use_attributes(),
                   edge_style=use_attributes())

art.set_picker(10)
ax.set_title('Click on the failed edge!')
fig.canvas.mpl_connect('pick_event', hilighter)
plt.show()

which produce interactive plots; here we can click on an optical edge and see which optical channels fail:

srlg1 srlg2 srlg3