Optimize parameterized UGate into 1 RXGate + 2 RZGate
What should we add?
Because RXGate is available as a basis gate thanks to the fractional gates support, it would be nice if Qiskit could optimize UGate into 1 RXGate + 2 RZGate as follows.
import numpy as np
from qiskit import QuantumCircuit, generate_preset_pass_manager
from qiskit.circuit import ParameterVector
from qiskit.quantum_info import Operator
x = ParameterVector("x", 3)
qc = QuantumCircuit(1)
qc.u(x[0], x[1], x[2], 0)
pm = generate_preset_pass_manager(optimization_level=3, basis_gates=["rz", "rx"])
tqc = pm.run(qc)
print("optimization level", 3)
print(tqc)
print()
qc2 = QuantumCircuit(1)
qc2.rz(x[2] - np.pi/2, 0)
qc2.rx(x[0], 0)
qc2.rz(x[1] + np.pi/2, 0)
print("hand optimization")
print(qc2)
rng = np.random.default_rng(123)
for _ in range(100):
params = 2 * rng.random(3) - 1
op = Operator(qc.assign_parameters(params))
op2 = Operator(qc2.assign_parameters(params))
assert op.equiv(op2)
print("pass")
qiskit 1.2.4, 1.3.0rc1, main branch
optimization level 3
global phase: x[1]/2 + x[2]/2
┌──────────┐┌─────────┐┌──────────────┐┌─────────┐┌───────────────┐
q: ┤ Rz(x[2]) ├┤ Rx(π/2) ├┤ Rz(x[0] + π) ├┤ Rx(π/2) ├┤ Rz(x[1] + 3π) ├
└──────────┘└─────────┘└──────────────┘└─────────┘└───────────────┘
hand optimization
┌────────────────┐┌──────────┐┌────────────────┐
q: ┤ Rz(x[2] - π/2) ├┤ Rx(x[0]) ├┤ Rz(x[1] + π/2) ├
└────────────────┘└──────────┘└────────────────┘
pass
We currently don't optimize expressions containing parameter expressions, due to the overhead in handling the symbolic expressions. If the angles are bound, this should give the optimal decomposition, though, right?
Julien: this is something that we ought to be able to do during basis translation for the given circuit, even for parametric gates. Adding a direct rule to the BasisTranslator's equivalence library should convince it to do it, but that might have the knock-on effect of making other translations worse (probably not, but it's possible) - that's related to the trouble with the BasisTranslator you and I (and Imamichi-san and I) have talked about a bit offline.
Yes, if I bind parameter, the circuit becomes optimal. But users might want to evaluate ansatz with unbound UGates (e.g,. TwoLocal(n, 'u', 'cx')). So, I think it would be nice to optimize or translate UGate in the optimal way when RX is available as a basis gate. But, it's not urgent because the current behavior is not a bug.
┌───────────────────┐
q: ┤ U(0.1,0.01,0.001) ├
└───────────────────┘
optimization level 3
global phase: 0.0055
┌─────────────┐┌─────────┐┌────────────┐
q: ┤ Rz(-1.5698) ├┤ Rx(0.1) ├┤ Rz(1.5808) ├
└─────────────┘└─────────┘└────────────┘
We currently don't optimize expressions containing parameter expressions, due to the overhead in handling the symbolic expressions. If the angles are bound, this should give the optimal decomposition, though, right?
FYI: Jake developed BasisConstructor plugin https://github.com/Qiskit/qiskit-basis-constructor