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_5f0c654ec3d0407a8ba450ef53d8b079 cluster_ede3a92abca04dac88d580c2c95e9c4e cluster_0b3e680695e2468c9cbae77f53f2365e cluster_cecdc38348d542e3a199404141081757 cluster_8e90a2a37d3a47bf82fd5f7c243a3872 cluster_063a29d8bd114e9baf93eed211d43a3a cluster_9f63ba290ae44c098d51d29d0272fdeb 4f9e44c5a5e44426bcf4181d82cb2e47 0 6160b50573e343eba7deaf0e67c0d03d HamEvo 4f9e44c5a5e44426bcf4181d82cb2e47--6160b50573e343eba7deaf0e67c0d03d d9c551dd32604ad4bb82cf8e09e09441 1 479f848945e449128625a798456e6c71 HamEvo 6160b50573e343eba7deaf0e67c0d03d--479f848945e449128625a798456e6c71 bf9276c234894285a5b6912fe42be97d HamEvo 479f848945e449128625a798456e6c71--bf9276c234894285a5b6912fe42be97d de10bac8eb164e61ac951d04dfd9a91a X bf9276c234894285a5b6912fe42be97d--de10bac8eb164e61ac951d04dfd9a91a 0729c7d36aee4d4baba3b89eb0ee15d2 HamEvo de10bac8eb164e61ac951d04dfd9a91a--0729c7d36aee4d4baba3b89eb0ee15d2 bb03df4a3cd14b37ad638623c46dab0a HamEvo 0729c7d36aee4d4baba3b89eb0ee15d2--bb03df4a3cd14b37ad638623c46dab0a 9ba391c38da647a7a08fc4641f0b0e8e X bb03df4a3cd14b37ad638623c46dab0a--9ba391c38da647a7a08fc4641f0b0e8e 234d0886bc854faca1c857579c27545e 9ba391c38da647a7a08fc4641f0b0e8e--234d0886bc854faca1c857579c27545e 423de0569b894cadb21b2d4a8968ec7c HamEvo 234d0886bc854faca1c857579c27545e--423de0569b894cadb21b2d4a8968ec7c 11408367f02047f39f8ffaed8823f240 HamEvo 423de0569b894cadb21b2d4a8968ec7c--11408367f02047f39f8ffaed8823f240 d800e2b93f3549729798f4af68b4682d 11408367f02047f39f8ffaed8823f240--d800e2b93f3549729798f4af68b4682d bf6864b5ba824d5e9db41d49e6e54ccb d800e2b93f3549729798f4af68b4682d--bf6864b5ba824d5e9db41d49e6e54ccb f479ca7b41dc4192992f60935ce835ae 221e0e2808f74d48a965455c295f9e0f t = -3.14 d9c551dd32604ad4bb82cf8e09e09441--221e0e2808f74d48a965455c295f9e0f 042971fb761d4d9e9313bcec906ee17c 2 f36117efd2284a01a1d3d5a0fe8a40a8 t = 3.142 221e0e2808f74d48a965455c295f9e0f--f36117efd2284a01a1d3d5a0fe8a40a8 f81fdb0058f3461cbf94a4c565dd1383 t = -3.14 f36117efd2284a01a1d3d5a0fe8a40a8--f81fdb0058f3461cbf94a4c565dd1383 4d8cbfdc2f2242b7ba71b44c19d867b2 f81fdb0058f3461cbf94a4c565dd1383--4d8cbfdc2f2242b7ba71b44c19d867b2 c734e8a4909f40f29b08f102a9b55087 t = 1.571 4d8cbfdc2f2242b7ba71b44c19d867b2--c734e8a4909f40f29b08f102a9b55087 e9b8bfb4c9c04efdb1f056ec48d02827 t = 1.571 c734e8a4909f40f29b08f102a9b55087--e9b8bfb4c9c04efdb1f056ec48d02827 1d5d296a30394ec0947bebe4b8ee6a27 e9b8bfb4c9c04efdb1f056ec48d02827--1d5d296a30394ec0947bebe4b8ee6a27 ce15f60a7b974723b5b052b3f8735626 X 1d5d296a30394ec0947bebe4b8ee6a27--ce15f60a7b974723b5b052b3f8735626 8c127514af584d44ab42c88751caee05 t = 1.571 ce15f60a7b974723b5b052b3f8735626--8c127514af584d44ab42c88751caee05 ef56ba00a7344846acd363613d2f0cae t = 1.571 8c127514af584d44ab42c88751caee05--ef56ba00a7344846acd363613d2f0cae bb41fafe9543448180482413e9ee1e8f X ef56ba00a7344846acd363613d2f0cae--bb41fafe9543448180482413e9ee1e8f bb41fafe9543448180482413e9ee1e8f--f479ca7b41dc4192992f60935ce835ae 44b3fc31d4bd41ab81dbfce12ca69841 c0a72720dbde44a1b1ef4dde925dc316 042971fb761d4d9e9313bcec906ee17c--c0a72720dbde44a1b1ef4dde925dc316 bb1c682fb42243d1847475cc0b8a3c65 c0a72720dbde44a1b1ef4dde925dc316--bb1c682fb42243d1847475cc0b8a3c65 fedd6fdf0c3f4fc9966f054d03690d9d bb1c682fb42243d1847475cc0b8a3c65--fedd6fdf0c3f4fc9966f054d03690d9d 1cb3c69ee63942e0a7965ba64a9ef960 X fedd6fdf0c3f4fc9966f054d03690d9d--1cb3c69ee63942e0a7965ba64a9ef960 d863a4465f79485f9eb9a3b35bbdaa6e 1cb3c69ee63942e0a7965ba64a9ef960--d863a4465f79485f9eb9a3b35bbdaa6e 7f2d2bcf77ec447590dc90202fb2e467 d863a4465f79485f9eb9a3b35bbdaa6e--7f2d2bcf77ec447590dc90202fb2e467 19d50577c5a046759485d1b8e4bfbced X 7f2d2bcf77ec447590dc90202fb2e467--19d50577c5a046759485d1b8e4bfbced 6bc66f2c2eae43cdb57047945bdedcbd X 19d50577c5a046759485d1b8e4bfbced--6bc66f2c2eae43cdb57047945bdedcbd 3051dd7251884d698a1e03668f99630d 6bc66f2c2eae43cdb57047945bdedcbd--3051dd7251884d698a1e03668f99630d 1a2150d54ac643fb95ad4937a4fdb45e 3051dd7251884d698a1e03668f99630d--1a2150d54ac643fb95ad4937a4fdb45e 7e1bc9debff3484d8a32142efb164ae1 X 1a2150d54ac643fb95ad4937a4fdb45e--7e1bc9debff3484d8a32142efb164ae1 7e1bc9debff3484d8a32142efb164ae1--44b3fc31d4bd41ab81dbfce12ca69841

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_d5a4f5a794d245bb8681ee8e7c100fec cluster_d3a155378c7844588f34c6da19c513c3 abf6c57704e14e50894f1e8d827459c2 0 6397861893544e479be1da64f6b8024a X abf6c57704e14e50894f1e8d827459c2--6397861893544e479be1da64f6b8024a 33e1f250a222470295bfbede61bcc3a5 1 a1410ecd052447dd85b25da541281c82 HamEvo 6397861893544e479be1da64f6b8024a--a1410ecd052447dd85b25da541281c82 7c7573e58c324105805af73aecf5d9b3 X a1410ecd052447dd85b25da541281c82--7c7573e58c324105805af73aecf5d9b3 0aebc350588b45a4b254ce63de4a74a9 7c7573e58c324105805af73aecf5d9b3--0aebc350588b45a4b254ce63de4a74a9 a317e7516d564bb1b02fd672f4a835b0 HamEvo 0aebc350588b45a4b254ce63de4a74a9--a317e7516d564bb1b02fd672f4a835b0 d0bca08db8d64e8c95895d9cb3b33de7 a317e7516d564bb1b02fd672f4a835b0--d0bca08db8d64e8c95895d9cb3b33de7 4fd7b797ac8c443da521128862eab73b d0bca08db8d64e8c95895d9cb3b33de7--4fd7b797ac8c443da521128862eab73b c534b7e7a207412382b008ae0e79b0ed 47981ab332a1458d8a857083284ea861 33e1f250a222470295bfbede61bcc3a5--47981ab332a1458d8a857083284ea861 cdeb76fec084448688bf009da5c85dab 2 6efe9431286749c6a3d2dbc09fe8263f t = -0.50 47981ab332a1458d8a857083284ea861--6efe9431286749c6a3d2dbc09fe8263f 899aa480434e41ce9392902ce700b6f8 6efe9431286749c6a3d2dbc09fe8263f--899aa480434e41ce9392902ce700b6f8 6382b567ed15487bb2d85d03645f33cf X 899aa480434e41ce9392902ce700b6f8--6382b567ed15487bb2d85d03645f33cf c7b473daedad42fdbe008c00f69e8293 t = -0.50 6382b567ed15487bb2d85d03645f33cf--c7b473daedad42fdbe008c00f69e8293 6618177ee3924c1cb1e060963db41a52 X c7b473daedad42fdbe008c00f69e8293--6618177ee3924c1cb1e060963db41a52 6618177ee3924c1cb1e060963db41a52--c534b7e7a207412382b008ae0e79b0ed c4af95834ce04592b3347227ec47ee3a 742f96162bbf4f95a4be2fbe0f0a17cd X cdeb76fec084448688bf009da5c85dab--742f96162bbf4f95a4be2fbe0f0a17cd fe4b26f56f5341cf89ffa0b0138041a2 742f96162bbf4f95a4be2fbe0f0a17cd--fe4b26f56f5341cf89ffa0b0138041a2 254ce6c33f4f40aebad49f21c5827851 X fe4b26f56f5341cf89ffa0b0138041a2--254ce6c33f4f40aebad49f21c5827851 121aaa4384be41e0aa21a2b125d80b39 X 254ce6c33f4f40aebad49f21c5827851--121aaa4384be41e0aa21a2b125d80b39 2d9402361ae34424b22e78f61ab1c8a5 121aaa4384be41e0aa21a2b125d80b39--2d9402361ae34424b22e78f61ab1c8a5 ec9152c634ee4202814f1c0b3f0b424b X 2d9402361ae34424b22e78f61ab1c8a5--ec9152c634ee4202814f1c0b3f0b424b ec9152c634ee4202814f1c0b3f0b424b--c4af95834ce04592b3347227ec47ee3a

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_f8ea64e4a611424ea79974a7016a6b5b cluster_2d7c1c741bcc442aa2fd1969d7531951 9b2ace622cc540f8b610affd423f0a59 0 90a12d9b3c784126b4c3947c62da0f49 X 9b2ace622cc540f8b610affd423f0a59--90a12d9b3c784126b4c3947c62da0f49 d74483a92e8c47ab82ca1e082a1c46f7 1 88185d8d125a46c680fab4eb844e09c3 HamEvo 90a12d9b3c784126b4c3947c62da0f49--88185d8d125a46c680fab4eb844e09c3 cfb7e6f9259a40baac7f2ca172117021 X 88185d8d125a46c680fab4eb844e09c3--cfb7e6f9259a40baac7f2ca172117021 7f2817b1e4c84193b0189d2f9a57bf14 cfb7e6f9259a40baac7f2ca172117021--7f2817b1e4c84193b0189d2f9a57bf14 85a5d2e9fae045ceaaf2615996b1652d HamEvo 7f2817b1e4c84193b0189d2f9a57bf14--85a5d2e9fae045ceaaf2615996b1652d 44a5ade7ed854d909eb1e6557fd0aa78 85a5d2e9fae045ceaaf2615996b1652d--44a5ade7ed854d909eb1e6557fd0aa78 b958cd858fcb47f6abecff2a3ed359d0 44a5ade7ed854d909eb1e6557fd0aa78--b958cd858fcb47f6abecff2a3ed359d0 0196b4a798164171904fb7df7c54ba87 b48ae681fdf84ac4b610e1d693bb8b17 d74483a92e8c47ab82ca1e082a1c46f7--b48ae681fdf84ac4b610e1d693bb8b17 6419479a59df4a1985cab6fed006a112 2 9c8b7c6008164564ac4ded868368297d t = -500. b48ae681fdf84ac4b610e1d693bb8b17--9c8b7c6008164564ac4ded868368297d 75488e79b868492c8f2dca4ab74f2717 9c8b7c6008164564ac4ded868368297d--75488e79b868492c8f2dca4ab74f2717 22b03cb65ab04bae99ae0292ed9abd8f X 75488e79b868492c8f2dca4ab74f2717--22b03cb65ab04bae99ae0292ed9abd8f d164bf66695a405789b50f572d3ffc20 t = -500. 22b03cb65ab04bae99ae0292ed9abd8f--d164bf66695a405789b50f572d3ffc20 81499cf0cb564a57a7f53938fb02caaf X d164bf66695a405789b50f572d3ffc20--81499cf0cb564a57a7f53938fb02caaf 81499cf0cb564a57a7f53938fb02caaf--0196b4a798164171904fb7df7c54ba87 5e19fc9292f24c538d45be4534b85e07 0e0eb301c2ca4f86a711b08a1d0b297a X 6419479a59df4a1985cab6fed006a112--0e0eb301c2ca4f86a711b08a1d0b297a cf708dfd907c4f7f973194f9d59d464b 0e0eb301c2ca4f86a711b08a1d0b297a--cf708dfd907c4f7f973194f9d59d464b 933625926b104a968303dfec71fd3f94 X cf708dfd907c4f7f973194f9d59d464b--933625926b104a968303dfec71fd3f94 0bb4330103cb4352a9cb06309f45dc72 X 933625926b104a968303dfec71fd3f94--0bb4330103cb4352a9cb06309f45dc72 473986579f75450bb30cb82d30ce635f 0bb4330103cb4352a9cb06309f45dc72--473986579f75450bb30cb82d30ce635f 0148f3af26cf45268de20dfce7bd5bb2 X 473986579f75450bb30cb82d30ce635f--0148f3af26cf45268de20dfce7bd5bb2 0148f3af26cf45268de20dfce7bd5bb2--5e19fc9292f24c538d45be4534b85e07

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