-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdisjoint_graph.py
172 lines (131 loc) · 4.33 KB
/
disjoint_graph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
'''
Library functions for working w/graphs that are not specific to an algorithm.
'''
import logging
import networkx as nx
lg = logging.getLogger("cc")
def flatten(paths):
'''Compute and return flattened graph, given paths.
By flattened graph, we mean one created from the union of a set of paths.
@param paths: paths to flatten
@return flattened: flattened NetworkX Graph
'''
used = nx.Graph()
lg.debug("paths: %s" % paths)
for path in paths.values():
lg.debug("flattening path: %s" % path)
used.add_path(path)
return used
def loop_graph(n):
'''Return loop graph with n nodes.'''
g = nx.path_graph(n)
# Add loop edge
g.add_edge(g.number_of_nodes() - 1, 0)
return g
def set_unit_weights(g):
'''Set edge weights for NetworkX graph to 1 & return.'''
set_weights(g, 1.0)
def set_weights(g, weight):
'''Set edge weights for NetworkX graph to specified weight & return.'''
for src, dst in g.edges():
g[src][dst]['weight'] = weight
return g
def nx_graph_from_tuples(undir_tuples, dir_tuples = None):
g = nx.Graph()
for a, b, w in undir_tuples:
g.add_edge(a, b, weight = w)
if dir_tuples:
g = nx.DiGraph(g)
for a, b, w in dir_tuples:
g.add_edge(a, b, weight = w)
return g
def vertex_disjoint(paths):
'''Check if provided paths are vertex-disjoint.
@param paths: list of path lists
'''
vertices = set([])
for path in paths:
for n in path:
if n in vertices:
return False
vertices.add(n)
return True
def edge_disjoint(paths):
'''Check if provided paths are edge-disjoint.
@param paths: list of path lists
'''
edges = set([])
# Ensure edge disjointness
for path in paths:
for i, n in enumerate(path):
if i != len(path) - 1:
e = (n, path[i + 1])
if e in edges:
return False
edges.add(e)
e_rev = (path[i + 1], n)
if e_rev in edges:
return False
edges.add(e_rev)
return True
def pathlen(g, path):
'''Return sum of path weights.
@param g: NetworkX Graph
@param path: list of nodes
@return length: sum of path weights
'''
pathlen = 0
for i, n in enumerate(path):
if i != len(path) - 1:
pathlen += g[n][path[i+1]]['weight']
return pathlen
def edges_on_path(l):
'''Return list of edges on a path list.'''
return [(l[i], l[i + 1]) for i in range(len(l) - 1)]
def interlacing_edges(list1, list2):
'''Return edges in common between two paths.
Input paths are considered interlacing, even if they go in the opposite
direction across the same link. In that case, a single edge will be
return in whatever order NetworkX prefers for an undirected edge.
'''
l1 = edges_on_path(list1)
l1.extend(edges_on_path([i for i in reversed(list1)]))
l2 = edges_on_path(list2)
l2.extend(edges_on_path([i for i in reversed(list2)]))
combined = [e for e in l1 if e in l2]
return nx.Graph(combined).edges()
def flip_and_negate_path(g, path):
'''Return new directed graph with the given path flipped & negated.
@param g: NetworkX Graph (undirected)
@param path: list of nodes in path
@return g2: NetworkX DiGraph, modified
'''
g2 = nx.DiGraph(g)
for i, n in enumerate(path):
if i != len(path) - 1:
n_next = path[i + 1]
# Remove forward edge, leaving only reverse edge.
g2.remove_edge(n, n_next)
# Flip edge weight to negative of the original edge..
g2[n_next][n]['weight'] *= -1
return g2
def remove_edge_bidir(g, src, dst):
'''Remove edge plus one in opposite direction.
@param g: NetworkX DiGraph
@param src: source node
@param dst: destination node
'''
g.remove_edge(src, dst)
g.remove_edge(dst, src)
def add_edge_bidir(g, src, dst, weight = None):
'''Add edge plus one in opposite direction.
@param g: NetworkX DiGraph
@param src: source node
@param dst: destination node
@param weight: optional weight to set for both
'''
g.add_edge(src, dst)
g.add_edge(dst, src)
if weight:
g[src][dst]['weight'] = weight
g[dst][src]['weight'] = weight