I'm working with the pulse module in Pennylane, specifically focusing on the architecture of transmon qubits. I have a slight suspicion that there might be missing or extra $\hbar$ in the source code. Let me explain:
According to the documentation for transmon_interaction, it seems to assume the convention $\hbar = 1$. The same happens with qml.evolve. Therefore, in my code, I am following this convention and ignoring all factors of $\hbar$. However, this approach doesn't seem consistent with the results I get.
Specifically, if I create a 2-qubit transmon_interaction with a minimal coupling to isolate the qubits and add a simple constant pulse on the first qubit of the form $A \sigma_0^X$, the first qubit should undergo an $X$-rotation. The rotation angle after evolving the system for a duration $T$ should be $\theta = A T$, while the second qubit should remain unchanged. Thus, if I evolve the system with $A$ and $T$ satisfying $AT = \pi$, I expect to get the state $|1\rangle$. However, this is not what I observe. To illustrate this, I use the following code:
I create an instance of the Hamiltonian with transmon_interaction and make a copy of it. In this copy, I multiply all coefficients by hbar. Then, I add the same pulse to both Hamiltonians and evolve with the described amplitude and duration. Here is the code:
import pennylane as qml
from copy import copy
from pennylane import numpy as np
hbar = 1.05457182e-34
w0 = 2
pennylane hamiltonian without hbar
h_no_hbar = qml.pulse.transmon_interaction(w0, wires=range(2), connections=[[0,1]], coupling=1e-10)
pennylane hamiltonian with hbar
h_hbar = copy(h_no_hbar)
h_hbar.coeffs_fixed = [x * hbar for x in h_hbar.coeffs_fixed]
pulse
angle = np.pi/2 # from 0 to 1
amplitude = 5
duration = angle / amplitude # evolve to |1>
pulse = qml.X(0) * amplitude
dev = qml.device('default.qubit', wires=range(2))
@qml.qnode(dev)
def circuit(hamiltonian_base):
qml.evolve(hamiltonian_base + pulse)(params=[], t=duration)
return qml.density_matrix(0)
dm_no_hbar = circuit(h_no_hbar)
dm_hbar = circuit(h_hbar)
print(f'{dm_no_hbar = }\n', f'{dm_hbar = }')
These are the results:
dm_no_hbar = tensor([[ 0.86949015+0.j , -0.16400325-0.2942445j],
[-0.16400325+0.2942445j, 0.13050969+0.j ]],
dtype=complex64, requires_grad=True)
dm_hbar = tensor([[ 0.0000000e+00+0.j, -1.3252368e-34+0.j],
[-1.3252368e-34+0.j, 9.9999881e-01+0.j]],
dtype=complex64, requires_grad=True)
As seen, the expected behavior is obtained only when the Hamiltonian coefficients are multiplied by $\hbar$. I have inspected the source code but couldn’t find where an extra $\hbar$ factor might have been included, which I would need to compensate for externally, as it appears I am currently doing. This makes me wonder if I am missing something important here.
Does anyone have any idea? Thanks in advance!