Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Apr 11, 2024
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
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.
Loading