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_32629e48d37d409fa492fb22a8babfbf cluster_0ea22f072aef4f85a655688235f9a808 cluster_8a91c6b45e3940d7a01066d5f96ffba9 cluster_d885960fc1104f57aa43d99aeb9c7fdd cluster_d3a3e2c84349471fb936741de486c597 cluster_295d40188fad4932a302e7ea743dda8f cluster_c962b86f8de34d02838bb4e602d8c996 4f19b5797652451790049a4f9bc32352 0 04cb460816f642c8b785985fc629b487 HamEvo 4f19b5797652451790049a4f9bc32352--04cb460816f642c8b785985fc629b487 20f7ba524dfd488dad587896e912b1b7 1 e2efa476f4a9407985f3dcfee04fda06 HamEvo 04cb460816f642c8b785985fc629b487--e2efa476f4a9407985f3dcfee04fda06 de327eeb3ec94c9f8ea148aeb633c8b6 HamEvo e2efa476f4a9407985f3dcfee04fda06--de327eeb3ec94c9f8ea148aeb633c8b6 2fa557425d73453482466eabb61385a1 X de327eeb3ec94c9f8ea148aeb633c8b6--2fa557425d73453482466eabb61385a1 4af76754f12a4b5e8520e8d8a72c5452 HamEvo 2fa557425d73453482466eabb61385a1--4af76754f12a4b5e8520e8d8a72c5452 811b9e65a3084809b23f3e1a4cde73eb HamEvo 4af76754f12a4b5e8520e8d8a72c5452--811b9e65a3084809b23f3e1a4cde73eb 6acda10c4b6e429db6a72fb9339ec101 X 811b9e65a3084809b23f3e1a4cde73eb--6acda10c4b6e429db6a72fb9339ec101 667be6cd9c514f00b992d7974425afb1 6acda10c4b6e429db6a72fb9339ec101--667be6cd9c514f00b992d7974425afb1 abbf64bce94b46aeab71eb945fecc493 HamEvo 667be6cd9c514f00b992d7974425afb1--abbf64bce94b46aeab71eb945fecc493 9911b7dffd6a43e4aceefbd6070f55b5 HamEvo abbf64bce94b46aeab71eb945fecc493--9911b7dffd6a43e4aceefbd6070f55b5 c79d658e36134f1fb983bb5b8bf2c3b3 9911b7dffd6a43e4aceefbd6070f55b5--c79d658e36134f1fb983bb5b8bf2c3b3 6f53be4aff0d4d818ca2ef388f6b18e4 c79d658e36134f1fb983bb5b8bf2c3b3--6f53be4aff0d4d818ca2ef388f6b18e4 5f9c3b2bdc904eb2bb3543a78f8ddb43 25bda047d85b4384adfcc79f1f73ae23 t = -3.14 20f7ba524dfd488dad587896e912b1b7--25bda047d85b4384adfcc79f1f73ae23 65bcd3ca11fa43afbe43e7351ac1d3d1 2 c742a1a538904cd98f558f4bfa2b2537 t = 3.142 25bda047d85b4384adfcc79f1f73ae23--c742a1a538904cd98f558f4bfa2b2537 0b7a437327424ffd96015677fd2a9727 t = -3.14 c742a1a538904cd98f558f4bfa2b2537--0b7a437327424ffd96015677fd2a9727 09224e90551149af95de97c4b61c576a 0b7a437327424ffd96015677fd2a9727--09224e90551149af95de97c4b61c576a 7394cb0c26374a2ba788b3cb13ac9e02 t = 1.571 09224e90551149af95de97c4b61c576a--7394cb0c26374a2ba788b3cb13ac9e02 82f6e3bf844a47bfa2d3a2607e48529f t = 1.571 7394cb0c26374a2ba788b3cb13ac9e02--82f6e3bf844a47bfa2d3a2607e48529f b7d620ae6644434ab5ea82ac9512c8f7 82f6e3bf844a47bfa2d3a2607e48529f--b7d620ae6644434ab5ea82ac9512c8f7 c8f413546918456cabb840fdd2ff947f X b7d620ae6644434ab5ea82ac9512c8f7--c8f413546918456cabb840fdd2ff947f 0497a42f655f460c98dfe9400dd0a6b2 t = 1.571 c8f413546918456cabb840fdd2ff947f--0497a42f655f460c98dfe9400dd0a6b2 05522213f88f48a0a8c8495b270a7447 t = 1.571 0497a42f655f460c98dfe9400dd0a6b2--05522213f88f48a0a8c8495b270a7447 d4cbdf5574684972b407c8dbbca7eb23 X 05522213f88f48a0a8c8495b270a7447--d4cbdf5574684972b407c8dbbca7eb23 d4cbdf5574684972b407c8dbbca7eb23--5f9c3b2bdc904eb2bb3543a78f8ddb43 61f17b6e018745939c67ba1ca4b05f11 d508e8da5e7c4bb7961bf1e997748f11 65bcd3ca11fa43afbe43e7351ac1d3d1--d508e8da5e7c4bb7961bf1e997748f11 12a26a1b02aa4eef80549a79ffca1956 d508e8da5e7c4bb7961bf1e997748f11--12a26a1b02aa4eef80549a79ffca1956 d7f7f1509844468a891717b3053b9aa1 12a26a1b02aa4eef80549a79ffca1956--d7f7f1509844468a891717b3053b9aa1 3d2237a2402a410294a48b5515a7f304 X d7f7f1509844468a891717b3053b9aa1--3d2237a2402a410294a48b5515a7f304 cff70700c9544da3ac444271f3da4cfa 3d2237a2402a410294a48b5515a7f304--cff70700c9544da3ac444271f3da4cfa ffc7be57a2b64dcc8297f9597b94bafe cff70700c9544da3ac444271f3da4cfa--ffc7be57a2b64dcc8297f9597b94bafe 53eb3a0895e84e3d9f4acfad1d1db806 X ffc7be57a2b64dcc8297f9597b94bafe--53eb3a0895e84e3d9f4acfad1d1db806 4351dbb964db49259ed931502f818615 X 53eb3a0895e84e3d9f4acfad1d1db806--4351dbb964db49259ed931502f818615 d93e58f13b0743f9b362f24d13a9ad54 4351dbb964db49259ed931502f818615--d93e58f13b0743f9b362f24d13a9ad54 f72c7d752ca64cf48c6d1bba8b2341c9 d93e58f13b0743f9b362f24d13a9ad54--f72c7d752ca64cf48c6d1bba8b2341c9 7d2cec821402406da6cad0046d20b645 X f72c7d752ca64cf48c6d1bba8b2341c9--7d2cec821402406da6cad0046d20b645 7d2cec821402406da6cad0046d20b645--61f17b6e018745939c67ba1ca4b05f11

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_a1480668f32f4509bb3d8a6781445844 cluster_bd9c0bfe257443b09c2938dc12f4091f 75e1ef0526684bf4abc4b6111c9b2686 0 4419ab694bd5458687c7b36b32feae0d X 75e1ef0526684bf4abc4b6111c9b2686--4419ab694bd5458687c7b36b32feae0d 1c1e282ebecd480bb4b22df1ef1504ba 1 a7915ae7ffcc410dae03197792f06380 HamEvo 4419ab694bd5458687c7b36b32feae0d--a7915ae7ffcc410dae03197792f06380 47cc674fe51e4bb68849c8026350de78 X a7915ae7ffcc410dae03197792f06380--47cc674fe51e4bb68849c8026350de78 20526c285a264d17af112f3945a2183d 47cc674fe51e4bb68849c8026350de78--20526c285a264d17af112f3945a2183d 167223adf7f847a883be1eb4524ade36 HamEvo 20526c285a264d17af112f3945a2183d--167223adf7f847a883be1eb4524ade36 849249f443614dffa8473998e8c008da 167223adf7f847a883be1eb4524ade36--849249f443614dffa8473998e8c008da f34244e47adf434d8c6b7b58b330a30d 849249f443614dffa8473998e8c008da--f34244e47adf434d8c6b7b58b330a30d 694b8dd857cc4de7a1c57284c8ca792d 22895bd91e9747eb8c63ea992f4ca4c4 1c1e282ebecd480bb4b22df1ef1504ba--22895bd91e9747eb8c63ea992f4ca4c4 96d00f0c9d0440349c0ae3381325b670 2 9bac0578a20f425bb07c2962352c1103 t = -0.50 22895bd91e9747eb8c63ea992f4ca4c4--9bac0578a20f425bb07c2962352c1103 0cdd519c3db34409857dcfd67dc9781a 9bac0578a20f425bb07c2962352c1103--0cdd519c3db34409857dcfd67dc9781a 4728d320b0514cc887d13b0de392153a X 0cdd519c3db34409857dcfd67dc9781a--4728d320b0514cc887d13b0de392153a 22c29b567cb8487f86aef8ab054799b7 t = -0.50 4728d320b0514cc887d13b0de392153a--22c29b567cb8487f86aef8ab054799b7 94d8dc3e92f542158442e13b600508f3 X 22c29b567cb8487f86aef8ab054799b7--94d8dc3e92f542158442e13b600508f3 94d8dc3e92f542158442e13b600508f3--694b8dd857cc4de7a1c57284c8ca792d 9854423671a341e198c89c86e055476e 5c2a5783d5a940589055d46c818c0714 X 96d00f0c9d0440349c0ae3381325b670--5c2a5783d5a940589055d46c818c0714 e07036638db742029fdf71c1abb0e1d4 5c2a5783d5a940589055d46c818c0714--e07036638db742029fdf71c1abb0e1d4 7eccdd046d21412c92571b9096a5633b X e07036638db742029fdf71c1abb0e1d4--7eccdd046d21412c92571b9096a5633b a89b8a1aec45411689777e082a36b15d X 7eccdd046d21412c92571b9096a5633b--a89b8a1aec45411689777e082a36b15d 4a1775a8e5804ab5ac8e2f7258e05ce8 a89b8a1aec45411689777e082a36b15d--4a1775a8e5804ab5ac8e2f7258e05ce8 318020dd1bfd4649a9d49977657e6840 X 4a1775a8e5804ab5ac8e2f7258e05ce8--318020dd1bfd4649a9d49977657e6840 318020dd1bfd4649a9d49977657e6840--9854423671a341e198c89c86e055476e

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_86ad8d0b3e77424e86cfe2dd7146435b cluster_4ce77ca381304e49a0041c0be3428a5e ba8e858e72304ba4a69835ac6753e77f 0 3433ecec246f4e4380d90da537bd660a X ba8e858e72304ba4a69835ac6753e77f--3433ecec246f4e4380d90da537bd660a 2e19d4ce00c2451dadc0e9e9116d436c 1 44329ae9141244fea60caf729437bcfc HamEvo 3433ecec246f4e4380d90da537bd660a--44329ae9141244fea60caf729437bcfc c47a0d8b5fd54196aa119e69c4e85c6b X 44329ae9141244fea60caf729437bcfc--c47a0d8b5fd54196aa119e69c4e85c6b 4cb15cef3aa5432c8edfc3fb89140f46 c47a0d8b5fd54196aa119e69c4e85c6b--4cb15cef3aa5432c8edfc3fb89140f46 5aa44c22b63a4d6ca8c29411f4c209c4 HamEvo 4cb15cef3aa5432c8edfc3fb89140f46--5aa44c22b63a4d6ca8c29411f4c209c4 2da5540f49b94d86974420c00ef84b58 5aa44c22b63a4d6ca8c29411f4c209c4--2da5540f49b94d86974420c00ef84b58 2eb182aa9d9e416b9db6bb4bd03466f0 2da5540f49b94d86974420c00ef84b58--2eb182aa9d9e416b9db6bb4bd03466f0 86caa75fb1ca4f38bd8edde5a3dd6e6a 590acb5533f44581991df578bbede928 2e19d4ce00c2451dadc0e9e9116d436c--590acb5533f44581991df578bbede928 fd2179a0b266463c9782593d4d5a808e 2 0f52a936484c41179447b9b8de653e0f t = -500. 590acb5533f44581991df578bbede928--0f52a936484c41179447b9b8de653e0f b42a21f0d7fb4c9d963795a25822e1bf 0f52a936484c41179447b9b8de653e0f--b42a21f0d7fb4c9d963795a25822e1bf e4ec3ebabdd1416b8943ca24f84315f7 X b42a21f0d7fb4c9d963795a25822e1bf--e4ec3ebabdd1416b8943ca24f84315f7 c555102198bd4307923b98c358cfd2e5 t = -500. e4ec3ebabdd1416b8943ca24f84315f7--c555102198bd4307923b98c358cfd2e5 d3f237a97dbd4a62ba6bd90497e3618a X c555102198bd4307923b98c358cfd2e5--d3f237a97dbd4a62ba6bd90497e3618a d3f237a97dbd4a62ba6bd90497e3618a--86caa75fb1ca4f38bd8edde5a3dd6e6a 1583a23315a44bdfb7b05bcef9c2a2c4 32297412b45c4ad09596462d0b819ca8 X fd2179a0b266463c9782593d4d5a808e--32297412b45c4ad09596462d0b819ca8 9dbc9011c5b54283b407a5cab27da73b 32297412b45c4ad09596462d0b819ca8--9dbc9011c5b54283b407a5cab27da73b a46c02b72a2e44d8a33e99125c99370b X 9dbc9011c5b54283b407a5cab27da73b--a46c02b72a2e44d8a33e99125c99370b 0b7f8504d33644b9bf84a4bc71242080 X a46c02b72a2e44d8a33e99125c99370b--0b7f8504d33644b9bf84a4bc71242080 643dc15a09624318941ba64d18abab3a 0b7f8504d33644b9bf84a4bc71242080--643dc15a09624318941ba64d18abab3a ca6cb9c2d69647639abbddc3635f41ea X 643dc15a09624318941ba64d18abab3a--ca6cb9c2d69647639abbddc3635f41ea ca6cb9c2d69647639abbddc3635f41ea--1583a23315a44bdfb7b05bcef9c2a2c4

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