Skip to content

Commit c696bdc

Browse files
Add a matrix class to enable str()
1 parent a1f1b5c commit c696bdc

File tree

2 files changed

+93
-50
lines changed

2 files changed

+93
-50
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,7 @@ docs/_build/
131131
target/
132132

133133
# Pycharm
134-
venv
134+
venv/
135+
136+
# VS Code
137+
.vscode/

cyaron/graph.py

Lines changed: 89 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from .utils import *
22
import random
3+
from typing import TypeVar, Callable
34

45

56
class Edge:
67
"""Class Edge: A class of the edge in the graph"""
8+
79
def __init__(self, u, v, w):
810
"""__init__(self, u, v, w) -> None
911
Initialize a edge.
@@ -26,11 +28,13 @@ def unweighted_edge(edge):
2628
"""unweighted_edge(edge) -> str
2729
Return a string to output the edge without weight. The string contains the start vertex, end vertex(u,v) and splits with space.
2830
"""
29-
return '%d %d'%(edge.start,edge.end)
31+
return '%d %d' % (edge.start, edge.end)
32+
3033

3134
class Graph:
3235
"""Class Graph: A class of the graph
3336
"""
37+
3438
def __init__(self, point_count, directed=False):
3539
"""__init__(self, point_count) -> None
3640
Initialize a graph.
@@ -50,13 +54,7 @@ def to_matrix(self, **kwargs):
5054
-> the mapping from the old values in matrix and the edges to the new values in matrix.
5155
Note that the index start from 0 and the values in the Column 0 or the Row 0 are always the default.
5256
"""
53-
default = kwargs.get("default", -1)
54-
merge = kwargs.get("merge", lambda val, edge: edge.weight)
55-
n = len(self.edges)
56-
matrix = [[default for _ in range(n)] for _ in range(n)]
57-
for edge in self.iterate_edges():
58-
matrix[edge.start][edge.end] = merge(matrix[edge.start][edge.end], edge)
59-
return matrix
57+
return GraphMatrix(self)
6058

6159
def to_str(self, **kwargs):
6260
"""to_str(self, **kwargs) -> str
@@ -75,7 +73,8 @@ def to_str(self, **kwargs):
7573
edge_buf = []
7674
for edge in self.iterate_edges():
7775
edge_buf.append(
78-
Edge(new_node_id[edge.start], new_node_id[edge.end], edge.weight))
76+
Edge(new_node_id[edge.start], new_node_id[edge.end],
77+
edge.weight))
7978
random.shuffle(edge_buf)
8079
for edge in edge_buf:
8180
if not self.directed and random.randint(0, 1) == 0:
@@ -173,9 +172,10 @@ def tree(point_count, chain=0, flower=0, **kwargs):
173172
if not list_like(weight_limit):
174173
weight_limit = (1, weight_limit)
175174
weight_gen = kwargs.get(
176-
"weight_gen", lambda: random.randint(
177-
weight_limit[0], weight_limit[1]))
178-
father_gen = kwargs.get("father_gen", lambda cur: random.randrange(1, cur))
175+
"weight_gen",
176+
lambda: random.randint(weight_limit[0], weight_limit[1]))
177+
father_gen = kwargs.get("father_gen",
178+
lambda cur: random.randrange(1, cur))
179179

180180
if not 0 <= chain <= 1 or not 0 <= flower <= 1:
181181
raise Exception("chain and flower must be between 0 and 1")
@@ -222,33 +222,35 @@ def binary_tree(point_count, left=0, right=0, **kwargs):
222222
if not list_like(weight_limit):
223223
weight_limit = (1, weight_limit)
224224
weight_gen = kwargs.get(
225-
"weight_gen", lambda: random.randint(
226-
weight_limit[0], weight_limit[1]))
225+
"weight_gen",
226+
lambda: random.randint(weight_limit[0], weight_limit[1]))
227227

