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_3e791478aa714233a34fc57b9037693c cluster_27c65a2d4a094ec4b87783654572663a cluster_4f656bb8a6684149a51334a94d57c889 cluster_312d765f35aa41b9a125f6365bc6cb82 cluster_48dfdd98670f442a9ef6c69677357726 cluster_07571382211448e8a3abe2735efc7989 cluster_47edbf651af34abb87d29ca97929af15 7fa5549ccd4448aebe5f8e476b44a968 0 3f94cce3d8c746568c881e844fddc3a6 HamEvo 7fa5549ccd4448aebe5f8e476b44a968--3f94cce3d8c746568c881e844fddc3a6 13be355fcee34e25b230a4d931414789 1 4b57b64d52b1419da42f6888fd624226 HamEvo 3f94cce3d8c746568c881e844fddc3a6--4b57b64d52b1419da42f6888fd624226 38191e01143a48cd8af4da8a12b74f01 HamEvo 4b57b64d52b1419da42f6888fd624226--38191e01143a48cd8af4da8a12b74f01 eb1902a1cba7474ba35cddf11afc48d5 X 38191e01143a48cd8af4da8a12b74f01--eb1902a1cba7474ba35cddf11afc48d5 3b501122d16e4b4297e4ef9925480bcc HamEvo eb1902a1cba7474ba35cddf11afc48d5--3b501122d16e4b4297e4ef9925480bcc 966b4d0fcdba47ea92065ef700a4143f HamEvo 3b501122d16e4b4297e4ef9925480bcc--966b4d0fcdba47ea92065ef700a4143f e37ce407b9b54e38a8d0d5f032cda9f7 X 966b4d0fcdba47ea92065ef700a4143f--e37ce407b9b54e38a8d0d5f032cda9f7 b4268ce3d868469ca05c0031fdcdd8e5 e37ce407b9b54e38a8d0d5f032cda9f7--b4268ce3d868469ca05c0031fdcdd8e5 3f8ef3788ba94080ac3a292f9a7ece0d HamEvo b4268ce3d868469ca05c0031fdcdd8e5--3f8ef3788ba94080ac3a292f9a7ece0d a639438616d747e1a57f4bdb480fe48c HamEvo 3f8ef3788ba94080ac3a292f9a7ece0d--a639438616d747e1a57f4bdb480fe48c 72ddf01025584437818c8b69cd3b28e3 a639438616d747e1a57f4bdb480fe48c--72ddf01025584437818c8b69cd3b28e3 eeaf80e891ad4f9b99e2dc3a9238d1a3 72ddf01025584437818c8b69cd3b28e3--eeaf80e891ad4f9b99e2dc3a9238d1a3 aca3c62794774067829f46dd4adb89b4 d2835930f21849cfaf36a6c17482362f t = -3.14 13be355fcee34e25b230a4d931414789--d2835930f21849cfaf36a6c17482362f 619280c030df47caad714799c8482c59 2 86afeebf34a3470a8202e8ee80aa04f6 t = 3.142 d2835930f21849cfaf36a6c17482362f--86afeebf34a3470a8202e8ee80aa04f6 995acfe6ffef40ce80ba70a6b06ed7ec t = -3.14 86afeebf34a3470a8202e8ee80aa04f6--995acfe6ffef40ce80ba70a6b06ed7ec 22787eb7b28b4735b9e0fb8dd3eb44b0 995acfe6ffef40ce80ba70a6b06ed7ec--22787eb7b28b4735b9e0fb8dd3eb44b0 ee1ba330e07e493abac2c237d545e4b9 t = 1.571 22787eb7b28b4735b9e0fb8dd3eb44b0--ee1ba330e07e493abac2c237d545e4b9 c23bc46426ce416ab17104f18555bea4 t = 1.571 ee1ba330e07e493abac2c237d545e4b9--c23bc46426ce416ab17104f18555bea4 e5bf00be33374095b03571b501dd2077 c23bc46426ce416ab17104f18555bea4--e5bf00be33374095b03571b501dd2077 d18a03f94bc04c53b15ea9d9b9cde950 X e5bf00be33374095b03571b501dd2077--d18a03f94bc04c53b15ea9d9b9cde950 fa6fd633475c48fba19f864ba7ae555b t = 1.571 d18a03f94bc04c53b15ea9d9b9cde950--fa6fd633475c48fba19f864ba7ae555b 77623c295f574c748d8346b06dac2334 t = 1.571 fa6fd633475c48fba19f864ba7ae555b--77623c295f574c748d8346b06dac2334 37f5c4706c014ce4b326a462767106a5 X 77623c295f574c748d8346b06dac2334--37f5c4706c014ce4b326a462767106a5 37f5c4706c014ce4b326a462767106a5--aca3c62794774067829f46dd4adb89b4 3cd652f2add248b8b0d9d11fb885b5a2 973d778da1e2411998ae8c6ef18979de 619280c030df47caad714799c8482c59--973d778da1e2411998ae8c6ef18979de 179f5c3050664be29469bc643cc19a71 973d778da1e2411998ae8c6ef18979de--179f5c3050664be29469bc643cc19a71 ee813e39b2d04cefb3ccedd39ede5dd3 179f5c3050664be29469bc643cc19a71--ee813e39b2d04cefb3ccedd39ede5dd3 724c71b692a24259b9585f37c580e1b5 X ee813e39b2d04cefb3ccedd39ede5dd3--724c71b692a24259b9585f37c580e1b5 74b27c6fda5b4068a60b0806e92409df 724c71b692a24259b9585f37c580e1b5--74b27c6fda5b4068a60b0806e92409df 876f35382ee8427da5cd74ba805a8de1 74b27c6fda5b4068a60b0806e92409df--876f35382ee8427da5cd74ba805a8de1 28a1f5db10f34dd5af324534fe796206 X 876f35382ee8427da5cd74ba805a8de1--28a1f5db10f34dd5af324534fe796206 705ce059166c4560b18532ae4888181a X 28a1f5db10f34dd5af324534fe796206--705ce059166c4560b18532ae4888181a 34a62cc82af74ff0826b04b68529df03 705ce059166c4560b18532ae4888181a--34a62cc82af74ff0826b04b68529df03 8b82b9101fd548eb9d43709956f9c52c 34a62cc82af74ff0826b04b68529df03--8b82b9101fd548eb9d43709956f9c52c 5583af1aa3a143f094c64fc59b632aa3 X 8b82b9101fd548eb9d43709956f9c52c--5583af1aa3a143f094c64fc59b632aa3 5583af1aa3a143f094c64fc59b632aa3--3cd652f2add248b8b0d9d11fb885b5a2

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:

