Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.23k stars 2.36k forks source link

Opt. Lvl. 2: commutation analysis `Cannot apply Operation: reset` #10482

Closed MattePalte closed 1 year ago

MattePalte commented 1 year ago

Environment

What is happening?

Transpiling (opt.lvl.2) a circuit with initialize() with a quantum state that should behave like a reset() leads to an error.

How can we reproduce the issue?

Run this python script:

from qiskit import QuantumCircuit, QuantumRegister, transpile
qreg = QuantumRegister(1, 'q')
circuit = QuantumCircuit(qreg)
circuit.h(qreg[0])
# this crashes:
quantum_state = [1, 0]
circuit.initialize(quantum_state, qreg[0])
# this works (although equivalent in principle):
# circuit.reset(qreg[0])
circuit.measure_all()

print(circuit.draw())
res = transpile(circuit, optimization_level=2)

Produces this output and error:

        ┌───┐┌─────────────────┐ ░ ┌─┐
     q: ┤ H ├┤ Initialize(1,0) ├─░─┤M├
        └───┘└─────────────────┘ ░ └╥┘
meas: 1/════════════════════════════╩═
                                    0
Traceback (most recent call last):
  File "/myfile.py", line 13, in <mod
ule>                                                                                                                   res = transpile(circuit, optimization_level=2)
  File ".../qiskit/compiler/transpiler.py", line 380, in transpile                                                                                                    _serial_transpile_circuit(
  File ".../qiskit/compiler/transpiler.py", line 462, in _serial_transpile_circuit                                                                                    result = pass_manager.run(circuit, callback=callback, output_name=output_name)
  File ".../qiskit/transpiler/passmanager.py", line 537, in run                                                                                                       return super().run(circuits, output_name, callback)
  File ".../qiskit/transpiler/passmanager.py", line 231, in run                                                                                                       return self._run_single_circuit(circuits, output_name, callback)
  File ".../qiskit/transpiler/passmanager.py", line 292, in _run_single_circuit                                                                                       result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
  File ".../qiskit/transpiler/runningpassmanager.py", line 125, in run                                                                                                dag = self._do_pass(pass_, dag, passset.options)
  File ".../qiskit/transpiler/runningpassmanager.py", line 169, in _do_pass                                                                                           dag = self._do_pass(required_pass, dag, options)
  File ".../qiskit/transpiler/runningpassmanager.py", line 173, in _do_pass                                                                                           dag = self._run_this_pass(pass_, dag)
  File ".../qiskit/transpiler/runningpassmanager.py", line 227, in _run_this_pass                                                                                     pass_.run(FencedDAGCircuit(dag))
  File ".../qiskit/transpiler/passes/optimization/commutation_analysis.py", line 75, in run                                                                           does_commute = self.comm_checker.commute(
  File ".../qiskit/circuit/commutation_checker.py", line 135, in commute                                                                                              operator_1 = Operator(op1, input_dims=(2,) * len(qarg1), output_dims=(2,) * len(qarg1))
  File ".../qiskit/quantum_info/operators/operator.py", line 85, in __init__                                                                                          self._data = self._init_instruction(data).data
  File ".../qiskit/quantum_info/operators/operator.py", line 614, in _init_instruction                                                                                op._append_instruction(instruction)
  File ".../qiskit/quantum_info/operators/operator.py", line 691, in _append_instruction                                                                              self._append_instruction(instruction.operation, qargs=new_qargs)
  File ".../qiskit/quantum_info/operators/operator.py", line 658, in _append_instruction                                                                              raise QiskitError(f"Cannot apply Operation: {obj.name}")
qiskit.exceptions.QiskitError: 'Cannot apply Operation: reset'

The variant with reset() instead of initialize() works fine.

What should happen?

The transpiler should not crash but rather recognize that the initialize is a reset operation and handle it in the same way. Please correct me if I am wrong, the initialize([1, 0], qreg[0]) should be equivalent to reset(qreg[0]) and both should initialize the qubit to the |0> state (assuming that the default state of a qubit is |0>). Source: initialize and reset.

Any suggestions?

What about adding a pass that converts all the initialize() operations to reset() operations (whenever applicable) before the transpiler starts?

jakelishman commented 1 year ago

Duplicate of #8050