Skip to content

Commit f866ff6

Browse files
committed
normalized Chimera, Pegasus and Zephyr layouts to unit square
1 parent 4ade84b commit f866ff6

6 files changed

+78
-43
lines changed

dwave_networkx/drawing/chimera_layout.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,11 @@ def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2):
141141
"""
142142
import numpy as np
143143

144+
center_pad = 1
144145
tile_center = t // 2
145-
tile_length = t + 3 # 1 for middle of cross, 2 for spacing between tiles
146+
tile_length = t + 2 + center_pad # 2 for spacing between tiles
146147
# want the enter plot to fill in [0, 1] when scale=1
147-
scale /= max(m, n) * tile_length - 3
148+
scale /= max(m, n) * tile_length - 2 - center_pad
148149

149150
grid_offsets = {}
150151

@@ -153,10 +154,11 @@ def chimera_node_placer_2d(m, n, t, scale=1., center=None, dim=2):
153154
else:
154155
center = np.asarray(center)
155156

156-
paddims = dim - 2
157-
if paddims < 0:
157+
if dim < 2:
158158
raise ValueError("layout must have at least two dimensions")
159159

160+
paddims = np.zeros(dim - 2, dtype='float')
161+
160162
if len(center) != dim:
161163
raise ValueError("length of center coordinates must match dimension of layout")
162164

@@ -167,24 +169,24 @@ def _xy_coords(i, j, u, k):
167169
if k < tile_center:
168170
p = k
169171
else:
170-
p = k + 1
172+
p = k + center_pad
171173

172174
if u:
173-
xy = np.array([tile_center, -1 * p])
175+
xy = np.array([tile_center, -1 * p], dtype='float')
174176
else:
175-
xy = np.array([p, -1 * tile_center])
177+
xy = np.array([p, -1 * tile_center], dtype='float')
176178

177179
# next offset the corrdinates based on the which tile
178180
if i > 0 or j > 0:
179181
if (i, j) in grid_offsets:
180182
xy += grid_offsets[(i, j)]
181183
else:
182-
off = np.array([j * tile_length, -1 * i * tile_length])
184+
off = np.array([j * tile_length, -1 * i * tile_length], dtype='float')
183185
xy += off
184186
grid_offsets[(i, j)] = off
185187

186188
# convention for Chimera-lattice pictures is to invert the y-axis
187-
return np.hstack((xy * scale, np.zeros(paddims))) + center
189+
return np.hstack((xy * scale, paddims)) + center
188190

189191
return _xy_coords
190192

dwave_networkx/drawing/pegasus_layout.py

+18-18
Original file line numberDiff line numberDiff line change
@@ -129,48 +129,48 @@ def pegasus_node_placer_2d(G, scale=1., center=None, dim=2, crosses=False):
129129
"""
130130
import numpy as np
131131

132-
m = G.graph.get('rows')
133-
h_offsets = G.graph.get("horizontal_offsets")
134-
v_offsets = G.graph.get("vertical_offsets")
135-
tile_width = G.graph.get("tile")
132+
m = G.graph['rows']
133+
h_offsets = G.graph["horizontal_offsets"]
134+
v_offsets = G.graph["vertical_offsets"]
135+
tile_width = G.graph["tile"]
136+
odd_k_wobble = .05
136137
tile_center = tile_width / 2 - .5
138+
cross_shift = 2 if crosses else 0
137139

138140
# want the enter plot to fill in [0, 1] when scale=1
139-
scale /= m * tile_width
141+
scale /= m*tile_width - 2*odd_k_wobble - 1
140142

141143
if center is None:
142144
center = np.zeros(dim)
143145
else:
144146
center = np.asarray(center)
145147

146-
paddims = dim - 2
147-
if paddims < 0:
148+
center[0] -= (cross_shift + odd_k_wobble)*scale
149+
center[1] -= (cross_shift - odd_k_wobble)*scale
150+
151+
if dim < 0:
148152
raise ValueError("layout must have at least two dimensions")
149153

154+
paddims = np.zeros(dim - 2)
155+
150156
if len(center) != dim:
151157
raise ValueError("length of center coordinates must match dimension of layout")
152158

153-
if crosses:
154-
# adjustment for crosses
155-
cross_shift = 2.
156-
else:
157-
cross_shift = 0.
158-
159159
def _xy_coords(u, w, k, z):
160160
# orientation, major perpendicular offset, minor perpendicular offset, parallel offset
161161

162162
if k % 2:
163-
p = -.1
163+
p = -odd_k_wobble
164164
else:
165-
p = .1
165+
p = odd_k_wobble
166166

167167
if u:
168-
xy = np.array([z*tile_width+h_offsets[k] + tile_center, -tile_width*w-k-p+cross_shift])
168+
xy = np.array([z*tile_width+h_offsets[k] + tile_center, -tile_width*w-k-p+cross_shift], dtype='float')
169169
else:
170-
xy = np.array([tile_width*w+k+p+cross_shift, -z*tile_width-v_offsets[k]-tile_center])
170+
xy = np.array([tile_width*w+k+p+cross_shift, -z*tile_width-v_offsets[k]-tile_center], dtype='float')
171171

172172
# convention for Pegasus-lattice pictures is to invert the y-axis
173-
return np.hstack((xy * scale, np.zeros(paddims))) + center
173+
return np.hstack((xy * scale, paddims)) + center
174174

175175
return _xy_coords
176176

dwave_networkx/drawing/zephyr_layout.py