228228
if not 0 <= left <= 1 or not 0 <= right <= 1:
229229
raise Exception("left and right must be between 0 and 1")
230230
if left + right > 1:
231231
raise Exception("left plus right must be smaller than 1")
232-
233-
can_left=[1]
234-
can_right=[1]
232+
233+
can_left = [1]
234+
can_right = [1]
235235
graph = Graph(point_count, directed)
236236
for i in range(2, point_count + 1):
237237
edge_pos = random.random()
238238
node = 0
239239
# Left
240-
if edge_pos < left or left + right < edge_pos <= (1.0 - left - right) / 2:
241-
point_index = random.randint(0,len(can_left)-1)
240+
if edge_pos < left or left + right < edge_pos <= (1.0 - left -
241+
right) / 2:
242+
point_index = random.randint(0, len(can_left) - 1)
242243
node = can_left[point_index]
243-
del_last_node = can_left.pop() # Save a copy of the last element
244+
del_last_node = can_left.pop(
245+
) # Save a copy of the last element
244246
if point_index < len(can_left):
245247
# If the chosen element isn't the last one,
246248
# Copy the last one to the position of the chosen one
247249
can_left[point_index] = del_last_node
248250
# Right
249251
else:
250-
# elif left <= edge_pos <= left + right or (1.0 - left - right) / 2 < edge_pos < 1:
251-
point_index = random.randint(0,len(can_right)-1)
252+
# elif left <= edge_pos <= left + right or (1.0 - left - right) / 2 < edge_pos < 1:
253+
point_index = random.randint(0, len(can_right) - 1)
252254
node = can_right[point_index]
253255
del_last_node = can_right.pop()
254256
if point_index < len(can_right):
@@ -282,16 +284,17 @@ def graph(point_count, edge_count, **kwargs):
282284
if not list_like(weight_limit):
283285
weight_limit = (1, weight_limit)
284286
weight_gen = kwargs.get(
285-
"weight_gen", lambda: random.randint(
286-
weight_limit[0], weight_limit[1]))
287+
"weight_gen",
288+
lambda: random.randint(weight_limit[0], weight_limit[1]))
287289
graph = Graph(point_count, directed)
288290
used_edges = set()
289291
i = 0
290292
while i < edge_count:
291293
u = random.randint(1, point_count)
292294
v = random.randint(1, point_count)
293295

294-
if (not self_loop and u == v) or (not repeated_edges and (u, v) in used_edges):
296+
if (not self_loop and u == v) or (not repeated_edges and
297+
(u, v) in used_edges):
295298
# Then we generate a new pair of nodes
296299
continue
297300

@@ -322,30 +325,33 @@ def DAG(point_count, edge_count, **kwargs):
322325
-> the generator of the weights. It should return the weight. The default way is to use the random.randint()
323326
"""
324327
if edge_count < point_count - 1:
325-
raise Exception("the number of edges of connected graph must more than the number of nodes - 1")
328+
raise Exception(
329+
"the number of edges of connected graph must more than the number of nodes - 1"
330+
)
326331

327-
self_loop = kwargs.get("self_loop", False) # DAG default has no loop
332+
self_loop = kwargs.get("self_loop", False) # DAG default has no loop
328333
repeated_edges = kwargs.get("repeated_edges", True)
329334
loop = kwargs.get("loop", False)
330335
weight_limit = kwargs.get("weight_limit", (1, 1))
331336
if not list_like(weight_limit):
332337
weight_limit = (1, weight_limit)
333338
weight_gen = kwargs.get(
334-
"weight_gen", lambda: random.randint(
335-
weight_limit[0], weight_limit[1]))
336-
339+
"weight_gen",
340+
lambda: random.randint(weight_limit[0], weight_limit[1]))
341+
337342
used_edges = set()
338-
edge_buf = list(Graph.tree(point_count, weight_gen=weight_gen).iterate_edges())
343+
edge_buf = list(
344+
Graph.tree(point_count, weight_gen=weight_gen).iterate_edges())
339345
graph = Graph(point_count, directed=True)
340346

341347
for edge in edge_buf:
342348
if loop and random.randint(1, 2) == 1:
343349
edge.start, edge.end = edge.end, edge.start
344350
graph.add_edge(edge.start, edge.end, weight=edge.weight)
345-
351+
346352
if not repeated_edges:
347353
used_edges.add((edge.start, edge.end))
348-
354+
349355
i = point_count - 1
350356
while i < edge_count:
351357
u = random.randint(1, point_count)
@@ -354,7 +360,8 @@ def DAG(point_count, edge_count, **kwargs):
354360
if not loop and u > v:
355361
u, v = v, u
356362

357-
if (not self_loop and u == v) or (not repeated_edges and (u, v) in used_edges):
363+
if (not self_loop and u == v) or (not repeated_edges and
364+
(u, v) in used_edges):
358365
# Then we generate a new pair of nodes
359366
continue
360367

@@ -382,32 +389,35 @@ def UDAG(point_count, edge_count, **kwargs):
382389
= lambda: random.randint(weight_limit[0], weight_limit[1])
383390
-> the generator of the weights. It should return the weight. The default way is to use the random.randint()
384391
"""
385-
if edge_count < point_count - 1:
386-
raise Exception("the number of edges of connected graph must more than the number of nodes - 1")
392+
if edge_count < point_count - 1:
393+
raise Exception(
394+
"the number of edges of connected graph must more than the number of nodes - 1"
395+
)
387396

