11from .utils import *
22import random
3+ from typing import TypeVar , Callable
34
45
56class 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
3134class 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