Skip to content

Commit ffb3739

Browse files
weilycoderMr-Python-in-China
authored andcommitted
Support undirected graph
1 parent 16e7935 commit ffb3739

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

cyaron/graph.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ class SwitchGraph:
4444
def get_edges(self):
4545
ret: List[Tuple[int, int]] = []
4646
for k in self.__edges:
47-
ret.extend(itertools.repeat(k, self.__edges[k]))
48-
return ret
47+
if self.directed or k[0] <= k[1]:
48+
ret.extend(itertools.repeat(k, self.__edges[k]))
49+
return sorted(ret)
4950

5051
def __insert(self, u: int, v: int):
5152
if (u, v) not in self.__edges:
@@ -78,9 +79,9 @@ def __init__(self,
7879
self.__edges = {}
7980
for e in E:
8081
if isinstance(e, Edge):
81-
self.__insert(e.start, e.end)
82+
self.insert(e.start, e.end)
8283
else:
83-
self.__insert(e[0], e[1])
84+
self.insert(e[0], e[1])
8485

8586
def switch(self, *, self_loop: bool = False, repeated_edges: bool = False):
8687
"""Mutates the current directed graph by swapping pairs of edges, without impacting the degree sequence.
@@ -94,8 +95,8 @@ def switch(self, *, self_loop: bool = False, repeated_edges: bool = False):
9495
first, second = random.choices(list(self.__edges.keys()),
9596
list(self.__edges.values()),
9697
k=2)
97-
x1, y1 = first
98-
x2, y2 = second
98+
x1, y1 = first if self.directed else sorted(first)
99+
x2, y2 = second if self.directed else sorted(second)
99100

100101
if self_loop:
101102
if x1 == x2 or y1 == y2:
@@ -162,6 +163,51 @@ def from_directed_degree_sequence(
162163

163164
return ret
164165

166+
@staticmethod
167+
def from_undirected_degree_sequence(
168+
degree_sequence: Sequence[int],
169+
start_id: int = 1,
170+
*,
171+
self_loop: bool = False,
172+
repeated_edges: bool = False) -> "SwitchGraph":
173+
if any(x < 0 for x in degree_sequence):
174+
raise ValueError("Degree sequence is not graphical.")
175+
176+
if sum(degree_sequence) % 2 != 0:
177+
raise ValueError("Degree sequence is not graphical.")
178+
179+
if len(degree_sequence) == 0:
180+
return SwitchGraph((), False)
181+
182+
degseq = [[deg, i] for i, deg in enumerate(degree_sequence, start_id)]
183+
degseq.sort(reverse=True)
184+
185+
edges: List[Tuple[int, int]] = []
186+
try:
187+
while len(edges) * 2 < sum(degree_sequence):
188+
deg, x = degseq[0]
189+
degseq[0][0] = 0
190+
if self_loop:
191+
while deg > 1:
192+
deg -= 2
193+
edges.append((x, x))
194+
if not repeated_edges:
195+
break
196+
y = 1
197+
while deg:
198+
while deg and degseq[y][0]:
199+
deg -= 1
200+
degseq[y][0] -= 1
201+
edges.append((x, degseq[y][1]))
202+
if not repeated_edges:
203+
break
204+
y += 1
205+
degseq.sort(reverse=True)
206+
except IndexError:
207+
raise ValueError("Degree sequence is not graphical.")
208+
209+
return SwitchGraph(edges, False)
210+
165211
def __iter__(self):
166212
return iter(self.__edges)
167213

0 commit comments

Comments
 (0)