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_2a4c97e16bfa4867b5d9bab0c51d1e3d cluster_3b6fd3d5c2fb432bacc3ecffdefae682 cluster_53ab8dd50fda432eb23c49eb11f1d583 cluster_ce3c410946474463a670c7426d35acb5 cluster_c31b9f2e70f3409b9798de901095b52d cluster_066d14ad96ad4590b5f6a716ec745aff cluster_7f39ad96858141a2ace79f480362dda1 0db4901daad4448e854f0a53053c2564 0 e9c4e2db7c5349339a7fd8fe3fd2c770 HamEvo 0db4901daad4448e854f0a53053c2564--e9c4e2db7c5349339a7fd8fe3fd2c770 17d00348e34e4a14bbec681894f061c4 1 f688bb7a1c9a4d22bed35a18b6d11897 HamEvo e9c4e2db7c5349339a7fd8fe3fd2c770--f688bb7a1c9a4d22bed35a18b6d11897 b55c00ba671143c19dbd71e13b3b25ae HamEvo f688bb7a1c9a4d22bed35a18b6d11897--b55c00ba671143c19dbd71e13b3b25ae fdc86af93b16401594172609db67b7b1 X b55c00ba671143c19dbd71e13b3b25ae--fdc86af93b16401594172609db67b7b1 bf0a44e1a9a74139805a117ff947a633 HamEvo fdc86af93b16401594172609db67b7b1--bf0a44e1a9a74139805a117ff947a633 0abd1a2c77f74625af0c26ec6584c03b HamEvo bf0a44e1a9a74139805a117ff947a633--0abd1a2c77f74625af0c26ec6584c03b 5aebf386dc9c4bd6a705857bd05ed470 X 0abd1a2c77f74625af0c26ec6584c03b--5aebf386dc9c4bd6a705857bd05ed470 ad6616efc70f4b8d893b11a9dfbf942d 5aebf386dc9c4bd6a705857bd05ed470--ad6616efc70f4b8d893b11a9dfbf942d dfe41531f3704dc2a553754031ed8cd4 HamEvo ad6616efc70f4b8d893b11a9dfbf942d--dfe41531f3704dc2a553754031ed8cd4 07e8042883384df8ae31177ef73de722 HamEvo dfe41531f3704dc2a553754031ed8cd4--07e8042883384df8ae31177ef73de722 64b97b74d885482d8056925f2044219d 07e8042883384df8ae31177ef73de722--64b97b74d885482d8056925f2044219d 9c28ae93615a4d0fa891744a37e0155b 64b97b74d885482d8056925f2044219d--9c28ae93615a4d0fa891744a37e0155b 6f5cee8590f4498bbca6a88037bc6aa4 5924b574c0284ffbb6966ca0634fd7d8 t = -3.14 17d00348e34e4a14bbec681894f061c4--5924b574c0284ffbb6966ca0634fd7d8 77aa7d2acb944f7fb356b452401678bc 2 c5f03aaa28854fe38be53f5a4ed2b35a t = 3.142 5924b574c0284ffbb6966ca0634fd7d8--c5f03aaa28854fe38be53f5a4ed2b35a 5296d4195174458fb7a0cb26bc769672 t = -3.14 c5f03aaa28854fe38be53f5a4ed2b35a--5296d4195174458fb7a0cb26bc769672 9c115e3b30a14138ae585cb7be1b7b24 5296d4195174458fb7a0cb26bc769672--9c115e3b30a14138ae585cb7be1b7b24 4664540e2a7c4355a2c1945553549a0d t = 1.571 9c115e3b30a14138ae585cb7be1b7b24--4664540e2a7c4355a2c1945553549a0d 287faa899e8542cba023f3f1332ce51c t = 1.571 4664540e2a7c4355a2c1945553549a0d--287faa899e8542cba023f3f1332ce51c 3188bfd6bdba4255b1dbd774e0ae2fb8 287faa899e8542cba023f3f1332ce51c--3188bfd6bdba4255b1dbd774e0ae2fb8 c90cd744527d470a8566bfbadaaa1a10 X 3188bfd6bdba4255b1dbd774e0ae2fb8--c90cd744527d470a8566bfbadaaa1a10 b87abf50342d4e588c5c0f54001826c0 t = 1.571 c90cd744527d470a8566bfbadaaa1a10--b87abf50342d4e588c5c0f54001826c0 92321945eed34008b77301d1b66e40cd t = 1.571 b87abf50342d4e588c5c0f54001826c0--92321945eed34008b77301d1b66e40cd 359a27c155f9490b9fcc64afabdc931d X 92321945eed34008b77301d1b66e40cd--359a27c155f9490b9fcc64afabdc931d 359a27c155f9490b9fcc64afabdc931d--6f5cee8590f4498bbca6a88037bc6aa4 a7aeb669809d4ec3b62926156b259248 48e36788994b476eb437ca1de558c8bb 77aa7d2acb944f7fb356b452401678bc--48e36788994b476eb437ca1de558c8bb 4aaec7b977ab4157924767f1d902cd19 48e36788994b476eb437ca1de558c8bb--4aaec7b977ab4157924767f1d902cd19 25cf080f50e9492493d9c4a8962614c6 4aaec7b977ab4157924767f1d902cd19--25cf080f50e9492493d9c4a8962614c6 16e13355d22643fa94393b92adac6e85 X 25cf080f50e9492493d9c4a8962614c6--16e13355d22643fa94393b92adac6e85 8414f4c38312469ca8aadbc5f17286a0 16e13355d22643fa94393b92adac6e85--8414f4c38312469ca8aadbc5f17286a0 1941376320e64fb3bf37b90ece3f0389 8414f4c38312469ca8aadbc5f17286a0--1941376320e64fb3bf37b90ece3f0389 3d611397d2ef4c96ac90b70f0fea63a9 X 1941376320e64fb3bf37b90ece3f0389--3d611397d2ef4c96ac90b70f0fea63a9 4c93fb103f9840c0b9413b84101326e9 X 3d611397d2ef4c96ac90b70f0fea63a9--4c93fb103f9840c0b9413b84101326e9 282173d54bab4fa5a1f9a7d7bee6068e 4c93fb103f9840c0b9413b84101326e9--282173d54bab4fa5a1f9a7d7bee6068e 6004f27013214bca91742fc5f0cd163d 282173d54bab4fa5a1f9a7d7bee6068e--6004f27013214bca91742fc5f0cd163d e7d2cba5bd97437db415c421b931e8e5 X 6004f27013214bca91742fc5f0cd163d--e7d2cba5bd97437db415c421b931e8e5 e7d2cba5bd97437db415c421b931e8e5--a7aeb669809d4ec3b62926156b259248

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_4467ccce4f154d5eb09bb5c07ea2641a cluster_155677286bba4d7fa8afd6cc846a1795 27ad2594e1c24e2c9d9feab58b60d456 0 76634e212f3547a5a0a729cce58a8319 X 27ad2594e1c24e2c9d9feab58b60d456--76634e212f3547a5a0a729cce58a8319 e0b4a60f64684c68b9fae31e453ceff1 1 64982daf10414e18bde799e7f14b1dbb HamEvo 76634e212f3547a5a0a729cce58a8319--64982daf10414e18bde799e7f14b1dbb 76ea4afacef449e4a35c23389343af6b X 64982daf10414e18bde799e7f14b1dbb--76ea4afacef449e4a35c23389343af6b 0b7bd280c18f499ab2df54759457a4d9 76ea4afacef449e4a35c23389343af6b--0b7bd280c18f499ab2df54759457a4d9 73a989e9b18e4f3aaa27dd1e11321115 HamEvo 0b7bd280c18f499ab2df54759457a4d9--73a989e9b18e4f3aaa27dd1e11321115 277f50d283464b3f933f55ffadf80a8e 73a989e9b18e4f3aaa27dd1e11321115--277f50d283464b3f933f55ffadf80a8e 5f0ec1b94e1e4e50b1e649119c9a7880 277f50d283464b3f933f55ffadf80a8e--5f0ec1b94e1e4e50b1e649119c9a7880 5871ce39bf314db58d330642aad49425 f435b5fb90d243e8a13b2ab3e6d79a6f e0b4a60f64684c68b9fae31e453ceff1--f435b5fb90d243e8a13b2ab3e6d79a6f 414ed36b3f0e47eb92b6a4f1a4d9b111 2 c2a1e882c7004ae2b15f45d6ebb79958 t = -0.50 f435b5fb90d243e8a13b2ab3e6d79a6f--c2a1e882c7004ae2b15f45d6ebb79958 c5d27f2328a645cc9bfdb8c12382efd5 c2a1e882c7004ae2b15f45d6ebb79958--c5d27f2328a645cc9bfdb8c12382efd5 7575645322364e8eba9e4ccbf176a791 X c5d27f2328a645cc9bfdb8c12382efd5--7575645322364e8eba9e4ccbf176a791 563bd3f755d34b2090f761f5c0234bfc t = -0.50 7575645322364e8eba9e4ccbf176a791--563bd3f755d34b2090f761f5c0234bfc 19226e42f8aa4cee834c52510ffa58a3 X 563bd3f755d34b2090f761f5c0234bfc--19226e42f8aa4cee834c52510ffa58a3 19226e42f8aa4cee834c52510ffa58a3--5871ce39bf314db58d330642aad49425 3899bfbeacb14ea19e745a2de2101912 67a430af683741beb0f35413cd096667 X 414ed36b3f0e47eb92b6a4f1a4d9b111--67a430af683741beb0f35413cd096667 21531e603326431eae09380f8a4aa1cc 67a430af683741beb0f35413cd096667--21531e603326431eae09380f8a4aa1cc 7555e5124d52485fa8cda93eaa6c7438 X 21531e603326431eae09380f8a4aa1cc--7555e5124d52485fa8cda93eaa6c7438 0303d1bd7ef2401a9e382065435fe488 X 7555e5124d52485fa8cda93eaa6c7438--0303d1bd7ef2401a9e382065435fe488 abcbe3dfa0d0424cb7fe43f1f9b0265f 0303d1bd7ef2401a9e382065435fe488--abcbe3dfa0d0424cb7fe43f1f9b0265f fd12193c873c4fe790a9f7c14f3ca645 X abcbe3dfa0d0424cb7fe43f1f9b0265f--fd12193c873c4fe790a9f7c14f3ca645 fd12193c873c4fe790a9f7c14f3ca645--3899bfbeacb14ea19e745a2de2101912

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_92ee9f7de5a545adb149789c04fa9b40 cluster_bdb60bfc878e4913961d58304b87d4d8 21ee9907963f4d738d02f8a7c26fd382 0 e25913c8cd454446a219b16f60ec7cdb X 21ee9907963f4d738d02f8a7c26fd382--e25913c8cd454446a219b16f60ec7cdb 455240e4b6ef41b6a38c4abe2560fed6 1 19b427ac7bf84128b218d5a0f024dc9f HamEvo e25913c8cd454446a219b16f60ec7cdb--19b427ac7bf84128b218d5a0f024dc9f 8d344103dd44438bb645165a5b2b4109 X 19b427ac7bf84128b218d5a0f024dc9f--8d344103dd44438bb645165a5b2b4109 03ee40dc40ed4d14bf9b5c6ae2ec87e8 8d344103dd44438bb645165a5b2b4109--03ee40dc40ed4d14bf9b5c6ae2ec87e8 e5440d78a76c48b4b6f2e9d2c6b6caaf HamEvo 03ee40dc40ed4d14bf9b5c6ae2ec87e8--e5440d78a76c48b4b6f2e9d2c6b6caaf ca0237c592664bf487ec0cfb386f1209 e5440d78a76c48b4b6f2e9d2c6b6caaf--ca0237c592664bf487ec0cfb386f1209 ff8d53b53add4673ac19001dd2f2d56f ca0237c592664bf487ec0cfb386f1209--ff8d53b53add4673ac19001dd2f2d56f 7aa6037c4a2743e7bc8e561a050c0b69 086b79b834cd4da7955caf7f031624a6 455240e4b6ef41b6a38c4abe2560fed6--086b79b834cd4da7955caf7f031624a6 d0df0a284b21458785dfc24bd5818614 2 04e37f6cadb74d2782adc3469febc9f9 t = -500. 086b79b834cd4da7955caf7f031624a6--04e37f6cadb74d2782adc3469febc9f9 1bb1246317bd46c496b975da9a0b5033 04e37f6cadb74d2782adc3469febc9f9--1bb1246317bd46c496b975da9a0b5033 c8088ce3d52b4f07b55642b6295ba534 X 1bb1246317bd46c496b975da9a0b5033--c8088ce3d52b4f07b55642b6295ba534 798611a3736d4458b087aa8f60dbb847 t = -500. c8088ce3d52b4f07b55642b6295ba534--798611a3736d4458b087aa8f60dbb847 848eadb79195491bb4a08dacc2e01359 X 798611a3736d4458b087aa8f60dbb847--848eadb79195491bb4a08dacc2e01359 848eadb79195491bb4a08dacc2e01359--7aa6037c4a2743e7bc8e561a050c0b69 a55a4b6ce01c43f2bbc87e8828aef8e6 b72caf10d06647fea87a319360df596f X d0df0a284b21458785dfc24bd5818614--b72caf10d06647fea87a319360df596f 5f4e21df9a1a47f6a705e246387b70ba b72caf10d06647fea87a319360df596f--5f4e21df9a1a47f6a705e246387b70ba 2b67d29ab3c14f3f88e59b108777589a X 5f4e21df9a1a47f6a705e246387b70ba--2b67d29ab3c14f3f88e59b108777589a a8dec661443b4e24a7743ca273dae5cf X 2b67d29ab3c14f3f88e59b108777589a--a8dec661443b4e24a7743ca273dae5cf 81dca087d32a4b09b66558cf1f427f7d a8dec661443b4e24a7743ca273dae5cf--81dca087d32a4b09b66558cf1f427f7d ffbb14cc0a03490eabcb5263e4eb21a1 X 81dca087d32a4b09b66558cf1f427f7d--ffbb14cc0a03490eabcb5263e4eb21a1 ffbb14cc0a03490eabcb5263e4eb21a1--a55a4b6ce01c43f2bbc87e8828aef8e6

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