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_1a9a2c6e383f4b4cad6252c5aef2466a cluster_9d0cefbc3a86408786f249cb2a9110e1 cluster_6510cf6f5f5a4211ac8b4968db582fa7 cluster_7c07c8c0de8d4fcf829f1b02f48b85c7 cluster_a34abdd372be4363a72dcbed4aae5bea cluster_e99ed4bb8daa493bbf34c4fae796dfad cluster_bf44306a9ade41fb97051690615a6cff d4e02561034a4e2299556b1bef6038dc 0 807da75a7c1e4ef187e6ae996504b297 HamEvo d4e02561034a4e2299556b1bef6038dc--807da75a7c1e4ef187e6ae996504b297 ef41e8f0c5194ebfac0667f03f2280da 1 b1ac888fdaeb4586ad3aba89ff0007bf HamEvo 807da75a7c1e4ef187e6ae996504b297--b1ac888fdaeb4586ad3aba89ff0007bf 39ea37fb3b734f068d4d6878e02bd9a6 HamEvo b1ac888fdaeb4586ad3aba89ff0007bf--39ea37fb3b734f068d4d6878e02bd9a6 14043022dc22463992f962f8fdbdecc3 X 39ea37fb3b734f068d4d6878e02bd9a6--14043022dc22463992f962f8fdbdecc3 ff2e9681f042491f87ed973aaf94276d HamEvo 14043022dc22463992f962f8fdbdecc3--ff2e9681f042491f87ed973aaf94276d f85b6cb1b0244c9da5782e1734ec06a3 HamEvo ff2e9681f042491f87ed973aaf94276d--f85b6cb1b0244c9da5782e1734ec06a3 936426cbb3254679b8da91a26310156e X f85b6cb1b0244c9da5782e1734ec06a3--936426cbb3254679b8da91a26310156e 74310359d5ca440da9d036f3019ad9ac 936426cbb3254679b8da91a26310156e--74310359d5ca440da9d036f3019ad9ac 19d8489c0eea415094d2042a02159e22 HamEvo 74310359d5ca440da9d036f3019ad9ac--19d8489c0eea415094d2042a02159e22 9d22f3dcf63a403d95bf13558a5d7ae0 HamEvo 19d8489c0eea415094d2042a02159e22--9d22f3dcf63a403d95bf13558a5d7ae0 56e3ee07ec244757a54f7e9bc4a5052e 9d22f3dcf63a403d95bf13558a5d7ae0--56e3ee07ec244757a54f7e9bc4a5052e 8be438c11414489d8846b078ddf03d02 56e3ee07ec244757a54f7e9bc4a5052e--8be438c11414489d8846b078ddf03d02 6a5ada6dd59645d4b2f303be9da09a5e 4f427c5eed544f79be8a49a87a4d672b t = -3.14 ef41e8f0c5194ebfac0667f03f2280da--4f427c5eed544f79be8a49a87a4d672b 61991f8937d24a8fb4f7f4c7229dc579 2 a5f1b0a2e75947628780a8cfacd239d0 t = 3.142 4f427c5eed544f79be8a49a87a4d672b--a5f1b0a2e75947628780a8cfacd239d0 5fc5bfaa37934ceb9be2aa4d800d92f7 t = -3.14 a5f1b0a2e75947628780a8cfacd239d0--5fc5bfaa37934ceb9be2aa4d800d92f7 808cd86c675549a1b40628501751ce1e 5fc5bfaa37934ceb9be2aa4d800d92f7--808cd86c675549a1b40628501751ce1e 1c16ff154e734fcba14b0a90af0a0a4d t = 1.571 808cd86c675549a1b40628501751ce1e--1c16ff154e734fcba14b0a90af0a0a4d 556ab6efde0347189c068cdb1807c6f1 t = 1.571 1c16ff154e734fcba14b0a90af0a0a4d--556ab6efde0347189c068cdb1807c6f1 38ab8ff6695d49739adcd24665792319 556ab6efde0347189c068cdb1807c6f1--38ab8ff6695d49739adcd24665792319 7fae0a6ab3c24a2e89fe01a8c19e9fd0 X 38ab8ff6695d49739adcd24665792319--7fae0a6ab3c24a2e89fe01a8c19e9fd0 470473f5bd6b4f38a428407ff936452f t = 1.571 7fae0a6ab3c24a2e89fe01a8c19e9fd0--470473f5bd6b4f38a428407ff936452f 100b31bdd88341c68f5681fddfe138b1 t = 1.571 470473f5bd6b4f38a428407ff936452f--100b31bdd88341c68f5681fddfe138b1 21153948a8e74b31a5c9ef4098817127 X 100b31bdd88341c68f5681fddfe138b1--21153948a8e74b31a5c9ef4098817127 21153948a8e74b31a5c9ef4098817127--6a5ada6dd59645d4b2f303be9da09a5e 403e291933a74f088b588b34e199bdbf cb3d1693647d4335aabd8f21d6bdfdcb 61991f8937d24a8fb4f7f4c7229dc579--cb3d1693647d4335aabd8f21d6bdfdcb 07bfb6384df14291bfa4d757bd509fcc cb3d1693647d4335aabd8f21d6bdfdcb--07bfb6384df14291bfa4d757bd509fcc 797059b0598a43eeb478ad29b8e8d5be 07bfb6384df14291bfa4d757bd509fcc--797059b0598a43eeb478ad29b8e8d5be ca6f2e6bc79a45958b0292014c1f6f11 X 797059b0598a43eeb478ad29b8e8d5be--ca6f2e6bc79a45958b0292014c1f6f11 916cdd3467944c8f8641940b112ba8e6 ca6f2e6bc79a45958b0292014c1f6f11--916cdd3467944c8f8641940b112ba8e6 0058b2a4684c4ea8b06bb179643191ae 916cdd3467944c8f8641940b112ba8e6--0058b2a4684c4ea8b06bb179643191ae 0899a798452a40f48a523087fcaa0c49 X 0058b2a4684c4ea8b06bb179643191ae--0899a798452a40f48a523087fcaa0c49 490609cbe92642e38e3609d6a5a2fe20 X 0899a798452a40f48a523087fcaa0c49--490609cbe92642e38e3609d6a5a2fe20 4d9f7019867f4e6bad2f1ba59d593cae 490609cbe92642e38e3609d6a5a2fe20--4d9f7019867f4e6bad2f1ba59d593cae aed071660b2a46e19b8960013cdf237f 4d9f7019867f4e6bad2f1ba59d593cae--aed071660b2a46e19b8960013cdf237f 6027ecd8e85149b9bc6976afccb37c6e X aed071660b2a46e19b8960013cdf237f--6027ecd8e85149b9bc6976afccb37c6e 6027ecd8e85149b9bc6976afccb37c6e--403e291933a74f088b588b34e199bdbf

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_27f1e0575f3f4ab8bbac4657e8e1dd32 cluster_24c79c3b889449cbaee0f7536e0fe7e4 6136fe3f64a74e82a51f06e046c4eabe 0 3d3f2d9bbc324aab86c14b712b69c5ce X 6136fe3f64a74e82a51f06e046c4eabe--3d3f2d9bbc324aab86c14b712b69c5ce 5e823c23b35345569e26f1d463c54859 1 43df8415e77c421ebb7c4ca47cb7aa62 HamEvo 3d3f2d9bbc324aab86c14b712b69c5ce--43df8415e77c421ebb7c4ca47cb7aa62 2fda70f8085f4f3c86b3372cd470933f X 43df8415e77c421ebb7c4ca47cb7aa62--2fda70f8085f4f3c86b3372cd470933f c7af00d5d25d4334b506fbd09a293376 2fda70f8085f4f3c86b3372cd470933f--c7af00d5d25d4334b506fbd09a293376 66877e84d88c41dc938ad8692d009257 HamEvo c7af00d5d25d4334b506fbd09a293376--66877e84d88c41dc938ad8692d009257 3e59733b923c480bb49a563337929757 66877e84d88c41dc938ad8692d009257--3e59733b923c480bb49a563337929757 6c39e91fb0b04aaea8f280934b8896fe 3e59733b923c480bb49a563337929757--6c39e91fb0b04aaea8f280934b8896fe 78ebe36828e24493b1e5e7863ef301fe 19f123b5d64e46cf938036469aa129a8 5e823c23b35345569e26f1d463c54859--19f123b5d64e46cf938036469aa129a8 b21ecaad6bcf463a9a14f4cb9d096a32 2 ce49b7e5cd12413c9a1c98aa91a93886 t = -0.50 19f123b5d64e46cf938036469aa129a8--ce49b7e5cd12413c9a1c98aa91a93886 29505e5fb76c456082023ed56b4c406a ce49b7e5cd12413c9a1c98aa91a93886--29505e5fb76c456082023ed56b4c406a 6cf3bd0dda5349619f75e765d14f7082 X 29505e5fb76c456082023ed56b4c406a--6cf3bd0dda5349619f75e765d14f7082 393256e6ce344c3aad55d4bf55d809a5 t = -0.50 6cf3bd0dda5349619f75e765d14f7082--393256e6ce344c3aad55d4bf55d809a5 9270ab53fa734e52bdace0bbe818b9af X 393256e6ce344c3aad55d4bf55d809a5--9270ab53fa734e52bdace0bbe818b9af 9270ab53fa734e52bdace0bbe818b9af--78ebe36828e24493b1e5e7863ef301fe 9f4d402d785847638d78063f5325cef1 85313c265d944f7cb2f6ec52174d89aa X b21ecaad6bcf463a9a14f4cb9d096a32--85313c265d944f7cb2f6ec52174d89aa 02b865f5a79c4fc4a87225deae892040 85313c265d944f7cb2f6ec52174d89aa--02b865f5a79c4fc4a87225deae892040 0555a96267194a69bd0a4f952eccb77c X 02b865f5a79c4fc4a87225deae892040--0555a96267194a69bd0a4f952eccb77c 539fe2f6a6694e0ebf8dd691ba0792c4 X 0555a96267194a69bd0a4f952eccb77c--539fe2f6a6694e0ebf8dd691ba0792c4 d95dce9f47e74d35b1d3004842c7ae22 539fe2f6a6694e0ebf8dd691ba0792c4--d95dce9f47e74d35b1d3004842c7ae22 fd9c57ebd64a4667982cd0d387478de9 X d95dce9f47e74d35b1d3004842c7ae22--fd9c57ebd64a4667982cd0d387478de9 fd9c57ebd64a4667982cd0d387478de9--9f4d402d785847638d78063f5325cef1

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_a73cf69fd4ac4def96adaac2ce969661 cluster_027c7fc1723e4bbdb512b821be9cdb6b e0a3475897114840a9f5f7b5a9a393fc 0 7b1dadb260bb4284a3ba92acea371ae5 X e0a3475897114840a9f5f7b5a9a393fc--7b1dadb260bb4284a3ba92acea371ae5 870da743fd58492e934797fb3c4c585f 1 e9dc3bf74cf74f468b300f36d1a2702d HamEvo 7b1dadb260bb4284a3ba92acea371ae5--e9dc3bf74cf74f468b300f36d1a2702d 8d93a8cb967e441188017930eb9862c1 X e9dc3bf74cf74f468b300f36d1a2702d--8d93a8cb967e441188017930eb9862c1 a8f0a1fd07154935a10f9cc155809c89 8d93a8cb967e441188017930eb9862c1--a8f0a1fd07154935a10f9cc155809c89 058765ccbae34c5ca17ced35f115e134 HamEvo a8f0a1fd07154935a10f9cc155809c89--058765ccbae34c5ca17ced35f115e134 c6e25d14857d4580898a114c0ba35339 058765ccbae34c5ca17ced35f115e134--c6e25d14857d4580898a114c0ba35339 c1bcb925d0174487a44daf505170586f c6e25d14857d4580898a114c0ba35339--c1bcb925d0174487a44daf505170586f 61eb2815e8a6484ca8e1186cd9e6f7f5 bb8660fd047a48ae9dc39ed341c709da 870da743fd58492e934797fb3c4c585f--bb8660fd047a48ae9dc39ed341c709da 7b02531641f2449793b5ae596bded429 2 c4f2fe34215a470fad4ee12c49bc40fb t = -500. bb8660fd047a48ae9dc39ed341c709da--c4f2fe34215a470fad4ee12c49bc40fb 49ac249295314dc088a58aa9f44fc8c8 c4f2fe34215a470fad4ee12c49bc40fb--49ac249295314dc088a58aa9f44fc8c8 49420b3645594cad9f26422d4282701c X 49ac249295314dc088a58aa9f44fc8c8--49420b3645594cad9f26422d4282701c c3a07437e7d64d57b940313bdaf8032b t = -500. 49420b3645594cad9f26422d4282701c--c3a07437e7d64d57b940313bdaf8032b e0d3fe1670bb4df29e3582307c3d3918 X c3a07437e7d64d57b940313bdaf8032b--e0d3fe1670bb4df29e3582307c3d3918 e0d3fe1670bb4df29e3582307c3d3918--61eb2815e8a6484ca8e1186cd9e6f7f5 50961bb953bf4c3b8be6c96813e2ced2 80abee229f524592b050cb26996c68eb X 7b02531641f2449793b5ae596bded429--80abee229f524592b050cb26996c68eb 4a7d0ad5e9c244abb20281b9c7995a43 80abee229f524592b050cb26996c68eb--4a7d0ad5e9c244abb20281b9c7995a43 e0642bca9db442aca2fc25170d9cd9b6 X 4a7d0ad5e9c244abb20281b9c7995a43--e0642bca9db442aca2fc25170d9cd9b6 e03c3f13c1ed40bf927bcf0fc432a6ac X e0642bca9db442aca2fc25170d9cd9b6--e03c3f13c1ed40bf927bcf0fc432a6ac 94346723241f49a7939915c4dcfca437 e03c3f13c1ed40bf927bcf0fc432a6ac--94346723241f49a7939915c4dcfca437 16225461f112482db5f3d8504d3db250 X 94346723241f49a7939915c4dcfca437--16225461f112482db5f3d8504d3db250 16225461f112482db5f3d8504d3db250--50961bb953bf4c3b8be6c96813e2ced2

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