Skip to content

CNOT with interacting qubits

Digital-analog quantum computing focuses on using single qubit digital gates combined with more complex and device-dependent analog interactions to represent quantum programs. This paradigm has been shown to be universal for quantum computation1. However, while this approach may have advantages when adapting quantum programs to real devices, known quantum algorithms are very often expressed in a fully digital paradigm. As such, it is also important to have concrete ways to transform from one paradigm to another.

This tutorial will exemplify the DAQC transformation starting with the representation of a simple digital CNOT using the universality of the Ising Hamiltonian2.

CNOT with CPHASE

Let's look at a single example of how the digital-analog transformation can be used to perform a CNOT on two qubits inside a register of globally interacting qubits.

First, note that the CNOT can be decomposed with two Hadamard and a CPHASE gate with \(\phi=\pi\):

import torch
from qadence import chain, sample, product_state

from qadence.draw import display
from qadence import X, I, Z, H, N, CPHASE, CNOT, HamEvo, PI

n_qubits = 2

# CNOT gate
cnot_gate = CNOT(0, 1)

# CNOT decomposed
phi = PI
cnot_decomp = chain(H(1), CPHASE(0, 1, phi), H(1))

init_state = product_state("10")
sample from CNOT gate and 100 shots = [Counter({'11': 100})]
sample from decomposed CNOT gate and 100 shots = [Counter({'11': 100})]

The CPHASE matrix is diagonal, and can be implemented by exponentiating an Ising-like Hamiltonian, or generator,

\[\text{CPHASE}(i,j,\phi)=\text{exp}\left(-i\phi \mathcal{H}_\text{CP}(i, j)\right)\]
\[\begin{aligned} \mathcal{H}_\text{CP}&=-\frac{1}{4}(I_i-Z_i)(I_j-Z_j)\\ &=-N_iN_j \end{aligned}\]

where the number operator \(N_i = \frac{1}{2}(I_i-Z_i)=\hat{n}_i\) is used, leading to an Ising-like interaction \(\hat{n}_i\hat{n}_j\) realisable in neutral-atom systems. Let's rebuild the CNOT using this evolution.

from qadence import kron, block_to_tensor

# Hamiltonian for the CPHASE gate
h_cphase = (-1.0) * kron(N(0), N(1))

# Exponentiating and time-evolving the Hamiltonian until t=phi.
cphase_evo = HamEvo(h_cphase, phi)

# Check that we have the CPHASE gate:
cphase_matrix = block_to_tensor(CPHASE(0, 1, phi))
cphase_evo_matrix = block_to_tensor(cphase_evo)
cphase_matrix == cphase_evo_matrix: True

Now that the CPHASE generator is checked, it can be applied to the CNOT:

# CNOT with Hamiltonian Evolution
cnot_evo = chain(
    H(1),
    cphase_evo,
    H(1)
)

# Initialize state to check CNOTs sample outcomes.
init_state = product_state("10")
sample cnot_gate = [Counter({'11': 100})]
sample cnot_evo = [Counter({'11': 100})]

Thus, a CNOT gate can be created by combining a few single-qubit gates together with a two-qubit Ising interaction between the control and the target qubit which is the essence of the Ising transform proposed in the seminal DAQC paper2 for \(ZZ\) interactions. In Qadence, both \(ZZ\) and \(NN\) interactions are supported.

CNOT in an interacting system of three qubits

Consider a simple experimental setup with \(n=3\) interacting qubits laid out in a triangular grid. For the sake of simplicity, all qubits interact with each other with an \(NN\)-Ising interaction of constant strength \(g_\text{int}\). The Hamiltonian for the system can be written by summing interaction terms over all pairs:

\[\mathcal{H}_\text{sys}=\sum_{i=0}^{n}\sum_{j=0}^{i-1}g_\text{int}N_iN_j,\]

which in this case leads to only three interaction terms,

\[\mathcal{H}_\text{sys}=g_\text{int}(N_0N_1+N_1N_2+N_0N_2)\]

This generator can be easily built in Qadence:

from qadence import add, kron
n_qubits = 3

# Interaction strength.
g_int = 1.0

# Build a list of interactions.
interaction_list = []
for i in range(n_qubits):
    for j in range(i):
        interaction_list.append(g_int * kron(N(i), N(j)))

