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 ϕ=π:

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,

CPHASE(i,j,ϕ)=exp(iϕHCP(i,j))
HCP=14(IiZi)(IjZj)=NiNj

where the number operator Ni=12(IiZi)=n^i is used, leading to an Ising-like interaction n^in^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 gint. The Hamiltonian for the system can be written by summing interaction terms over all pairs:

Hsys=i=0nj=0i1gintNiNj,

which in this case leads to only three interaction terms,

Hsys=gint(N0N1+N1N2+N0N2)

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 Htarget (here the unitary of the gate) until a specified time tf by using only the evolution of a build Hamiltonian Hbuild (here Hsys) together with local X-gates. In Qadence, daqc_transform is applicable for Htarget and Hbuild 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_6fb0152f58204b4c89185359ff5ff192 cluster_35bb67d182df449287e395f48c81cfdf cluster_b3e270c49c194cab9d9f623aeb72fa76 cluster_7f4ffb432d9c40738828cc08480e1585 cluster_04d699874eac4062b9fbca1d7c1f0b33 cluster_edbbf8e155c048879b9237c85461d1f1 cluster_8a98cc9a2625447fb7d5be87d8ddcef3 1c0cdb666add4bb0a3c42bda71a362a2 0 09834e1ef1834aea8dd7d3b094a2b509 HamEvo 1c0cdb666add4bb0a3c42bda71a362a2--09834e1ef1834aea8dd7d3b094a2b509 cd656fd00a3a4d1b98b58d57bf620d2a 1 e90e9cb91aea4e2ba943a30b90fad68a HamEvo 09834e1ef1834aea8dd7d3b094a2b509--e90e9cb91aea4e2ba943a30b90fad68a f3947713fa1d40f280bd665026a3bf99 HamEvo e90e9cb91aea4e2ba943a30b90fad68a--f3947713fa1d40f280bd665026a3bf99 fecc4b33366d436b932f4d7a87a81ddf X f3947713fa1d40f280bd665026a3bf99--fecc4b33366d436b932f4d7a87a81ddf 2979478688a24268aec0db62580ba2c4 HamEvo fecc4b33366d436b932f4d7a87a81ddf--2979478688a24268aec0db62580ba2c4 c7b6054d4bc5449998b2b4463cf70f79 HamEvo 2979478688a24268aec0db62580ba2c4--c7b6054d4bc5449998b2b4463cf70f79 432aa2524f7d4cb588cfc8e7645f4978 X c7b6054d4bc5449998b2b4463cf70f79--432aa2524f7d4cb588cfc8e7645f4978 41c6acf7ce66497396810ddb3b7c37eb 432aa2524f7d4cb588cfc8e7645f4978--41c6acf7ce66497396810ddb3b7c37eb 5428e023689b45ff950f808a7357a6ca HamEvo 41c6acf7ce66497396810ddb3b7c37eb--5428e023689b45ff950f808a7357a6ca 938c944353d249ddb44e24f870fae138 HamEvo 5428e023689b45ff950f808a7357a6ca--938c944353d249ddb44e24f870fae138 1663cde9797d4c50b06a3b17e88972e0 938c944353d249ddb44e24f870fae138--1663cde9797d4c50b06a3b17e88972e0 95a4c396693f4f408aa73fd408c9c10a 1663cde9797d4c50b06a3b17e88972e0--95a4c396693f4f408aa73fd408c9c10a b6431f751ae14ea8ae0706fd064c9752 d8db54775cde4ae196565c055a9b0451 t = -3.14 cd656fd00a3a4d1b98b58d57bf620d2a--d8db54775cde4ae196565c055a9b0451 0249598ea58e4b8b88b82e6f83e59393 2 45d6d609795945c69488fcbb038c0949 t = 3.142 d8db54775cde4ae196565c055a9b0451--45d6d609795945c69488fcbb038c0949 b57a33362bf94ff6afbaa2542c1f3fcb t = -3.14 45d6d609795945c69488fcbb038c0949--b57a33362bf94ff6afbaa2542c1f3fcb 6fab2bdeca2c4fef861673a9b10c04ff b57a33362bf94ff6afbaa2542c1f3fcb--6fab2bdeca2c4fef861673a9b10c04ff 946adf4e8f704dc0ab912927817bfc07 t = 1.571 6fab2bdeca2c4fef861673a9b10c04ff--946adf4e8f704dc0ab912927817bfc07 5ede70a677904ea4b60927a6d47d0868 t = 1.571 946adf4e8f704dc0ab912927817bfc07--5ede70a677904ea4b60927a6d47d0868 1eac0f36ae164301869a7ea2b6342f02 5ede70a677904ea4b60927a6d47d0868--1eac0f36ae164301869a7ea2b6342f02 4e237d9c13d84624bd8276aa362163ee X 1eac0f36ae164301869a7ea2b6342f02--4e237d9c13d84624bd8276aa362163ee 193ffcbcb90b425a8ee29c274887c2e5 t = 1.571 4e237d9c13d84624bd8276aa362163ee--193ffcbcb90b425a8ee29c274887c2e5 28e6125c4b6d4d33bd5da327f3f75b98 t = 1.571 193ffcbcb90b425a8ee29c274887c2e5--28e6125c4b6d4d33bd5da327f3f75b98 b975389ebcbd403890ee7115dab89dbe X 28e6125c4b6d4d33bd5da327f3f75b98--b975389ebcbd403890ee7115dab89dbe b975389ebcbd403890ee7115dab89dbe--b6431f751ae14ea8ae0706fd064c9752 dc932613cf4b4a4f9354a3a4be1d2b48 bb39dec877304d60b5abd7564522baba 0249598ea58e4b8b88b82e6f83e59393--bb39dec877304d60b5abd7564522baba 2d5862b65d6b4f98b485baa7d8ba61d3 bb39dec877304d60b5abd7564522baba--2d5862b65d6b4f98b485baa7d8ba61d3 18ef03329ac54ca88ea27f97ddb111ef 2d5862b65d6b4f98b485baa7d8ba61d3--18ef03329ac54ca88ea27f97ddb111ef f5728a14258543b884c32af230bc6e0a X 18ef03329ac54ca88ea27f97ddb111ef--f5728a14258543b884c32af230bc6e0a 092854c4d6094f9c87c929d2bc2aba88 f5728a14258543b884c32af230bc6e0a--092854c4d6094f9c87c929d2bc2aba88 3f468b9a2f104004bcf3d8c509cbea32 092854c4d6094f9c87c929d2bc2aba88--3f468b9a2f104004bcf3d8c509cbea32 34074d0179fd477aa41d76b3cb4585bc X 3f468b9a2f104004bcf3d8c509cbea32--34074d0179fd477aa41d76b3cb4585bc 739ff00e61544ed2b79a6f3c5e2985e5 X 34074d0179fd477aa41d76b3cb4585bc--739ff00e61544ed2b79a6f3c5e2985e5 af68dc3d19794a20913d86e171f6e315 739ff00e61544ed2b79a6f3c5e2985e5--af68dc3d19794a20913d86e171f6e315 3f4a7131633e41fcb76795208f8a00d0 af68dc3d19794a20913d86e171f6e315--3f4a7131633e41fcb76795208f8a00d0 a719d2fc89624d6c8fcc5d3a8bbe60ce X 3f4a7131633e41fcb76795208f8a00d0--a719d2fc89624d6c8fcc5d3a8bbe60ce a719d2fc89624d6c8fcc5d3a8bbe60ce--dc932613cf4b4a4f9354a3a4be1d2b48

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(n1) 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(n1) 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(n1) 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_e30ed3611ddc44118168138a2a691448 cluster_b3f0a65728b2436b82afdfa8aaa8a087 03d92dde30d4479685e9f31c11108443 0 6e71fe179c3d4e2e8527de643a73f0dc X 03d92dde30d4479685e9f31c11108443--6e71fe179c3d4e2e8527de643a73f0dc 69877bd517954d878950fd366bebab38 1 4791aa25df3c4237a0e0cf8b7f809c85 HamEvo 6e71fe179c3d4e2e8527de643a73f0dc--4791aa25df3c4237a0e0cf8b7f809c85 f7c2f376863c40e08817e52fc8aeac9c X 4791aa25df3c4237a0e0cf8b7f809c85--f7c2f376863c40e08817e52fc8aeac9c d1cde4877d1a4b59a2e549753303d336 f7c2f376863c40e08817e52fc8aeac9c--d1cde4877d1a4b59a2e549753303d336 9d4f1f8e8a724fc3b17d4635ad8c7194 HamEvo d1cde4877d1a4b59a2e549753303d336--9d4f1f8e8a724fc3b17d4635ad8c7194 c7fab87518744d088b8d950c2db07cc8 9d4f1f8e8a724fc3b17d4635ad8c7194--c7fab87518744d088b8d950c2db07cc8 747f8ab8e94e427abac4ecbf6cbff69f c7fab87518744d088b8d950c2db07cc8--747f8ab8e94e427abac4ecbf6cbff69f b8788dfe7ee04a9cb0a773124e607605 855f8c8ca06f4eecafc5ffd91262b45c 69877bd517954d878950fd366bebab38--855f8c8ca06f4eecafc5ffd91262b45c c921dde6285d4a259c769bb4018861bd 2 e51e8733d1684635a807ae4a76b446c8 t = -0.50 855f8c8ca06f4eecafc5ffd91262b45c--e51e8733d1684635a807ae4a76b446c8 8324ba2b83a0409b8d7a61a756a8c38b e51e8733d1684635a807ae4a76b446c8--8324ba2b83a0409b8d7a61a756a8c38b 73d547f6f4714eb78f3c8a4dbe9a7186 X 8324ba2b83a0409b8d7a61a756a8c38b--73d547f6f4714eb78f3c8a4dbe9a7186 791027d5f9c244beb66a3dc9f43edf5d t = -0.50 73d547f6f4714eb78f3c8a4dbe9a7186--791027d5f9c244beb66a3dc9f43edf5d b1caa796e6894a0fa6161b87cf093f63 X 791027d5f9c244beb66a3dc9f43edf5d--b1caa796e6894a0fa6161b87cf093f63 b1caa796e6894a0fa6161b87cf093f63--b8788dfe7ee04a9cb0a773124e607605 7a0fc45a6a374794b2f88960c8558923 ddd7130d805c4134ad17bd7c7a290e87 X c921dde6285d4a259c769bb4018861bd--ddd7130d805c4134ad17bd7c7a290e87 8782c1c57c6c4bea810666c19eee83d4 ddd7130d805c4134ad17bd7c7a290e87--8782c1c57c6c4bea810666c19eee83d4 193dfe910fb24cb28847a8721699d51f X 8782c1c57c6c4bea810666c19eee83d4--193dfe910fb24cb28847a8721699d51f b563c98936ce4e5d9c5390ff356a114c X 193dfe910fb24cb28847a8721699d51f--b563c98936ce4e5d9c5390ff356a114c 99232d1c112f499982f92248c273314f b563c98936ce4e5d9c5390ff356a114c--99232d1c112f499982f92248c273314f 05b4c264dc9c4c5c8d537bec86c5e92a X 99232d1c112f499982f92248c273314f--05b4c264dc9c4c5c8d537bec86c5e92a 05b4c264dc9c4c5c8d537bec86c5e92a--7a0fc45a6a374794b2f88960c8558923

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_0659708993aa4c2d9d14a575007d0b90 cluster_e8ffabf12552431eb392413f6606fa60 640929f8a337491e8b8d6f4542ed318c 0 dac4eaeaa6d04cf1869318aa2773d279 X 640929f8a337491e8b8d6f4542ed318c--dac4eaeaa6d04cf1869318aa2773d279 f9adc240018343efa40d02bdf035e1ae 1 88e94897a5894db8a36cf6d46515e630 HamEvo dac4eaeaa6d04cf1869318aa2773d279--88e94897a5894db8a36cf6d46515e630 cc81247d9a1f49d0b9df55e789462383 X 88e94897a5894db8a36cf6d46515e630--cc81247d9a1f49d0b9df55e789462383 264a38af53e94122aa1d566ce39431f0 cc81247d9a1f49d0b9df55e789462383--264a38af53e94122aa1d566ce39431f0 d6af009949b44b478caf169b720d3ed6 HamEvo 264a38af53e94122aa1d566ce39431f0--d6af009949b44b478caf169b720d3ed6 6e44084eacc943bab7290dbddf2eca12 d6af009949b44b478caf169b720d3ed6--6e44084eacc943bab7290dbddf2eca12 d31857b52c7040b1b07da0936d6b8c6b 6e44084eacc943bab7290dbddf2eca12--d31857b52c7040b1b07da0936d6b8c6b b83074040bea492aa1c8d3aae630e131 b4175003654144db96dabb6d236dcdc3 f9adc240018343efa40d02bdf035e1ae--b4175003654144db96dabb6d236dcdc3 0850c754048e4165b6121a3270636e4f 2 4e8d3c6141e84c9c9c16fba8b7101b29 t = -500. b4175003654144db96dabb6d236dcdc3--4e8d3c6141e84c9c9c16fba8b7101b29 e2e153c8802d4fd69bd11ac3aa539d3a 4e8d3c6141e84c9c9c16fba8b7101b29--e2e153c8802d4fd69bd11ac3aa539d3a ebc690fdade84e418c645a0ea15fd182 X e2e153c8802d4fd69bd11ac3aa539d3a--ebc690fdade84e418c645a0ea15fd182 92ddd19d4d3a46b7832781fef2ff25b8 t = -500. ebc690fdade84e418c645a0ea15fd182--92ddd19d4d3a46b7832781fef2ff25b8 e7ffcecb9238421d9caf4639b496bc0a X 92ddd19d4d3a46b7832781fef2ff25b8--e7ffcecb9238421d9caf4639b496bc0a e7ffcecb9238421d9caf4639b496bc0a--b83074040bea492aa1c8d3aae630e131 9b15f91db26740668a6d2b7b31ca09fe e5d86795b85d45e4b99ec6705fcbe8de X 0850c754048e4165b6121a3270636e4f--e5d86795b85d45e4b99ec6705fcbe8de a3f53c864efd45cd97db2c94eafc2465 e5d86795b85d45e4b99ec6705fcbe8de--a3f53c864efd45cd97db2c94eafc2465 cd50c82e5ea242fe8661c246665e3fa5 X a3f53c864efd45cd97db2c94eafc2465--cd50c82e5ea242fe8661c246665e3fa5 50e7cce150d347f597f37c0b8d153d69 X cd50c82e5ea242fe8661c246665e3fa5--50e7cce150d347f597f37c0b8d153d69 a62f5a5e6079474a888ab14d1d1ff89e 50e7cce150d347f597f37c0b8d153d69--a62f5a5e6079474a888ab14d1d1ff89e 61dec6f253bd4b2487cfaf13109b34e9 X a62f5a5e6079474a888ab14d1d1ff89e--61dec6f253bd4b2487cfaf13109b34e9 61dec6f253bd4b2487cfaf13109b34e9--9b15f91db26740668a6d2b7b31ca09fe

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