quarkcircuit 0.3.0.dev2__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/PKG-INFO +1 -1
  2. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/pyproject.toml +1 -1
  3. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/backend.py +23 -19
  4. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/decompose.py +35 -1
  5. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/layout.py +150 -125
  6. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/matrix.py +12 -1
  7. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/quantumcircuit.py +95 -24
  8. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/quantumcircuit_helpers.py +75 -36
  9. quarkcircuit-0.3.2/quark/circuit/routing.py +660 -0
  10. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/test_transpiler.py +7 -4
  11. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/translate.py +5 -0
  12. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/transpiler.py +20 -6
  13. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quarkcircuit.egg-info/PKG-INFO +1 -1
  14. quarkcircuit-0.3.0.dev2/quark/circuit/routing.py +0 -455
  15. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/README.md +0 -0
  16. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/__init__.py +0 -0
  17. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/basepasses.py +0 -0
  18. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/dag.py +0 -0
  19. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/optimize.py +0 -0
  20. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quark/circuit/utils.py +0 -0
  21. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quarkcircuit.egg-info/SOURCES.txt +0 -0
  22. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quarkcircuit.egg-info/dependency_links.txt +0 -0
  23. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quarkcircuit.egg-info/requires.txt +0 -0
  24. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/quarkcircuit.egg-info/top_level.txt +0 -0
  25. {quarkcircuit-0.3.0.dev2 → quarkcircuit-0.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quarkcircuit
3
- Version: 0.3.0.dev2
3
+ Version: 0.3.2
4
4
  Summary: Construction, visualization, and transpilation of quantum circuits
5
5
  Author-email: Xiaoxiao Xiao <xiaoxx@baqis.ac.cn>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quarkcircuit"
7
- version = "0.3.0dev2"
7
+ version = "0.3.2"
8
8
  authors = [
9
9
  { name="Xiaoxiao Xiao", email="xiaoxx@baqis.ac.cn" }
10
10
  ]
@@ -56,7 +56,7 @@ class Backend:
56
56
  self.priority_qubits = self.chip_info['priority_qubits']
57
57
  self.qubits_with_attributes = self._collect_qubits_with_attributes()
58
58
  self.couplers_with_attributes = self._collect_couplers_with_attributes()
59
- elif chip in ['Baihua','Dongling','Haituo','Yunmeng','Miaofeng',]:
59
+ elif chip in ['Baihua','Dongling','Haituo','Yunmeng','Miaofeng','Yudu','Hongluo']:
60
60
  self.chip_name = chip
61
61
  try:
62
62
  self.chip_info = load_chip_basic_info(chip)
@@ -140,14 +140,14 @@ class Backend:
140
140
  G.add_edges_from(self.couplers_with_attributes)
141
141
  return G
142
142
 
143
- def draw(self,show_couplers_fidelity:bool = False, show_quibts_attributes:Literal['T1','T2','fidelity','frequency','']='',
143
+ def draw(self,show_couplers_fidelity:bool = False, show_qubits_attributes:Literal['T1','T2','fidelity','frequency','']='',
144
144
  show_qubits_index:bool=False,show_couplers_index:bool=False,
145
- highlight_nodes:list = [], save_svg_fname: str|None = None,):
145
+ highlight_nodes:list = [], save_svg_fname: str|None = None):
146
146
  """Draw the chip layout.
147
147
 
148
148
  Args:
149
149
  show_couplers_fidelity (bool, optional): Whether to display the fidelity of couplers. Defaults to False.
150
- show_quibts_attributes (Literal['T1', 'T2', 'fidelity', 'frequancy', ''], optional):
150
+ show_qubits_attributes (Literal['T1', 'T2', 'fidelity', 'frequancy', ''], optional):
151
151
  Specify which qubit attribute to display. Options include:
152
152
  - 'T1': Display the T1 time of qubits (in microseconds).
153
153
  - 'T2': Display the T2 time of qubits (in microseconds).
@@ -167,7 +167,7 @@ class Backend:
167
167
 
168
168
  Notes:
169
169
  - `highlight_nodes` specifies the qubits to be visually highlighted.
170
- - `show_couplers_fidelity` and `show_quibts_attributes` can be enabled simultaneously without conflicts.
170
+ - `show_couplers_fidelity` and `show_qubits_attributes` can be enabled simultaneously without conflicts.
171
171
  - When `save_svg_fname` is provided, the drawing will be saved as an SVG file.
172
172
  """
173
173
  import matplotlib.pyplot as plt
@@ -176,15 +176,15 @@ class Backend:
176
176
 
177
177
 
178
178
  edge_fidelity = nx.get_edge_attributes(self.graph, 'fidelity')
179
- node_attributes = nx.get_node_attributes(self.graph,show_quibts_attributes)
179
+ node_attributes = nx.get_node_attributes(self.graph,show_qubits_attributes)
180
180
  if show_couplers_fidelity:
181
- if set(list(edge_fidelity.values())) == {None}:
181
+ if set(list(edge_fidelity.values())) == {0}:
182
182
  print('The two-qubit gate fidelity is N/A now.')
183
183
  is_edge_info_avaliable = False
184
184
  else:
185
185
  is_edge_info_avaliable = True
186
- if show_quibts_attributes:
187
- if set(list(node_attributes.values())) == {None}:
186
+ if show_qubits_attributes:
187
+ if set(list(node_attributes.values())) == {0}:
188
188
  print('The qubit attributes is N/A now.')
189
189
  is_node_info_avaliable = False
190
190
  else:
@@ -213,13 +213,13 @@ class Backend:
213
213
  else:
214
214
  edge_labels[k] = self.graph.edges[k].get('index')
215
215
 
216
- if show_quibts_attributes != '' and is_node_info_avaliable is True:
216
+ if show_qubits_attributes != '' and is_node_info_avaliable is True:
217
217
  min_attributes = sorted(list(node_attributes.values()))[0]
218
218
  max_attributes = sorted(list(node_attributes.values()))[-1]
219
219
  node_norm = Normalize(vmin = min_attributes, vmax = max_attributes)
220
220
  node_cmap = LinearSegmentedColormap.from_list('truncated_blues', plt.get_cmap('Blues')(np.linspace(0.31, 1.0, 1000))) #plt.get_cmap('Blues')
221
221
  node_colors = [ScalarMappable(norm = node_norm, cmap = node_cmap).to_rgba(attribute) for attribute in node_attributes.values()]
222
- if show_quibts_attributes == 'fidelity':
222
+ if show_qubits_attributes == 'fidelity':
223
223
  if show_qubits_index:
224
224
  node_labels = {node:node for node in self.graph.nodes()}
225
225
  else:
@@ -244,6 +244,8 @@ class Backend:
244
244
  figsize = (15, 13)
245
245
 
246
246
  if len(highlight_nodes) > 0:
247
+ if isinstance(highlight_nodes, list) and any(isinstance(i, list) for i in highlight_nodes):
248
+ highlight_nodes = list(set(e for sub in highlight_nodes for e in sub))
247
249
  node_colors_update = []
248
250
  node_labels_update = {}
249
251
  for idx, node in enumerate(self.graph.nodes()):
@@ -273,16 +275,16 @@ class Backend:
273
275
  pos = nx.get_node_attributes(self.graph, 'coordinate')
274
276
  nx.draw(self.graph, pos,ax=ax, with_labels=False, node_color=node_colors, node_size=800, edgecolors='white',edge_color = edge_colors ,width = 18,)
275
277
  nx.draw_networkx_labels(self.graph,pos,labels=node_labels,font_size=node_font_size, font_color='white')
276
- nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels,font_size=8, font_color='white',bbox=dict(facecolor='none', edgecolor='none'))
278
+ nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels,font_size=8, font_color='white',bbox=dict(facecolor='none', edgecolor='none'),rotate=False)
277
279
 
