Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/qc_compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
DEFAULT_TWO_QUBIT_ERROR,
DEFAULT_TWO_QUBIT_GATE_TIME,
TWO_QUBIT_GATES,
clbit_index,
compute_circuit_depth,
compute_cnot_count,
compute_idle_fraction,
get_avg_gate_time,
get_backend_properties,
qubit_index,
)

__all__ = [
Expand Down Expand Up @@ -63,9 +65,11 @@
"QCompilerResult",
"ScheduleResult",
"TranspileConfig",
"clbit_index",
"compute_circuit_depth",
"compute_cnot_count",
"compute_idle_fraction",
"get_avg_gate_time",
"get_backend_properties",
"qubit_index",
]
7 changes: 4 additions & 3 deletions src/qc_compiler/batching.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from qiskit import QuantumCircuit

from qc_compiler.cost_model import CostModel
from qc_compiler.utils import qubit_index


@dataclass
Expand Down Expand Up @@ -298,7 +299,7 @@ def _compute_core_hash(self, circuit: QuantumCircuit) -> int:
gate_name = instr.operation.name
if gate_name in ("measure", "barrier", "reset", "snapshot"):
continue
qubits = tuple(circuit.find_bit(q).index for q in instr.qubits)
qubits = tuple(qubit_index(circuit, q) for q in instr.qubits)
params = tuple(
float(p) if hasattr(p, '__float__') else str(p)
for p in instr.operation.params
Expand Down Expand Up @@ -328,7 +329,7 @@ def _detect_measurement_basis(
if instr.operation.name == "measure":
measure_indices.add(idx)
for q in instr.qubits:
measured_qubits.add(circuit.find_bit(q).index)
measured_qubits.add(qubit_index(circuit, q))

if not measured_qubits:
return "none"
Expand All @@ -347,7 +348,7 @@ def _detect_measurement_basis(
if instr.operation.name in ("measure", "barrier", "reset", "snapshot"):
continue
if len(instr.qubits) == 1:
qubit_idx = circuit.find_bit(instr.qubits[0]).index
qubit_idx = qubit_index(circuit, instr.qubits[0])
if qubit_idx in measured_qubits:
pre_measure_gates[qubit_idx].append(
instr.operation.name
Expand Down
5 changes: 3 additions & 2 deletions src/qc_compiler/cost_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
TWO_QUBIT_GATES,
compute_circuit_depth,
get_backend_properties,
qubit_index,
)

SINGLE_QUBIT_GATES = {"id", "rz", "sx", "x", "h", "s", "t", "p", "u", "u1", "u2", "u3"}
Expand Down Expand Up @@ -212,7 +213,7 @@ def estimate_gate_error(
for instr in circuit.data:
gate_name = instr.operation.name
qubits = tuple(
circuit.find_bit(q).index for q in instr.qubits
qubit_index(circuit, q) for q in instr.qubits
)
if len(qubits) == 2 and gate_name in TWO_QUBIT_GATES:
fidelity = self._get_gate_fidelity_for_pair(
Expand Down Expand Up @@ -473,7 +474,7 @@ def _get_measured_qubits(self, circuit: QuantumCircuit) -> list[int]:
for instr in circuit.data:
if instr.operation.name == "measure":
for qubit in instr.qubits:
measured.add(circuit.find_bit(qubit).index)
measured.add(qubit_index(circuit, qubit))
if not measured:
return []
return sorted(measured)
Expand Down
7 changes: 4 additions & 3 deletions src/qc_compiler/cutting.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
DEFAULT_T2_TIME,
DEFAULT_TWO_QUBIT_ERROR,
TWO_QUBIT_GATES,
qubit_index,
)


Expand Down Expand Up @@ -367,7 +368,7 @@ def _find_cut_candidates(
for idx, instr in enumerate(circuit.data):
gate_name = instr.operation.name
qubits = tuple(
circuit.find_bit(q).index for q in instr.qubits
qubit_index(circuit, q) for q in instr.qubits
)

if gate_name in TWO_QUBIT_GATES and len(qubits) == 2:
Expand Down Expand Up @@ -596,7 +597,7 @@ def union(x, y):

for idx, instr in enumerate(circuit.data):
qubits = tuple(
circuit.find_bit(q).index for q in instr.qubits
qubit_index(circuit, q) for q in instr.qubits
)
if len(qubits) == 2:
q0, q1 = qubits
Expand Down Expand Up @@ -638,7 +639,7 @@ def _extract_subcircuit(

for idx, instr in enumerate(circuit.data):
gate_qubits = tuple(
circuit.find_bit(q).index for q in instr.qubits
qubit_index(circuit, q) for q in instr.qubits
)

if idx in cut_gate_indices:
Expand Down
5 changes: 3 additions & 2 deletions src/qc_compiler/fusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from qiskit.synthesis import OneQubitEulerDecomposer

from qc_compiler.cost_model import CircuitMetrics, CostModel
from qc_compiler.utils import qubit_index


@dataclass
Expand Down Expand Up @@ -302,7 +303,7 @@ def _find_single_qubit_chains(

affected_qubits = set()
for q in instr.qubits:
qidx = circuit.find_bit(q).index
qidx = qubit_index(circuit, q)
affected_qubits.add(qidx)
for q in affected_qubits:
if q in active_chains:
Expand All @@ -314,7 +315,7 @@ def _find_single_qubit_chains(
continue

if len(instr.qubits) == 1:
qubit_idx = circuit.find_bit(instr.qubits[0]).index
qubit_idx = qubit_index(circuit, instr.qubits[0])

if qubit_idx in active_chains:
active_chains[qubit_idx][2].append(idx)
Expand Down
30 changes: 15 additions & 15 deletions src/qc_compiler/scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from qiskit import QuantumCircuit

from qc_compiler.cost_model import CostModel
from qc_compiler.utils import DEFAULT_SINGLE_QUBIT_GATE_TIME
from qc_compiler.utils import DEFAULT_SINGLE_QUBIT_GATE_TIME, clbit_index, qubit_index


@dataclass
Expand Down Expand Up @@ -214,14 +214,14 @@ def _asap_schedule(self, circuit: QuantumCircuit) -> QuantumCircuit:

for instr in circuit.data:
gate = instr.operation
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]

earliest_cycle = max(qubit_next_cycle[q] for q in qubits) if qubits else 0

gate_duration = self._get_gate_duration(gate.name, qubits)

target_qubits = [circuit.qubits[q] for q in qubits]
target_clbits = [circuit.find_bit(c).index for c in instr.clbits]
target_clbits = [clbit_index(circuit, c) for c in instr.clbits]
clbit_refs = [scheduled.clbits[i] for i in target_clbits] if target_clbits else []

scheduled.append(gate, target_qubits, clbit_refs)
Expand Down Expand Up @@ -271,7 +271,7 @@ def _alap_schedule(self, circuit: QuantumCircuit) -> QuantumCircuit:

for i in range(len(circuit.data) - 1, -1, -1):
instr = circuit.data[i]
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]

if not qubits:
gate_latest_start[i] = 0
Expand Down Expand Up @@ -299,9 +299,9 @@ def _alap_schedule(self, circuit: QuantumCircuit) -> QuantumCircuit:
for i in gate_order:
instr = circuit.data[i]
gate = instr.operation
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]
target_qubits = [circuit.qubits[q] for q in qubits]
target_clbits = [circuit.find_bit(c).index for c in instr.clbits]
target_clbits = [clbit_index(circuit, c) for c in instr.clbits]
clbit_refs = [scheduled.clbits[j] for j in target_clbits] if target_clbits else []

scheduled.append(gate, target_qubits, clbit_refs)
Expand Down Expand Up @@ -351,23 +351,23 @@ def _coherence_aware_schedule(

qubit_first_gate = [-1] * circuit.num_qubits
for i, instr in enumerate(circuit.data):
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]
for q in qubits:
if qubit_first_gate[q] == -1:
qubit_first_gate[q] = i

for i, instr in enumerate(circuit.data):
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]
for q in qubits:
if qubit_latest_gate[q] >= 0:
predecessors[i].add(qubit_latest_gate[q])
qubit_latest_gate[q] = i

for i in range(num_gates - 1):
if circuit.data[i].operation.name == "barrier":
for q in [circuit.find_bit(q).index for q in circuit.data[i].qubits]:
for q in [qubit_index(circuit, q) for q in circuit.data[i].qubits]:
for j in range(i + 1, num_gates):
jqubits = [circuit.find_bit(q).index for q in circuit.data[j].qubits]
jqubits = [qubit_index(circuit, q) for q in circuit.data[j].qubits]
if q in jqubits:
predecessors[j].add(i)

Expand All @@ -391,15 +391,15 @@ def _coherence_aware_schedule(
if not ready:
break

ready.sort(key=lambda i: min(t2_priority.get(q, float('inf')) for q in [circuit.find_bit(q).index for q in circuit.data[i].qubits]) if circuit.data[i].qubits else float('inf'))
ready.sort(key=lambda i: min(t2_priority.get(q, float('inf')) for q in [qubit_index(circuit, q) for q in circuit.data[i].qubits]) if circuit.data[i].qubits else float('inf'))

gate_idx = ready[0]

instr = circuit.data[gate_idx]
gate = instr.operation
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]
target_qubits = [circuit.qubits[q] for q in qubits]
target_clbits = [circuit.find_bit(c).index for c in instr.clbits]
target_clbits = [clbit_index(circuit, c) for c in instr.clbits]
clbit_refs = [scheduled.clbits[j] for j in target_clbits] if target_clbits else []

scheduled.append(gate, target_qubits, clbit_refs)
Expand Down Expand Up @@ -440,7 +440,7 @@ def _compute_idle_times(
qubit_active_cycles = {q: 0 for q in range(circuit.num_qubits)}
for instr in circuit.data:
for qubit in instr.qubits:
qidx = circuit.find_bit(qubit).index
qidx = qubit_index(circuit, qubit)
qubit_active_cycles[qidx] += 1

idle_times = {}
Expand All @@ -464,7 +464,7 @@ def _compute_asap_starts(self, circuit: QuantumCircuit) -> list[int]:
starts = []

for instr in circuit.data:
qubits = [circuit.find_bit(q).index for q in instr.qubits]
qubits = [qubit_index(circuit, q) for q in instr.qubits]
if not qubits:
starts.append(0)
continue
Expand Down
29 changes: 29 additions & 0 deletions src/qc_compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,35 @@
DEFAULT_TWO_QUBIT_GATE_TIME = 300e-9


def qubit_index(circuit: QuantumCircuit, qubit) -> int:
"""Get the integer index of a qubit in a circuit.

Uses circuit.find_bit() for compatibility, but can be updated
if Qiskit deprecates find_bit in a future release.

Args:
circuit: The quantum circuit.
qubit: A qubit reference from circuit.data.

Returns:
Integer index of the qubit.
"""
return circuit.find_bit(qubit).index


def clbit_index(circuit: QuantumCircuit, clbit) -> int:
"""Get the integer index of a classical bit in a circuit.

Args:
circuit: The quantum circuit.
clbit: A classical bit reference from circuit.data.

Returns:
Integer index of the classical bit.
"""
return circuit.find_bit(clbit).index


def get_backend_properties(backend: BackendV2) -> dict:
"""Extract calibration properties from a quantum backend.

Expand Down
Loading