InfluenceDiffusion 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/Graph.py +478 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/Trace.py +431 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/__init__.py +4 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/estimation_models/BaseWeightEstimator.py +436 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/estimation_models/EMEstimation.py +236 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/estimation_models/OptimEstimation.py +291 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/estimation_models/__init__.py +3 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/influence_models.py +614 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion/utils.py +29 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion.egg-info/PKG-INFO +15 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion.egg-info/SOURCES.txt +15 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion.egg-info/dependency_links.txt +1 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion.egg-info/requires.txt +6 -0
- InfluenceDiffusion-0.0.3/InfluenceDiffusion.egg-info/top_level.txt +1 -0
- InfluenceDiffusion-0.0.3/PKG-INFO +15 -0
- InfluenceDiffusion-0.0.3/setup.cfg +4 -0
- InfluenceDiffusion-0.0.3/setup.py +33 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
from typing import List, Tuple, Union, Dict
|
|
4
|
+
import networkx as nx
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Graph(nx.DiGraph):
|
|
8
|
+
def __init__(self, edge_list: List[Tuple[int, int]],
|
|
9
|
+
directed: bool = True,
|
|
10
|
+
weights: Union[np.array, List[float]] = None):
|
|
11
|
+
"""
|
|
12
|
+
Initialize a directed or undirected graph from an edge list.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
edge_list : List[Tuple[int, int]]
|
|
17
|
+
List of tuples (source, sink) representing edges of the graph.
|
|
18
|
+
directed : bool, optional
|
|
19
|
+
Flag to indicate whether the graph is directed (default is True).
|
|
20
|
+
weights : Union[None, List[float]], optional
|
|
21
|
+
Optional weights for each edge. If None, all edges are assigned a weight of 1.
|
|
22
|
+
"""
|
|
23
|
+
self.directed = directed
|
|
24
|
+
self.edge_array = np.array(edge_list, dtype=int)
|
|
25
|
+
|
|
26
|
+
if not self.directed:
|
|
27
|
+
reverse_edge_array = self.edge_array[:, [1, 0]]
|
|
28
|
+
self.edge_array = np.concatenate([self.edge_array, reverse_edge_array])
|
|
29
|
+
|
|
30
|
+
super().__init__(self.edge_array.tolist())
|
|
31
|
+
|
|
32
|
+
if weights is not None:
|
|
33
|
+
assert len(weights) == len(edge_list), "number of edges is different from number of weights"
|
|
34
|
+
else:
|
|
35
|
+
weights = np.ones(len(edge_list))
|
|
36
|
+
self.weights = np.array(weights) if directed else np.hstack([weights] * 2)
|
|
37
|
+
self.edge_2_index = {tuple(edge): idx for idx, edge in enumerate(self.edge_array)}
|
|
38
|
+
|
|
39
|
+
def rename_graph_vertices(self, old_2_new_vertex_name_dict: Union[None, Dict] = None) -> "Graph":
|
|
40
|
+
"""
|
|
41
|
+
Rename graph vertices according to the provided mapping or re-index them.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
old_2_new_vertex_name_dict : Union[None, Dict], optional
|
|
46
|
+
Mapping of old vertex names to new names.
|
|
47
|
+
If None, re-indexes vertices to [0, 1, ..., |V|-1].
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
Graph
|
|
52
|
+
The updated graph instance with renamed vertices.
|
|
53
|
+
"""
|
|
54
|
+
if old_2_new_vertex_name_dict is None:
|
|
55
|
+
old_vertex_names = sorted(list(self.get_vertices()))
|
|
56
|
+
old_2_new_vertex_name_dict = {name: idx for idx, name in enumerate(old_vertex_names)}
|
|
57
|
+
|
|
58
|
+
self.edge_array[:, 0] = list(map(lambda v: old_2_new_vertex_name_dict[v], self.edge_array[:, 0]))
|
|
59
|
+
self.edge_array[:, 1] = list(map(lambda v: old_2_new_vertex_name_dict[v], self.edge_array[:, 1]))
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def set_weights(self, weights: Union[str, np.array]) -> "Graph":
|
|
63
|
+
"""
|
|
64
|
+
Set weights for the edges in the graph.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
weights : Union[str, np.array]
|
|
69
|
+
Array of weights for the edges.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
Graph
|
|
74
|
+
The current graph instance with updated weights.
|
|
75
|
+
|
|
76
|
+
Raises
|
|
77
|
+
------
|
|
78
|
+
AssertionError
|
|
79
|
+
If the number of weights does not match the number of edges.
|
|
80
|
+
"""
|
|
81
|
+
assert len(weights) == self.count_edges(), "number of weights different from the number of edges"
|
|
82
|
+
self.weights = np.array(weights)
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def get_edges(self, as_array: bool = False) -> Union[np.array, List[Tuple[int, int]]]:
|
|
86
|
+
"""
|
|
87
|
+
Retrieve the edges of the graph.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
as_array : bool, optional
|
|
92
|
+
If True, returns edges as a numpy array. If False, returns as a list of tuples (default is False).
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
Union[np.array, List[Tuple[int, int]]]
|
|
97
|
+
The edges of the graph in the specified format.
|
|
98
|
+
"""
|
|
99
|
+
if as_array:
|
|
100
|
+
return self.edge_array
|
|
101
|
+
return [tuple(edge) for edge in self.edge_array]
|
|
102
|
+
|
|
103
|
+
def get_vertices(self) -> set:
|
|
104
|
+
"""
|
|
105
|
+
Get the set of all vertices in the graph.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
set
|
|
110
|
+
A set containing all vertex identifiers.
|
|
111
|
+
"""
|
|
112
|
+
return set(self.nodes)
|
|
113
|
+
|
|
114
|
+
def get_sources(self) -> set:
|
|
115
|
+
"""
|
|
116
|
+
Get the set of source vertices in the graph.
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
set
|
|
121
|
+
A set containing all source vertices.
|
|
122
|
+
"""
|
|
123
|
+
return set(self.edge_array[:, 0])
|
|
124
|
+
|
|
125
|
+
def get_sinks(self) -> set:
|
|
126
|
+
"""
|
|
127
|
+
Get the set of sink vertices in the graph.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
set
|
|
132
|
+
A set containing all sink vertices.
|
|
133
|
+
"""
|
|
134
|
+
return set(self.edge_array[:, 1])
|
|
135
|
+
|
|
136
|
+
def count_edges(self) -> int:
|
|
137
|
+
"""
|
|
138
|
+
Count the number of edges in the graph.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
int
|
|
143
|
+
The total number of edges.
|
|
144
|
+
"""
|
|
145
|
+
return len(self.edge_array)
|
|
146
|
+
|
|
147
|
+
def count_vertices(self) -> int:
|
|
148
|
+
"""
|
|
149
|
+
Count the number of vertices in the graph.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
int
|
|
154
|
+
The total number of vertices.
|
|
155
|
+
"""
|
|
156
|
+
return len(self.get_vertices())
|
|
157
|
+
|
|
158
|
+
def get_children_mask(self, vertex: int) -> np.array:
|
|
159
|
+
"""
|
|
160
|
+
Create a mask for edges originating from a specified vertex.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
vertex : int
|
|
165
|
+
The vertex for which to find children.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
np.array
|
|
170
|
+
A boolean array mask indicating edges originating from the vertex.
|
|
171
|
+
"""
|
|
172
|
+
return self.edge_array[:, 0] == vertex
|
|
173
|
+
|
|
174
|
+
def get_children(self, vertex: int, out_type: Union[set, list, np.array] = set) -> Union[set, list, np.array]:
|
|
175
|
+
"""
|
|
176
|
+
Get the children (outgoing edges) of a specified vertex.
|
|
177
|
+
|
|
178
|
+
Parameters
|
|
179
|
+
----------
|
|
180
|
+
vertex : int
|
|
181
|
+
The vertex for which to find children.
|
|
182
|
+
out_type : Union[set, list, np.array], optional
|
|
183
|
+
The type of output to return (default is set).
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
Union[set, list, np.array]
|
|
188
|
+
The children of the vertex in the specified output type.
|
|
189
|
+
"""
|
|
190
|
+
return out_type(self.edge_array[:, 1][self.get_children_mask(vertex)])
|
|
191
|
+
|
|
192
|
+
def get_parents_mask(self, vertex: int) -> np.array:
|
|
193
|
+
"""
|
|
194
|
+
Create a mask for edges leading to a specified vertex.
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
vertex : int
|
|
199
|
+
The vertex for which to find parents.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
np.array
|
|
204
|
+
A boolean array mask indicating edges leading to the vertex.
|
|
205
|
+
"""
|
|
206
|
+
return self.edge_array[:, 1] == vertex
|
|
207
|
+
|
|
208
|
+
def get_parents(self, vertex: int, out_type: Union[set, list, np.array] = set) -> Union[set, list, np.array]:
|
|
209
|
+
"""
|
|
210
|
+
Get the parents (incoming edges) of a specified vertex.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
vertex : int
|
|
215
|
+
The vertex for which to find parents.
|
|
216
|
+
out_type : Union[set, list, np.array], optional
|
|
217
|
+
The type of output to return (default is set).
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
Union[set, list, np.array]
|
|
222
|
+
The parents of the vertex in the specified output type.
|
|
223
|
+
"""
|
|
224
|
+
return out_type(self.edge_array[:, 0][self.get_parents_mask(vertex)])
|
|
225
|
+
|
|
226
|
+
def get_vertex_2_indegree_dict(self, weighted: bool = False) -> Dict[int, Union[float, int]]:
|
|
227
|
+
"""
|
|
228
|
+
Get a dictionary mapping vertices to their indegrees.
|
|
229
|
+
|
|
230
|
+
Parameters
|
|
231
|
+
----------
|
|
232
|
+
weighted : bool, optional
|
|
233
|
+
If True, returns weighted indegrees; otherwise, returns simple counts (default is False).
|
|
234
|
+
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
Dict[int, Union[float, int]]
|
|
238
|
+
A dictionary where keys are vertex identifiers and values are their indegrees.
|
|
239
|
+
"""
|
|
240
|
+
return {vertex: self.get_indegree(vertex, weighted=weighted) for vertex in self.get_vertices()}
|
|
241
|
+
|
|
242
|
+
def get_outdegree(self, vertex: int, weighted: bool = False) -> Union[float, int]:
|
|
243
|
+
"""
|
|
244
|
+
Get the outdegree of a specified vertex.
|
|
245
|
+
|
|
246
|
+
Parameters
|
|
247
|
+
----------
|
|
248
|
+
vertex : int
|
|
249
|
+
The vertex for which to find the outdegree.
|
|
250
|
+
weighted : bool, optional
|
|
251
|
+
If True, returns the weighted outdegree; otherwise, returns simple counts (default is False).
|
|
252
|
+
|
|
253
|
+
Returns
|
|
254
|
+
-------
|
|
255
|
+
Union[float, int]
|
|
256
|
+
The outdegree of the vertex.
|
|
257
|
+
"""
|
|
258
|
+
children_weights = self.weights[self.edge_array[:, 0] == vertex]
|
|
259
|
+
return np.sum(children_weights) if weighted else len(children_weights)
|
|
260
|
+
|
|
261
|
+
def get_all_outdegrees(self, weighted: bool = False) -> np.array:
|
|
262
|
+
"""
|
|
263
|
+
Get outdegrees for all vertices in the graph.
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
weighted : bool, optional
|
|
268
|
+
If True, returns weighted outdegrees; otherwise, returns simple counts (default is False).
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
np.array
|
|
273
|
+
An array of outdegrees for all vertices.
|
|
274
|
+
"""
|
|
275
|
+
return np.array([self.get_outdegree(v, weighted=weighted) for v in self.get_vertices()])
|
|
276
|
+
|
|
277
|
+
def get_avg_outdegree(self, weighted: bool = False) -> Union[float, int]:
|
|
278
|
+
"""
|
|
279
|
+
Calculate the average outdegree of all vertices.
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
weighted : bool, optional
|
|
284
|
+
If True, uses weighted outdegrees; otherwise, uses simple counts (default is False).
|
|
285
|
+
|
|
286
|
+
Returns
|
|
287
|
+
-------
|
|
288
|
+
Union[float, int]
|
|
289
|
+
The average outdegree of the vertices.
|
|
290
|
+
"""
|
|
291
|
+
return np.mean(self.get_all_outdegrees(weighted=weighted))
|
|
292
|
+
|
|
293
|
+
def get_max_outdegree(self, weighted: bool = False) -> Union[float, int]:
|
|
294
|
+
"""
|
|
295
|
+
Get the maximum outdegree among all vertices.
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
weighted : bool, optional
|
|
300
|
+
If True, considers weighted outdegrees; otherwise, uses simple counts (default is False).
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
Union[float, int]
|
|
305
|
+
The maximum outdegree.
|
|
306
|
+
"""
|
|
307
|
+
return np.max(self.get_all_outdegrees(weighted))
|
|
308
|
+
|
|
309
|
+
def get_indegree(self, vertex: int, weighted: bool = False) -> Union[float, int]:
|
|
310
|
+
"""
|
|
311
|
+
Get the indegree of a specified vertex.
|
|
312
|
+
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
vertex : int
|
|
316
|
+
The vertex for which to find the indegree.
|
|
317
|
+
weighted : bool, optional
|
|
318
|
+
If True, returns the weighted indegree; otherwise, returns simple counts (default is False).
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
Union[float, int]
|
|
323
|
+
The indegree of the vertex.
|
|
324
|
+
"""
|
|
325
|
+
parent_weights = self.weights[self.edge_array[:, 1] == vertex]
|
|
326
|
+
return np.sum(parent_weights) if weighted else len(parent_weights)
|
|
327
|
+
|
|
328
|
+
def get_indegrees_dict(self, weighted: bool = False) -> Dict[int, Union[int, float]]:
|
|
329
|
+
"""
|
|
330
|
+
Get a mapping from vertex to its indegree for all vertices in the graph.
|
|
331
|
+
|
|
332
|
+
Parameters
|
|
333
|
+
----------
|
|
334
|
+
weighted : bool, optional
|
|
335
|
+
If True, returns weighted indegrees; otherwise, returns simple counts (default is False).
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
np.array
|
|
340
|
+
An array of indegrees for all vertices.
|
|
341
|
+
"""
|
|
342
|
+
return {v: self.get_indegree(v, weighted=weighted) for v in self.get_vertices()}
|
|
343
|
+
|
|
344
|
+
def get_all_indegrees(self, weighted: bool = False) -> np.array:
|
|
345
|
+
"""
|
|
346
|
+
Get indegrees for all vertices in the graph.
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
weighted : bool, optional
|
|
351
|
+
If True, returns weighted indegrees; otherwise, returns simple counts (default is False).
|
|
352
|
+
|
|
353
|
+
Returns
|
|
354
|
+
-------
|
|
355
|
+
np.array
|
|
356
|
+
An array of indegrees for all vertices.
|
|
357
|
+
"""
|
|
358
|
+
indegrees_dict = self.get_indegrees_dict(weighted=weighted)
|
|
359
|
+
return np.array(list(indegrees_dict.values()))
|
|
360
|
+
|
|
361
|
+
def get_max_indegree(self, weighted: bool = False) -> Union[int, float]:
|
|
362
|
+
"""
|
|
363
|
+
Get the maximum indegree among all vertices.
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
weighted : bool, optional
|
|
368
|
+
If True, considers weighted indegrees; otherwise, uses simple counts (default is False).
|
|
369
|
+
|
|
370
|
+
Returns
|
|
371
|
+
-------
|
|
372
|
+
Union[int, float]
|
|
373
|
+
The maximum indegree.
|
|
374
|
+
"""
|
|
375
|
+
return np.max(self.get_all_indegrees(weighted))
|
|
376
|
+
|
|
377
|
+
def get_avg_indegree(self, weighted: bool = False) -> float:
|
|
378
|
+
"""
|
|
379
|
+
Calculate the average indegree of all vertices.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
weighted : bool, optional
|
|
384
|
+
If True, uses weighted indegrees; otherwise, uses simple counts (default is False).
|
|
385
|
+
|
|
386
|
+
Returns
|
|
387
|
+
-------
|
|
388
|
+
float
|
|
389
|
+
The average indegree of the vertices.
|
|
390
|
+
"""
|
|
391
|
+
return np.mean(self.get_all_indegrees(weighted))
|
|
392
|
+
|
|
393
|
+
def get_edge_index(self, edge: Tuple[int, int]) -> int:
|
|
394
|
+
"""
|
|
395
|
+
Get the index of a specified edge.
|
|
396
|
+
|
|
397
|
+
Parameters
|
|
398
|
+
----------
|
|
399
|
+
edge : Tuple[int, int]
|
|
400
|
+
The edge for which to find the index.
|
|
401
|
+
|
|
402
|
+
Returns
|
|
403
|
+
-------
|
|
404
|
+
int
|
|
405
|
+
The index of the edge in the graph.
|
|
406
|
+
"""
|
|
407
|
+
return self.edge_2_index[tuple(edge)]
|
|
408
|
+
|
|
409
|
+
def get_edge_weight(self, edge: Tuple[int, int]) -> float:
|
|
410
|
+
"""
|
|
411
|
+
Get the weight of a specified edge.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
edge : Tuple[int, int]
|
|
416
|
+
The edge for which to retrieve the weight.
|
|
417
|
+
|
|
418
|
+
Returns
|
|
419
|
+
-------
|
|
420
|
+
float
|
|
421
|
+
The weight of the edge.
|
|
422
|
+
"""
|
|
423
|
+
return self.weights[self.get_edge_index(edge)]
|
|
424
|
+
|
|
425
|
+
def get_edges_mask_from_set_to_vertex(self, vertex_set: set, vertex: int) -> np.array:
|
|
426
|
+
"""
|
|
427
|
+
Create a mask for edges leading from a set of vertices to a specified vertex.
|
|
428
|
+
|
|
429
|
+
Parameters
|
|
430
|
+
----------
|
|
431
|
+
vertex_set : set
|
|
432
|
+
A set of source vertices.
|
|
433
|
+
vertex : int
|
|
434
|
+
The target vertex.
|
|
435
|
+
|
|
436
|
+
Returns
|
|
437
|
+
-------
|
|
438
|
+
np.array
|
|
439
|
+
A boolean array mask indicating which edges lead from vertices in vertex_set to the specified vertex.
|
|
440
|
+
"""
|
|
441
|
+
parent_edges_mask = self.get_parents_mask(vertex)
|
|
442
|
+
parent_vertices = self.edge_array[:, 0][parent_edges_mask]
|
|
443
|
+
parent_edges_mask[parent_edges_mask] = [(parent in vertex_set) for parent in parent_vertices]
|
|
444
|
+
return parent_edges_mask
|
|
445
|
+
|
|
446
|
+
def get_adj_matrix(self) -> np.array:
|
|
447
|
+
"""
|
|
448
|
+
Generate the adjacency matrix of the graph.
|
|
449
|
+
|
|
450
|
+
Returns
|
|
451
|
+
-------
|
|
452
|
+
np.array
|
|
453
|
+
The adjacency matrix as a numpy array.
|
|
454
|
+
"""
|
|
455
|
+
vertices = list(self.get_vertices())
|
|
456
|
+
n_vertex = len(vertices)
|
|
457
|
+
adj_matrix = pd.DataFrame(np.zeros((n_vertex, n_vertex)), columns=vertices, index=vertices)
|
|
458
|
+
for (v1, v2), weight in zip(self.edge_array, self.weights):
|
|
459
|
+
adj_matrix.at[v1, v2] = weight
|
|
460
|
+
|
|
461
|
+
return adj_matrix
|
|
462
|
+
|
|
463
|
+
def is_edge_in_graph(self, edge: Tuple[int, int]) -> bool:
|
|
464
|
+
"""
|
|
465
|
+
Check if a specified edge exists in the graph.
|
|
466
|
+
|
|
467
|
+
Parameters
|
|
468
|
+
----------
|
|
469
|
+
edge : Tuple[int, int]
|
|
470
|
+
The edge to check.
|
|
471
|
+
|
|
472
|
+
Returns
|
|
473
|
+
-------
|
|
474
|
+
bool
|
|
475
|
+
True if the edge exists in the graph, False otherwise.
|
|
476
|
+
"""
|
|
477
|
+
source, sink = edge
|
|
478
|
+
return sink in self.get_children(source)
|