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 = [OrderedCounter({'11': 100})]
sample from decomposed CNOT gate and 100 shots = [OrderedCounter({'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 = [OrderedCounter({'11': 100})]
sample cnot_evo = [OrderedCounter({'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_e552e081e16c49a6a1541637eb267252 cluster_1dc21d2ce6154345a9013a6ff1d35d96 cluster_a5ad4ba89b69449b87731952203dba44 cluster_b0f5464fb1b54d4d8ff8e28b61e0b353 cluster_e7508c1ecfcd43c4a321780857a5bb1a cluster_79ed2cd7f15944e2b80e74a54a087281 cluster_fd9843f1b7e7485cbac8a59c1bda61e4 512c87e6799a4c1e9d799ed5cb3f45e7 0 e20a089b91984944822b5d9515866d4f HamEvo 512c87e6799a4c1e9d799ed5cb3f45e7--e20a089b91984944822b5d9515866d4f 9428ef8b6033402b8818764d3e5efc65 1 b98a9e7126c74f4aa6dd79bd2f2adc90 HamEvo e20a089b91984944822b5d9515866d4f--b98a9e7126c74f4aa6dd79bd2f2adc90 bdd571ed507b4b55a0e29370a37b1af8 HamEvo b98a9e7126c74f4aa6dd79bd2f2adc90--bdd571ed507b4b55a0e29370a37b1af8 408627fbcaa04cb09c08808ae72372d2 X bdd571ed507b4b55a0e29370a37b1af8--408627fbcaa04cb09c08808ae72372d2 f4b14ad4e6fb43fd9f3f7c48da4f31c5 HamEvo 408627fbcaa04cb09c08808ae72372d2--f4b14ad4e6fb43fd9f3f7c48da4f31c5 7eae56bfc85b4b2e8af8a28fa0c0ffbc HamEvo f4b14ad4e6fb43fd9f3f7c48da4f31c5--7eae56bfc85b4b2e8af8a28fa0c0ffbc c0be34440e88418389c4d9097c5a916c X 7eae56bfc85b4b2e8af8a28fa0c0ffbc--c0be34440e88418389c4d9097c5a916c 0d584a6bf9a444d9819cf6d682cc36e7 c0be34440e88418389c4d9097c5a916c--0d584a6bf9a444d9819cf6d682cc36e7 3b6a752198bc44fb8b881f0a8f38682d HamEvo 0d584a6bf9a444d9819cf6d682cc36e7--3b6a752198bc44fb8b881f0a8f38682d 603071d3c3db4b0ca4c67ecd7d850e8f HamEvo 3b6a752198bc44fb8b881f0a8f38682d--603071d3c3db4b0ca4c67ecd7d850e8f e2b1674a9c5c4883b4cbf09d35e3c0e9 603071d3c3db4b0ca4c67ecd7d850e8f--e2b1674a9c5c4883b4cbf09d35e3c0e9 1dafdf9e2f7d47d889696aa36d983359 e2b1674a9c5c4883b4cbf09d35e3c0e9--1dafdf9e2f7d47d889696aa36d983359 0b30ff18b9ca4d3b81ef6a031df72f47 6ffab37a297d434bbe6514f5d7e83451 t = -3.14 9428ef8b6033402b8818764d3e5efc65--6ffab37a297d434bbe6514f5d7e83451 1d61a6fd89d94186bf71905b0e0c33e7 2 70c2a7f3a47443c281296301b450963f t = 3.142 6ffab37a297d434bbe6514f5d7e83451--70c2a7f3a47443c281296301b450963f c2ff43bab96c4c95b8978cd7596a969d t = -3.14 70c2a7f3a47443c281296301b450963f--c2ff43bab96c4c95b8978cd7596a969d d5671eee64d84f83bfc62d1d2a2f7ecd c2ff43bab96c4c95b8978cd7596a969d--d5671eee64d84f83bfc62d1d2a2f7ecd 23ae09d964104270aa1ea72ae725d7f9 t = 1.571 d5671eee64d84f83bfc62d1d2a2f7ecd--23ae09d964104270aa1ea72ae725d7f9 41c1a9ff782445a99fc318d1df3b2120 t = 1.571 23ae09d964104270aa1ea72ae725d7f9--41c1a9ff782445a99fc318d1df3b2120 5225ca72b14844b78d113ade8ad74614 41c1a9ff782445a99fc318d1df3b2120--5225ca72b14844b78d113ade8ad74614 e40e2ad7f19c4ab882ecef1a2b83ffc5 X 5225ca72b14844b78d113ade8ad74614--e40e2ad7f19c4ab882ecef1a2b83ffc5 bc73c33589024c978466893d4641f8d5 t = 1.571 e40e2ad7f19c4ab882ecef1a2b83ffc5--bc73c33589024c978466893d4641f8d5 b9b70569ce144be5979b4ea2325afba2 t = 1.571 bc73c33589024c978466893d4641f8d5--b9b70569ce144be5979b4ea2325afba2 53bcba2903f34d4bb433fba0dbf9cce9 X b9b70569ce144be5979b4ea2325afba2--53bcba2903f34d4bb433fba0dbf9cce9 53bcba2903f34d4bb433fba0dbf9cce9--0b30ff18b9ca4d3b81ef6a031df72f47 e9fe63d016334c54900fdebb115a9f7b 6a2684a3b2334826981c9126a8561606 1d61a6fd89d94186bf71905b0e0c33e7--6a2684a3b2334826981c9126a8561606 41b920d2e2864a4a8a17104d92cf6468 6a2684a3b2334826981c9126a8561606--41b920d2e2864a4a8a17104d92cf6468 7850e919896a4c7c8051213bdc3967ff 41b920d2e2864a4a8a17104d92cf6468--7850e919896a4c7c8051213bdc3967ff f54472ac2a1244c39604e90d7a7c30e1 X 7850e919896a4c7c8051213bdc3967ff--f54472ac2a1244c39604e90d7a7c30e1 617cb34957c84c16914c6625e2043128 f54472ac2a1244c39604e90d7a7c30e1--617cb34957c84c16914c6625e2043128 1ec26a3680674c9c9097391720d04981 617cb34957c84c16914c6625e2043128--1ec26a3680674c9c9097391720d04981 389dc18b8ae04b8ca6d56d4347816a02 X 1ec26a3680674c9c9097391720d04981--389dc18b8ae04b8ca6d56d4347816a02 86fd8ab003a5453393c666e88bc2f684 X 389dc18b8ae04b8ca6d56d4347816a02--86fd8ab003a5453393c666e88bc2f684 78ff083425f44e8ba0f3af612441b59a 86fd8ab003a5453393c666e88bc2f684--78ff083425f44e8ba0f3af612441b59a 42d15a8891ab4534b3ecfc7004d5545f 78ff083425f44e8ba0f3af612441b59a--42d15a8891ab4534b3ecfc7004d5545f 798c98c6a98a461294aa81ed6ae52128 X 42d15a8891ab4534b3ecfc7004d5545f--798c98c6a98a461294aa81ed6ae52128 798c98c6a98a461294aa81ed6ae52128--e9fe63d016334c54900fdebb115a9f7b

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 = [OrderedCounter({'111': 100})]
sample cnot_dacq = [OrderedCounter({'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_d40ec51c22f140b6a6f30d77c44b4888 cluster_3e89b93c39664eb9a9c08ce2dea9e5b9 16b98e9576be4337b001848a71bc3902 0 ad879e9452844a438757ebc64c87fc38 X 16b98e9576be4337b001848a71bc3902--ad879e9452844a438757ebc64c87fc38 03b9ffb35e374dd8a33575d7f2920e19 1 ac24da1a4bb94a38b22444b6644c6376 HamEvo ad879e9452844a438757ebc64c87fc38--ac24da1a4bb94a38b22444b6644c6376 a0e342af3dac4769aa3d01ce74aa4008 X ac24da1a4bb94a38b22444b6644c6376--a0e342af3dac4769aa3d01ce74aa4008 26e1f18bc3794c1a8dcfbbcce1460e26 a0e342af3dac4769aa3d01ce74aa4008--26e1f18bc3794c1a8dcfbbcce1460e26 bc7d582b64254af9a1dcdc6717d282a0 HamEvo 26e1f18bc3794c1a8dcfbbcce1460e26--bc7d582b64254af9a1dcdc6717d282a0 8119652ec8664d49bbb68b1724593270 bc7d582b64254af9a1dcdc6717d282a0--8119652ec8664d49bbb68b1724593270 9a0579737fb54a1aa0fd20536fa5d54d 8119652ec8664d49bbb68b1724593270--9a0579737fb54a1aa0fd20536fa5d54d e9a5de76c56940d882bc6d62200d00db 93f16b263e824a8db3221943f8daa91a 03b9ffb35e374dd8a33575d7f2920e19--93f16b263e824a8db3221943f8daa91a d8357694280443bbbe6128a3d912331e 2 a773548da6b34fa59486790a4499e79e t = -0.50 93f16b263e824a8db3221943f8daa91a--a773548da6b34fa59486790a4499e79e f45b615b170a4a5c97793587de348243 a773548da6b34fa59486790a4499e79e--f45b615b170a4a5c97793587de348243 f291f6108d594241b696468738b2d9f8 X f45b615b170a4a5c97793587de348243--f291f6108d594241b696468738b2d9f8 255dc87734f24e26ba8127b4903baedc t = -0.50 f291f6108d594241b696468738b2d9f8--255dc87734f24e26ba8127b4903baedc 26fddce5f3a84930825ddbf6633d2e61 X 255dc87734f24e26ba8127b4903baedc--26fddce5f3a84930825ddbf6633d2e61 26fddce5f3a84930825ddbf6633d2e61--e9a5de76c56940d882bc6d62200d00db edc97a7f152649ecb876020622b21c28 baa6eec458c64906b15e5e776bd09c82 X d8357694280443bbbe6128a3d912331e--baa6eec458c64906b15e5e776bd09c82 2513703a3ee649c9926e91c4bb0259de baa6eec458c64906b15e5e776bd09c82--2513703a3ee649c9926e91c4bb0259de 9b4cb5d91e8c4fe58a06715773f42a4a X 2513703a3ee649c9926e91c4bb0259de--9b4cb5d91e8c4fe58a06715773f42a4a 4be8bb419c8d4dfc91346d3bb0498cdd X 9b4cb5d91e8c4fe58a06715773f42a4a--4be8bb419c8d4dfc91346d3bb0498cdd c9dcc16656734569a289184ac01e734f 4be8bb419c8d4dfc91346d3bb0498cdd--c9dcc16656734569a289184ac01e734f 45e307c06ec1402e83ff66dee63570aa X c9dcc16656734569a289184ac01e734f--45e307c06ec1402e83ff66dee63570aa 45e307c06ec1402e83ff66dee63570aa--edc97a7f152649ecb876020622b21c28

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_7638bdee73df40259e2a78dcb7138c9c cluster_d89c1668040949b59814dc29d3d1f422 1f32b3b4571e427b99d5d452fe7dc8ac 0 f59733b4e6c9405c9c620d4b14497cc9 X 1f32b3b4571e427b99d5d452fe7dc8ac--f59733b4e6c9405c9c620d4b14497cc9 5260cfafda674232a9faf06ac9099a10 1 c6d0b1211f2b4462bf83bd7dc944572e HamEvo f59733b4e6c9405c9c620d4b14497cc9--c6d0b1211f2b4462bf83bd7dc944572e 821dd4ce12f446598f6a6590466afca4 X c6d0b1211f2b4462bf83bd7dc944572e--821dd4ce12f446598f6a6590466afca4 a450d82c64c946669a70750211b4ddcd 821dd4ce12f446598f6a6590466afca4--a450d82c64c946669a70750211b4ddcd 41a02326b01d47808e4d2c004430a116 HamEvo a450d82c64c946669a70750211b4ddcd--41a02326b01d47808e4d2c004430a116 9bbd27bb2f2c4050b8695169dfb3e928 41a02326b01d47808e4d2c004430a116--9bbd27bb2f2c4050b8695169dfb3e928 53be2b797859498db94e87af97624959 9bbd27bb2f2c4050b8695169dfb3e928--53be2b797859498db94e87af97624959 9cf0b43917a0406fa9e0dbf08e459f85 c20b91f337224795963bad913e5747f2 5260cfafda674232a9faf06ac9099a10--c20b91f337224795963bad913e5747f2 c4ffc9a79ef949c3a9f65d63bc9b48d8 2 505fc176acb7451eac070fbf046685a7 t = -500. c20b91f337224795963bad913e5747f2--505fc176acb7451eac070fbf046685a7 bb8f1bf151194347886ed45e2786e0f8 505fc176acb7451eac070fbf046685a7--bb8f1bf151194347886ed45e2786e0f8 02dde272797f41cc982309a98341e9d4 X bb8f1bf151194347886ed45e2786e0f8--02dde272797f41cc982309a98341e9d4 fbbd1f362f624f1fb945bb7b667b5ef7 t = -500. 02dde272797f41cc982309a98341e9d4--fbbd1f362f624f1fb945bb7b667b5ef7 9ec5ef1c91434ad4b982e202625ee1b7 X fbbd1f362f624f1fb945bb7b667b5ef7--9ec5ef1c91434ad4b982e202625ee1b7 9ec5ef1c91434ad4b982e202625ee1b7--9cf0b43917a0406fa9e0dbf08e459f85 42907cb7f3d8416393954ba8e02d59fe 3f9c25e55dac44b3996066fc4847cb39 X c4ffc9a79ef949c3a9f65d63bc9b48d8--3f9c25e55dac44b3996066fc4847cb39 400ec32f3e144c20aeb3ccafa14958c7 3f9c25e55dac44b3996066fc4847cb39--400ec32f3e144c20aeb3ccafa14958c7 bae29b62b89b4adb9a2f7a27183eac2f X 400ec32f3e144c20aeb3ccafa14958c7--bae29b62b89b4adb9a2f7a27183eac2f 5658bb6589cf493ab98abe3c3b914bf7 X bae29b62b89b4adb9a2f7a27183eac2f--5658bb6589cf493ab98abe3c3b914bf7 d3607906ee8d406497926ad11c04d311 5658bb6589cf493ab98abe3c3b914bf7--d3607906ee8d406497926ad11c04d311 a9709b5c064c463b97e5d2b1882c5bd4 X d3607906ee8d406497926ad11c04d311--a9709b5c064c463b97e5d2b1882c5bd4 a9709b5c064c463b97e5d2b1882c5bd4--42907cb7f3d8416393954ba8e02d59fe

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