# test QFT for N=4
= 0.5 * torch.tensor([[1, 1, 1, 1],
QFT_2_qubits 1, 1j, -1, -1j],
[1, -1, 1, -1],
[1, -1j, -1, 1j]], dtype=torch.complex128)
[
assert torch.allclose(SpecialUnitaries.QFT(num_qubits=2), QFT_2_qubits)
Compilation benchmark
Special unitaries
Quantum Fourier transform
\[ \begin{equation} \mathrm{QFT}: |x\rangle \mapsto \frac{1}{\sqrt{N}} \sum_{k=0}^{N-1} \omega_N^{xk}\;|k\rangle, \end{equation} \] where \[ \begin{equation} \omega_N=\exp{\frac{2\pi i}{N}} \quad\text{and}\quad N=2^{\text{qubits}}. \end{equation} \]
SpecialUnitaries
SpecialUnitaries ()
Special unitary matrices to benchmark compilation.
round(SpecialUnitaries.QFT(3), 3) np.
tensor([[ 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j, 0.3540+0.0000j],
[ 0.3540+0.0000j, 0.2500+0.2500j, 0.0000+0.3540j, -0.2500+0.2500j, -0.3540+0.0000j, -0.2500-0.2500j, 0.0000-0.3540j, 0.2500-0.2500j],
[ 0.3540+0.0000j, 0.0000+0.3540j, -0.3540+0.0000j, 0.0000-0.3540j, 0.3540+0.0000j, 0.0000+0.3540j, -0.3540+0.0000j, 0.0000-0.3540j],
[ 0.3540+0.0000j, -0.2500+0.2500j, 0.0000-0.3540j, 0.2500+0.2500j, -0.3540+0.0000j, 0.2500-0.2500j, 0.0000+0.3540j, -0.2500-0.2500j],
[ 0.3540+0.0000j, -0.3540+0.0000j, 0.3540+0.0000j, -0.3540+0.0000j, 0.3540+0.0000j, -0.3540+0.0000j, 0.3540+0.0000j, -0.3540+0.0000j],
[ 0.3540+0.0000j, -0.2500-0.2500j, 0.0000+0.3540j, 0.2500-0.2500j, -0.3540+0.0000j, 0.2500+0.2500j, 0.0000-0.3540j, -0.2500+0.2500j],
[ 0.3540+0.0000j, 0.0000-0.3540j, -0.3540+0.0000j, 0.0000+0.3540j, 0.3540+0.0000j, 0.0000-0.3540j, -0.3540+0.0000j, 0.0000+0.3540j],
[ 0.3540+0.0000j, 0.2500-0.2500j, 0.0000-0.3540j, -0.2500-0.2500j, -0.3540+0.0000j, -0.2500+0.2500j, 0.0000+0.3540j, 0.2500+0.2500j]], dtype=torch.complex128)
Hamiltonian evolutions
assert torch.allclose(sigma_x@sigma_x, torch.eye(2, dtype=torch.complex128))
assert torch.allclose(sigma_y@sigma_y, torch.eye(2, dtype=torch.complex128))
assert torch.allclose(sigma_z@sigma_z, torch.eye(2, dtype=torch.complex128))
qubit_tensor_product
qubit_tensor_product (num_qubits:int, *ops:torch.Tensor, pos:Union[int,Sequence[int]])
Make tensor product with identities, assumes ops
placed at pos
in the tensor product ordering.
\(\sigma_x \otimes I\):
2, sigma_x, pos=0) qubit_tensor_product(
tensor([[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]], dtype=torch.complex128)
\(I \otimes \sigma_x\):
2, sigma_x, pos=-1) qubit_tensor_product(
tensor([[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]], dtype=torch.complex128)
\(\sigma_z \otimes \sigma_z\):
2, sigma_z, sigma_z, pos=[0, 1]) qubit_tensor_product(
tensor([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j],
[ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j],
[ 0.+0.j, -0.+0.j, -0.+0.j, 1.-0.j]], dtype=torch.complex128)
Base Hamiltonian
BaseHamiltonian
BaseHamiltonian (device:Union[str,torch.device,NoneType]=None)
Base implementation of a Hamiltonian.
Ising Hamiltonian
Defined as \[ H = -J \sum_{\langle i, j \rangle} \sigma_i^z \sigma_j^z - h \sum_i \sigma_i^x, \] where \(J\) is the coupling constant and \(h\) a magnetic field.
IsingHamiltonian
IsingHamiltonian (h:float, J:float, num_qubits:int, periodic_boundary:bool=True, device:Union[str,torch.device,NoneType]=None)
Implementation of the Ising Hamiltonian on a qubit chain.
= IsingHamiltonian(h=0, J=1, num_qubits=2)
hamiltonian hamiltonian.data
tensor([[-2.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 2.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 2.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, -2.+0.j]], dtype=torch.complex128)
Eigenvalues of this Hamiltonian:
torch.linalg.eigvalsh(hamiltonian.data)
tensor([-2., -2., 2., 2.], dtype=torch.float64)
= torch.linalg.eigh(hamiltonian.data)
e, v v
tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]], dtype=torch.complex128)
And the evolution unitary is:
=np.pi/6) hamiltonian.get_evolution(t
tensor([[0.5000+0.8660j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],
[0.0000+0.0000j, 0.5000-0.8660j, 0.0000+0.0000j, 0.0000+0.0000j],
[0.0000+0.0000j, 0.0000+0.0000j, 0.5000-0.8660j, 0.0000+0.0000j],
[0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.5000+0.8660j]], dtype=torch.complex128)
XXZ Hamiltonian
Defined as \[ H = -J \sum_{\langle i, j \rangle} ( \sigma_i^x \sigma_j^x + \sigma_i^y \sigma_j^y + \Delta \sigma_i^z \sigma_j^z ) - h \sum_i \sigma_i^x, \] where \(J\) is the coupling constant, \(\Delta\) a perturbation and \(h\) a magnetic field.
XXZHamiltonian
XXZHamiltonian (h:float, J:float, delta:float, num_qubits:int, periodic_boundary:bool=True, device:Union[str,torch.device,NoneType]=None)
Implementation of the XXZ Hamiltonian on a qubit chain.
= XXZHamiltonian(h=1, J=1, delta=1, num_qubits=2)
hamiltonian hamiltonian.data
tensor([[-2.+0.j, -1.+0.j, -1.+0.j, 0.+0.j],
[-1.+0.j, 2.+0.j, -4.+0.j, -1.+0.j],
[-1.+0.j, -4.+0.j, 2.+0.j, -1.+0.j],
[ 0.+0.j, -1.+0.j, -1.+0.j, -2.+0.j]], dtype=torch.complex128)
Eigenvalues of this Hamiltonian:
torch.linalg.eigvalsh(hamiltonian.data)
tensor([-4.0000e+00, -2.0000e+00, 8.8818e-16, 6.0000e+00], dtype=torch.float64)
And the evolution unitary is:
=np.pi/6) hamiltonian.get_evolution(t
tensor([[ 0.3750+0.6495j, -0.3750+0.2165j, -0.3750+0.2165j, -0.1250-0.2165j],
[-0.3750+0.2165j, -0.3750+0.2165j, 0.6250+0.2165j, -0.3750+0.2165j],
[-0.3750+0.2165j, 0.6250+0.2165j, -0.3750+0.2165j, -0.3750+0.2165j],
[-0.1250-0.2165j, -0.3750+0.2165j, -0.3750+0.2165j, 0.3750+0.6495j]], dtype=torch.complex128)
=np.pi/6, split_complex_channel=True) hamiltonian.get_evolution(t
tensor([[[ 0.3750, -0.3750, -0.3750, -0.1250],
[-0.3750, -0.3750, 0.6250, -0.3750],
[-0.3750, 0.6250, -0.3750, -0.3750],
[-0.1250, -0.3750, -0.3750, 0.3750]],
[[ 0.6495, 0.2165, 0.2165, -0.2165],
[ 0.2165, 0.2165, 0.2165, 0.2165],
[ 0.2165, 0.2165, 0.2165, 0.2165],
[-0.2165, 0.2165, 0.2165, 0.6495]]], dtype=torch.float64)