-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcompilation.py
116 lines (93 loc) · 3.83 KB
/
compilation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import math
import re
from pathlib import Path
from qiskit.dagcircuit import DAGDependency
def is_qasm_file(filename):
# Check if the file has a .qasm extension
if not filename.endswith(".qasm"):
return False
try:
file_path = Path(filename)
with Path.open(file_path) as file:
# Read the first line of the file (7th line, specific to MQT Bench)
for _f in range(7):
first_line = file.readline()
# Check if the first line contains the OPENQASM identifier
return "OPENQASM" in first_line
except OSError:
# If the file cannot be opened, return False
return False
def extract_qubits_from_gate(gate_line):
"""Extract qubit numbers from a gate operation line."""
# Regular expression to match qubits (assuming they are in the format q[<number>])
pattern = re.compile(r"q\[(\d+)\]")
matches = pattern.findall(gate_line)
# Convert matched qubit numbers to integers
return [int(match) for match in matches]
def parse_qasm(filename):
"""Parse a QASM file and return qubits used for each gate, preserving their order."""
gates_and_qubits = []
# if filename is str
if not isinstance(filename, Path):
filename = Path(filename)
with Path.open(filename) as file:
for _line in file:
line = _line.strip()
# Check if line represents a gate operation
if not line.startswith(("OPENQASM", "include", "qreg", "creg", "gate", "barrier", "measure")):
qubits = extract_qubits_from_gate(line)
if qubits:
gates_and_qubits.append(tuple(qubits))
return gates_and_qubits
def get_front_layer(dag):
"""Get the front layer of the DAG."""
front_layer = []
for node in dag.get_nodes():
# If a node has no predecessors, it's in the front layer
if not dag.direct_predecessors(node.node_id):
front_layer.append(node)
return front_layer
def remove_node(dag, node):
"""Execute a node and update the DAG (remove the node and its edges)."""
# if dag.direct_successors(node.node_id):
# for successor in dag.direct_successors(node.node_id):
# dag._multi_graph.remove_edge(node.node_id, successor)
dag._multi_graph.remove_node(node.node_id)
def find_best_gate(front_layer, dist_map):
"""Find the best gate to execute based on distance."""
min_gate_cost = math.inf
for _i, gate_node in enumerate(front_layer):
qubit_indices = gate_node.qindices
gate_cost = max([dist_map[qs] for qs in qubit_indices])
# if both ions of 2-qubit gate are in pz execute 2-qubit gate
if len(qubit_indices) == 2 and gate_cost == 0:
return gate_node
if gate_cost < min_gate_cost:
min_gate_cost = gate_cost
best_gate = gate_node
return best_gate
def manual_copy_dag(dag):
new_dag = DAGDependency()
# Recreate quantum registers in the new DAG
for qreg in dag.qregs.values():
new_dag.add_qreg(qreg)
# Iterate over all operation nodes in the original DAG and copy them
for node in dag.get_nodes():
new_dag.add_op_node(node.op, node.qargs, node.cargs)
return new_dag
def update_sequence(dag, dist_map):
"""Get the sequence of gates from the DAG. Creates a new DAG and removes all gates from it while creating the sequence."""
working_dag = manual_copy_dag(dag)
sequence = []
i = 0
while True:
first_gates = get_front_layer(working_dag)
if not first_gates:
break
first_gate_to_excute = find_best_gate(first_gates, dist_map)
if i == 0:
first_node = first_gate_to_excute
i = 1
remove_node(working_dag, first_gate_to_excute)
sequence.append(first_gate_to_excute.qindices)
return sequence, first_node