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_634a8ea8b91747119f38a15f9107d72a cluster_1ef5c58a31604f1f8ca6bcd9ee6890e2 cluster_cfe8d4dbe594426ca533aea2e73f5eb1 cluster_e735bb9ddef3400d8aa2baea03e3458f cluster_783bf2ab68d24991988fe18e6cd3c069 cluster_a08ae363f10942f5971ad1c2ffc3ddb0 cluster_123c1aedce974fe58726b29cf346099d 2245a229cefe43cb8bcd873044f874ae 0 ec80fb775e4d40bdb20a16eabd5401d7 HamEvo 2245a229cefe43cb8bcd873044f874ae--ec80fb775e4d40bdb20a16eabd5401d7 c6437aae1b51465d9c1525b6dca9454c 1 6c810c31c7e74e918035b52f16615e07 HamEvo ec80fb775e4d40bdb20a16eabd5401d7--6c810c31c7e74e918035b52f16615e07 ec99bc1bfbda4e54944186a5098d57b1 HamEvo 6c810c31c7e74e918035b52f16615e07--ec99bc1bfbda4e54944186a5098d57b1 bb89fe123cba4a51894e39fc64778a04 X ec99bc1bfbda4e54944186a5098d57b1--bb89fe123cba4a51894e39fc64778a04 47dfaaf8d31c4ef0a975ca4a4c1b2ddb HamEvo bb89fe123cba4a51894e39fc64778a04--47dfaaf8d31c4ef0a975ca4a4c1b2ddb e722087a41c7414b961e3647ca49d4f0 HamEvo 47dfaaf8d31c4ef0a975ca4a4c1b2ddb--e722087a41c7414b961e3647ca49d4f0 0d3aea03822849adabd353901e644373 X e722087a41c7414b961e3647ca49d4f0--0d3aea03822849adabd353901e644373 a78c3e3b9f384c4f909fb30bad8ea5d0 0d3aea03822849adabd353901e644373--a78c3e3b9f384c4f909fb30bad8ea5d0 a97245174b8446f990da881dcc9dcaf0 HamEvo a78c3e3b9f384c4f909fb30bad8ea5d0--a97245174b8446f990da881dcc9dcaf0 22933e6bbd2b4ccb85ddc95f38ace563 HamEvo a97245174b8446f990da881dcc9dcaf0--22933e6bbd2b4ccb85ddc95f38ace563 c416e26f28a644e389c1460cc00bfdfc 22933e6bbd2b4ccb85ddc95f38ace563--c416e26f28a644e389c1460cc00bfdfc b31197adb17b4928ab981b1aad26368c c416e26f28a644e389c1460cc00bfdfc--b31197adb17b4928ab981b1aad26368c 315d81ebd84b4e48b3bc7e954564512b 25bb71c703374d0195f03b3717866939 t = -3.142 c6437aae1b51465d9c1525b6dca9454c--25bb71c703374d0195f03b3717866939 6d9fad433d654b2fbefe2fa1bcce9323 2 691aa2734364447cb06a25399f2231c4 t = 3.142 25bb71c703374d0195f03b3717866939--691aa2734364447cb06a25399f2231c4 610f791a185143a9a20373081aa974ac t = -3.142 691aa2734364447cb06a25399f2231c4--610f791a185143a9a20373081aa974ac 46f235f5c8d54bc2ace281ce18d77983 610f791a185143a9a20373081aa974ac--46f235f5c8d54bc2ace281ce18d77983 545c8ba88b914381a31848f4ef1e8d2b t = 1.571 46f235f5c8d54bc2ace281ce18d77983--545c8ba88b914381a31848f4ef1e8d2b 6b3561978737496a8cfd3c7fd2facc0d t = 1.571 545c8ba88b914381a31848f4ef1e8d2b--6b3561978737496a8cfd3c7fd2facc0d 8b3626a631624f11be30887041881f20 6b3561978737496a8cfd3c7fd2facc0d--8b3626a631624f11be30887041881f20 a2e8b47cf9504a3d94214d2760703893 X 8b3626a631624f11be30887041881f20--a2e8b47cf9504a3d94214d2760703893 07961532c4bb4110bebff73db13ea21a t = 1.571 a2e8b47cf9504a3d94214d2760703893--07961532c4bb4110bebff73db13ea21a a73d1452169f4550a8ce8dc92d6d63a3 t = 1.571 07961532c4bb4110bebff73db13ea21a--a73d1452169f4550a8ce8dc92d6d63a3 d09a707850e544369d041210d6d5d6f0 X a73d1452169f4550a8ce8dc92d6d63a3--d09a707850e544369d041210d6d5d6f0 d09a707850e544369d041210d6d5d6f0--315d81ebd84b4e48b3bc7e954564512b 769dde1907ba435e9e88709aa5fcb448 b0e9d15d43894e97b3ad1ed0832a2dc7 6d9fad433d654b2fbefe2fa1bcce9323--b0e9d15d43894e97b3ad1ed0832a2dc7 ce125d51b01541b0b8ae9654871572b8 b0e9d15d43894e97b3ad1ed0832a2dc7--ce125d51b01541b0b8ae9654871572b8 4d6a0daa02f643b6814927fd2a76ba3c ce125d51b01541b0b8ae9654871572b8--4d6a0daa02f643b6814927fd2a76ba3c f2b65156fdff4537b7b6f1f5a33a23f5 X 4d6a0daa02f643b6814927fd2a76ba3c--f2b65156fdff4537b7b6f1f5a33a23f5 aa9198a3c373471fa96b67424cd66171 f2b65156fdff4537b7b6f1f5a33a23f5--aa9198a3c373471fa96b67424cd66171 17d8efb3ec85435b9bd745d8a8370283 aa9198a3c373471fa96b67424cd66171--17d8efb3ec85435b9bd745d8a8370283 8e9dd685593a4aaeb2f2dafd6a50b773 X 17d8efb3ec85435b9bd745d8a8370283--8e9dd685593a4aaeb2f2dafd6a50b773 cee98ba206554a1d96377c497a4c0c77 X 8e9dd685593a4aaeb2f2dafd6a50b773--cee98ba206554a1d96377c497a4c0c77 b151bc58b1fc454f8cd70edc8f0ebb2d cee98ba206554a1d96377c497a4c0c77--b151bc58b1fc454f8cd70edc8f0ebb2d 85ce8e2e101b424cbe9b46bf4cf57c71 b151bc58b1fc454f8cd70edc8f0ebb2d--85ce8e2e101b424cbe9b46bf4cf57c71 d3e366b63c9c48ec9b8c282f6fba9dac X 85ce8e2e101b424cbe9b46bf4cf57c71--d3e366b63c9c48ec9b8c282f6fba9dac d3e366b63c9c48ec9b8c282f6fba9dac--769dde1907ba435e9e88709aa5fcb448

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_d9b646df72b14a72ae7633f763396686 cluster_85751fe7daa842bebdcf00356894bf95 db81a21b2a0f466d802af48ab54d6711 0 28dc4b9dcf90487eb7a079573077c898 X db81a21b2a0f466d802af48ab54d6711--28dc4b9dcf90487eb7a079573077c898 e5d4dc8af1904849a887ffbcc33b7c1a 1 d2f3f7d2959c4d50baf13c4b988fdd85 HamEvo 28dc4b9dcf90487eb7a079573077c898--d2f3f7d2959c4d50baf13c4b988fdd85 a6d9421a0bd34a2389b60eae0b57a370 X d2f3f7d2959c4d50baf13c4b988fdd85--a6d9421a0bd34a2389b60eae0b57a370 5cd9c23853be48c7a28c8dbbb6d00961 a6d9421a0bd34a2389b60eae0b57a370--5cd9c23853be48c7a28c8dbbb6d00961 2468ce05e7d741869bb6d9bde9638c8d HamEvo 5cd9c23853be48c7a28c8dbbb6d00961--2468ce05e7d741869bb6d9bde9638c8d 6e8957b3660b4579943da543359e6b53 2468ce05e7d741869bb6d9bde9638c8d--6e8957b3660b4579943da543359e6b53 9a003926c0ed430e80da046867e8512d 6e8957b3660b4579943da543359e6b53--9a003926c0ed430e80da046867e8512d f9bf76896bef4aac9dbe52548494a397 5f5a4537d9504ebeb36adf5a65fc679a e5d4dc8af1904849a887ffbcc33b7c1a--5f5a4537d9504ebeb36adf5a65fc679a 3cec9b2b5f124d339dee41cfff0e2740 2 30f38ec8edbe4c629bb3cc42a4e2ed40 t = -0.500 5f5a4537d9504ebeb36adf5a65fc679a--30f38ec8edbe4c629bb3cc42a4e2ed40 74d8be659a9e4c6a88539ccbce16e7c0 30f38ec8edbe4c629bb3cc42a4e2ed40--74d8be659a9e4c6a88539ccbce16e7c0 bef651d829734fea85b2da068dcba12a X 74d8be659a9e4c6a88539ccbce16e7c0--bef651d829734fea85b2da068dcba12a 4218830eb7db43aeb32c88ded13fa7cc t = -0.500 bef651d829734fea85b2da068dcba12a--4218830eb7db43aeb32c88ded13fa7cc 6735260f9dcf49e6a756356999f154ce X 4218830eb7db43aeb32c88ded13fa7cc--6735260f9dcf49e6a756356999f154ce 6735260f9dcf49e6a756356999f154ce--f9bf76896bef4aac9dbe52548494a397 0d27ad53848a411190f7677a6c70b4f4 3b579c3763054727a7cab23ce385e53f X 3cec9b2b5f124d339dee41cfff0e2740--3b579c3763054727a7cab23ce385e53f 512ccec2d45540ce93eebc8ebb013330 3b579c3763054727a7cab23ce385e53f--512ccec2d45540ce93eebc8ebb013330 b0755cf04fed43bc8c745d15b8935fba X 512ccec2d45540ce93eebc8ebb013330--b0755cf04fed43bc8c745d15b8935fba 1747b07678b34c5486ba02826cda251f X b0755cf04fed43bc8c745d15b8935fba--1747b07678b34c5486ba02826cda251f b96cd519dddf4e24bf099f34c76da2de 1747b07678b34c5486ba02826cda251f--b96cd519dddf4e24bf099f34c76da2de 8584fd83d4c44199bfefa4fabd27b4ab X b96cd519dddf4e24bf099f34c76da2de--8584fd83d4c44199bfefa4fabd27b4ab 8584fd83d4c44199bfefa4fabd27b4ab--0d27ad53848a411190f7677a6c70b4f4

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_c35d7f5c09ff49c898ef0869d459d682 cluster_c4ccee7c0f6a417bbc030ea4448ca14d 1d47a015a2a6477fa26a7b3c315b6678 0 d6908d9780f3488c9a0a195186789f1f X 1d47a015a2a6477fa26a7b3c315b6678--d6908d9780f3488c9a0a195186789f1f 875ca6876c344ac6a58dc51d8eac49fa 1 c772183b5ffc4b4f90649e9fc680d0ab HamEvo d6908d9780f3488c9a0a195186789f1f--c772183b5ffc4b4f90649e9fc680d0ab 1446509e7b6a41b1abff9b01101bf2c7 X c772183b5ffc4b4f90649e9fc680d0ab--1446509e7b6a41b1abff9b01101bf2c7 217a10a92022449a9386357a2a98ddf5 1446509e7b6a41b1abff9b01101bf2c7--217a10a92022449a9386357a2a98ddf5 72b128e7809c4c92845268db591decc1 HamEvo 217a10a92022449a9386357a2a98ddf5--72b128e7809c4c92845268db591decc1 61075b965e65499183e57eadae520d0d 72b128e7809c4c92845268db591decc1--61075b965e65499183e57eadae520d0d 306df4bc83234c7d81d39ca87c612bad 61075b965e65499183e57eadae520d0d--306df4bc83234c7d81d39ca87c612bad 4560970e4a5b4a6ca123f73a19c45056 85f5004311c24edcbbf3dd5fc0d780fd 875ca6876c344ac6a58dc51d8eac49fa--85f5004311c24edcbbf3dd5fc0d780fd 7fb398f98c8840f8a72f9baea5a2a314 2 5d3b512d289c4a01a19114a708302923 t = -500.000000000000 85f5004311c24edcbbf3dd5fc0d780fd--5d3b512d289c4a01a19114a708302923 45a4c1e226724aeea612b08c35f4742f 5d3b512d289c4a01a19114a708302923--45a4c1e226724aeea612b08c35f4742f 724182a4eda24b5cbefc342dae13a973 X 45a4c1e226724aeea612b08c35f4742f--724182a4eda24b5cbefc342dae13a973 b56dc6389c0149149ae45bdbd3166d84 t = -500.000000000000 724182a4eda24b5cbefc342dae13a973--b56dc6389c0149149ae45bdbd3166d84 cfaec5f5901b4be9ac431c95ed6f9c0c X b56dc6389c0149149ae45bdbd3166d84--cfaec5f5901b4be9ac431c95ed6f9c0c cfaec5f5901b4be9ac431c95ed6f9c0c--4560970e4a5b4a6ca123f73a19c45056 5f89247a26f44c1fb9638ce9c29e51fc 356be98436ed4e3a94c2079a8dfac1de X 7fb398f98c8840f8a72f9baea5a2a314--356be98436ed4e3a94c2079a8dfac1de 4e32a250b8894415b852de79fd0df07b 356be98436ed4e3a94c2079a8dfac1de--4e32a250b8894415b852de79fd0df07b b4ec1c6cd950463980492d9165e57b28 X 4e32a250b8894415b852de79fd0df07b--b4ec1c6cd950463980492d9165e57b28 bd99a0ddaf454b2f8a3945564153e645 X b4ec1c6cd950463980492d9165e57b28--bd99a0ddaf454b2f8a3945564153e645 01eececbabf1420aa75b929e57825aaf bd99a0ddaf454b2f8a3945564153e645--01eececbabf1420aa75b929e57825aaf 65a3e993c4904643a572a059527ff0cc X 01eececbabf1420aa75b929e57825aaf--65a3e993c4904643a572a059527ff0cc 65a3e993c4904643a572a059527ff0cc--5f89247a26f44c1fb9638ce9c29e51fc

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