h_sys = add(*interaction_list)
h_sys = AddBlock(0,1,2)
├── [mul: 1.000] 
   └── KronBlock(0,1)
       ├── N(1)
       └── N(0)
├── [mul: 1.000] 
   └── KronBlock(0,2)
       ├── N(2)
       └── N(0)
└── [mul: 1.000] 
    └── KronBlock(1,2)
        ├── N(2)
        └── N(1)

Now let's consider that the experimental system is fixed, and qubits can not be isolated one from another. The options are:

  • Turn on or off the global system Hamiltonian.
  • Perform local single-qubit rotations.

To perform a fully digital CNOT(0,1), the interacting control on qubit 0 and target on qubit 1 must be isolated from the third one to implement the gate directly. While this can be achieved for a three-qubit system, it becomes experimentally untractable when scaling the qubit count.

However, this is not the case within the digital-analog paradigm. In fact, the two qubit Ising interaction required for the CNOT can be represented with a combination of the global system Hamiltonian and a specific set of single-qubit rotations. Full details about this transformation are to be found in the DAQC paper2 but a more succint yet in-depth description takes place in the next section. It is conveniently available in Qadence by calling the daqc_transform function.

In the most general sense, the daqc_transform function will return a circuit that represents the evolution of a target Hamiltonian \(\mathcal{H}_\text{target}\) (here the unitary of the gate) until a specified time \(t_f\) by using only the evolution of a build Hamiltonian \(\mathcal{H}_\text{build}\) (here \(\mathcal{H}_\text{sys}\)) together with local \(X\)-gates. In Qadence, daqc_transform is applicable for \(\mathcal{H}_\text{target}\) and \(\mathcal{H}_\text{build}\) composed only of \(ZZ\)- or \(NN\)-interactions. These generators are parsed by the daqc_transform function and the appropriate type is automatically determined together with the appropriate single-qubit detunings and global phases.

Let's apply it for the CNOT implementation:

from qadence import daqc_transform, Strategy

# Settings for the target CNOT operation
i = 0  # Control qubit
j = 1  # Target qubit
k = 2  # The extra qubit

# Define the target CNOT operation
# by composing with identity on the extra qubit.
cnot_target = kron(CNOT(i, j), I(k))

# The two-qubit NN-Ising interaction term for the CPHASE
h_int = (-1.0) * kron(N(i), N(j))

# Transforming the two-qubit Ising interaction using only our system Hamiltonian
transformed_ising = daqc_transform(
    n_qubits=3,        # Total number of qubits in the transformation
    gen_target=h_int,  # The target Ising generator
    t_f=PI,            # The target evolution time
    gen_build=h_sys,   # The building block Ising generator to be used
    strategy=Strategy.SDAQC,   # Currently only sDAQC is implemented
    ignore_global_phases=False  # Global phases from mapping between Z and N
)

