Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
benchmark.py
Go to the documentation of this file.
1 from squander.partitioning.partition import PartitionCircuitQasm, kahn_partition, translate_param_order
2 import glob
3 import os
4 from qiskit import QuantumCircuit
5 from qiskit.transpiler import PassManager
6 from qiskit.transpiler.passes import CollectMultiQBlocks, ConsolidateBlocks
7 from squander import utils
8 
9 import asyncio
10 from bqskit import Circuit
11 import bqskit.ir
12 from bqskit.passes.partitioning.quick import QuickPartitioner
13 from bqskit.passes.partitioning.greedy import GreedyPartitioner #too slow
14 from bqskit.passes.partitioning.cluster import ClusteringPartitioner #does a bad job at minimizing partitions
15 from bqskit.passes.partitioning.scan import ScanPartitioner
16 
17 bqs_to_squander = {bqskit.ir.gates.constant.cx.CNOTGate: "CNOT",
18  bqskit.ir.gates.constant.t.TGate: "T",
19  bqskit.ir.gates.constant.h.HGate: "H",
20  bqskit.ir.gates.constant.tdg.TdgGate: "TDG",
21  bqskit.ir.gates.constant.x.XGate: "X",
22  bqskit.ir.gates.constant.y.YGate: "Y",
23  bqskit.ir.gates.constant.z.ZGate: "Z",
24  bqskit.ir.gates.constant.sx.SXGate: "SX",
25  bqskit.ir.gates.constant.ch.CHGate: "CH",
26  bqskit.ir.gates.constant.cz.CZGate: "CZ",
27  bqskit.ir.gates.parameterized.cry.CRYGate: "CRY",
28  bqskit.ir.gates.parameterized.u3.U3Gate: "U3",
29  bqskit.ir.gates.parameterized.rz.RZGate: "RZ",
30  bqskit.ir.gates.parameterized.ry.RYGate: "RY",
31  bqskit.ir.gates.parameterized.rx.RXGate: "RX",}
32 
33 def get_qiskit_partitions(circ, qc, max_partition_size):
34  pm = PassManager([
35  CollectMultiQBlocks(max_block_size=max_partition_size),
36  ])
37  pm.run(qc)
38  blocks = pm.property_set['block_list']
39  L = [{(frozenset(qc.find_bit(x)[0] for x in dagop.qargs), dagop.name.upper().replace("CX", "CNOT")) for dagop in block} for block in blocks]
40  assert len(qc.data) == sum(map(len, blocks))
41  return kahn_partition(circ, max_partition_size, L)
42 
43 def do_get_qiskit_partitions(filename, max_partition_size):
44  circ, parameters, qc = utils.qasm_to_squander_circuit(filename, True)
45  partitioned_circ, param_order, _ = get_qiskit_partitions(circ, qc, max_partition_size)
46  param_reordered = translate_param_order(parameters, param_order)
47  return partitioned_circ, param_reordered
48 
49 def get_bqskit_partitions(filename, partitioner, max_partition_size):
50  if partitioner == "Quick":
51  partitioner = QuickPartitioner(block_size=max_partition_size)
52  elif partitioner == "Scan":
53  partitioner = ScanPartitioner(block_size=max_partition_size)
54  elif partitioner == "Greedy":
55  partitioner = GreedyPartitioner(block_size=max_partition_size)
56  elif partitioner == "Cluster":
57  partitioner = ClusteringPartitioner(block_size=max_partition_size)
58  bq_circuit = Circuit.from_file(filename)
59  asyncio.run(partitioner.run(bq_circuit, None))
60  # Count number of blocks (partitions)
61  circ, parameters, qc = utils.qasm_to_squander_circuit(filename, True)
62  L = [{(frozenset(curloc.location[x] for x in op.location), bqs_to_squander[type(op.gate)]) for op in curloc.gate._circuit.operations()} for curloc in bq_circuit.operations()]
63  return kahn_partition(circ, max_partition_size, L)
65  max_partition_size = 4
66  files = glob.glob("benchmarks/partitioning/test_circuit/*.qasm")
67  print("Total QASM:", len(files))
68  allfiles = {}
69  for filename in files:
70  qc = QuantumCircuit.from_qasm_file(filename)
71  num_gates = len(qc.data)
72  fname = os.path.basename(filename)
73  print(f"{fname} qubits {qc.num_qubits} gates {num_gates}")
74  if num_gates > 1024:
75  continue
76  res = {}
77  partitioned_circuit, parameters = PartitionCircuitQasm( filename, max_partition_size )
78  res["Greedy"] = len(partitioned_circuit.get_Gates())
79  print("ILP")
80  partitioned_circuit_ilp, parameters_ilp = PartitionCircuitQasm( filename, max_partition_size, True )
81  res["ILP"] = len(partitioned_circuit_ilp.get_Gates())
82  res["Qiskit"] = do_get_qiskit_partitions(filename, max_partition_size)
83  for name in ("Quick", "Greedy", "Scan", "Cluster"):
84  print(name)
85  res[f"BQSKit-{name}"] = get_bqskit_partitions(filename, name, max_partition_size)
86  allfiles[fname] = (qc.num_qubits, num_gates, res)
87  print(fname, allfiles[fname])
88  print(allfiles)
89  import matplotlib.pyplot as plt
90  sorted_items = sorted(allfiles.items(), key=lambda item: (item[1][0], item[1][1]))
91  circuits_sorted = [name for name, _ in sorted_items]
92  markers = ["o", "*", "D", "s"]
93  for i, strat in enumerate(("Greedy","ILP","Qiskit", "BQSKit-Quick")):
94  y = [allfiles[name][2][strat] for name in circuits_sorted]
95  plt.plot(circuits_sorted, y, marker=markers[i], label=strat)
96  plt.xlabel("Circuit (sorted by qubits, gates)")
97  plt.ylabel("Partition Count")
98  plt.title("Partition Count per Circuit by Strategy")
99  plt.xticks(rotation=45, ha="right")
100  plt.legend()
101  plt.tight_layout()
102  plt.grid(True)
103  plt.savefig("partition_counts.svg", format="svg", transparent=True)
104 
105 if __name__ == "__main__":
def translate_param_order
Definition: partition.py:187
def test_partitions()
Definition: benchmark.py:64
def do_get_qiskit_partitions(filename, max_partition_size)
Definition: benchmark.py:43
def PartitionCircuitQasm
Definition: partition.py:242
def get_bqskit_partitions(filename, partitioner, max_partition_size)
Definition: benchmark.py:49
def get_qiskit_partitions(circ, qc, max_partition_size)
Definition: benchmark.py:33
def kahn_partition(c, max_qubit, preparts=None)
Definition: partition.py:25