Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit 055f988

Browse files
committed
Merge branch 'python-better-embeddings' into develop
(This also adds the "selection chances" result script)
2 parents e3beaf2 + 12c8537 commit 055f988

10 files changed

Lines changed: 687 additions & 448 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ external/lemon.tar.gz
77

88
# Python
99
__pycache__
10+
out/
11+
logs/
1012

1113
# Prerequisites
1214
*.d

python/src/drawing/draw.py

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
class DrawEmbedding():
99

10+
def init_figure(self):
11+
self.fig = plt.figure()
12+
plt.subplots_adjust(left=0.0, right=1.0,
13+
bottom=0.0, top=1.0,
14+
wspace=0.1, hspace=0.1)
15+
1016
def __init__(self, m, n, t):
1117
self.total_steps = 0
1218

@@ -22,13 +28,9 @@ def __init__(self, m, n, t):
2228
self.px = 1/plt.rcParams['figure.dpi'] # pixel in inches
2329
plt.rcParams.update({'axes.titlesize': 24})
2430

25-
# Init figure
26-
self.fig = plt.figure()
27-
plt.subplots_adjust(left=0.0, right=1.0,
28-
bottom=0.0, top=1.0,
29-
wspace=0.1, hspace=0.1)
30-
3131
self.col = 0
32+
self.m = m
33+
self.n = n
3234

3335
self.init_chimera_graph(m, n, t)
3436

@@ -49,7 +51,7 @@ def draw_chimera_graph(self):
4951