# display(transformed_ising)
%3 cluster_3d507d6c934c4898b0e15d53e3647e20 cluster_a163c2a403474fe5903e1085666d4f3e cluster_16e551a7e71e4b55b9ca8c512111b5d3 cluster_fb09eb6b3d044db28efe17013e7f3be4 cluster_22d81f6ca60940b08a88d16ca289669e cluster_16e612bb4edb4bf1bf0b8d72c4541b5d cluster_f4cba4b57f8348458473e3b38a739d6a fb105d7f38ed4a87b6893ed761ee4066 0 c61abaffeb614e7d9a22f77514f75bf5 HamEvo fb105d7f38ed4a87b6893ed761ee4066--c61abaffeb614e7d9a22f77514f75bf5 6a320573cbc74299bca17f26d445e1cb 1 c26a559818ab487493d85b5328cab35d HamEvo c61abaffeb614e7d9a22f77514f75bf5--c26a559818ab487493d85b5328cab35d 2a04eeaa5d724425ba2bc7a03364c1ef HamEvo c26a559818ab487493d85b5328cab35d--2a04eeaa5d724425ba2bc7a03364c1ef de56d3ee69824f9c9c1407857be92d24 X 2a04eeaa5d724425ba2bc7a03364c1ef--de56d3ee69824f9c9c1407857be92d24 a007fb3d33a24d6891b51d1e58810b8e HamEvo de56d3ee69824f9c9c1407857be92d24--a007fb3d33a24d6891b51d1e58810b8e 70dd95d5b6c548f28a4884f8c350f7f2 HamEvo a007fb3d33a24d6891b51d1e58810b8e--70dd95d5b6c548f28a4884f8c350f7f2 b76dafe19f88420ea786b5add80f6421 X 70dd95d5b6c548f28a4884f8c350f7f2--b76dafe19f88420ea786b5add80f6421 bfeb275fd7ee4fba9625390244511a50 b76dafe19f88420ea786b5add80f6421--bfeb275fd7ee4fba9625390244511a50 a5ef34da3f1c4384b6b95b2b40360af3 HamEvo bfeb275fd7ee4fba9625390244511a50--a5ef34da3f1c4384b6b95b2b40360af3 c26e97b4510747d493ba95b779176fba HamEvo a5ef34da3f1c4384b6b95b2b40360af3--c26e97b4510747d493ba95b779176fba 02d9c13844df4c6da3f2a489f0da0edc c26e97b4510747d493ba95b779176fba--02d9c13844df4c6da3f2a489f0da0edc 768c03cbbc87416f81bc531d33c2a3ef 02d9c13844df4c6da3f2a489f0da0edc--768c03cbbc87416f81bc531d33c2a3ef 223eddfadeca4af6b665c3826e0ed035 b3b1b5fce32d422882c86fa1c1735aa0 t = -3.14 6a320573cbc74299bca17f26d445e1cb--b3b1b5fce32d422882c86fa1c1735aa0 bb716aa4a1e44869884275d9415e3b4d 2 b49440f71c9b44d783dde5106dadc6e1 t = 3.142 b3b1b5fce32d422882c86fa1c1735aa0--b49440f71c9b44d783dde5106dadc6e1 9eea6b7b88774a85b887e05483ad32d1 t = -3.14 b49440f71c9b44d783dde5106dadc6e1--9eea6b7b88774a85b887e05483ad32d1 e5de1c9a72fc4dd4a6bfbed8b5e3548f 9eea6b7b88774a85b887e05483ad32d1--e5de1c9a72fc4dd4a6bfbed8b5e3548f bb78396b162c4ae9b5cb0dc36f6ead60 t = 1.571 e5de1c9a72fc4dd4a6bfbed8b5e3548f--bb78396b162c4ae9b5cb0dc36f6ead60 e81dfd7df3c648ccaa9eaaaaebf2e415 t = 1.571 bb78396b162c4ae9b5cb0dc36f6ead60--e81dfd7df3c648ccaa9eaaaaebf2e415 aedcd29149c94bf285c865f0c7192cdc e81dfd7df3c648ccaa9eaaaaebf2e415--aedcd29149c94bf285c865f0c7192cdc 93c13eba82ae471d9e366f74025ec8f4 X aedcd29149c94bf285c865f0c7192cdc--93c13eba82ae471d9e366f74025ec8f4 2ace2c85d9ce4ba2ac1e03c074897a7f t = 1.571 93c13eba82ae471d9e366f74025ec8f4--2ace2c85d9ce4ba2ac1e03c074897a7f c70037946a7643c39edfcdddcc09dabd t = 1.571 2ace2c85d9ce4ba2ac1e03c074897a7f--c70037946a7643c39edfcdddcc09dabd c9e7350a05154997bea39a03b2e25769 X c70037946a7643c39edfcdddcc09dabd--c9e7350a05154997bea39a03b2e25769 c9e7350a05154997bea39a03b2e25769--223eddfadeca4af6b665c3826e0ed035 498db845c5544c8b82a181f6174691e4 b94f480c5a224a6681200426afac6ea2 bb716aa4a1e44869884275d9415e3b4d--b94f480c5a224a6681200426afac6ea2 d8f4c3074c9e470a8e5eb6097da37ba2 b94f480c5a224a6681200426afac6ea2--d8f4c3074c9e470a8e5eb6097da37ba2 a2235eccde0c4784a2243736e0a58306 d8f4c3074c9e470a8e5eb6097da37ba2--a2235eccde0c4784a2243736e0a58306 0c6b611312b5422d87f75af62ff38d95 X a2235eccde0c4784a2243736e0a58306--0c6b611312b5422d87f75af62ff38d95 4af6939d9aa34642b6ef8c724c126160 0c6b611312b5422d87f75af62ff38d95--4af6939d9aa34642b6ef8c724c126160 bc1cd2caa8724bec8c0ef08c05493440 4af6939d9aa34642b6ef8c724c126160--bc1cd2caa8724bec8c0ef08c05493440 da6f9d82e953481f96eb2b22dfc7c872 X bc1cd2caa8724bec8c0ef08c05493440--da6f9d82e953481f96eb2b22dfc7c872 3c97423725e04c7db2d9f6e3f89b13d0 X da6f9d82e953481f96eb2b22dfc7c872--3c97423725e04c7db2d9f6e3f89b13d0 59b9f51a496140218f1b04d6384d92c5 3c97423725e04c7db2d9f6e3f89b13d0--59b9f51a496140218f1b04d6384d92c5 60b5b464b54947719588da8ea935303f 59b9f51a496140218f1b04d6384d92c5--60b5b464b54947719588da8ea935303f 597e4473634d4f948ba600141ab71d4c X 60b5b464b54947719588da8ea935303f--597e4473634d4f948ba600141ab71d4c 597e4473634d4f948ba600141ab71d4c--498db845c5544c8b82a181f6174691e4