388397
self_loop = kwargs.get("self_loop", True)
389398
repeated_edges = kwargs.get("repeated_edges", True)
390399
weight_limit = kwargs.get("weight_limit", (1, 1))
391400
if not list_like(weight_limit):
392401
weight_limit = (1, weight_limit)
393402
weight_gen = kwargs.get(
394-
"weight_gen", lambda: random.randint(
395-
weight_limit[0], weight_limit[1]))
396-
403+
"weight_gen",
404+
lambda: random.randint(weight_limit[0], weight_limit[1]))
405+
397406
used_edges = set()
398407
graph = Graph.tree(point_count, weight_gen=weight_gen, directed=False)
399408

400409
for edge in graph.iterate_edges():
401410
if not repeated_edges:
402411
used_edges.add((edge.start, edge.end))
403412
used_edges.add((edge.end, edge.start))
404-
413+
405414
i = point_count - 1
406415
while i < edge_count:
407416
u = random.randint(1, point_count)
408417
v = random.randint(1, point_count)
409418

410-
if (not self_loop and u == v) or (not repeated_edges and (u, v) in used_edges):
419+
if (not self_loop and u == v) or (not repeated_edges and
420+
(u, v) in used_edges):
411421
# Then we generate a new pair of nodes
412422
continue
413423

@@ -441,8 +451,8 @@ def hack_spfa(point_count, **kwargs):
441451
if not list_like(weight_limit):
442452
weight_limit = (1, weight_limit)
443453
weight_gen = kwargs.get(
444-
"weight_gen", lambda: random.randint(
445-
weight_limit[0], weight_limit[1]))
454+
"weight_gen",
455+
lambda: random.randint(weight_limit[0], weight_limit[1]))
446456

447457
point_to_skip = point_count + 3
448458
graph = Graph(point_count, directed)
@@ -452,19 +462,49 @@ def hack_spfa(point_count, **kwargs):
452462

453463
for i in range(1, half):
454464
(x, y) = (i, i + 1)
455-
graph.add_edge(x + (x >= point_to_skip), y +
456-
(y >= point_to_skip), weight=weight_gen())
465+
graph.add_edge(x + (x >= point_to_skip),
466+
y + (y >= point_to_skip),
467+
weight=weight_gen())
457468
(x, y) = (i + half, i + half + 1)
458-
graph.add_edge(x + (x >= point_to_skip), y +
459-
(y >= point_to_skip), weight=weight_gen())
469+
graph.add_edge(x + (x >= point_to_skip),
470+
y + (y >= point_to_skip),
471+
weight=weight_gen())
460472
for i in range(1, half + 1):
461473
(x, y) = (i, i + half)
462-
graph.add_edge(x + (x >= point_to_skip), y +
463-
(y >= point_to_skip), weight=weight_gen())
474+
graph.add_edge(x + (x >= point_to_skip),
475+
y + (y >= point_to_skip),
476+
weight=weight_gen())
464477

465478
for i in range(extraedg):
466479
u = random.randint(1, point_count)
467480
v = random.randint(1, point_count)
468481
graph.add_edge(u, v, weight=weight_gen())
469482

470483
return graph
484+
485+
486+
T = TypeVar('T')
487+
488+
489+
class GraphMatrix:
490+
"""Class GraphMatrix: A class of the graph represented by adjacency matrix"""
491+
492+
def __init__(self,
493+
graph: Graph,
494+
default: T = -1,
495+
merge: Callable[[T, Edge],
496+
T] = lambda val, edge: edge.weight):
497+
"""
498+
Args:
499+
graph: the graph to convert,
500+
default: the default value when the edge does not exist,
501+
merge: the mapping from the old values in matrix and the edges to the new values in matrix.
502+
"""
503+
n = len(graph.edges)
504+
self.matrix = [[default for _ in range(n)] for _ in range(n)]
505+
for edge in graph.iterate_edges():
506+
self.matrix[edge.start][edge.end] = merge(
507+
self.matrix[edge.start][edge.end], edge)
508+
509+
def __str__(self):
510+
return '\n'.join([' '.join(map(str, row)) for row in self.matrix])

0 commit comments

Comments
 (0)