+13-16
Original file line numberDiff line numberDiff line change
@@ -113,40 +113,37 @@ def zephyr_node_placer_2d(G, scale=1., center=None, dim=2):
113113
"""
114114
import numpy as np
115115

116-
m = G.graph.get('rows')
117-
tile_width = G.graph.get("tile")
116+
m = G.graph['rows']
117+
tile_width = 2*G.graph["tile"]
118118

119-
# want the enter plot to fill in [0, 1] when scale=1
120-
scale /= m * tile_width
119+
if dim < 2:
120+
raise ValueError("layout must have at least two dimensions")
121+
122+
paddims = np.zeros(dim - 2)
121123

122124
if center is None:
123125
center = np.zeros(dim)
124126
else:
125127
center = np.asarray(center)
126128

127-
paddims = dim - 2
128-
if paddims < 0:
129-
raise ValueError("layout must have at least two dimensions")
130-
131129
if len(center) != dim:
132130
raise ValueError("length of center coordinates must match dimension of layout")
133131

134132
def _xy_coords(u, w, k, j, z):
135133
# orientation, major perpendicular offset, secondary perpendicular offset, minor perpendicular offset, parallel offset
136-
W = 2*tile_width*w + 2*k + .625*j + .125
137-
Z = (2*z+j+1)*2*tile_width - .5
138-
134+
W = tile_width*w + 2*k + .625*j
135+
Z = (2*z+j+1)*tile_width - .6875
139136
if u:
140-
xy = np.array([Z, -W])
137+
xy = np.array([Z, -W], dtype='float')
141138
else:
142-
xy = np.array([W, -Z])
143-
139+
xy = np.array([W, -Z], dtype='float')
144140

145-
return np.hstack((xy * scale, np.zeros(paddims))) + center
141+
return np.hstack((xy * scale, paddims)) + center
146142

143+
# want the enter plot to fill in [0, 1] when scale=1
144+
scale /= max(map(abs, _xy_coords(0, 2*m, G.graph["tile"]-1, 1, m-1)))
147145
return _xy_coords
148146

149-
150147
def draw_zephyr(G, **kwargs):
151148
"""Draws graph G in a Zephyr topology.
152149

tests/test_chimera_layout.py

+12
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,15 @@ def test_draw_overlapped_chimera_embedding(self):
116116
emb = {0: [1, 5], 1: [5, 9, 13], 2: [25, 29], 3: [17, 21]}
117117
dnx.draw_chimera_embedding(C, emb, overlapped_embedding=True)
118118
dnx.draw_chimera_embedding(C, emb, overlapped_embedding=True, show_labels=True)
119+
120+
def test_layout_bounds(self):
121+
for C in [dnx.chimera_graph(1, 1, 4), dnx.chimera_graph(2, 2, 2), dnx.chimera_graph(4, 4, 4), dnx.chimera_graph(2, 2, 8)]:
122+
pos = dnx.chimera_layout(C)
123+
minx = min(x for x, y in pos.values())
124+
miny = min(y for x, y in pos.values())
125+
maxx = max(x for x, y in pos.values())
126+
maxy = max(y for x, y in pos.values())
127+
self.assertAlmostEqual(minx, 0)
128+
self.assertAlmostEqual(maxx, 1)
129+
self.assertAlmostEqual(miny, -1)
130+
self.assertAlmostEqual(maxy, 0)

tests/test_pegasus_layout.py

+12
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,15 @@ def test_draw_overlapped_chimera_embedding(self):
102102
emb = {0: [12, 35], 1: [12, 31], 2: [32], 3: [14]}
103103
dnx.draw_pegasus_embedding(C, emb, overlapped_embedding=True)
104104
dnx.draw_pegasus_embedding(C, emb, overlapped_embedding=True, show_labels=True)
105+
106+
def test_layout_bounds(self):
107+
for P in [dnx.pegasus_graph(2, fabric_only=False), dnx.pegasus_graph(3, fabric_only=False), dnx.pegasus_graph(4, fabric_only=False)]:
108+
pos = dnx.pegasus_layout(P)
109+
minx = min(x for x, y in pos.values())
110+
miny = min(y for x, y in pos.values())
111+
maxx = max(x for x, y in pos.values())
112+
maxy = max(y for x, y in pos.values())
113+
self.assertAlmostEqual(minx, 0)
114+
self.assertAlmostEqual(maxx, 1)
115+
self.assertAlmostEqual(miny, -1)
116+
self.assertAlmostEqual(maxy, 0)

tests/test_zephyr_layout.py

+12
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,15 @@ def test_draw_overlapped_zephyr_embedding(self):
109109
emb = {0: [1, 3], 1: [3, 128, 15], 2: [25, 140], 3: [17, 122]}
110110
dnx.draw_zephyr_embedding(C, emb, overlapped_embedding=True)
111111
dnx.draw_zephyr_embedding(C, emb, overlapped_embedding=True, show_labels=True)
112+
113+
def test_layout_bounds(self):
114+
for Z in [dnx.zephyr_graph(2), dnx.zephyr_graph(3), dnx.zephyr_graph(4), dnx.zephyr_graph(2, 8)]:
115+
pos = dnx.zephyr_layout(Z)
116+
minx = min(x for x, y in pos.values())
117+
miny = min(y for x, y in pos.values())
118+
maxx = max(x for x, y in pos.values())
119+
maxy = max(y for x, y in pos.values())
120+
self.assertAlmostEqual(minx, 0)
121+
self.assertAlmostEqual(maxx, 1)
122+
self.assertAlmostEqual(miny, -1)
123+
self.assertAlmostEqual(maxy, 0)

0 commit comments

Comments
 (0)