The output circuit displays three groups of system Hamiltonian evolutions which account for global-phases and single-qubit detunings related to the mapping between the \(Z\) and \(N\) operators. Optionally, global phases can be ignored.

In general, the mapping of a \(n\)-qubit Ising Hamiltonian to another will require at most \(n(n-1)\) evolutions. The transformed circuit performs these evolutions for specific times that are computed from the solution of a linear system of equations involving the set of interactions in the target and build Hamiltonians.

In this case, the mapping is exact when using the step-wise DAQC strategy (Strategy.SDAQC) available in Qadence. In banged DAQC (Strategy.BDAQC) the mapping is approximate, but easier to implement on a physical device with always-on interactions such as neutral-atom systems.

Just as before, the transformed Ising circuit can be checked to exactly recover the CPHASE gate:

# CPHASE on (i, j), Identity on third qubit:
cphase_matrix = block_to_tensor(kron(CPHASE(i, j, phi), I(k)))

# CPHASE using the transformed circuit:
cphase_evo_matrix = block_to_tensor(transformed_ising)

# Check that it implements the CPHASE.
# Will fail if global phases are ignored.
cphase_matrix == cphase_evo_matrix : True

The CNOT gate can now finally be built:

from qadence import equivalent_state, run, sample

cnot_daqc = chain(
    H(j),
    transformed_ising,
    H(j)
)

# And finally apply the CNOT on a specific 3-qubit initial state:
init_state = product_state("101")

# Check we get an equivalent wavefunction
wf_cnot = run(n_qubits, block=cnot_target, state=init_state)
wf_daqc = run(n_qubits, block=cnot_daqc, state=init_state)

# Visualize the CNOT bit-flip in samples.
wf_cnot == wf_dacq : True
sample cnot_target = [Counter({'111': 100})]
sample cnot_dacq = [Counter({'111': 100})]

As one can see, a CNOT operation has been succesfully implemented on the desired target qubits by using only the global system as the building block Hamiltonian and single-qubit rotations. Decomposing a single digital gate into an Ising Hamiltonian serves as a proof of principle for the potential of this technique to represent universal quantum computation.

Technical details on the DAQC transformation

  • The mapping between target generator and final circuit is performed by solving a linear system of size \(n(n-1)\) where \(n\) is the number of qubits, so it can be computed efficiently (i.e., with a polynomial cost in the number of qubits).
  • The linear system to be solved is actually not invertible for \(n=4\) qubits. This is very specific edge case requiring a workaround, that is currently not yet implemented.
  • As mentioned, the final circuit has at most \(n(n-1)\) slices, so there is at most a quadratic overhead in circuit depth.

Finally, and most important to its usage:

  • The target Hamiltonian should be sufficiently represented in the building block Hamiltonian.

To illustrate this point, consider the following target and build Hamiltonians:

And now we perform the DAQC transform by setting g_int=1.0, exactly matching the target Hamiltonian:

transformed_ising = daqc_transform(
    n_qubits=3,
    gen_target=gen_target,
    t_f=1.0,
    gen_build=gen_build(g_int=1.0),
)

