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_835a46a87cb94040826fe3a1c274e586 cluster_59e577323f02423c8c0ebe5cce1e07df cluster_9243984b32c3461383764a8e090c218f cluster_2515503bb3264f6d9fb048899c05b3ed cluster_90f54e4b67a34187bb6edce0ecfdae0d cluster_188f60174ba442d0a603dc352ab90037 cluster_5e1134da1dad48d081c37d6f7848ada4 dd811887e8f342e18b39c75e4920c5a7 0 ce4650fec0314f3fa31870af7b11226d HamEvo dd811887e8f342e18b39c75e4920c5a7--ce4650fec0314f3fa31870af7b11226d a0300f6403f74d2eaca53938485a9dff 1 049e4cdb01a74b00ba55138c23bde77f HamEvo ce4650fec0314f3fa31870af7b11226d--049e4cdb01a74b00ba55138c23bde77f b64a73d4626a42f19b90b84b0606f33c HamEvo 049e4cdb01a74b00ba55138c23bde77f--b64a73d4626a42f19b90b84b0606f33c caeba3313b5f451f9f2e0d9d9ac38770 X b64a73d4626a42f19b90b84b0606f33c--caeba3313b5f451f9f2e0d9d9ac38770 414f246d8da443dd9fe6bf85fc299de9 HamEvo caeba3313b5f451f9f2e0d9d9ac38770--414f246d8da443dd9fe6bf85fc299de9 999cac7a808c4f74be3b140db19f98e7 HamEvo 414f246d8da443dd9fe6bf85fc299de9--999cac7a808c4f74be3b140db19f98e7 fa57aa5f73004c219bc716a048a8e5eb X 999cac7a808c4f74be3b140db19f98e7--fa57aa5f73004c219bc716a048a8e5eb 9e8f17b1a2a54530a713030cdea22b25 fa57aa5f73004c219bc716a048a8e5eb--9e8f17b1a2a54530a713030cdea22b25 75f5fb1265a4422c81969a4a54bdb350 HamEvo 9e8f17b1a2a54530a713030cdea22b25--75f5fb1265a4422c81969a4a54bdb350 80b4b2c6b5b243c5abf02ccc1d37232c HamEvo 75f5fb1265a4422c81969a4a54bdb350--80b4b2c6b5b243c5abf02ccc1d37232c 60316991a60b450988f6a2c7bbe31fa5 80b4b2c6b5b243c5abf02ccc1d37232c--60316991a60b450988f6a2c7bbe31fa5 f2309cf940264a209f34ab8d88b1a395 60316991a60b450988f6a2c7bbe31fa5--f2309cf940264a209f34ab8d88b1a395 be005a8362214f93a576a97670a9c28f bd059aa00af94d4ba9a8dd4b24fa91a7 t = -3.142 a0300f6403f74d2eaca53938485a9dff--bd059aa00af94d4ba9a8dd4b24fa91a7 b1a9ca89fb4d4a99b923ae1933ddeeef 2 325d695819164815b84c404e19bd6b12 t = 3.142 bd059aa00af94d4ba9a8dd4b24fa91a7--325d695819164815b84c404e19bd6b12 5ffaa1b4b52a4520b093f3e53d9aa21b t = -3.142 325d695819164815b84c404e19bd6b12--5ffaa1b4b52a4520b093f3e53d9aa21b 9262dcaacbd046fd902d43d503bd3884 5ffaa1b4b52a4520b093f3e53d9aa21b--9262dcaacbd046fd902d43d503bd3884 5481a2bf662444909befbb2149334cda t = 1.571 9262dcaacbd046fd902d43d503bd3884--5481a2bf662444909befbb2149334cda 2ff73281df83480895a959e25cc284d3 t = 1.571 5481a2bf662444909befbb2149334cda--2ff73281df83480895a959e25cc284d3 fdcffe82997641a8abb5880337c8d7e0 2ff73281df83480895a959e25cc284d3--fdcffe82997641a8abb5880337c8d7e0 b45cd5bec5214f289a2ffe0c29698369 X fdcffe82997641a8abb5880337c8d7e0--b45cd5bec5214f289a2ffe0c29698369 b57b9cf86f4a4c55a9dcfbb9ddb15575 t = 1.571 b45cd5bec5214f289a2ffe0c29698369--b57b9cf86f4a4c55a9dcfbb9ddb15575 02e058ca78e2442d9f7ac4f861600b14 t = 1.571 b57b9cf86f4a4c55a9dcfbb9ddb15575--02e058ca78e2442d9f7ac4f861600b14 e1dadf1723f44f2cac8be40660ab58a9 X 02e058ca78e2442d9f7ac4f861600b14--e1dadf1723f44f2cac8be40660ab58a9 e1dadf1723f44f2cac8be40660ab58a9--be005a8362214f93a576a97670a9c28f 17801a9218b74ced83f93e7d77ffa5a5 08a7a833c592436c870909cff4abf8fd b1a9ca89fb4d4a99b923ae1933ddeeef--08a7a833c592436c870909cff4abf8fd 1da83862f8e849328cb12db2bf39998b 08a7a833c592436c870909cff4abf8fd--1da83862f8e849328cb12db2bf39998b 817f3b0e6ce54dc0a14e40ee3fe5baae 1da83862f8e849328cb12db2bf39998b--817f3b0e6ce54dc0a14e40ee3fe5baae a55e1dceb33244a18fd404f0480098b8 X 817f3b0e6ce54dc0a14e40ee3fe5baae--a55e1dceb33244a18fd404f0480098b8 c4300b508f214c248c5e5a04debf86ff a55e1dceb33244a18fd404f0480098b8--c4300b508f214c248c5e5a04debf86ff 409722c02c164b7db6b78737ffc992d2 c4300b508f214c248c5e5a04debf86ff--409722c02c164b7db6b78737ffc992d2 3bdaebecd4c64deebcc9a381c6ce0a53 X 409722c02c164b7db6b78737ffc992d2--3bdaebecd4c64deebcc9a381c6ce0a53 08503b09178e430db1b16f6f316edceb X 3bdaebecd4c64deebcc9a381c6ce0a53--08503b09178e430db1b16f6f316edceb 6aeefd9d1a6f4acb8c03af685e8cfe1d 08503b09178e430db1b16f6f316edceb--6aeefd9d1a6f4acb8c03af685e8cfe1d 9a7a78d000564dbd8316d1670ee05bad 6aeefd9d1a6f4acb8c03af685e8cfe1d--9a7a78d000564dbd8316d1670ee05bad 80d5f16e42ff498c84304a8c74de38a2 X 9a7a78d000564dbd8316d1670ee05bad--80d5f16e42ff498c84304a8c74de38a2 80d5f16e42ff498c84304a8c74de38a2--17801a9218b74ced83f93e7d77ffa5a5

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_a481d69c7f1a4c8ca97e07aa941fd2ee cluster_6b630c0d0dca49319bd58034eb32190d c981cb0908be4001a280b48b656ba099 0 4ca335760aa44987a964c5840fb923c0 X c981cb0908be4001a280b48b656ba099--4ca335760aa44987a964c5840fb923c0 4955a7c33ba7452485c73f7d1e8a06ec 1 f3689c142c7749daa4ac0b03b65a1264 HamEvo 4ca335760aa44987a964c5840fb923c0--f3689c142c7749daa4ac0b03b65a1264 03532028ffc44c4484a709ed085d5ff0 X f3689c142c7749daa4ac0b03b65a1264--03532028ffc44c4484a709ed085d5ff0 8feb3ef847f046ee876f4ddaacc23c87 03532028ffc44c4484a709ed085d5ff0--8feb3ef847f046ee876f4ddaacc23c87 a8074e03c8614ccab09a30194032560d HamEvo 8feb3ef847f046ee876f4ddaacc23c87--a8074e03c8614ccab09a30194032560d 30f62e179fac49b98cf22557f52443e0 a8074e03c8614ccab09a30194032560d--30f62e179fac49b98cf22557f52443e0 1736b7bc09754e0d94f56a49ca3f745f 30f62e179fac49b98cf22557f52443e0--1736b7bc09754e0d94f56a49ca3f745f cf0a2a9132d34b8ca8049067471e37f4 572f8c07e7f7497e8cd6041424ec5f42 4955a7c33ba7452485c73f7d1e8a06ec--572f8c07e7f7497e8cd6041424ec5f42 2da4c246a709423088b0f10ae96bcb26 2 a18203fc04a3438285fa6260256a87ff t = -0.500 572f8c07e7f7497e8cd6041424ec5f42--a18203fc04a3438285fa6260256a87ff 62dbdd3ab96b497e8283a5217305c1e1 a18203fc04a3438285fa6260256a87ff--62dbdd3ab96b497e8283a5217305c1e1 487df8cdfaa9423c85ec6ca175bf97c5 X 62dbdd3ab96b497e8283a5217305c1e1--487df8cdfaa9423c85ec6ca175bf97c5 532b45fe79cd48c3bdf258b8840eaece t = -0.500 487df8cdfaa9423c85ec6ca175bf97c5--532b45fe79cd48c3bdf258b8840eaece 75188421ada3482a9ca2372a8945342b X 532b45fe79cd48c3bdf258b8840eaece--75188421ada3482a9ca2372a8945342b 75188421ada3482a9ca2372a8945342b--cf0a2a9132d34b8ca8049067471e37f4 10d536b9ee24493590ebfda4366bd386 28364f2f8c5a4e458f75c299047fb7f6 X 2da4c246a709423088b0f10ae96bcb26--28364f2f8c5a4e458f75c299047fb7f6 83920240b59641999b1b04bded18f27c 28364f2f8c5a4e458f75c299047fb7f6--83920240b59641999b1b04bded18f27c 88828eef25e94ba7b24438a5d274ba89 X 83920240b59641999b1b04bded18f27c--88828eef25e94ba7b24438a5d274ba89 c0a3a8aec3054deeaa7317d33878414c X 88828eef25e94ba7b24438a5d274ba89--c0a3a8aec3054deeaa7317d33878414c 0034b8bcd33c4f0da5753742a732fced c0a3a8aec3054deeaa7317d33878414c--0034b8bcd33c4f0da5753742a732fced 0cbac1ebb3f946b9879b61e29281a268 X 0034b8bcd33c4f0da5753742a732fced--0cbac1ebb3f946b9879b61e29281a268 0cbac1ebb3f946b9879b61e29281a268--10d536b9ee24493590ebfda4366bd386

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_9ab6937356df49919608e3e242af313b cluster_ba820ab16b144ceaa67fe23ba0637791 2b018add244d4fb1b8f4fd249f2d261d 0 cd94f5f7d8004b639d17690883b44a2e X 2b018add244d4fb1b8f4fd249f2d261d--cd94f5f7d8004b639d17690883b44a2e dd3d675698994b7faabd5378399c5386 1 294c7bbfb88044d3a571cbf00c89c672 HamEvo cd94f5f7d8004b639d17690883b44a2e--294c7bbfb88044d3a571cbf00c89c672 481ea78bf0e541cc914e5fe1d54bcdef X 294c7bbfb88044d3a571cbf00c89c672--481ea78bf0e541cc914e5fe1d54bcdef cb40b0fd2de64a0eb745bdb6a802c1a3 481ea78bf0e541cc914e5fe1d54bcdef--cb40b0fd2de64a0eb745bdb6a802c1a3 2894c3d3f4f64bbda090445f487cda44 HamEvo cb40b0fd2de64a0eb745bdb6a802c1a3--2894c3d3f4f64bbda090445f487cda44 1f31a94fc3af4fa5b0895f77856380e2 2894c3d3f4f64bbda090445f487cda44--1f31a94fc3af4fa5b0895f77856380e2 99970495c4c4476895b7e34de1ba87c3 1f31a94fc3af4fa5b0895f77856380e2--99970495c4c4476895b7e34de1ba87c3 4d3dfb27b26b4ad5bbb5b027254a5282 0c148f6f023b4fe5a6f4a3c4a21cfeb8 dd3d675698994b7faabd5378399c5386--0c148f6f023b4fe5a6f4a3c4a21cfeb8 ace6473cdd4347188107d4110f02a9e8 2 bc0ce15515494a1da689f51fe30fc339 t = -500.000000000000 0c148f6f023b4fe5a6f4a3c4a21cfeb8--bc0ce15515494a1da689f51fe30fc339 60890ab2358b4067adf4516e79178016 bc0ce15515494a1da689f51fe30fc339--60890ab2358b4067adf4516e79178016 2eb7210692124b9dbf7ad518de4426fd X 60890ab2358b4067adf4516e79178016--2eb7210692124b9dbf7ad518de4426fd 0c97e923068f4d71803d8ff4491a1333 t = -500.000000000000 2eb7210692124b9dbf7ad518de4426fd--0c97e923068f4d71803d8ff4491a1333 cc5ba7b20a1748a2acf43097f06c3b61 X 0c97e923068f4d71803d8ff4491a1333--cc5ba7b20a1748a2acf43097f06c3b61 cc5ba7b20a1748a2acf43097f06c3b61--4d3dfb27b26b4ad5bbb5b027254a5282 3f4388c4d7c0465f948221e114e32754 5a5f5e75f63b442593c30fef19e4811e X ace6473cdd4347188107d4110f02a9e8--5a5f5e75f63b442593c30fef19e4811e a159644e4d9e4ceb82e3b1fc2129b968 5a5f5e75f63b442593c30fef19e4811e--a159644e4d9e4ceb82e3b1fc2129b968 dce9207a4b99467aa56a363fd5069d29 X a159644e4d9e4ceb82e3b1fc2129b968--dce9207a4b99467aa56a363fd5069d29 8ba114b900f94e648ec4f134d5184461 X dce9207a4b99467aa56a363fd5069d29--8ba114b900f94e648ec4f134d5184461 a52db6a7f87c46a4a43ccd6690bf42e4 8ba114b900f94e648ec4f134d5184461--a52db6a7f87c46a4a43ccd6690bf42e4 223518ceccc84dfcadd06e91dac3f738 X a52db6a7f87c46a4a43ccd6690bf42e4--223518ceccc84dfcadd06e91dac3f738 223518ceccc84dfcadd06e91dac3f738--3f4388c4d7c0465f948221e114e32754

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