Skip to content

Commit

Permalink
Fix AerCompiler to use custom pass manager to decompose control flow …
Browse files Browse the repository at this point in the history
…ops (#2095)

* Fix AerCompiler to use basis_gates built from input circuit

* use custom pass manager to decompose dontrol flow ops

* remove unused import
  • Loading branch information
doichanj authored Apr 11, 2024
1 parent c0420ea commit cf510a2
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 32 deletions.
54 changes: 25 additions & 29 deletions qiskit_aer/backends/aer_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
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
Expand Down Expand Up @@ -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).
Expand All @@ -92,17 +93,14 @@ def compile(self, circuits, basis_gates=None, optypes=None):
# 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)
Expand Down Expand Up @@ -214,7 +212,6 @@ def _inline_circuit(self, circ, continue_label, break_label, bit_map=None):
)
else:
ret._append(instruction)

return ret

def _convert_jump_conditional(self, cond_tuple, bit_map):
Expand Down Expand Up @@ -272,7 +269,9 @@ def _inline_for_loop_op(self, instruction, parent, bit_map):
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:
Expand Down Expand Up @@ -323,7 +322,8 @@ def _inline_while_loop_op(self, instruction, parent, bit_map):
)
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)

Expand Down Expand Up @@ -371,9 +371,9 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b
)
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 = {
Expand All @@ -385,11 +385,9 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b
}
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)

Expand Down Expand Up @@ -468,23 +466,21 @@ def _inline_switch_case_op(self, instruction, continue_label, break_label, paren

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(
case_data.body, continue_label, break_label, case_data.bit_map
),
qargs,
cargs,
child = self._inline_circuit(
case_data.body, continue_label, break_label, case_data.bit_map
)
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 = {
Expand Down
4 changes: 1 addition & 3 deletions qiskit_aer/backends/aerbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,9 +517,7 @@ def _compile(self, circuits, **run_options):
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit cf510a2

Please sign in to comment.