# display(transformed_ising)
%3 cluster_fc0aa313ab174454ba8bdf84408a1f86 cluster_b0fd25131fcb445591193b9b068a0cbf 8699f966048a42a9b890641be5a97bc1 0 0c70f71c452c4647af7c275a1eae80e1 X 8699f966048a42a9b890641be5a97bc1--0c70f71c452c4647af7c275a1eae80e1 61bfcdda8d1f4345b53e4867a3c2f5a3 1 6ae4915dcf7f44f7ae2d7b8049de4ee9 HamEvo 0c70f71c452c4647af7c275a1eae80e1--6ae4915dcf7f44f7ae2d7b8049de4ee9 f5a74e2cc35b42ba902bdab3def08a2d X 6ae4915dcf7f44f7ae2d7b8049de4ee9--f5a74e2cc35b42ba902bdab3def08a2d af35c08d2ea640878d63950c7811b718 f5a74e2cc35b42ba902bdab3def08a2d--af35c08d2ea640878d63950c7811b718 9707b15ec49d48a7893f450c9040462d HamEvo af35c08d2ea640878d63950c7811b718--9707b15ec49d48a7893f450c9040462d 3f54437b6e8c4c72973f781713acfb01 9707b15ec49d48a7893f450c9040462d--3f54437b6e8c4c72973f781713acfb01 215df820903c4756b97c8f335255f92a 3f54437b6e8c4c72973f781713acfb01--215df820903c4756b97c8f335255f92a e034d80a199844b0869b3e4b05edc257 9dbea0da45c94e61b519186492ac1378 61bfcdda8d1f4345b53e4867a3c2f5a3--9dbea0da45c94e61b519186492ac1378 f1f4b420a59442aaa1b0534357a4a598 2 9eed75091fad472184d9b7147000ebc2 t = -0.50 9dbea0da45c94e61b519186492ac1378--9eed75091fad472184d9b7147000ebc2 d33ab7478124444aabd059bb06f8a31a 9eed75091fad472184d9b7147000ebc2--d33ab7478124444aabd059bb06f8a31a ffc8336aba274a588f77a3997f03e8e9 X d33ab7478124444aabd059bb06f8a31a--ffc8336aba274a588f77a3997f03e8e9 dcc330c8fb714b6db9e831c8de060579 t = -0.50 ffc8336aba274a588f77a3997f03e8e9--dcc330c8fb714b6db9e831c8de060579 33c9b12154a847cf848d58251bd32083 X dcc330c8fb714b6db9e831c8de060579--33c9b12154a847cf848d58251bd32083 33c9b12154a847cf848d58251bd32083--e034d80a199844b0869b3e4b05edc257 0541763ef5de4c2fac77894e3ec5cc00 886b4e720a0146009c0927712803265f X f1f4b420a59442aaa1b0534357a4a598--886b4e720a0146009c0927712803265f 33090ec1346f43db8209e0007093a0b3 886b4e720a0146009c0927712803265f--33090ec1346f43db8209e0007093a0b3 5a8be5503fb54cff8404149b0ab7e4eb X 33090ec1346f43db8209e0007093a0b3--5a8be5503fb54cff8404149b0ab7e4eb df01ce66ba6d4f60aeec15aa9bd49926 X 5a8be5503fb54cff8404149b0ab7e4eb--df01ce66ba6d4f60aeec15aa9bd49926 100edc9bea0e439390fedc4cc0cb2be7 df01ce66ba6d4f60aeec15aa9bd49926--100edc9bea0e439390fedc4cc0cb2be7 3cacc89aeb424b0996fbc4f2ecb261dc X 100edc9bea0e439390fedc4cc0cb2be7--3cacc89aeb424b0996fbc4f2ecb261dc 3cacc89aeb424b0996fbc4f2ecb261dc--0541763ef5de4c2fac77894e3ec5cc00

Now, if the interaction between qubits 0 and 1 is weakened in the build Hamiltonian:

transformed_ising = daqc_transform(
    n_qubits=3,
    gen_target=gen_target,
    t_f=1.0,
    gen_build=gen_build(g_int=0.001),
)