278
- if show_quibts_attributes != '' and is_node_info_avaliable is True:
279
- if show_quibts_attributes == 'T1':
280
+ if show_qubits_attributes != '' and is_node_info_avaliable is True:
281
+ if show_qubits_attributes == 'T1':
280
282
  show_label = 'T1 ($\mu s$)'
281
- elif show_quibts_attributes == 'T2':
283
+ elif show_qubits_attributes == 'T2':
282
284
  show_label = 'T2 ($\mu s$)'
283
- elif show_quibts_attributes == 'fidelity':
285
+ elif show_qubits_attributes == 'fidelity':
284
286
  show_label = 'Single qubit gate fidelity'
285
- elif show_quibts_attributes == 'frequency':
287
+ elif show_qubits_attributes == 'frequency':
286
288
  show_label = 'Frequency (GHz)'
287
289
  node_sm = ScalarMappable(cmap=node_cmap, norm=node_norm)
288
290
  node_sm.set_array(list(node_attributes.values())) # 设置包含数据的数组
@@ -298,12 +300,14 @@ class Backend:
298
300
  edge_cbar = fig.colorbar(edge_sm, ax=ax, orientation='horizontal', pad=0.001, fraction=0.0333, aspect=25)# 调整颜色条大小和位置,放置在底部
299
301
  edge_cbar.set_label('CZ fidelity')
300
302
 
301
- xlim = ax.get_xlim()
303
+ xlim = ax.get_xlim()
302
304
  ylim = ax.get_ylim()
303
305
  xpos = (xlim[0] + xlim[1]) / 2
304
- ypos = ylim[1] * 0.96
306
+ ypos = ylim[0] - (ylim[1] - ylim[0]) * -0.03 # 计算标题位置
305
307
  ax.text(xpos, ypos, f'{self.chip_name}', va='center', ha='center', fontsize=24, fontweight='bold', color='k', family='serif')
306
308
 
309
+ ax.invert_yaxis() # y 轴正半轴朝下
310
+
307
311
  if save_svg_fname:
308
312
  plt.savefig(save_svg_fname + '.svg', transparent=True, dpi=300, bbox_inches='tight')
