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_160cf212883841cb9789e2f4b4de3e18 cluster_dea7aa47f08345829b093e138b51f6f2 cluster_b6cd4cf8c4ce4ce79fb248a7344f12be cluster_06653cf508a6441381f9de52ffd129af cluster_e6eec4fc985c483db64eb3ba6feaf3aa cluster_22690af367764f2db9e39d3af1717bfd cluster_d1b6e658d3404d6b8d2c70b43c990648 4c4b9739cd5e4f5497f38c46d9e3c789 0 d61f302029414e47a41215caeaee5a86 HamEvo 4c4b9739cd5e4f5497f38c46d9e3c789--d61f302029414e47a41215caeaee5a86 df693a01c520492ea67014afbd6d09c7 1 a247bde89a5e48a2a8fe59c465da599f HamEvo d61f302029414e47a41215caeaee5a86--a247bde89a5e48a2a8fe59c465da599f fd28ecd5ca5540309d80f717f5b0dcc1 HamEvo a247bde89a5e48a2a8fe59c465da599f--fd28ecd5ca5540309d80f717f5b0dcc1 0120a01a8b6141f18300176d4ad40dc9 X fd28ecd5ca5540309d80f717f5b0dcc1--0120a01a8b6141f18300176d4ad40dc9 06640f36db36422d8f6f9d02f7acee66 HamEvo 0120a01a8b6141f18300176d4ad40dc9--06640f36db36422d8f6f9d02f7acee66 242d16f0222542699a6237087914d646 HamEvo 06640f36db36422d8f6f9d02f7acee66--242d16f0222542699a6237087914d646 9147188f8c33468eacc7f8693a080891 X 242d16f0222542699a6237087914d646--9147188f8c33468eacc7f8693a080891 c01b27cafc1c46e8a8f6b577eb95280f 9147188f8c33468eacc7f8693a080891--c01b27cafc1c46e8a8f6b577eb95280f fc0880b776084c0aa5997a85d0514f4c HamEvo c01b27cafc1c46e8a8f6b577eb95280f--fc0880b776084c0aa5997a85d0514f4c 8a21f191084849bfbe664c06af0bbca0 HamEvo fc0880b776084c0aa5997a85d0514f4c--8a21f191084849bfbe664c06af0bbca0 40724a238f424891b006672ed71482a9 8a21f191084849bfbe664c06af0bbca0--40724a238f424891b006672ed71482a9 ccc12e1abf62469ab357764c34b05b25 40724a238f424891b006672ed71482a9--ccc12e1abf62469ab357764c34b05b25 5c9b73fb24034dbfa51f5e2c8da0d830 077897c409554491afa960521427e1a0 t = -3.142 df693a01c520492ea67014afbd6d09c7--077897c409554491afa960521427e1a0 14d214cbb7cd4632b10b79bbe9718001 2 cccad2214d3e4e1e8a7c6e35ce267688 t = 3.142 077897c409554491afa960521427e1a0--cccad2214d3e4e1e8a7c6e35ce267688 55c5f68362624d21bf1a0373b62d96c7 t = -3.142 cccad2214d3e4e1e8a7c6e35ce267688--55c5f68362624d21bf1a0373b62d96c7 958e86d34a544b16a3d1bbf3d79eb667 55c5f68362624d21bf1a0373b62d96c7--958e86d34a544b16a3d1bbf3d79eb667 193d3237f04c45d5b8348bf3da75a8a3 t = 1.571 958e86d34a544b16a3d1bbf3d79eb667--193d3237f04c45d5b8348bf3da75a8a3 ea6e1ca332494a8a95a5594a407f662d t = 1.571 193d3237f04c45d5b8348bf3da75a8a3--ea6e1ca332494a8a95a5594a407f662d 7f07e5d926b94d739c2c8e3c5b71f2c5 ea6e1ca332494a8a95a5594a407f662d--7f07e5d926b94d739c2c8e3c5b71f2c5 151633c1f4aa468f82a9d44b7c8f5b98 X 7f07e5d926b94d739c2c8e3c5b71f2c5--151633c1f4aa468f82a9d44b7c8f5b98 30448eeafc334617a980bf4fea6ee61b t = 1.571 151633c1f4aa468f82a9d44b7c8f5b98--30448eeafc334617a980bf4fea6ee61b 87d40aec06774ed8940e898779901d46 t = 1.571 30448eeafc334617a980bf4fea6ee61b--87d40aec06774ed8940e898779901d46 d88cca2e3a7d4598a9de161ded044b35 X 87d40aec06774ed8940e898779901d46--d88cca2e3a7d4598a9de161ded044b35 d88cca2e3a7d4598a9de161ded044b35--5c9b73fb24034dbfa51f5e2c8da0d830 60527d65ab3542ccbac2dcfe5930322b a6faf7b0a3f148a5851facc64f355d0a 14d214cbb7cd4632b10b79bbe9718001--a6faf7b0a3f148a5851facc64f355d0a 6369d9fec4244a2e95c4736d015a3a20 a6faf7b0a3f148a5851facc64f355d0a--6369d9fec4244a2e95c4736d015a3a20 95fd19d49ae3419e828939f5147075fe 6369d9fec4244a2e95c4736d015a3a20--95fd19d49ae3419e828939f5147075fe 6348fe5a362f482ca9fa3b77e443eba4 X 95fd19d49ae3419e828939f5147075fe--6348fe5a362f482ca9fa3b77e443eba4 8d11ce555f6b4bdfba2bf62a410c2beb 6348fe5a362f482ca9fa3b77e443eba4--8d11ce555f6b4bdfba2bf62a410c2beb f0beabf80b2642eabc4d370d08b2555a 8d11ce555f6b4bdfba2bf62a410c2beb--f0beabf80b2642eabc4d370d08b2555a 92a2c02aea5f4a978ddc32f9ec41fa72 X f0beabf80b2642eabc4d370d08b2555a--92a2c02aea5f4a978ddc32f9ec41fa72 36862515c3aa4000815525b878ab31dc X 92a2c02aea5f4a978ddc32f9ec41fa72--36862515c3aa4000815525b878ab31dc b36ae90edd044d6b81a1b6486b72e273 36862515c3aa4000815525b878ab31dc--b36ae90edd044d6b81a1b6486b72e273 c7648e35dc2143ebb605849debb5958b b36ae90edd044d6b81a1b6486b72e273--c7648e35dc2143ebb605849debb5958b f7bafc4652784875a40a86bd41a81030 X c7648e35dc2143ebb605849debb5958b--f7bafc4652784875a40a86bd41a81030 f7bafc4652784875a40a86bd41a81030--60527d65ab3542ccbac2dcfe5930322b

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_d7e69e7bc1224a5fa5cfc26d82b6b2d0 cluster_e6192fe94d6b47b7a58f36cc684c95ca 3e4b930fb6fe4fe1b576085a1daff7d3 0 f6bd6e2fa9b6446395ca9b2b6fe55d9a X 3e4b930fb6fe4fe1b576085a1daff7d3--f6bd6e2fa9b6446395ca9b2b6fe55d9a ca1fec7a79704c289c6a4c90f2e30094 1 10480688a17e49ff90a1fb1300466642 HamEvo f6bd6e2fa9b6446395ca9b2b6fe55d9a--10480688a17e49ff90a1fb1300466642 6c24f59dc63149889a72f0bdd1ba4e8f X 10480688a17e49ff90a1fb1300466642--6c24f59dc63149889a72f0bdd1ba4e8f 88222ffad5114f88905ada8b5a7b5d46 6c24f59dc63149889a72f0bdd1ba4e8f--88222ffad5114f88905ada8b5a7b5d46 06c6cf67dc62440ebc87dd3d8415a39f HamEvo 88222ffad5114f88905ada8b5a7b5d46--06c6cf67dc62440ebc87dd3d8415a39f e8fa14ac43b04bc09689e7aac948728f 06c6cf67dc62440ebc87dd3d8415a39f--e8fa14ac43b04bc09689e7aac948728f e0cc1d4712fd4041a2cd6ecaa32b10ea e8fa14ac43b04bc09689e7aac948728f--e0cc1d4712fd4041a2cd6ecaa32b10ea c1585a84b752440c97dfa73770885104 e3cb272687e54a5d86409f45e1796a40 ca1fec7a79704c289c6a4c90f2e30094--e3cb272687e54a5d86409f45e1796a40 e066e4962d9c4adabbd7cbb8eeda6711 2 2517e0748ef54c77b730dd1097d7ef75 t = -0.500 e3cb272687e54a5d86409f45e1796a40--2517e0748ef54c77b730dd1097d7ef75 5cb3b0ad1e4c44df8474c1d8171e9be8 2517e0748ef54c77b730dd1097d7ef75--5cb3b0ad1e4c44df8474c1d8171e9be8 481d112fbfb44c6e88e0801244b29964 X 5cb3b0ad1e4c44df8474c1d8171e9be8--481d112fbfb44c6e88e0801244b29964 a5656cb69057411682ba83ff74b21d8c t = -0.500 481d112fbfb44c6e88e0801244b29964--a5656cb69057411682ba83ff74b21d8c 6698eaa824ad4c3fa4abfc0099402151 X a5656cb69057411682ba83ff74b21d8c--6698eaa824ad4c3fa4abfc0099402151 6698eaa824ad4c3fa4abfc0099402151--c1585a84b752440c97dfa73770885104 bf5c8af3eb6b4431ba00c3f8360b8487 9340ba929a4d43479ec63ec606daa4dc X e066e4962d9c4adabbd7cbb8eeda6711--9340ba929a4d43479ec63ec606daa4dc 39e8182365f34270b4f5f3ff47e6c247 9340ba929a4d43479ec63ec606daa4dc--39e8182365f34270b4f5f3ff47e6c247 93b595b9a61d498bbc2bdc00c6ddb72e X 39e8182365f34270b4f5f3ff47e6c247--93b595b9a61d498bbc2bdc00c6ddb72e e548d9c0eb124896a946f1f3f5ae7aec X 93b595b9a61d498bbc2bdc00c6ddb72e--e548d9c0eb124896a946f1f3f5ae7aec 40ca32872122489295c7db6df6e019a9 e548d9c0eb124896a946f1f3f5ae7aec--40ca32872122489295c7db6df6e019a9 c2257fccf1d646df954fe3fe77c7b06c X 40ca32872122489295c7db6df6e019a9--c2257fccf1d646df954fe3fe77c7b06c c2257fccf1d646df954fe3fe77c7b06c--bf5c8af3eb6b4431ba00c3f8360b8487

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_d238afca6ccf47adb4c847904bdddde6 cluster_67a024a9e4df4acab8c944039be3185a a9258df3f6a3488190e51033990f8499 0 8067f574fd0d4f0c868c45fc50407bed X a9258df3f6a3488190e51033990f8499--8067f574fd0d4f0c868c45fc50407bed abd9c8d6e7a24afca78e614e21c4f339 1 bd92672970b44a97bc835b53244a9e5f HamEvo 8067f574fd0d4f0c868c45fc50407bed--bd92672970b44a97bc835b53244a9e5f 0c3ecc023b464025acf0507d5e6a53ad X bd92672970b44a97bc835b53244a9e5f--0c3ecc023b464025acf0507d5e6a53ad 3300cc24659448a8be0ab4f89d366eed 0c3ecc023b464025acf0507d5e6a53ad--3300cc24659448a8be0ab4f89d366eed c4ad68851d494de9964b73488c005162 HamEvo 3300cc24659448a8be0ab4f89d366eed--c4ad68851d494de9964b73488c005162 d082537e8c814c138bcb6e6c3f4927f9 c4ad68851d494de9964b73488c005162--d082537e8c814c138bcb6e6c3f4927f9 9a71316605874dbca1860b1a4ae0c07f d082537e8c814c138bcb6e6c3f4927f9--9a71316605874dbca1860b1a4ae0c07f 286507f16bae4659ab1d3cdd695e4ebb 8618e50401ef452f89810589b557fa38 abd9c8d6e7a24afca78e614e21c4f339--8618e50401ef452f89810589b557fa38 24745435525542daa0c72ee9d7937500 2 c0dd33165f1341bd89a9ca2d5e25d00f t = -500.000000000000 8618e50401ef452f89810589b557fa38--c0dd33165f1341bd89a9ca2d5e25d00f 378a5969e7874474b3e977fb3b05b055 c0dd33165f1341bd89a9ca2d5e25d00f--378a5969e7874474b3e977fb3b05b055 433c09878ebc48e18a9ea893bc11fc90 X 378a5969e7874474b3e977fb3b05b055--433c09878ebc48e18a9ea893bc11fc90 adb14c7676994dd5ae5f1e94849d539c t = -500.000000000000 433c09878ebc48e18a9ea893bc11fc90--adb14c7676994dd5ae5f1e94849d539c c0c6ec86908449aca18a0ab33d3ddd55 X adb14c7676994dd5ae5f1e94849d539c--c0c6ec86908449aca18a0ab33d3ddd55 c0c6ec86908449aca18a0ab33d3ddd55--286507f16bae4659ab1d3cdd695e4ebb f9fa1c6fa22b4d21aa3578ee0cc22f1d 8bebb7b97c9040ff805f60fa3c9e502e X 24745435525542daa0c72ee9d7937500--8bebb7b97c9040ff805f60fa3c9e502e e55cacf8d7d1412396007da0c41261a0 8bebb7b97c9040ff805f60fa3c9e502e--e55cacf8d7d1412396007da0c41261a0 4070a193a79b44bba6585f4104eb0bdd X e55cacf8d7d1412396007da0c41261a0--4070a193a79b44bba6585f4104eb0bdd 54bf57ca3e9c468186729cac2b695807 X 4070a193a79b44bba6585f4104eb0bdd--54bf57ca3e9c468186729cac2b695807 e018febe484e488183827a4ef6d25192 54bf57ca3e9c468186729cac2b695807--e018febe484e488183827a4ef6d25192 a90ca523cd2c4e9e9434276fe27f7ad1 X e018febe484e488183827a4ef6d25192--a90ca523cd2c4e9e9434276fe27f7ad1 a90ca523cd2c4e9e9434276fe27f7ad1--f9fa1c6fa22b4d21aa3578ee0cc22f1d

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