# display(transformed_ising)
%3 cluster_85371198b9b34455a313b6ba3eceeb1f cluster_82ed3edaf06948d4b96a1af3d55b2c0e 4396e3dc25d24716988e57e1805bf108 0 66ca85dfb4e24d06b9755f9bc4530698 X 4396e3dc25d24716988e57e1805bf108--66ca85dfb4e24d06b9755f9bc4530698 19dbf5ea1a844050bb00365ff67bbdd4 1 a7e20bbfe4924fe796097cdda26fa7ff HamEvo 66ca85dfb4e24d06b9755f9bc4530698--a7e20bbfe4924fe796097cdda26fa7ff 9493a651921d4178a2b20d090822814f X a7e20bbfe4924fe796097cdda26fa7ff--9493a651921d4178a2b20d090822814f 87e8e7ac3071422e8676b3af48d35d96 9493a651921d4178a2b20d090822814f--87e8e7ac3071422e8676b3af48d35d96 466d05a04e734e66831fac640e0cd41b HamEvo 87e8e7ac3071422e8676b3af48d35d96--466d05a04e734e66831fac640e0cd41b a50c47aa07f74430ae0533ac3dbab6c1 466d05a04e734e66831fac640e0cd41b--a50c47aa07f74430ae0533ac3dbab6c1 76087cedcbfe47c0b8a011986fd21261 a50c47aa07f74430ae0533ac3dbab6c1--76087cedcbfe47c0b8a011986fd21261 c415dea798aa4c45b0d702b0f2ab44a2 bf2b131791b8405d95165f77a4e0fe0e 19dbf5ea1a844050bb00365ff67bbdd4--bf2b131791b8405d95165f77a4e0fe0e 57e9f8e6b1c14661af402805fdb93446 2 2c54c4e1d51140ce8cdf5851c9d03678 t = -500. bf2b131791b8405d95165f77a4e0fe0e--2c54c4e1d51140ce8cdf5851c9d03678 2bfab4cdbdfe4a6a95dcb4b47245d1f0 2c54c4e1d51140ce8cdf5851c9d03678--2bfab4cdbdfe4a6a95dcb4b47245d1f0 cc1fced0db7d4d3791ed6304931fd355 X 2bfab4cdbdfe4a6a95dcb4b47245d1f0--cc1fced0db7d4d3791ed6304931fd355 d8c3bd2fec3d440196fd190976f82eef t = -500. cc1fced0db7d4d3791ed6304931fd355--d8c3bd2fec3d440196fd190976f82eef 69521a441d29484bb0bcc626525fb909 X d8c3bd2fec3d440196fd190976f82eef--69521a441d29484bb0bcc626525fb909 69521a441d29484bb0bcc626525fb909--c415dea798aa4c45b0d702b0f2ab44a2 1d1ce856328648e0a66f20353e6c34a4 4c855f5c5e75494b9ba0f52b08cfcf91 X 57e9f8e6b1c14661af402805fdb93446--4c855f5c5e75494b9ba0f52b08cfcf91 67ee602ac3ad4948b93dac58e31f486f 4c855f5c5e75494b9ba0f52b08cfcf91--67ee602ac3ad4948b93dac58e31f486f e9fbb51ce3ef402f9047a3da571a48a1 X 67ee602ac3ad4948b93dac58e31f486f--e9fbb51ce3ef402f9047a3da571a48a1 bf3a4e4a7edb447d8e6be8dada691a8b X e9fbb51ce3ef402f9047a3da571a48a1--bf3a4e4a7edb447d8e6be8dada691a8b 77f90ecdfb9e4de49fd617b78bfc9a1d bf3a4e4a7edb447d8e6be8dada691a8b--77f90ecdfb9e4de49fd617b78bfc9a1d 68003217b1a943b8b24196a0d80bb87b X 77f90ecdfb9e4de49fd617b78bfc9a1d--68003217b1a943b8b24196a0d80bb87b 68003217b1a943b8b24196a0d80bb87b--1d1ce856328648e0a66f20353e6c34a4

The times slices using the build Hamiltonian need now to evolve for much longer to represent the same interaction since it is not sufficiently represented in the building block Hamiltonian.

In the limit where that interaction is not present, the transform will not work:

try:
    transformed_ising = daqc_transform(
        n_qubits=3,
        gen_target=gen_target,
        t_f=1.0,
        gen_build=gen_build(g_int = 0.0),
    )
except ValueError as error:
    print("Error:", error)
Error: Incompatible interactions between target and build Hamiltonians.

References