Hi all, I am trying to perform Hamiltonian simulation in pennylane and I am facing some issues although the concept is very simple. The actual code is quite large so here is a part of what I am trying to do: during gate synthesis when I am reducing the L_{2} norm between the actual gate output(e.g. Hadamard) and parameterized gate (here it would be SU(2)(\alpha, \beta, \gamma) for single wire==qubit) via GradientDescentOptimizer the final output i.e. the SU(2) with optimized \alpha_{optimzed}, \beta_{optimzed}, \gamma_{optimzed} is not providing the exact Hadamard. I know that if we break the Hadamard it will simply give R_y(-\pi/2).\sigma_x but still, I am getting
Thanks for your response. Can you just clarify that whether it is possible to decompose Hadamard in terms of only rotation gates? As we know H=R_y(-\pi/2).(e^{i\pi/2} R_x(\pi)) but I wish to obtain this decomposition via stochastic optimization!
Can you just clarify that whether it is possible to decompose Hadamard in terms of only rotation gates?
Do you mean specifically in terms of qml.Rot? The decomposition above into phase shifts and X rotations is a standard decomposition into single-qubit rotations. The code below shows how you can optimize the variational parameters for this decomposition:
import pennylane as qml
from pennylane import numpy as np
dev = qml.device("default.qubit.autograd", wires=1)
def decomposition(params):
qml.PhaseShift(params[0], wires=0)
qml.RX(params[1], wires=0)
qml.PhaseShift(params[2], wires=0)
@qml.qnode(dev, diff_method="backprop")
def f(params, state, apply_inv=True):
qml.BasisState(np.array([state]), wires=0)
decomposition(params)
if apply_inv:
qml.Hadamard(wires=0).inv()
return qml.state()
params = np.random.random(3)
Id = np.eye(2, requires_grad=False)
def cost_state(params, state):
return np.sum(np.abs(f(params, state) - Id[state]))
def cost(params):
return sum(cost_state(params, i) for i in range(2))
opt = qml.GradientDescentOptimizer(stepsize=0.01)
for i in range(300):
params = opt.step(cost, params)
if i % 20 == 0:
print(f"Cost at step {i}:", cost(params))
def get_unitary(params):
return np.array([f(params, i, apply_inv=False) for i in range(2)]).T
print("\nOptimized unitary:\n", get_unitary(params))
print("Ideal unitary:\n", qml.Hadamard.matrix)
print("\nOptimized params:", params.numpy())
print("Expected params: ", np.array([np.pi / 2] * 3))
Note that this optimization ensures that both input states |0> and |1> are mapped to their expected outputs.
I believe using Rot alone can only approximate the Hadamard gate up to a global phase, so won’t work in the above example. You could consider changing the cost function from the norm to the fidelity (which is insensitive to global phase) and using just Rot will then probably work.
Hi @Tom_Bromley,
Thank you very much for your beautiful response and the above solution is perfect. And as a response to your query, I thought we can decompose any unitary in terms of rotations and a global phase because that’s what we need to produce any general unitary \in SU(2) i.e. U=e^{i\phi} R_{n1}(\theta_1)R_{n2}(\theta_2)R_{n1}(\theta_3). But still the above solution worth it.