Fix AerCompiler to use custom pass manager to decompose control flow ops (#2095)

* Fix AerCompiler to use basis_gates built from input circuit

* use custom pass manager to decompose dontrol flow ops

* remove unused import
This commit is contained in:
Jun Doi 2024-04-11 16:55:57 +09:00 committed by GitHub
parent c0420ea7b5
commit cf510a2a45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 32 deletions

View File

@ -36,7 +36,10 @@ from qiskit.circuit.controlflow import (
SwitchCaseOp,
CASE_DEFAULT,
)
from qiskit.compiler import transpile
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import Decompose
from qiskit.qobj import QobjExperimentHeader
from qiskit_aer.aererror import AerError
from qiskit_aer.noise import NoiseModel
@ -67,13 +70,11 @@ class AerCompiler:
def __init__(self):
self._last_flow_id = -1
def compile(self, circuits, basis_gates=None, optypes=None):
def compile(self, circuits, optypes=None):
"""compile a circuit that have control-flow instructions.
Args:
circuits (QuantumCircuit or list): The QuantumCircuits to be compiled
basis_gates (list): basis gates to decompose sub-circuits
(default: None).
optypes (list): list of instruction type sets for each circuit
(default: None).
@ -92,17 +93,14 @@ class AerCompiler:
# Make a shallow copy incase we modify it
compiled_optypes = list(optypes)
if isinstance(circuits, list):
basis_gates = basis_gates + ["mark", "jump"]
compiled_circuits = []
for idx, circuit in enumerate(circuits):
# Resolve initialize
circuit = self._inline_initialize(circuit, compiled_optypes[idx])
if self._is_dynamic(circuit, compiled_optypes[idx]):
compiled_circ = transpile(
self._inline_circuit(circuit, None, None),
basis_gates=basis_gates,
optimization_level=0,
)
pm = PassManager([Decompose(["mark", "jump"])])
compiled_circ = pm.run(self._inline_circuit(circuit, None, None))
compiled_circuits.append(compiled_circ)
# Recompute optype for compiled circuit
compiled_optypes[idx] = circuit_optypes(compiled_circ)
@ -214,7 +212,6 @@ class AerCompiler:
)
else:
ret._append(instruction)
return ret
def _convert_jump_conditional(self, cond_tuple, bit_map):
@ -272,7 +269,9 @@ class AerCompiler:
inlined_body = self._inline_circuit(body, continue_label, break_label, inner_bit_map)
if loop_parameter is not None:
inlined_body = inlined_body.assign_parameters({loop_parameter: index})
parent.append(inlined_body, qargs, cargs)
# parent.append(inlined_body, qargs, cargs)
for inst in inlined_body:
parent.append(inst, qargs, cargs)
parent.append(AerMark(continue_label, len(qargs), len(cargs)), qargs, cargs)
if inlined_body is not None:
@ -323,7 +322,8 @@ class AerCompiler:
)
parent.append(AerJump(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(AerMark(loop_start_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(inlined_body, qargs, cargs)
for inst in inlined_body:
parent.append(inst, qargs, cargs)
parent.append(AerJump(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(AerMark(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
@ -371,9 +371,9 @@ class AerCompiler:
)
parent.append(AerJump(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(AerMark(if_true_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(
self._inline_circuit(true_body, continue_label, break_label, true_bit_map), qargs, cargs
)
child = self._inline_circuit(true_body, continue_label, break_label, true_bit_map)
for inst in child.data:
parent.append(inst, qargs, cargs)
if false_body:
false_bit_map = {
@ -385,11 +385,9 @@ class AerCompiler:
}
parent.append(AerJump(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(AerMark(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(
self._inline_circuit(false_body, continue_label, break_label, false_bit_map),
qargs,
cargs,
)
child = self._inline_circuit(false_body, continue_label, break_label, false_bit_map)
for inst in child.data:
parent.append(inst, qargs, cargs)
parent.append(AerMark(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
@ -468,23 +466,21 @@ class AerCompiler:
for case_data in case_data_list:
parent.append(AerMark(case_data.label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(
self._inline_circuit(
child = self._inline_circuit(
case_data.body, continue_label, break_label, case_data.bit_map
),
qargs,
cargs,
)
for inst in child.data:
parent.append(inst, qargs, cargs)
parent.append(AerJump(switch_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
parent.append(AerMark(switch_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs)
def compile_circuit(circuits, basis_gates=None, optypes=None):
def compile_circuit(circuits, optypes=None):
"""
compile a circuit that have control-flow instructions
"""
return AerCompiler().compile(circuits, basis_gates, optypes)
return AerCompiler().compile(circuits, optypes)
BACKEND_RUN_ARG_TYPES = {

View File

@ -517,9 +517,7 @@ class AerBackend(Backend, ABC):
optypes = [circuit_optypes(circ) for circ in circuits]
# Compile Qasm3 instructions
circuits, optypes = compile_circuit(
circuits, basis_gates=self.configuration().basis_gates, optypes=optypes
)
circuits, optypes = compile_circuit(circuits, optypes=optypes)
# run option noise model
circuits, noise_model, run_options = self._assemble_noise_model(

View File

@ -0,0 +1,9 @@
---
fixes:
- |
When the circuit is a dynamic circuit, the input circuit was not correctly
transpiled in AerCompiler that causes wrong noise simulation result,
because some gates noise to be applied were transpiled to other gates.
This fix uses custom pass manager to decompose only jump and mark ops
Aer uses internally.