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

n_qubits = 2

# CNOT gate
cnot_gate = CNOT(0, 1)

# CNOT decomposed
phi = torch.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.00000000000000] 
   └── KronBlock(0,1)
       ├── N(1)
       └── N(0)
├── [mul: 1.00000000000000] 
   └── KronBlock(0,2)
       ├── N(2)
       └── N(0)
└── [mul: 1.00000000000000] 
    └── 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=torch.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_711ed245ee254a6aa70095bd9b4ed8b4 cluster_521a0938af1f4e34b0ba4faa09721369 cluster_57fc70a864794dc483899cb3c28ae59b cluster_1b69a9485533477ea3f2a9badc1c6aab cluster_75d186f20b004ec8965f9e7196f8ea45 cluster_b8999ba155db431186f4e523c2ec1797 cluster_f679be00163a47a8957aa86105e7c75d 24821ab51037459089266b3b7b9389d3 0 36a4ea9ce7f54beb91776d7f1bbafd28 HamEvo 24821ab51037459089266b3b7b9389d3--36a4ea9ce7f54beb91776d7f1bbafd28 7f6056758bd444588f7f0f2aac1b9db6 1 bcfa4d8b1d2b4e0982468a0620a32a13 HamEvo 36a4ea9ce7f54beb91776d7f1bbafd28--bcfa4d8b1d2b4e0982468a0620a32a13 6373dcefca934ae397ccb89e17bac16f HamEvo bcfa4d8b1d2b4e0982468a0620a32a13--6373dcefca934ae397ccb89e17bac16f a9e32ecff3384f0ab8bfb7989ce3ad02 X 6373dcefca934ae397ccb89e17bac16f--a9e32ecff3384f0ab8bfb7989ce3ad02 f0ff3eb211de4e7294c7d0d3eb225091 HamEvo a9e32ecff3384f0ab8bfb7989ce3ad02--f0ff3eb211de4e7294c7d0d3eb225091 ff10d7b19c574e3b964aae4957f45864 HamEvo f0ff3eb211de4e7294c7d0d3eb225091--ff10d7b19c574e3b964aae4957f45864 83703ef81ded460ebff09d683a45275c X ff10d7b19c574e3b964aae4957f45864--83703ef81ded460ebff09d683a45275c dede5145d8d1459db9d8d76317e6608a 83703ef81ded460ebff09d683a45275c--dede5145d8d1459db9d8d76317e6608a d7f5c889ccf9432a99ef19ff04e06271 HamEvo dede5145d8d1459db9d8d76317e6608a--d7f5c889ccf9432a99ef19ff04e06271 38347243dc77480d8000baa4d20234fe HamEvo d7f5c889ccf9432a99ef19ff04e06271--38347243dc77480d8000baa4d20234fe 065e4bbf5c164c5c9787f03cf01f5032 38347243dc77480d8000baa4d20234fe--065e4bbf5c164c5c9787f03cf01f5032 f22a8c3cf31849e89026b095f2c1eb98 065e4bbf5c164c5c9787f03cf01f5032--f22a8c3cf31849e89026b095f2c1eb98 fbdf386699bc4d2e99b1c372b1b1a05d b227194820044cb098566b8f04a1900c t = -3.142 7f6056758bd444588f7f0f2aac1b9db6--b227194820044cb098566b8f04a1900c 3e7d80949f5144c1985f1bbc151e7806 2 29599b28345248a095e14277331415a8 t = 3.142 b227194820044cb098566b8f04a1900c--29599b28345248a095e14277331415a8 ea0bd12c873a4723ac5563dc6e985a80 t = -3.142 29599b28345248a095e14277331415a8--ea0bd12c873a4723ac5563dc6e985a80 d91e65f52185459d84a805250470b4b3 ea0bd12c873a4723ac5563dc6e985a80--d91e65f52185459d84a805250470b4b3 b2c42c3578b047f2855e764cf35b6e50 t = 1.571 d91e65f52185459d84a805250470b4b3--b2c42c3578b047f2855e764cf35b6e50 e41810a27cb844c1b457063bd51a07bb t = 1.571 b2c42c3578b047f2855e764cf35b6e50--e41810a27cb844c1b457063bd51a07bb 5135b4e89320489ea305e4d0c2a9f8ff e41810a27cb844c1b457063bd51a07bb--5135b4e89320489ea305e4d0c2a9f8ff fca6c8a2eeff4107ad75570db33b8024 X 5135b4e89320489ea305e4d0c2a9f8ff--fca6c8a2eeff4107ad75570db33b8024 30c39f1d72ec48de9ffeaad99e576697 t = 1.571 fca6c8a2eeff4107ad75570db33b8024--30c39f1d72ec48de9ffeaad99e576697 ddbd4d45d417459083ffad09041a4be5 t = 1.571 30c39f1d72ec48de9ffeaad99e576697--ddbd4d45d417459083ffad09041a4be5 9cb1abf2e8ab4621956503939d5f1364 X ddbd4d45d417459083ffad09041a4be5--9cb1abf2e8ab4621956503939d5f1364 9cb1abf2e8ab4621956503939d5f1364--fbdf386699bc4d2e99b1c372b1b1a05d 01745c262248465ab02f08d32618fd74 780cdf8e2d514f609378602eb3316214 3e7d80949f5144c1985f1bbc151e7806--780cdf8e2d514f609378602eb3316214 71f51802b9024da28921b5068f946dfe 780cdf8e2d514f609378602eb3316214--71f51802b9024da28921b5068f946dfe 2468450373fb4d019367f1fd77aa8627 71f51802b9024da28921b5068f946dfe--2468450373fb4d019367f1fd77aa8627 022d566c0b5149c9b58f72575bf4b524 X 2468450373fb4d019367f1fd77aa8627--022d566c0b5149c9b58f72575bf4b524 6ffb4f0438bb468d85919bb7e0653829 022d566c0b5149c9b58f72575bf4b524--6ffb4f0438bb468d85919bb7e0653829 bd7de8d67004467aa838182cc0853939 6ffb4f0438bb468d85919bb7e0653829--bd7de8d67004467aa838182cc0853939 4d40b29c6ac6498aafd1d984c45158f6 X bd7de8d67004467aa838182cc0853939--4d40b29c6ac6498aafd1d984c45158f6 a7adcdc5722445eabd3c6288e566f5e7 X 4d40b29c6ac6498aafd1d984c45158f6--a7adcdc5722445eabd3c6288e566f5e7 893a27a60cb74c77b3f5c302f88ba0f9 a7adcdc5722445eabd3c6288e566f5e7--893a27a60cb74c77b3f5c302f88ba0f9 08e910ef4420449aa162ae0761a967a7 893a27a60cb74c77b3f5c302f88ba0f9--08e910ef4420449aa162ae0761a967a7 a71664d586ea41d3ab7c4372a450dd02 X 08e910ef4420449aa162ae0761a967a7--a71664d586ea41d3ab7c4372a450dd02 a71664d586ea41d3ab7c4372a450dd02--01745c262248465ab02f08d32618fd74

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_c53209159e184a2c8bd2fd75b3ebae5f cluster_b2d73112493c497e863683344c632c3b e024fd1e9fc2489f9f135c9c36e98753 0 8b57be7e33d949bfa319948b32b05d48 X e024fd1e9fc2489f9f135c9c36e98753--8b57be7e33d949bfa319948b32b05d48 e0e22405cd604cbdb2e6234f7d3d3a46 1 bbd30e91a0c940d291aca8e3b28af14f HamEvo 8b57be7e33d949bfa319948b32b05d48--bbd30e91a0c940d291aca8e3b28af14f 7e20433f75324326a24c1f4b49391bb8 X bbd30e91a0c940d291aca8e3b28af14f--7e20433f75324326a24c1f4b49391bb8 bdd4647552214f408dfd76ee97e723ba 7e20433f75324326a24c1f4b49391bb8--bdd4647552214f408dfd76ee97e723ba 41f510ef38fa4d5aba4e5825e802570f HamEvo bdd4647552214f408dfd76ee97e723ba--41f510ef38fa4d5aba4e5825e802570f a1ad5cb9cd5042d5bfbc5396fc732123 41f510ef38fa4d5aba4e5825e802570f--a1ad5cb9cd5042d5bfbc5396fc732123 48d18749e48c48e3b911d0a6999ae385 a1ad5cb9cd5042d5bfbc5396fc732123--48d18749e48c48e3b911d0a6999ae385 3c3cfede803942db91e0e7d7502c6db4 6c01b4dc499047768b7e58f96aec4d25 e0e22405cd604cbdb2e6234f7d3d3a46--6c01b4dc499047768b7e58f96aec4d25 0dbc690104c5439e89a9a507d84a78dc 2 6b485c1e01814570bccb822e67982a7f t = -0.500 6c01b4dc499047768b7e58f96aec4d25--6b485c1e01814570bccb822e67982a7f 398429a7816d4478925d2f3f7305bfb1 6b485c1e01814570bccb822e67982a7f--398429a7816d4478925d2f3f7305bfb1 6116bfe4dfcc40bc939d23fd71bb913c X 398429a7816d4478925d2f3f7305bfb1--6116bfe4dfcc40bc939d23fd71bb913c 792c8bf3a3364d9aba439d3208ac2be8 t = -0.500 6116bfe4dfcc40bc939d23fd71bb913c--792c8bf3a3364d9aba439d3208ac2be8 ca8261bc52ce4ce8b23c2172010b9c54 X 792c8bf3a3364d9aba439d3208ac2be8--ca8261bc52ce4ce8b23c2172010b9c54 ca8261bc52ce4ce8b23c2172010b9c54--3c3cfede803942db91e0e7d7502c6db4 61a675e76da74806a74642d13ecbfe3f fe9b88bce01c4d1cb93b4145b060e04d X 0dbc690104c5439e89a9a507d84a78dc--fe9b88bce01c4d1cb93b4145b060e04d 033f00e803ea42409f21b82cf079531f fe9b88bce01c4d1cb93b4145b060e04d--033f00e803ea42409f21b82cf079531f f290da1277b24fb7a66622ed96527dd1 X 033f00e803ea42409f21b82cf079531f--f290da1277b24fb7a66622ed96527dd1 dd1d76af67c7408287449344517e1b90 X f290da1277b24fb7a66622ed96527dd1--dd1d76af67c7408287449344517e1b90 603d0dab9a0844238f2f6d22813b2561 dd1d76af67c7408287449344517e1b90--603d0dab9a0844238f2f6d22813b2561 4046cf36ff564aa98ba25bb95c824e31 X 603d0dab9a0844238f2f6d22813b2561--4046cf36ff564aa98ba25bb95c824e31 4046cf36ff564aa98ba25bb95c824e31--61a675e76da74806a74642d13ecbfe3f

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_0897753d71924cfa92ccfe62b56ec08f cluster_142410410e18493db7b304b8f44c1730 9d4a19745b33437d805179fbc6a88393 0 5208aba35e0048368ac8d14807d9433d X 9d4a19745b33437d805179fbc6a88393--5208aba35e0048368ac8d14807d9433d d7d3d30567da4533875dbedb4519e146 1 dc78db547fd84f4ebe6574990f5ff9a3 HamEvo 5208aba35e0048368ac8d14807d9433d--dc78db547fd84f4ebe6574990f5ff9a3 bd4381d069b54d5cb7d1b1f2f54a4e2b X dc78db547fd84f4ebe6574990f5ff9a3--bd4381d069b54d5cb7d1b1f2f54a4e2b 60362b72621c41f994948d6dd096fc02 bd4381d069b54d5cb7d1b1f2f54a4e2b--60362b72621c41f994948d6dd096fc02 cdef7890d0de4e778dd044b70c575499 HamEvo 60362b72621c41f994948d6dd096fc02--cdef7890d0de4e778dd044b70c575499 25c95048e5fa466cb0933e80bc388536 cdef7890d0de4e778dd044b70c575499--25c95048e5fa466cb0933e80bc388536 76ff921e9ce14812bc449090a0960933 25c95048e5fa466cb0933e80bc388536--76ff921e9ce14812bc449090a0960933 b809128f12434abfa2662aa3f90a6f03 c206bea8ba2646dda8e24a41c8aee6ed d7d3d30567da4533875dbedb4519e146--c206bea8ba2646dda8e24a41c8aee6ed 9c6aa9d680734f82be515d4a4fb06677 2 3bc326b17b6d41509ee0636f3f02581f t = -500.000000000000 c206bea8ba2646dda8e24a41c8aee6ed--3bc326b17b6d41509ee0636f3f02581f 60d65c64ebcb4d869085b9cb202dec70 3bc326b17b6d41509ee0636f3f02581f--60d65c64ebcb4d869085b9cb202dec70 f35f9a725bde4f00ae55fafb21af865f X 60d65c64ebcb4d869085b9cb202dec70--f35f9a725bde4f00ae55fafb21af865f afca812b60404d3aa0e3ab4bb7b05e65 t = -500.000000000000 f35f9a725bde4f00ae55fafb21af865f--afca812b60404d3aa0e3ab4bb7b05e65 828b700ca9a84d39988bb9e9e79f864a X afca812b60404d3aa0e3ab4bb7b05e65--828b700ca9a84d39988bb9e9e79f864a 828b700ca9a84d39988bb9e9e79f864a--b809128f12434abfa2662aa3f90a6f03 d110d7c4d95c48cea5eb6c0d21b3755a a5b4cb1ddf9c4926aea990391a13cada X 9c6aa9d680734f82be515d4a4fb06677--a5b4cb1ddf9c4926aea990391a13cada 6cd5b9c4dece479984dd86891c27994a a5b4cb1ddf9c4926aea990391a13cada--6cd5b9c4dece479984dd86891c27994a 97410f5aabc14b629822b5c6c80b0b65 X 6cd5b9c4dece479984dd86891c27994a--97410f5aabc14b629822b5c6c80b0b65 6670e21f4aa9473da9e44b14ef657cc9 X 97410f5aabc14b629822b5c6c80b0b65--6670e21f4aa9473da9e44b14ef657cc9 5533416a97ba438780087c93daf39efb 6670e21f4aa9473da9e44b14ef657cc9--5533416a97ba438780087c93daf39efb e45aceb0eec647bbbcdedd28bdaa59d1 X 5533416a97ba438780087c93daf39efb--e45aceb0eec647bbbcdedd28bdaa59d1 e45aceb0eec647bbbcdedd28bdaa59d1--d110d7c4d95c48cea5eb6c0d21b3755a

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