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.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=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_c01edc54794943779174bfc8d82cefec cluster_1956e29aad4c462888915dd134679c50 cluster_680eabf54da8445fb342837bc44bc9aa cluster_aea6501b0254492bb02329b9ec315e08 cluster_031c5f54ab0c4b8c9533a71d0b30f614 cluster_65de7fbb12464d5c90357a92070fe936 cluster_392180d2132d42ecb8a67add519ad80d 595106672bc14d66acfeb8ab82b73cbb 0 cc1488c7dad34beb84197191eb55a159 HamEvo 595106672bc14d66acfeb8ab82b73cbb--cc1488c7dad34beb84197191eb55a159 b1c66cb68a8341bc8b8d4cf872269ac6 1 dab8125d65b14f26a57a658f8277da29 HamEvo cc1488c7dad34beb84197191eb55a159--dab8125d65b14f26a57a658f8277da29 34b8ae51a7bf4a1aa353532664180aa8 HamEvo dab8125d65b14f26a57a658f8277da29--34b8ae51a7bf4a1aa353532664180aa8 73dfee07f4e14961bcdf1b84be5e6e7b X 34b8ae51a7bf4a1aa353532664180aa8--73dfee07f4e14961bcdf1b84be5e6e7b 2247ad30a716474c8414e22dc6e55b5f HamEvo 73dfee07f4e14961bcdf1b84be5e6e7b--2247ad30a716474c8414e22dc6e55b5f 571fd38cdebe4c978b5a5500ef9835ed HamEvo 2247ad30a716474c8414e22dc6e55b5f--571fd38cdebe4c978b5a5500ef9835ed 980cbc6ba2854b57b096f135268d0841 X 571fd38cdebe4c978b5a5500ef9835ed--980cbc6ba2854b57b096f135268d0841 d381f956a0804d7aa16dec78f45ca8b6 980cbc6ba2854b57b096f135268d0841--d381f956a0804d7aa16dec78f45ca8b6 fb9aedf762624c1ba2ededd10a82c78a HamEvo d381f956a0804d7aa16dec78f45ca8b6--fb9aedf762624c1ba2ededd10a82c78a e531f9f6db65413f9a167b30477171d1 HamEvo fb9aedf762624c1ba2ededd10a82c78a--e531f9f6db65413f9a167b30477171d1 bb248463dcd449c4b2990e89d158b5c3 e531f9f6db65413f9a167b30477171d1--bb248463dcd449c4b2990e89d158b5c3 fec117fc53b44f1ba27affcd1079a773 bb248463dcd449c4b2990e89d158b5c3--fec117fc53b44f1ba27affcd1079a773 bce83f4b05b24bd681f7a8489cf52d29 da0898a6bc46418f97ca769e46029fd3 t = -3.142 b1c66cb68a8341bc8b8d4cf872269ac6--da0898a6bc46418f97ca769e46029fd3 9d029c5d2f884fda93788f6511eb74dc 2 bb0e50ca55174d30bfb9077199d1e884 t = 3.142 da0898a6bc46418f97ca769e46029fd3--bb0e50ca55174d30bfb9077199d1e884 75f217d8277046f4993fcc8e542ead68 t = -3.142 bb0e50ca55174d30bfb9077199d1e884--75f217d8277046f4993fcc8e542ead68 ba0a6000c8a54804b57812bf7d1e1dec 75f217d8277046f4993fcc8e542ead68--ba0a6000c8a54804b57812bf7d1e1dec bf6400b0e913495780a321c244bb771d t = 1.571 ba0a6000c8a54804b57812bf7d1e1dec--bf6400b0e913495780a321c244bb771d bd4198c4e4e548ff8c1da6c4aabe3a0f t = 1.571 bf6400b0e913495780a321c244bb771d--bd4198c4e4e548ff8c1da6c4aabe3a0f d85033f6d30b4b9189b032124dd87def bd4198c4e4e548ff8c1da6c4aabe3a0f--d85033f6d30b4b9189b032124dd87def 1395f9666071401a9b0b5944db323155 X d85033f6d30b4b9189b032124dd87def--1395f9666071401a9b0b5944db323155 72f806241b3544369be81842da218377 t = 1.571 1395f9666071401a9b0b5944db323155--72f806241b3544369be81842da218377 b6f47eac814a409db8bfdb5cbd930fe5 t = 1.571 72f806241b3544369be81842da218377--b6f47eac814a409db8bfdb5cbd930fe5 cf251b1552d540ea8a3b48ec3b737d57 X b6f47eac814a409db8bfdb5cbd930fe5--cf251b1552d540ea8a3b48ec3b737d57 cf251b1552d540ea8a3b48ec3b737d57--bce83f4b05b24bd681f7a8489cf52d29 540d0ea7b030457cb3137c4f592ab552 b9fffb7d911c409bb5fa4e3109de851c 9d029c5d2f884fda93788f6511eb74dc--b9fffb7d911c409bb5fa4e3109de851c a27d8ba9e2a5450889f26d2b8e8d8afc b9fffb7d911c409bb5fa4e3109de851c--a27d8ba9e2a5450889f26d2b8e8d8afc c8b39a224d3040aeab88edf1229cd585 a27d8ba9e2a5450889f26d2b8e8d8afc--c8b39a224d3040aeab88edf1229cd585 3a834c78de8d4911addc380b4f04e4a2 X c8b39a224d3040aeab88edf1229cd585--3a834c78de8d4911addc380b4f04e4a2 781ccf2086a7434b976e31f05a247bef 3a834c78de8d4911addc380b4f04e4a2--781ccf2086a7434b976e31f05a247bef ba91c5ed1e4a4da8bf59d0dc0c598692 781ccf2086a7434b976e31f05a247bef--ba91c5ed1e4a4da8bf59d0dc0c598692 e6d0c82dc56f47579c0641eafcf52a99 X ba91c5ed1e4a4da8bf59d0dc0c598692--e6d0c82dc56f47579c0641eafcf52a99 afbc606504144edb951e889bb09c751f X e6d0c82dc56f47579c0641eafcf52a99--afbc606504144edb951e889bb09c751f 4a7ae97b5f1f459abef3d3608cceb7b7 afbc606504144edb951e889bb09c751f--4a7ae97b5f1f459abef3d3608cceb7b7 9a0d8d9257cd4935b2a06c0cac138bda 4a7ae97b5f1f459abef3d3608cceb7b7--9a0d8d9257cd4935b2a06c0cac138bda a9ebc23347134cfcb3c7a4991094a593 X 9a0d8d9257cd4935b2a06c0cac138bda--a9ebc23347134cfcb3c7a4991094a593 a9ebc23347134cfcb3c7a4991094a593--540d0ea7b030457cb3137c4f592ab552

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_8764d735d04d49ae8312771e068301b0 cluster_2e713df921b74d3d9eb8629b9ec6b26b e85b60249d0f41f0848e27286ffe0a31 0 36f13d844d7244e9a800934eeca84d84 X e85b60249d0f41f0848e27286ffe0a31--36f13d844d7244e9a800934eeca84d84 6b1d4b3576e24ff8987d7462cf497a40 1 08613032dc494bb9817db76050e6337a HamEvo 36f13d844d7244e9a800934eeca84d84--08613032dc494bb9817db76050e6337a 3f4f0ba8f1dc4c5c9dc2725bd77caa1e X 08613032dc494bb9817db76050e6337a--3f4f0ba8f1dc4c5c9dc2725bd77caa1e a7ace9a48ea74c269b21d3212ab92061 3f4f0ba8f1dc4c5c9dc2725bd77caa1e--a7ace9a48ea74c269b21d3212ab92061 2e7e7c6ea5974b84bc940248ec3fd17b HamEvo a7ace9a48ea74c269b21d3212ab92061--2e7e7c6ea5974b84bc940248ec3fd17b c9924481ae644ef4a4b7764530411d47 2e7e7c6ea5974b84bc940248ec3fd17b--c9924481ae644ef4a4b7764530411d47 5dc33185101d41ccb3d4471144c9b75e c9924481ae644ef4a4b7764530411d47--5dc33185101d41ccb3d4471144c9b75e 8eb3581744904ab18fab4b7714929095 07e8a190cd2a48af81d31c025efa9063 6b1d4b3576e24ff8987d7462cf497a40--07e8a190cd2a48af81d31c025efa9063 39a60eb18ea4424a8875499ac1aa8a57 2 fb974dd8dac444b1a8c40beeb09293a3 t = -0.500 07e8a190cd2a48af81d31c025efa9063--fb974dd8dac444b1a8c40beeb09293a3 fd6fa0a321994d90b9ddcd7d97e2a4f1 fb974dd8dac444b1a8c40beeb09293a3--fd6fa0a321994d90b9ddcd7d97e2a4f1 ac838f2b1df947bdbbc3ecd53ebc48df X fd6fa0a321994d90b9ddcd7d97e2a4f1--ac838f2b1df947bdbbc3ecd53ebc48df 7f25874cc0cc4bb0adbce827c85be4de t = -0.500 ac838f2b1df947bdbbc3ecd53ebc48df--7f25874cc0cc4bb0adbce827c85be4de c091122bd04340d3a92794bb792ce846 X 7f25874cc0cc4bb0adbce827c85be4de--c091122bd04340d3a92794bb792ce846 c091122bd04340d3a92794bb792ce846--8eb3581744904ab18fab4b7714929095 e4155e7245554f119fa6b3dd5ea30e35 f4683748c1b346a8b150ec589acc0923 X 39a60eb18ea4424a8875499ac1aa8a57--f4683748c1b346a8b150ec589acc0923 6025f9c6249746919006b5b94e52e727 f4683748c1b346a8b150ec589acc0923--6025f9c6249746919006b5b94e52e727 4822380c2ed54a39ba577db9bf6f5ba1 X 6025f9c6249746919006b5b94e52e727--4822380c2ed54a39ba577db9bf6f5ba1 1a4d767bed824424b64ca5b7be2355a7 X 4822380c2ed54a39ba577db9bf6f5ba1--1a4d767bed824424b64ca5b7be2355a7 e3107ce078f044ec93fbfe9d90d27967 1a4d767bed824424b64ca5b7be2355a7--e3107ce078f044ec93fbfe9d90d27967 053db3075b2d4b1c871abc1c4a5ee1d5 X e3107ce078f044ec93fbfe9d90d27967--053db3075b2d4b1c871abc1c4a5ee1d5 053db3075b2d4b1c871abc1c4a5ee1d5--e4155e7245554f119fa6b3dd5ea30e35

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_55d7d0ee415247d594bd9ec790b72af3 cluster_b9b0ae91ced5407780584c65435eecaa 1967b7b0a20d432d99cf0dd3ffb083d3 0 05f8f15411e143429b6b2beeba99a41e X 1967b7b0a20d432d99cf0dd3ffb083d3--05f8f15411e143429b6b2beeba99a41e d8bd7176a37d48158e07fac85d55fa1c 1 0b6ce24e2f9b4799878599a6f687af0e HamEvo 05f8f15411e143429b6b2beeba99a41e--0b6ce24e2f9b4799878599a6f687af0e 8bc3e8327ece4c8aa4aab678e514cc8b X 0b6ce24e2f9b4799878599a6f687af0e--8bc3e8327ece4c8aa4aab678e514cc8b 3bf4899b034a4e7da798406b58c0e41e 8bc3e8327ece4c8aa4aab678e514cc8b--3bf4899b034a4e7da798406b58c0e41e ee69871fa75b472bb633b9e2aa9bf628 HamEvo 3bf4899b034a4e7da798406b58c0e41e--ee69871fa75b472bb633b9e2aa9bf628 1bd22f0800744898a2bd1c1491fc6a9d ee69871fa75b472bb633b9e2aa9bf628--1bd22f0800744898a2bd1c1491fc6a9d 9fb9a46b750640a7be84df2d68c7fb07 1bd22f0800744898a2bd1c1491fc6a9d--9fb9a46b750640a7be84df2d68c7fb07 5436303dc78f44babee0600dc86da2bb 12f985483daa4ad780803bfe3292e8f0 d8bd7176a37d48158e07fac85d55fa1c--12f985483daa4ad780803bfe3292e8f0 30b792fd1b114dd78179f766639eb91f 2 f463907dc932460e891792fc01bd12fb t = -500.000000000000 12f985483daa4ad780803bfe3292e8f0--f463907dc932460e891792fc01bd12fb a7b7b828ce664e14bfe14f84366751dd f463907dc932460e891792fc01bd12fb--a7b7b828ce664e14bfe14f84366751dd dd54024c91c54ef8934f27208e5a7a04 X a7b7b828ce664e14bfe14f84366751dd--dd54024c91c54ef8934f27208e5a7a04 317b6f35ce3f425bb43854a36ec4321a t = -500.000000000000 dd54024c91c54ef8934f27208e5a7a04--317b6f35ce3f425bb43854a36ec4321a 8f9de433462d4a16a8cf2c3e2e7cab3c X 317b6f35ce3f425bb43854a36ec4321a--8f9de433462d4a16a8cf2c3e2e7cab3c 8f9de433462d4a16a8cf2c3e2e7cab3c--5436303dc78f44babee0600dc86da2bb 592b10dbfb0d4e5a846776da83b3410b 295001a8ac604cc4a61be943b9b7e9ac X 30b792fd1b114dd78179f766639eb91f--295001a8ac604cc4a61be943b9b7e9ac 8697a3dd297b4d8b92ce690bb8ae1838 295001a8ac604cc4a61be943b9b7e9ac--8697a3dd297b4d8b92ce690bb8ae1838 bdffd1eae8124b9b98f7a5588198981c X 8697a3dd297b4d8b92ce690bb8ae1838--bdffd1eae8124b9b98f7a5588198981c 8fbe411b574141168b84fd80afde7148 X bdffd1eae8124b9b98f7a5588198981c--8fbe411b574141168b84fd80afde7148 28c4a42413794d39a41ea8dd36610b5a 8fbe411b574141168b84fd80afde7148--28c4a42413794d39a41ea8dd36610b5a cadf6adb65c348e88923329f95020932 X 28c4a42413794d39a41ea8dd36610b5a--cadf6adb65c348e88923329f95020932 cadf6adb65c348e88923329f95020932--592b10dbfb0d4e5a846776da83b3410b

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