5052
# Labels
5153
# Shift labels
52-
pos_labels = {node: [pos[0] - 0.025, pos[1]]
54+
pos_labels = {node: [pos[0] - 0.020, pos[1]]
5355
for (node, pos) in self.pos_chimera.items()}
5456
nx.draw_networkx_labels(self.chimera_G,
5557
pos=pos_labels,
@@ -143,31 +145,31 @@ def show_embedding(self):
143145

144146
def draw_whole_embedding_step(self, nodes: set[int], edges: set[tuple[int, int, int]],
145147
mapping_G_to_H, title=''):
146-
ax = self.construct_subplot_to_the_right()
147-
ax.set_title(title)
148+
self.init_figure()
149+
self.fig.suptitle(title, fontsize=20)
148150
self.draw_chimera_and_embedding(nodes, edges, mapping_G_to_H)
149151
self.total_steps += 1
150152

151-
def construct_subplot_to_the_right(self) -> Axes:
152-
"""Constructs a new subplot to the right."""
153-
self.col += 1
154-
gs = gridspec.GridSpec(1, self.col)
153+
# def construct_subplot_to_the_right(self) -> Axes:
154+
# """Constructs a new subplot to the right."""
155+
# self.col += 1
156+
# gs = gridspec.GridSpec(1, self.col)
155157

156-
# Reposition subplots
157-
for i, ax in enumerate(self.fig.axes):
158-
# ax.set_position(gs[i, 0].get_position(self.fig))
159-
ax.set_subplotspec(gs[0, i])
158+
# # Reposition subplots
159+
# for i, ax in enumerate(self.fig.axes):
160+
# # ax.set_position(gs[i, 0].get_position(self.fig))
161+
# ax.set_subplotspec(gs[0, i])
160162

161-
# Add new subplot
162-
ax = self.fig.add_subplot(gs[0, self.col-1])
163-
ax.set_position(gs[0, self.col-1].get_position(self.fig))
163+
# # Add new subplot
164+
# ax = self.fig.add_subplot(gs[0, self.col-1])
165+
# ax.set_position(gs[0, self.col-1].get_position(self.fig))
164166

165-
return ax
167+
# return ax
166168

167169
def save_and_clear(self, path):
168-
self.fig.set_size_inches(self.total_steps*1000*self.px, 800*self.px)
170+
self.fig.set_size_inches(self.m*3, self.n*3)
169171
self.fig.savefig(path, bbox_inches='tight')
170-
plt.clf()
172+
plt.close(self.fig)
171173

172174

173175
def change_brightness(color, amount=1):

python/src/embedding/embedding.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ def get_embedded_nodes(self) -> set[int]:
3939
Returns:
4040
set[int]: The embedded nodes.
4141
"""
42-
return self.G_embedding.get_embedded_nodes()
42+
embedded_nodes = self.G_embedding.get_embedded_nodes()
43+
if not embedded_nodes:
44+
raise Exception('No nodes embedded yet')
45+
return embedded_nodes
4346

4447
def get_reachable_neighbors(self, source):
4548
return self.G_layout.get_neighbor_nodes(source)
@@ -153,6 +156,36 @@ def get_mapping_G_to_H(self):
153156
def get_nodes_G(self, node_H: int) -> set[int]:
154157
return self.mapping.get_nodes_G(node_H)
155158

159+
def get_nodes_H(self) -> set[int]:
160+
return self.H.get_nodes()
161+
162+
def get_supernode_degree_percentages(self) -> dict[int, float]:
163+
"""Returns a dictionary of percentages for each supernode indicating
164+
how many edges between supernodes are currently embedded in G compared
165+
to how many should be as specified in the input graph H."""
166+
degree_percentages = {}
167+
for source_H in self.H.get_nodes():
168+
expected_degree = len(self.H.get_neighbor_nodes(source_H))
169+
actual_degree = len(self.G_embedding_view.get_neighbor_nodes(source_H))
170+
degree_percentages[source_H] = actual_degree / expected_degree
171+
return degree_percentages
172+
173+
def _get_supernode_sizes(self) -> dict[int, int]:
174+
supernode_sizes = {}
175+
for source_H in self.H.get_nodes():
176+
supernode_nodes = self.get_nodes_in_supernode(source_H)
177+
supernode_sizes[source_H] = len(supernode_nodes)
178+
return supernode_sizes
179+
180+
def get_sorted_supernodes_by_size(self) -> list[int]:
181+
"""Returns a list of sorted supernode keys according to their size
182+
(how many nodes in the hardware graph they map onto).
183+
"""
184+
supernode_sizes = self._get_supernode_sizes()
185+
# sort according to value (supernode size)
186+
sorted_entries = sorted(supernode_sizes.items(), key=lambda item: item[1])
187+
return [entry[0] for entry in sorted_entries]
188+
156189
def try_embed_missing_edges(self) -> int:
157190
"""Tries to embed missing edges if possible.
158191
@@ -191,10 +224,15 @@ def try_embed_missing_edges(self) -> int:
191224

192225
return len(missing_edges_added)
193226

227+
def remove_redundancy(self) -> None:
228+
self.remove_redundant_supernode_nodes()
229+
self.remove_unnecessary_edges_between_supernodes()
230+
194231
def remove_unnecessary_edges_between_supernodes(self) -> None:
195232
"""Tries to remove unnecessary edges, e.g. multiple edges between
196233
two supernodes.
197234
"""
235+
logger.info('Remove unnecessary edges between supernodes')
198236
# For every supernode (chain)
199237
for supernode in self.H.get_nodes():
200238
considered_supernodes = []
@@ -221,6 +259,7 @@ def remove_unnecessary_edges_between_supernodes(self) -> None:
221259
# this must be preserved by this method
222260

223261
def remove_redundant_supernode_nodes(self):
262+
logger.info('Removing redundant supernode nodes')
224263
for supernode in self.H.get_nodes():
225264
self.remove_redundant_nodes_in_supernode(supernode)
226265

@@ -231,7 +270,6 @@ def remove_redundant_nodes_in_supernode(self, supernode) -> None:
231270
return
232271

233272
removed_nodes = set()
234-
235273
while True:
236274
removed_in_this_iteration = False
237275

python/src/results/chances.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[0.04 0. 0.04 0.25 0. 0.25 0.04 0.08 0.08 0.04 0.08 0.08]
2+
[0.07 0.08 0.08 0.11 0.1 0.12 0.05 0.03 0.08 0.02 0.14 0.12]
3+
4+
[0.5 0. 0. 0. 0. 0.5 0. 0. 0. 0. 0. 0. ]
5+
[0.06 0.01 0.1 0.07 0. 0.08 0.13 0.16 0.15 0.03 0.12 0.09]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
4+
with open('./chances.txt', 'r') as f:
5+
line1 = f.readline()
6+
line2 = f.readline()
7+
p1 = np.fromstring(line1[1:-1], sep=' ')
8+
p2 = np.fromstring(line2[1:-1], sep=' ')
9+
x = np.arange(len(p1))
10+
11+
12+
width = 0.35 # the width of the bars
13+
fig, ax = plt.subplots(figsize=(14, 11))
14+
rects1 = ax.bar(x - width/2, p1, width, label='without increase')
15+
rects2 = ax.bar(x + width/2, p2, width, label='with increase for small supernodes')
16+
17+
ax.set_xticks(x, x)
18+
ax.legend()
19+
ax.set_ylim(0, 0.2)
20+
21+
ax.bar_label(rects1, padding=3)
22+
ax.bar_label(rects2, padding=3)
23+
# fig.tight_layout()
24+
plt.xlabel('Supernode')
25+
plt.ylabel('Chance of selecting the supernode')
26+
plt.title('Selection chances')
27+
plt.show()
28+
29+
# plt.ylim(0, 0.2)
30+
# plt.plot(x, p1, marker='o', linestyle='--', label='without increase')
31+
# plt.plot(x, p2, marker='o', linestyle='--', label='with increase for small supernodes')
32+
# plt.xlabel('Supernodes')
33+
# plt.ylabel('Chance of selecting a supernode')
34+
# plt.title('Selection chances')
35+
# plt.legend()
36+
# plt.show()

0 commit comments

Comments
 (0)