# Interaction between qubits 0 and 1
gen_target = 1.0 * (Z(0) @ Z(1))

# Fixed interaction between qubits 1 and 2, and customizable between 0 and 1
def gen_build(g_int):
    return g_int * (Z(0) @ Z(1)) + 1.0 * (Z(1) @ Z(2))

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_ed9ca97901e0413ba473e2497891b6ca cluster_0370237a10f84df7a7949838f79479c3 0fefbb8a15c048eaa971ccdfd7fe3451 0 607c83dbec064b5895beff4ee453637c X 0fefbb8a15c048eaa971ccdfd7fe3451--607c83dbec064b5895beff4ee453637c 7d6d49f9d6f84448a3dd2be662d462f9 1 70ac431a6b034ba1adecac32b2cfcbc5 HamEvo 607c83dbec064b5895beff4ee453637c--70ac431a6b034ba1adecac32b2cfcbc5 8391a473c5c844359c28ac31fae0d86f X 70ac431a6b034ba1adecac32b2cfcbc5--8391a473c5c844359c28ac31fae0d86f 126a33b05df44643b95cce7fa8cdd3ea 8391a473c5c844359c28ac31fae0d86f--126a33b05df44643b95cce7fa8cdd3ea 9a1abed38c9a4f32b9723c6cf686f395 HamEvo 126a33b05df44643b95cce7fa8cdd3ea--9a1abed38c9a4f32b9723c6cf686f395 148ee98a60e644df824ce73e4e2af76a 9a1abed38c9a4f32b9723c6cf686f395--148ee98a60e644df824ce73e4e2af76a d303fe17423e4b1d87aa1968cbc894e1 148ee98a60e644df824ce73e4e2af76a--d303fe17423e4b1d87aa1968cbc894e1 e92b7ffda4b64cf4ade97337605abf49 4c27455457654bcd9dba0a086109b41d 7d6d49f9d6f84448a3dd2be662d462f9--4c27455457654bcd9dba0a086109b41d 3490bb1fc95e448abfdaefa0186835b8 2 3dfc92bc0f184a9daad59c0f84cb323e t = -0.50 4c27455457654bcd9dba0a086109b41d--3dfc92bc0f184a9daad59c0f84cb323e 8fe09780b8084d868469b23d36e1699b 3dfc92bc0f184a9daad59c0f84cb323e--8fe09780b8084d868469b23d36e1699b 373e4f1206c44a2bb6541e16045857b9 X 8fe09780b8084d868469b23d36e1699b--373e4f1206c44a2bb6541e16045857b9 3663e647985d4ffe8d868eef1495137a t = -0.50 373e4f1206c44a2bb6541e16045857b9--3663e647985d4ffe8d868eef1495137a 6aa058e5a259435cab2f33920e355854 X 3663e647985d4ffe8d868eef1495137a--6aa058e5a259435cab2f33920e355854 6aa058e5a259435cab2f33920e355854--e92b7ffda4b64cf4ade97337605abf49 dd2abd0f97314aee97b84ba6f65d4261 1d50469f62724423bd04baeee6e7efb5 X 3490bb1fc95e448abfdaefa0186835b8--1d50469f62724423bd04baeee6e7efb5 2edd4c6ccc5f4a7b8613bc5807ea45da 1d50469f62724423bd04baeee6e7efb5--2edd4c6ccc5f4a7b8613bc5807ea45da a22e8b0cdf724f92b3a6ddc9cee68663 X 2edd4c6ccc5f4a7b8613bc5807ea45da--a22e8b0cdf724f92b3a6ddc9cee68663 55f2f14eab3d412ab8508a7c59401fd8 X a22e8b0cdf724f92b3a6ddc9cee68663--55f2f14eab3d412ab8508a7c59401fd8 66878812b1454752b1b0d17a2d8757fa 55f2f14eab3d412ab8508a7c59401fd8--66878812b1454752b1b0d17a2d8757fa c334142763a94df4a1cd5a4f1e24c055 X 66878812b1454752b1b0d17a2d8757fa--c334142763a94df4a1cd5a4f1e24c055 c334142763a94df4a1cd5a4f1e24c055--dd2abd0f97314aee97b84ba6f65d4261

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_d63b4ba3134c471fbd8524aacf5c0aa5 cluster_8f3982c947d54efc97088f0c0557a14f ff67e896d34c41f681a0319135cb35b1 0 4762a39cf41a4f2684ab311ed5c903a6 X ff67e896d34c41f681a0319135cb35b1--4762a39cf41a4f2684ab311ed5c903a6 ff691117351343778b15d0e075e80086 1 7c05dcacab314fa59090c05764d44921 HamEvo 4762a39cf41a4f2684ab311ed5c903a6--7c05dcacab314fa59090c05764d44921 db2db94c5f7848f0a264002798adc302 X 7c05dcacab314fa59090c05764d44921--db2db94c5f7848f0a264002798adc302 58abf88ff7e9436dab5d9112adf0da5d db2db94c5f7848f0a264002798adc302--58abf88ff7e9436dab5d9112adf0da5d 7cb88b0d224347158b2e4463112607a6 HamEvo 58abf88ff7e9436dab5d9112adf0da5d--7cb88b0d224347158b2e4463112607a6 93edc912eb0545d3b14c821f322c01f3 7cb88b0d224347158b2e4463112607a6--93edc912eb0545d3b14c821f322c01f3 377b9b7e490d4f829299e5c86b3df5f0 93edc912eb0545d3b14c821f322c01f3--377b9b7e490d4f829299e5c86b3df5f0 7375d5890f594065b827cc3b3e343d67 0e7c4d1cfb2a49c795df57c877a79f02 ff691117351343778b15d0e075e80086--0e7c4d1cfb2a49c795df57c877a79f02 a6ce340ecf054b93b07c2296892fdcb1 2 60cb059fc3f54628821dd3df46947086 t = -500. 0e7c4d1cfb2a49c795df57c877a79f02--60cb059fc3f54628821dd3df46947086 990500618c85434daafa2b80fa254093 60cb059fc3f54628821dd3df46947086--990500618c85434daafa2b80fa254093 f3fc54692d83494cbc85bccb6550f8ca X 990500618c85434daafa2b80fa254093--f3fc54692d83494cbc85bccb6550f8ca 0d4fe090d71045bcb34af597414ab566 t = -500. f3fc54692d83494cbc85bccb6550f8ca--0d4fe090d71045bcb34af597414ab566 10e4a457427a4a579d22c6b73f85810f X 0d4fe090d71045bcb34af597414ab566--10e4a457427a4a579d22c6b73f85810f 10e4a457427a4a579d22c6b73f85810f--7375d5890f594065b827cc3b3e343d67 03ea8bcaebdc4b73adb15afbabd6eb9b f426bd2a504a4fbb8755917f312808ef X a6ce340ecf054b93b07c2296892fdcb1--f426bd2a504a4fbb8755917f312808ef 880c1fee8dff4c498487985139f06b8b f426bd2a504a4fbb8755917f312808ef--880c1fee8dff4c498487985139f06b8b dcc43ca8158d4f6e9e23c637859bfab5 X 880c1fee8dff4c498487985139f06b8b--dcc43ca8158d4f6e9e23c637859bfab5 003461039560400ba0fc3f1374ba1448 X dcc43ca8158d4f6e9e23c637859bfab5--003461039560400ba0fc3f1374ba1448 7b18dc4d98034dd1b35cbd882f427d35 003461039560400ba0fc3f1374ba1448--7b18dc4d98034dd1b35cbd882f427d35 da4f2105851548f4a468c36f4347ce18 X 7b18dc4d98034dd1b35cbd882f427d35--da4f2105851548f4a468c36f4347ce18 da4f2105851548f4a468c36f4347ce18--03ea8bcaebdc4b73adb15afbabd6eb9b

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