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_fed216d8bbe84746a59000d07668cbe3 cluster_ebbbbc2c1ef54419b671d15140e7f3e9 cluster_a113b48313c74460af252cec6ba5cfb1 cluster_8bde4925b25146599c271c7416b98695 cluster_6874878f38844c49bbeb9b5070e7235f cluster_409853f2eb444e37840f044d642062a3 cluster_9be3c4ae992e487c912906f3c3c80556 7565c707c9814d5489453ea0d659a2c9 0 a71245815daf40b4ae33d8ae31bf90bf HamEvo 7565c707c9814d5489453ea0d659a2c9--a71245815daf40b4ae33d8ae31bf90bf c0e8a2fd6e3f49659a0df0efc2808a47 1 ae4af9080ebd48458f35ade06a31c382 HamEvo a71245815daf40b4ae33d8ae31bf90bf--ae4af9080ebd48458f35ade06a31c382 a68794617fcf456e9742c6a6a9b505f0 HamEvo ae4af9080ebd48458f35ade06a31c382--a68794617fcf456e9742c6a6a9b505f0 975f19e72b03424ea16ef6b180a73729 X a68794617fcf456e9742c6a6a9b505f0--975f19e72b03424ea16ef6b180a73729 f59f8cfdf42e480b930847f007f5d58e HamEvo 975f19e72b03424ea16ef6b180a73729--f59f8cfdf42e480b930847f007f5d58e a3b9f287595f43babc95741998ad0bb5 HamEvo f59f8cfdf42e480b930847f007f5d58e--a3b9f287595f43babc95741998ad0bb5 312764c94c2a4a2fb13c623f29429fc1 X a3b9f287595f43babc95741998ad0bb5--312764c94c2a4a2fb13c623f29429fc1 90f1e828b497435d9891a4466fe7cd5b 312764c94c2a4a2fb13c623f29429fc1--90f1e828b497435d9891a4466fe7cd5b 82e0750d5fe24bb7873be54b6698f754 HamEvo 90f1e828b497435d9891a4466fe7cd5b--82e0750d5fe24bb7873be54b6698f754 1eaa8e9b392948278dd01e502b9802c2 HamEvo 82e0750d5fe24bb7873be54b6698f754--1eaa8e9b392948278dd01e502b9802c2 dbee4d3af4c94456b7a9452949a947f5 1eaa8e9b392948278dd01e502b9802c2--dbee4d3af4c94456b7a9452949a947f5 dc90158feb8d4454948fb6d7e918f67e dbee4d3af4c94456b7a9452949a947f5--dc90158feb8d4454948fb6d7e918f67e 3f77c8922c85409da7aebefd1f07a428 480e424f4dbf4b52882271da23464d53 t = -3.14 c0e8a2fd6e3f49659a0df0efc2808a47--480e424f4dbf4b52882271da23464d53 d045281048ab4cfbbbc6e6aaffaa843d 2 1a54330aa6054507a57e38d9701bd970 t = 3.142 480e424f4dbf4b52882271da23464d53--1a54330aa6054507a57e38d9701bd970 e9890c5f07b54f15a3fbd4fb723c9245 t = -3.14 1a54330aa6054507a57e38d9701bd970--e9890c5f07b54f15a3fbd4fb723c9245 c70560bb1e12482f96f59a6091f1e012 e9890c5f07b54f15a3fbd4fb723c9245--c70560bb1e12482f96f59a6091f1e012 c1e2833b5a72470e9f8ff116f3b572f7 t = 1.571 c70560bb1e12482f96f59a6091f1e012--c1e2833b5a72470e9f8ff116f3b572f7 3c58a9be235746628e87d2807f75de56 t = 1.571 c1e2833b5a72470e9f8ff116f3b572f7--3c58a9be235746628e87d2807f75de56 66c28415c4924a95896a6167590a8929 3c58a9be235746628e87d2807f75de56--66c28415c4924a95896a6167590a8929 b478a187ef1847c686f91023d7f9283e X 66c28415c4924a95896a6167590a8929--b478a187ef1847c686f91023d7f9283e 5bcc83621cdb4b92b23cccf5a204da38 t = 1.571 b478a187ef1847c686f91023d7f9283e--5bcc83621cdb4b92b23cccf5a204da38 d659a0987ce049db94606e371654972f t = 1.571 5bcc83621cdb4b92b23cccf5a204da38--d659a0987ce049db94606e371654972f 18a070dad8aa413685bdd2248e55f7c8 X d659a0987ce049db94606e371654972f--18a070dad8aa413685bdd2248e55f7c8 18a070dad8aa413685bdd2248e55f7c8--3f77c8922c85409da7aebefd1f07a428 756ba4efb2034e08a8e0a7db5f3a9eb0 bc29e7b657d149e9bd75e9092d701bf9 d045281048ab4cfbbbc6e6aaffaa843d--bc29e7b657d149e9bd75e9092d701bf9 20482e94a4d249a3a02a54d74e4fb55f bc29e7b657d149e9bd75e9092d701bf9--20482e94a4d249a3a02a54d74e4fb55f a7ceae620642439ea63d6c4600384dfc 20482e94a4d249a3a02a54d74e4fb55f--a7ceae620642439ea63d6c4600384dfc 9ae323c23514464cac620440e073d132 X a7ceae620642439ea63d6c4600384dfc--9ae323c23514464cac620440e073d132 90b481b720f34fbe9e9da7e0c8c64ab8 9ae323c23514464cac620440e073d132--90b481b720f34fbe9e9da7e0c8c64ab8 677e5745c9a9439fa2148c061da32ecd 90b481b720f34fbe9e9da7e0c8c64ab8--677e5745c9a9439fa2148c061da32ecd e249bac142af4a6186a84a00cd0ab829 X 677e5745c9a9439fa2148c061da32ecd--e249bac142af4a6186a84a00cd0ab829 9ac16e5ca58e4f6999fcc1ef90714168 X e249bac142af4a6186a84a00cd0ab829--9ac16e5ca58e4f6999fcc1ef90714168 85cf3ae99bff4528b89258e94dade2e6 9ac16e5ca58e4f6999fcc1ef90714168--85cf3ae99bff4528b89258e94dade2e6 3339c7f3908243d9a49d9a9481cebc23 85cf3ae99bff4528b89258e94dade2e6--3339c7f3908243d9a49d9a9481cebc23 a4e5a38602ab4fcb94b054320184c519 X 3339c7f3908243d9a49d9a9481cebc23--a4e5a38602ab4fcb94b054320184c519 a4e5a38602ab4fcb94b054320184c519--756ba4efb2034e08a8e0a7db5f3a9eb0

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_9d0c9ed0a7b14e3e8937bf22bfde12b8 cluster_67cbbfb0b49842899c9b5ebd888575fb d8a23ad4feb74e6c8ad61b93f7d0822d 0 ed0cc5899dd8437d85758a69bd3fa6d8 X d8a23ad4feb74e6c8ad61b93f7d0822d--ed0cc5899dd8437d85758a69bd3fa6d8 822dadb805ca4708b9461facf471054e 1 3123bbad64b046aca727e03e7ccdfd19 HamEvo ed0cc5899dd8437d85758a69bd3fa6d8--3123bbad64b046aca727e03e7ccdfd19 30d08310f9904ef98261e2e8441a2bc2 X 3123bbad64b046aca727e03e7ccdfd19--30d08310f9904ef98261e2e8441a2bc2 a909a100992a458db1861615b8ef4416 30d08310f9904ef98261e2e8441a2bc2--a909a100992a458db1861615b8ef4416 306c06e14e6b4e9dbd3709664e032dd0 HamEvo a909a100992a458db1861615b8ef4416--306c06e14e6b4e9dbd3709664e032dd0 d0d8b4ed2c584cdeae29b46395c7082c 306c06e14e6b4e9dbd3709664e032dd0--d0d8b4ed2c584cdeae29b46395c7082c 84884794df9f4736a97193ee955feabe d0d8b4ed2c584cdeae29b46395c7082c--84884794df9f4736a97193ee955feabe db882aa3d52b4464b75bbac08a0a357d 31c97ed15e7143feab23d76e23626d34 822dadb805ca4708b9461facf471054e--31c97ed15e7143feab23d76e23626d34 37f3c434a5d84667888d22b639ffa70b 2 2a4fdb4e70b940f6912aea1a70f7cc53 t = -0.50 31c97ed15e7143feab23d76e23626d34--2a4fdb4e70b940f6912aea1a70f7cc53 03e01e50f6584afc94b29a14ec529bf3 2a4fdb4e70b940f6912aea1a70f7cc53--03e01e50f6584afc94b29a14ec529bf3 a33ea5f95c6a443b89f991a4ab044de9 X 03e01e50f6584afc94b29a14ec529bf3--a33ea5f95c6a443b89f991a4ab044de9 a3275dc9311e4a5d9a8acc570b0bc635 t = -0.50 a33ea5f95c6a443b89f991a4ab044de9--a3275dc9311e4a5d9a8acc570b0bc635 ebfefc869ce249efb0750960b7dc8128 X a3275dc9311e4a5d9a8acc570b0bc635--ebfefc869ce249efb0750960b7dc8128 ebfefc869ce249efb0750960b7dc8128--db882aa3d52b4464b75bbac08a0a357d 854f6bb202314c11aaf257c6dcab10f1 90756b15986b446284c9fe57c162c07e X 37f3c434a5d84667888d22b639ffa70b--90756b15986b446284c9fe57c162c07e e6adc8e76a9e427ea50812d134aea7b3 90756b15986b446284c9fe57c162c07e--e6adc8e76a9e427ea50812d134aea7b3 7a0e903807844f57bcf0660ca5bcb6ef X e6adc8e76a9e427ea50812d134aea7b3--7a0e903807844f57bcf0660ca5bcb6ef 55c9fcec22a641b58296ef123b97bca7 X 7a0e903807844f57bcf0660ca5bcb6ef--55c9fcec22a641b58296ef123b97bca7 e3199256e4a44dcc8df88999ed1c8c00 55c9fcec22a641b58296ef123b97bca7--e3199256e4a44dcc8df88999ed1c8c00 6e0c3b6f43d74cdba1d307faead31e63 X e3199256e4a44dcc8df88999ed1c8c00--6e0c3b6f43d74cdba1d307faead31e63 6e0c3b6f43d74cdba1d307faead31e63--854f6bb202314c11aaf257c6dcab10f1

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_31763f91ce3342c9a3bbbb0e5884efe6 cluster_dcd449fdd65243bdbec8a4984b4e32f8 7d97174058e84e2e9943ed9032cdca3e 0 e4db181395334a28b60c293d011eb43b X 7d97174058e84e2e9943ed9032cdca3e--e4db181395334a28b60c293d011eb43b 5bccb4bb6bd84d73ae345f349bc17f9a 1 a0e5084514fa4183802bd5974dda2b12 HamEvo e4db181395334a28b60c293d011eb43b--a0e5084514fa4183802bd5974dda2b12 326bf10651ce4bf8a930e0866793f0d8 X a0e5084514fa4183802bd5974dda2b12--326bf10651ce4bf8a930e0866793f0d8 58748e38c37f4ba79766f3e6e88caf16 326bf10651ce4bf8a930e0866793f0d8--58748e38c37f4ba79766f3e6e88caf16 9351cc108e14451cb733fe12233f03ea HamEvo 58748e38c37f4ba79766f3e6e88caf16--9351cc108e14451cb733fe12233f03ea 2715cc6c936041d0ae4c4d51562057e0 9351cc108e14451cb733fe12233f03ea--2715cc6c936041d0ae4c4d51562057e0 612bf9461cce44c39544e5abe4b557d7 2715cc6c936041d0ae4c4d51562057e0--612bf9461cce44c39544e5abe4b557d7 89a36f327bd8467289a8fe694fff05ea be2f9806e8d34708a1cbd3a1d08da74a 5bccb4bb6bd84d73ae345f349bc17f9a--be2f9806e8d34708a1cbd3a1d08da74a f1f884df5e274b76a4a5fe5e331be651 2 abedca5ad27b428f92fb334db35229d4 t = -500. be2f9806e8d34708a1cbd3a1d08da74a--abedca5ad27b428f92fb334db35229d4 92dee8647eb8450688ae9734ad626e8f abedca5ad27b428f92fb334db35229d4--92dee8647eb8450688ae9734ad626e8f 4115f5c7dd4c489da169061d8a03aa17 X 92dee8647eb8450688ae9734ad626e8f--4115f5c7dd4c489da169061d8a03aa17 81e7e6320074402db1a58b515ce11173 t = -500. 4115f5c7dd4c489da169061d8a03aa17--81e7e6320074402db1a58b515ce11173 607ddc6f56134f63975607b68eaf8a29 X 81e7e6320074402db1a58b515ce11173--607ddc6f56134f63975607b68eaf8a29 607ddc6f56134f63975607b68eaf8a29--89a36f327bd8467289a8fe694fff05ea 8c93a0a0d36c432fa1ab4b295dd9294b 832d35de3de34bfb958966c452f1aaa1 X f1f884df5e274b76a4a5fe5e331be651--832d35de3de34bfb958966c452f1aaa1 c29ac0498be744b7b46415c218666560 832d35de3de34bfb958966c452f1aaa1--c29ac0498be744b7b46415c218666560 0dfcaccbf23a47e7a587dbbd2c28ac92 X c29ac0498be744b7b46415c218666560--0dfcaccbf23a47e7a587dbbd2c28ac92 56a358b0aaa44e8188247e87906deb29 X 0dfcaccbf23a47e7a587dbbd2c28ac92--56a358b0aaa44e8188247e87906deb29 8d52e4e232ce48e7bbb88a9619e75d23 56a358b0aaa44e8188247e87906deb29--8d52e4e232ce48e7bbb88a9619e75d23 b92c4e9a58c149a2a8e805aac0b2fc54 X 8d52e4e232ce48e7bbb88a9619e75d23--b92c4e9a58c149a2a8e805aac0b2fc54 b92c4e9a58c149a2a8e805aac0b2fc54--8c93a0a0d36c432fa1ab4b295dd9294b

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