309
313
  plt.show()
@@ -147,7 +147,7 @@ def cx_decompose(control_qubit: int, target_qubit: int,convert_single_qubit_gate
147
147
  return gates
148
148
 
149
149
  def cy_decompose(control_qubit: int, target_qubit: int, convert_single_qubit_gate_to_u:bool, two_qubit_gate_basis:Literal['cz','cx']) -> list:
150
- """ Decompose CY gate with kak algorithm.
150
+ """ Decompose CY gate to U3 gates and CZ gates.
151
151
 
152
152
  Args:
153
153
  control_qubit (int): The qubit used as control.
@@ -366,6 +366,40 @@ def rzz_decompose(theta:float, qubit1:int, qubit2:int, convert_single_qubit_gate
366
366
  gates += cx_decompose(qubit1,qubit2,convert_single_qubit_gate_to_u,two_qubit_gate_basis)
367
367
  return gates
368
368
 
369
+
370
+ def cp_decompose(theta:float, control_qubit:int, target_qubit:int, convert_single_qubit_gate_to_u:bool) -> list:
371
+ """Decompose CPhase gate to U3 gates and CZ gates. ref: Quantum Sci. Technol. 7 (2022) 025021
372
+
373
+ Args:
374
+ theta (float): The rotation angle of the gate.
375
+ control_qubit (int): The qubit used as control.
376
+ target_qubit (int): The qubit targeted by the gate.
377
+
378
+ Returns:
379
+ list: A list of U3 gates and CZ gates.
380
+ """
381
+ gates = []
382
+ if convert_single_qubit_gate_to_u:
383
+ gates.append(h2u(target_qubit))
384
+ else:
385
+ gates.append(('h',target_qubit))
386
+ gates.append(('cz', control_qubit, target_qubit))
387
+ if convert_single_qubit_gate_to_u:
388
+ gates.append(rx2u(theta/2,target_qubit))
389
+ else:
390
+ gates.append(('rx',theta/2,target_qubit))
391
+ gates.append(('cz', control_qubit, target_qubit))
392
+ if convert_single_qubit_gate_to_u:
393
+ gates.append(rz2u(-1*theta/2, control_qubit))
394
+ gates.append(h2u(target_qubit))
395
+ gates.append(rz2u(-1*theta/2,target_qubit))
396
+ else:
397
+ gates.append(('rz',-1*theta/2,control_qubit))
398
+ gates.append(('h',target_qubit))
399
+ gates.append(('rz',-1*theta/2,target_qubit))
400
+ return gates
401
+
402
+
369
403
  def ccx_decompose(control_qubit1: int, control_qubit2: int, target_qubit: int,):
370
404
  """Decompose ccx gate. Reference: A biological sequence comparison algorithm using quantum computers
371
405
 
@@ -29,16 +29,14 @@ import numpy as np
29
29
  from typing import Literal
30
30
  from itertools import combinations,zip_longest,product
31
31
  from multiprocessing import Pool
32
- from functools import partial,lru_cache
32
+ from functools import partial
33
33
  from .backend import Backend
34
34
 
35
35
  class Layout:
36
36
  """
37
37
  Responsible for selecting suitable qubit layouts from a given chip for a quantum circuit.
38
38
 
39
- This class generates qubit layouts based on the required number of qubits, performance metrics,
40
- and the topology of the chip. It is designed to help map and execute quantum circuits on
41
- specific quantum hardware.
39
+ This class generates qubit layouts based on the required number of qubits, performance metrics, and the topology of the chip. It is designed to help map and execute quantum circuits on specific quantum hardware.
42
40
  """
43
41
  def __init__(self,nqubits: int, chip_backend: Backend):
44
42
  """Initialize the Layout class with the required number of qubits and chip backend.
@@ -51,11 +49,11 @@ class Layout:
51
49
  self.nqubits = nqubits
52
50
  self.size = chip_backend.size
53
51
  self.priority_qubits = chip_backend.priority_qubits
54
- self.graph = chip_backend.edge_filtered_graph()
52
+ self.graph = chip_backend.edge_filtered_graph(thres=0.95)
55
53
  self.ncore = os.cpu_count() // 2
56
54
  self.fidelity_mean_threshold = 0.9
55
+ self.edge_fidelitys = nx.get_edge_attributes(self.graph,'fidelity')
57
56
 
58
- @lru_cache(maxsize=128)
59
57
  def _get_node_neighbours(self,node:int):
60
58
  return list(self.graph.neighbors(node))
61
59
 
@@ -154,7 +152,7 @@ class Layout:
154
152
  """
155
153
  subgraph = self.graph.subgraph(nodes)
156
154
  subgraph_degree = dict(subgraph.degree())
157
- subgraph_fidelity = np.array([data['fidelity'] for _, _, data in subgraph.edges(data=True)])
155
+ subgraph_fidelity = np.array([self.edge_fidelitys[(min(edge),max(edge))] for edge in subgraph.edges])
158
156
  fidelity_mean = np.mean(subgraph_fidelity)
159
157
  fidelity_var = np.var(subgraph_fidelity)
160
158
  if fidelity_mean >= self.fidelity_mean_threshold:
@@ -162,7 +160,7 @@ class Layout:
162
160
  return nodes_info
163
161
  else:
164
162
  return None
165
-
163
+
166
164
  def collect_all_subgraph_info_in_parallel(self):
167
165
  """Collects information about all subgraphs in parallel.
168
166
 
@@ -188,9 +186,8 @@ class Layout:
188
186
  tuple[list, list, list, list]: A tuple containing four lists, each corresponding
189
187
  to one of the four categories of subgraphs.
190
188
  """
191
- cycle_subgraph_list = []
192
- linear1_subgraph_list = []
193
- linear2_subgraph_list = []
189
+
190
+ linear_subgraph_list = []
194
191
  nonlinear_subgraph_list = []
195
192
  all_subgraph_info = self.collect_all_subgraph_info_in_parallel()
196
193
 
@@ -198,22 +195,10 @@ class Layout:
198
195
  nodes,subgraph_degree,fidelity_mean,fidelity_var = subgraph_info
199
196
  nodes_info = (nodes, fidelity_mean, fidelity_var)
200
197
  if max(subgraph_degree.values()) <= 2:
201
- if min(subgraph_degree.values()) == 2:
202
- cycle_subgraph_list.append(nodes_info)
203
- else:
204
- in_a_line = []
205
- for node1, node2 in combinations(nodes,2):
206
- if abs(node1-node2) <= (self.size[1]-1):
207
- in_a_line.append(True)
208
- else:
209
- in_a_line.append(False)
210
- if len(set(in_a_line)) == 1:
211
- linear1_subgraph_list.append(nodes_info)
212
- else:
213
- linear2_subgraph_list.append(nodes_info)
198
+ linear_subgraph_list.append(nodes_info)
214
199
  else:
215
200
  nonlinear_subgraph_list.append(nodes_info)
216
- return linear1_subgraph_list,linear2_subgraph_list,cycle_subgraph_list,nonlinear_subgraph_list
201
+ return linear_subgraph_list,nonlinear_subgraph_list
217
202
 
218
203
  def sort_subgraph_according_mean_fidelity(self, num:int=1, printdetails: bool = True):
219
204
  """Sort each of the four subgraph categories based on the main of fidelity on the edges (couplers),
@@ -226,40 +211,29 @@ class Layout:
226
211
  tuple[list, list, list, list]: Four sorted lists, each corresponding to one of the four
227
212
  subgraph categories, with subgraphs sorted by edge fidelity variance.
228
213
  """
229
- linear1_subgraph_list, linear2_subgraph_list, cycle_subgraph_list, nonlinear_subgraph_list = self.classify_all_subgraph_according_topology()
230
- linear1_subgraph_list_sort = sorted(linear1_subgraph_list,key=lambda x: x[1],reverse=True)
231
- linear2_subgraph_list_sort = sorted(linear2_subgraph_list,key=lambda x: x[1],reverse=True)
232
- cycle_subgraph_list_sort = sorted(cycle_subgraph_list,key=lambda x: x[1],reverse=True)
214
+ linear_subgraph_list, nonlinear_subgraph_list = self.classify_all_subgraph_according_topology()
215
+ linear_subgraph_list_sort = sorted(linear_subgraph_list,key=lambda x: x[1],reverse=True)
233
216
  nonlinear_subgraph_list_sort = sorted(nonlinear_subgraph_list,key=lambda x: x[1],reverse=True)
234
217
  if printdetails:
235
- print(len(linear1_subgraph_list_sort),len(linear2_subgraph_list_sort),len(cycle_subgraph_list_sort),len(nonlinear_subgraph_list_sort))
218
+ print(len(linear_subgraph_list_sort),len(nonlinear_subgraph_list_sort))
236
219
  print('The average fidelity is arranged in descending order,only print the first ten.')
237
220
  length = self.nqubits*5+22
238
221
 
239
- print('{:<3} | {:^{}} | {:^{}} | {:^{}} | {:^{}} |'.format(\
240
- 'idx','subgraph with linear1 topology',length,'subgraph with linear2 topology',length,'subgraph with cycle topology',length,'subgraph with nonlinear topology',length))
241
- for i, (linear1,linear2,cycle,nonlinear) in enumerate(zip_longest(linear1_subgraph_list_sort,\
242
- linear2_subgraph_list_sort,\
243
- cycle_subgraph_list_sort,\
244
- nonlinear_subgraph_list_sort, fillvalue=' ')):
245
- if i >= len(linear1_subgraph_list_sort):
246
- linear1 = ('( )',0.0,0.0)
247
- if i >= len(linear2_subgraph_list_sort):
248
- linear2 = ('( )',0.0,0.0)
249
- if i >= len(cycle_subgraph_list_sort):
250
- cycle = ('( )',0.0,0.0)
222
+ print('{:<3} | {:^{}} | {:^{}} '.format(\
223
+ 'idx','subgraph with linear topology',length,'subgraph with nonlinear topology',length))
224
+ for i, (linear,nonlinear) in enumerate(zip_longest(linear_subgraph_list_sort,nonlinear_subgraph_list_sort, fillvalue=' ')):
225
+ if i >= len(linear_subgraph_list_sort):
226
+ linear = ('( )',0.0,0.0)
251
227
  if i >= len(nonlinear_subgraph_list_sort):
252
228
  nonlinear = ('( )',0.0,0.0)
253
229
  if i <= num:
254
- print('{:<3} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f}'\
230
+ print('{:<3} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} '\
255
231
  .format(i, \
256
- str(linear1[0]),self.nqubits*5,linear1[1],linear1[2],\
257
- str(linear2[0]),self.nqubits*5,linear2[1],linear2[2],\
258
- str(cycle[0]),self.nqubits*5,cycle[1],cycle[2],\
232
+ str(linear[0]),self.nqubits*5,linear[1],linear[2],\
259
233
  str(nonlinear[0]),self.nqubits*5,nonlinear[1],nonlinear[2])\
260
234
  )
261
235
 
262
- return linear1_subgraph_list_sort[:num],linear2_subgraph_list_sort[:num],cycle_subgraph_list_sort[:num],nonlinear_subgraph_list_sort[:num]
236
+ return linear_subgraph_list_sort[:num],nonlinear_subgraph_list_sort[:num]
263
237
 
264
238
  def sort_subgraph_according_var_fidelity(self, num:int = 1, printdetails: bool = True):
265
239
  """
@@ -276,46 +250,47 @@ class Layout:
276
250
  tuple[list, list, list, list]: Four sorted lists, each corresponding to one of the four
277
251
  subgraph categories, with subgraphs sorted by edge fidelity variance.
278
252
  """
279
- linear1_subgraph_list, linear2_subgraph_list, cycle_subgraph_list, nonlinear_subgraph_list = self.classify_all_subgraph_according_topology()
280
- linear1_subgraph_list_sort = sorted(linear1_subgraph_list,key=lambda x: x[2])
281
- linear2_subgraph_list_sort = sorted(linear2_subgraph_list,key=lambda x: x[2])
282
- cycle_subgraph_list_sort = sorted(cycle_subgraph_list,key=lambda x: x[2])
253
+ linear_subgraph_list, nonlinear_subgraph_list = self.classify_all_subgraph_according_topology()
254
+ linear_subgraph_list_sort = sorted(linear_subgraph_list,key=lambda x: x[2])
283
255
  nonlinear_subgraph_list_sort = sorted(nonlinear_subgraph_list,key=lambda x: x[2])
284
256
 
285
257
  if printdetails:
286
- print(len(linear1_subgraph_list_sort),len(linear2_subgraph_list_sort),len(cycle_subgraph_list_sort),len(nonlinear_subgraph_list_sort))
258
+ print(len(linear_subgraph_list_sort),len(nonlinear_subgraph_list_sort))
287
259
  print('The average fidelity is arranged in descending order, only print the first ten.')
288
260
  length = self.nqubits*5+22
289
261
 
290
- print('{:<3} | {:^{}} | {:^{}} | {:^{}} | {:^{}} |'.format(\
291
- 'idx','subgraph with linear1 topology',length,'subgraph with linear2 topology',length,'subgraph with cycle topology',length,'subgraph with nonlinear topology',length))
292
- for i, (linear1,linear2,cycle,nonlinear) in enumerate(zip_longest(linear1_subgraph_list_sort,\
293
- linear2_subgraph_list_sort,\
294
- cycle_subgraph_list_sort,\
295
- nonlinear_subgraph_list_sort, fillvalue=' ')):
296
- if i >= len(linear1_subgraph_list_sort):
297
- linear1 = ('( )',0.0,0.0)
298
- if i >= len(linear2_subgraph_list_sort):
299
- linear2 = ('( )',0.0,0.0)
300
- if i >= len(cycle_subgraph_list_sort):
301
- cycle = ('( )',0.0,0.0)
262
+ print('{:<3} | {:^{}} | {:^{}} '.format(\
263
+ 'idx','subgraph with linear topology',length,'subgraph with nonlinear topology',length))
264
+ for i, (linear,nonlinear) in enumerate(zip_longest(linear_subgraph_list_sort, nonlinear_subgraph_list_sort, fillvalue=' ')):
265
+ if i >= len(linear_subgraph_list_sort):
266
+ linear = ('( )',0.0,0.0)
302
267
  if i >= len(nonlinear_subgraph_list_sort):
303
268
  nonlinear = ('( )',0.0,0.0)
304
269
 
305
270
  if i <= num:
306
- print('{:<3} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f}'\
271
+ print('{:<3} | {:<{}} {:<10.6f} {:<10.6f} | {:<{}} {:<10.6f} {:<10.6f} '\
307
272
  .format(i, \
308
- str(linear1[0]),self.nqubits*5,linear1[1],linear1[2],\
309
- str(linear2[0]),self.nqubits*5,linear2[1],linear2[2],\
310
- str(cycle[0]),self.nqubits*5,cycle[1],cycle[2],\
273
+ str(linear[0]),self.nqubits*5,linear[1],linear[2],\
311
274
  str(nonlinear[0]),self.nqubits*5,nonlinear[1],nonlinear[2])\
312
275
  )
313
276
 
314
- return linear1_subgraph_list_sort[:num],linear2_subgraph_list_sort[:num],cycle_subgraph_list_sort[:num],nonlinear_subgraph_list_sort[:num]
277
+ return linear_subgraph_list_sort[:num], nonlinear_subgraph_list_sort[:num]
278
+
279
+ def select_qubit_from_backend(self,):
280
+ # 当线路中只有一个qubit时,挑选单比特门保真度最大的比特
281
+
282
+ for nodes in nx.connected_components(self.graph):
283
+ if len(nodes) > 1:
284
+ subgraph = self.graph.subgraph(nodes)
285
+ break
286
+ node_fidelity_dic = nx.get_node_attributes(subgraph,'fidelity')
287
+ sorted_dict = dict(sorted(node_fidelity_dic.items(), key=lambda item: item[1], reverse=True))
288
+ qubit = list(sorted_dict.keys())[0]
289
+ return qubit, sorted_dict[qubit]
315
290
 
316
291
  def select_layout_from_backend(self,
317
292
  key: Literal['fidelity_mean', 'fidelity_var'] = 'fidelity_var',
318
- topology: Literal['cycle', 'linear1', 'linear', 'nonlinear'] = 'linear1',
293
+ topology: Literal['linear', 'nonlinear'] = 'linear',
319
294
  printdetails: bool = False):
320
295
  """
321
296
  Select a qubit layout based on the given performance metric and topology.
@@ -336,28 +311,16 @@ class Layout:
336
311
  list: A list of qubits representing the selected layout.
337
312
  """
338
313
  if key == 'fidelity_mean':
339
- linear1_list,linear2_list,cycle_list,nonlinear_list = self.sort_subgraph_according_mean_fidelity(printdetails=printdetails)
314
+ linear_list,nonlinear_list = self.sort_subgraph_according_mean_fidelity(printdetails=printdetails)
340
315
  elif key == 'fidelity_var':
341
- linear1_list,linear2_list,cycle_list,nonlinear_list = self.sort_subgraph_according_var_fidelity(printdetails=printdetails)
316
+ linear_list,nonlinear_list = self.sort_subgraph_according_var_fidelity(printdetails=printdetails)
342
317
 
343
- if topology == 'linear1':
344
- if len(linear1_list) == 0:
318
+ if topology == 'linear':
319
+ if len(linear_list) == 0:
345
320
  print(f'There is no {self.nqubits} qubits that meets both key = {key} and topology = {topology}. Please change the conditions.')
346
321
  return [] #exit(1)
347
322
  else:
348
- return linear1_list[0][0]
349
- elif topology == 'linear2':
350
- if len(linear2_list) == 0:
351
- print(f'There is no {self.nqubits} qubits that meets both key = {key} and topology = {topology}. Please change the conditions.')
352
- return [] #exit(1)
353
- else:
354
- return linear2_list[0][0]
355
- elif topology == 'cycle':
356
- if len(cycle_list) == 0:
357
- print(f'There is no {self.nqubits} qubits that meets both key = {key} and topology = {topology}. Please change the conditions.')
358
- return [] #exit(1)
359
- else:
360
- return cycle_list[0][0]
323
+ return linear_list[0][0]
361
324
  elif topology == 'nonlinear':
362
325
  if len(nonlinear_list) == 0:
363
326
  print(f'There is no {self.nqubits} qubits that meets both key = {key} and topology = {topology}. Please change the conditions.')
@@ -368,7 +331,7 @@ class Layout:
368
331
  def select_layout(self,
369
332
  target_qubits:list = [],
370
333
  use_chip_priority: bool = True,
371
- select_criteria: dict = {'key':'fidelity_var','topology':'linear1'},
334
+ select_criteria: dict = {'key':'fidelity_var','topology':'linear'},
372
335
  ):
373
336
 
374
337
  if target_qubits != []:
@@ -391,47 +354,109 @@ class Layout:
391
354
  if is_connected is False:
392
355
  raise(ValueError(f'The physical qubit layout {target_qubits} constructed from target_qubits is not connected.'))
393
356
  coupling_map = list(subgraph.edges)
394
- print(f'Physical qubits layout {target_qubits} are user-defined, with the corresponding coupling being {coupling_map}.')
395
- subgraph_fidelity = np.array([data['fidelity'] for _, _, data in subgraph.edges(data=True)])
396
- fidelity_mean = np.mean(subgraph_fidelity)
397
- fidelity_var = np.var(subgraph_fidelity)
398
- print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
357
+ print(f'Physical qubits layout {target_qubits} are user-defined, with the corresponding coupling being {coupling_map}.')
358
+
359
+ if len(subgraph.edges())>0:
360
+ subgraph_fidelity = np.array([self.edge_fidelitys[(min(edge),max(edge))] for edge in subgraph.edges])
361
+ fidelity_mean = np.mean(subgraph_fidelity)
362
+ fidelity_var = np.var(subgraph_fidelity)
363
+ print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
399
364
  return subgraph
400
- if use_chip_priority: # 如果列表中没有满足的比特则启动筛选,todos:把筛选机制转成数据库
365
+ if use_chip_priority: # 如果列表中没有满足的比特则启动筛选,如果是单比特则保留原比特,不再筛选,todos:把筛选机制转成数据库
401
366
  priority_qubits_list = self.priority_qubits
402
367
  for qubits in priority_qubits_list:
403
368
  if len(qubits) == self.nqubits:
404
369
  subgraph = self.graph.subgraph(qubits)
405
- coupling_map = list(subgraph.edges)
406
- print(f'Physical qubits layout {list(qubits)} are derived from the chip backend priority qubits, with the corresponding coupling being {coupling_map}.')
407
- subgraph_fidelity = np.array([data['fidelity'] for _, _, data in subgraph.edges(data=True)])
408
- fidelity_mean = np.mean(subgraph_fidelity)
409
- fidelity_var = np.var(subgraph_fidelity)
410
- print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
411
- return subgraph
370
+ if nx.is_connected(subgraph):
371
+ coupling_map = list(subgraph.edges)
372
+ print(f'Physical qubits layout {list(qubits)} are derived from the chip backend priority qubits, with the corresponding coupling being {coupling_map}.')
373
+ if len(subgraph.edges())>0:
374
+ subgraph_fidelity = np.array([self.edge_fidelitys[(min(edge),max(edge))] for edge in subgraph.edges])
375
+ fidelity_mean = np.mean(subgraph_fidelity)
376
+ fidelity_var = np.var(subgraph_fidelity)
377
+ print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
378
+ return subgraph
412
379
  print(f'No priority qubits with {self.nqubits} qubits found. it will check the select_criteria for search')
413
380
 
414
- key_first = select_criteria['key']
415
- topology_first = select_criteria['topology']
416
- all_keys = ['fidelity_var','fidelity_mean']
417
- all_topologys = ['linear1','linear2','cycle','nonlinear']
418
- all_keys.remove(key_first)
419
- all_topologys.remove(topology_first)
420
- sorted_keys = [key_first,] + all_keys
421
- sorted_topologys = [topology_first,] + all_topologys
422
- physical_qubits_layout = []
423
- for key, topology in product(sorted_keys,sorted_topologys):
424
- physical_qubits_layout = self.select_layout_from_backend(key=key,topology=topology)
425
- if physical_qubits_layout != []:
426
- break
427
- if physical_qubits_layout == []:
428
- raise(ValueError(f'Unable to find a suitable layout. If this message appears, please contact the developer for assistance.'))
429
- physical_qubits_layout = list(physical_qubits_layout)
430
- subgraph = self.graph.subgraph(physical_qubits_layout)
431
- coupling_map = list(subgraph.edges)
432
- print(f'Physical qubits layout {physical_qubits_layout} are selected by the Transpile algorithm using key = {key} and topology = {topology}, \nwith the corresponding coupling being {coupling_map}.')
433
- subgraph_fidelity = np.array([data['fidelity'] for _, _, data in subgraph.edges(data=True)])
434
- fidelity_mean = np.mean(subgraph_fidelity)
435
- fidelity_var = np.var(subgraph_fidelity)
436
- print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
437
- return subgraph
381
+ if self.nqubits == 1:
382
+ qubit, fidelity = self.select_qubit_from_backend()
383
+ #The selected qubit has the highest single-qubit gate fidelity.
384
+ print(f'The selected physical qubit {qubit} is recommend, with single-qubit gate fidelity {fidelity}')
385
+ subgraph = self.graph.subgraph([qubit])
386
+ return subgraph
387
+ elif 1< self.nqubits <= 10:
388
+ key_first = select_criteria['key']
389
+ topology_first = select_criteria['topology']
390
+ all_keys = ['fidelity_var','fidelity_mean']
391
+ all_topologys = ['linear','nonlinear']
392
+ all_keys.remove(key_first)
393
+ all_topologys.remove(topology_first)
394
+ sorted_keys = [key_first,] + all_keys
395
+ sorted_topologys = [topology_first,] + all_topologys
396
+ physical_qubits_layout = []
397
+ for key, topology in product(sorted_keys,sorted_topologys):
398
+ physical_qubits_layout = self.select_layout_from_backend(key=key,topology=topology)
399
+ if physical_qubits_layout != []:
400
+ break
401
+ if physical_qubits_layout == []:
402
+ raise(ValueError(f'Unable to find a suitable layout. If this message appears, please contact the developer for assistance.'))
403
+ physical_qubits_layout = list(physical_qubits_layout)
404
+ subgraph = self.graph.subgraph(physical_qubits_layout)
405
+ coupling_map = list(subgraph.edges)
406
+ print(f'Physical qubits layout {physical_qubits_layout} are selected by the Transpile algorithm using key = {key} and topology = {topology}, \nwith the corresponding coupling being {coupling_map}.')
407
+ subgraph_fidelity = np.array([self.edge_fidelitys[(min(edge),max(edge))] for edge in subgraph.edges])
408
+ fidelity_mean = np.mean(subgraph_fidelity)
409
+ fidelity_var = np.var(subgraph_fidelity)
410
+ print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
411
+ return subgraph
412
+ elif self.nqubits >10:
413
+ physical_qubits_layout = self.get_BFS_layout()
414
+ subgraph = self.graph.subgraph(physical_qubits_layout)
415
+ coupling_map = list(subgraph.edges)
416
+ print(f'Physical qubits layout {physical_qubits_layout} are selected by BFS algorithm with the corresponding coupling being {coupling_map}.')
417
+ subgraph_fidelity = np.array([self.edge_fidelitys[(min(edge),max(edge))] for edge in subgraph.edges])
418
+ fidelity_mean = np.mean(subgraph_fidelity)
419
+ fidelity_var = np.var(subgraph_fidelity)
420
+ print(f'The average fidelity of the coupler(s) between the selected qubits is {fidelity_mean}, and the variance of the fidelity is {fidelity_var}.')
421
+ return subgraph
422
+ else:
423
+ raise(ValueError('Wrong qubits error!'))
424
+
425
+ # large qubit layour
426
+ def get_one_component(self):
427
+ components = list(nx.connected_components(self.graph))
428
+ for i, comp in enumerate(components):
429
+ if len(comp)>=self.nqubits:
430
+ return comp
431
+ raise(ValueError(f'The user circuit requires {self.nqubits} more qubits than are available in the largest connected subgraph.'))
432
+
433
+ def get_BFS_layout(self):
434
+ """ Perform a breadth-first search (BFS) on the graph starting from the start node,
435
+ collecting up to `nqubits` unique nodes including the start node.
436
+
437
+ Returns:
438
+ list: A list of up to `nqubits` unique nodes, discovered in BFS order.
439
+ """
440
+ comp = self.get_one_component()
441
+ one_subgraph = self.graph.subgraph(comp)
442
+
443
+ if self.priority_qubits is None:
444
+ start_node = np.random.choice(comp)
445
+ else:
446
+ priority_qubits_list = list(set(i for sublist in self.priority_qubits for i in sublist))
447
+ start_node = np.random.choice(priority_qubits_list)
448
+
449
+ visited = set([start_node])
450
+ queue = [(start_node, 0)]
451
+
452
+ while queue and len(visited) < self.nqubits:
453
+ current_node, depth = queue.pop(0)
454
+ if depth >= self.nqubits - 1:
455
+ continue
456
+ for neighbor in one_subgraph.neighbors(current_node):
457
+ if neighbor not in visited:
458
+ visited.add(neighbor)
459
+ queue.append((neighbor, depth + 1))
460
+ if len(visited) == self.nqubits:
461
+ break
462
+ return list(visited)
@@ -316,6 +316,16 @@ def rzz_mat(theta: float) -> np.ndarray:
316
316
  ], dtype=complex
317
317
  )
318
318
 
319
+ def cp_mat(theta: float) -> np.ndarray:
320
+ return np.array(
321
+ [
322
+ [1, 0, 0, 0],
323
+ [0, 1, 0, 0],
324
+ [0, 0, 1, 0],
325
+ [0, 0, 0, np.exp(1j*theta)]
326
+ ], dtype=complex
327
+ )
328
+
319
329
  gate_matrix_dict = {
320
330
  'id':id_mat, 'x':x_mat, 'y':y_mat, 'z':z_mat, 'h':h_mat,
321
331
  's':s_mat, 'sdg':sdg_mat, 't':t_mat, 'tdg':tdg_mat, 'sx':sx_mat, 'sxdg':sxdg_mat,
@@ -323,5 +333,6 @@ gate_matrix_dict = {
323
333
  'cx':cx_mat, 'cnot':cx_mat, 'cy':cy_mat, 'cz':cz_mat,
324
334
  'rx':rx_mat, 'ry':ry_mat, 'rz':rz_mat,
325
335
  'p':p_mat, 'u':u_mat,'r':r_mat,
326
- 'rxx':rxx_mat,'ryy':ryy_mat,'rzz':rzz_mat,'ccz':ccz_mat,'ccx':ccx_mat,'cswap':cswap_mat,
336
+ 'rxx':rxx_mat,'ryy':ryy_mat,'rzz':rzz_mat, 'cp':cp_mat,
337
+ 'ccz':ccz_mat,'ccx':ccx_mat,'cswap':cswap_mat,
327
338
  }