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.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_87d37312eb7c4e87b9c4655a0474d254 cluster_5082c40c0c6c4d6697015c08be1fb075 cluster_b33c960e0320430c9505c7ecb26c9957 cluster_3557556059ff42329158508424ede111 cluster_e4d3d4b04f2144af82378d1db7b8856e cluster_3daa273a785348c5a92e425a61c2e411 cluster_b8dabd8b1fcf46ad90b037036fb9d868 ff132df459b54c8697ba2b50ab8982bc 0 5aef07370c144323b1f02a26c52c1ad7 HamEvo ff132df459b54c8697ba2b50ab8982bc--5aef07370c144323b1f02a26c52c1ad7 0e37399b01ff4278b90c35e8d4513f19 1 994fedf08cb843a08e5dd26e73f4375a HamEvo 5aef07370c144323b1f02a26c52c1ad7--994fedf08cb843a08e5dd26e73f4375a 534a31736d4a4b5ab5bf8ee8b744bce5 HamEvo 994fedf08cb843a08e5dd26e73f4375a--534a31736d4a4b5ab5bf8ee8b744bce5 0624ded5941c4ed1b69ade7522c130fa X 534a31736d4a4b5ab5bf8ee8b744bce5--0624ded5941c4ed1b69ade7522c130fa 2c694354bd51404c973f3d41c5fd8e5a HamEvo 0624ded5941c4ed1b69ade7522c130fa--2c694354bd51404c973f3d41c5fd8e5a c1c44db3c675434da3f4c3ac19bc4df4 HamEvo 2c694354bd51404c973f3d41c5fd8e5a--c1c44db3c675434da3f4c3ac19bc4df4 a80f177985fd43a297e79b7150e4b1f4 X c1c44db3c675434da3f4c3ac19bc4df4--a80f177985fd43a297e79b7150e4b1f4 9821399a37bc4518b51d9d2b29e1842e a80f177985fd43a297e79b7150e4b1f4--9821399a37bc4518b51d9d2b29e1842e 3f7166435baf433cb16eb6e1578d0025 HamEvo 9821399a37bc4518b51d9d2b29e1842e--3f7166435baf433cb16eb6e1578d0025 2ba61ec624ee4611a7e37328b11d82b2 HamEvo 3f7166435baf433cb16eb6e1578d0025--2ba61ec624ee4611a7e37328b11d82b2 bee88edbccb2478b9fba701bd03ba237 2ba61ec624ee4611a7e37328b11d82b2--bee88edbccb2478b9fba701bd03ba237 a69c3b1580104d9cbc333bdb1b99ce2c bee88edbccb2478b9fba701bd03ba237--a69c3b1580104d9cbc333bdb1b99ce2c 54d4c4361db548daa4d48084097254cd cd03d068e13e4c7eb25eb6bc44a68cff t = -3.14 0e37399b01ff4278b90c35e8d4513f19--cd03d068e13e4c7eb25eb6bc44a68cff e234c9b27fcd4ff9a3996ab10c8aa3a7 2 4756351c48bf4525b16853fc7b7eb728 t = 3.142 cd03d068e13e4c7eb25eb6bc44a68cff--4756351c48bf4525b16853fc7b7eb728 fdf5dbcaf2bb4aef8b3c1009664c0708 t = -3.14 4756351c48bf4525b16853fc7b7eb728--fdf5dbcaf2bb4aef8b3c1009664c0708 70e51a1f96394e3586eaed88784bf625 fdf5dbcaf2bb4aef8b3c1009664c0708--70e51a1f96394e3586eaed88784bf625 82bb58135c184b5c878a153abfe100fc t = 1.571 70e51a1f96394e3586eaed88784bf625--82bb58135c184b5c878a153abfe100fc 6bcaf87f078c454cad2bf04533342f72 t = 1.571 82bb58135c184b5c878a153abfe100fc--6bcaf87f078c454cad2bf04533342f72 93dc1169237a4fd992aa73b79a0631da 6bcaf87f078c454cad2bf04533342f72--93dc1169237a4fd992aa73b79a0631da 2929396657fa4ed6be2bd6380e2d5607 X 93dc1169237a4fd992aa73b79a0631da--2929396657fa4ed6be2bd6380e2d5607 29b61e45255641f7983e4643884cc80c t = 1.571 2929396657fa4ed6be2bd6380e2d5607--29b61e45255641f7983e4643884cc80c 457a00d660544fd3a352ff049ac7485e t = 1.571 29b61e45255641f7983e4643884cc80c--457a00d660544fd3a352ff049ac7485e f8403c2c847c442bb69871d41480ee4c X 457a00d660544fd3a352ff049ac7485e--f8403c2c847c442bb69871d41480ee4c f8403c2c847c442bb69871d41480ee4c--54d4c4361db548daa4d48084097254cd f2f2151f00af4fa99cd11d2be299e120 0d8ca14ad8e142959d75cd3a42aca7a0 e234c9b27fcd4ff9a3996ab10c8aa3a7--0d8ca14ad8e142959d75cd3a42aca7a0 4b4cec1318564ab7a4628bffd8d8b0d0 0d8ca14ad8e142959d75cd3a42aca7a0--4b4cec1318564ab7a4628bffd8d8b0d0 2e9ec2ce2a06437793959f68522dd694 4b4cec1318564ab7a4628bffd8d8b0d0--2e9ec2ce2a06437793959f68522dd694 24b61e789fce4399be1912623e3d37c6 X 2e9ec2ce2a06437793959f68522dd694--24b61e789fce4399be1912623e3d37c6 83cc40832ef44acaa7063e536c63921a 24b61e789fce4399be1912623e3d37c6--83cc40832ef44acaa7063e536c63921a f1d75a373c404b96a97c52afb0441165 83cc40832ef44acaa7063e536c63921a--f1d75a373c404b96a97c52afb0441165 695421632a924011a56df5eecdd13242 X f1d75a373c404b96a97c52afb0441165--695421632a924011a56df5eecdd13242 21c8c4d86db64006804ec9ef849896da X 695421632a924011a56df5eecdd13242--21c8c4d86db64006804ec9ef849896da 813bffb18b534739bb95668b88dedf21 21c8c4d86db64006804ec9ef849896da--813bffb18b534739bb95668b88dedf21 591e5e23157546ffa8f30f67c6988d14 813bffb18b534739bb95668b88dedf21--591e5e23157546ffa8f30f67c6988d14 70baddada0b8478f8203f6d197819e63 X 591e5e23157546ffa8f30f67c6988d14--70baddada0b8478f8203f6d197819e63 70baddada0b8478f8203f6d197819e63--f2f2151f00af4fa99cd11d2be299e120

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_bb9114a9c7014573b814da14ba4d13b8 cluster_28993acc086b4f7491d991250859140f 29fc78c41d9e4da5af86cc73a1d93126 0 1ea9cf97602f473b8544b53640f6600e X 29fc78c41d9e4da5af86cc73a1d93126--1ea9cf97602f473b8544b53640f6600e afd8733226014213943fb663e7e6f3ba 1 59ad18d920d04ecf90a6a3d43fc7dbda HamEvo 1ea9cf97602f473b8544b53640f6600e--59ad18d920d04ecf90a6a3d43fc7dbda 486d06f3218b4db4bf2e31219c7f4599 X 59ad18d920d04ecf90a6a3d43fc7dbda--486d06f3218b4db4bf2e31219c7f4599 ec2a1a22c1e7475d9eb90024e2e95e5a 486d06f3218b4db4bf2e31219c7f4599--ec2a1a22c1e7475d9eb90024e2e95e5a 2905bc9fccc44ae2b05fad008ed07c15 HamEvo ec2a1a22c1e7475d9eb90024e2e95e5a--2905bc9fccc44ae2b05fad008ed07c15 4312b770692344399412e4e4e47949a9 2905bc9fccc44ae2b05fad008ed07c15--4312b770692344399412e4e4e47949a9 e5d819d9e74249a5882ee6fc1e27f947 4312b770692344399412e4e4e47949a9--e5d819d9e74249a5882ee6fc1e27f947 5c0f4fafaabd4466a58b93debaab8708 2131668f448d41a8bb616baac8251c81 afd8733226014213943fb663e7e6f3ba--2131668f448d41a8bb616baac8251c81 6dae0f68d3f24841b2b54bbb0761c636 2 df7f501da41147988ef875b5032c45a5 t = -0.50 2131668f448d41a8bb616baac8251c81--df7f501da41147988ef875b5032c45a5 1d181a4e8ea04632ad7345249ce9b865 df7f501da41147988ef875b5032c45a5--1d181a4e8ea04632ad7345249ce9b865 9c0ac308d5914b2b972e880750e7ff2b X 1d181a4e8ea04632ad7345249ce9b865--9c0ac308d5914b2b972e880750e7ff2b a1f7b27bd48a4b4084f209c46b704b1d t = -0.50 9c0ac308d5914b2b972e880750e7ff2b--a1f7b27bd48a4b4084f209c46b704b1d 3d79f18af19c40c2844cdb5350ce8f90 X a1f7b27bd48a4b4084f209c46b704b1d--3d79f18af19c40c2844cdb5350ce8f90 3d79f18af19c40c2844cdb5350ce8f90--5c0f4fafaabd4466a58b93debaab8708 cdc4844ab23a4f189619afa0d43ccbd2 ed2b5a6ce925454f9aeb88d114fbedc2 X 6dae0f68d3f24841b2b54bbb0761c636--ed2b5a6ce925454f9aeb88d114fbedc2 449e3307b3014a93be4ce3a8177acca3 ed2b5a6ce925454f9aeb88d114fbedc2--449e3307b3014a93be4ce3a8177acca3 7109914788c04df1b7c084f42d5352c0 X 449e3307b3014a93be4ce3a8177acca3--7109914788c04df1b7c084f42d5352c0 779fbd7c8ebe4922a23d8e53de8b6f30 X 7109914788c04df1b7c084f42d5352c0--779fbd7c8ebe4922a23d8e53de8b6f30 7cf2b808f17e4e909e9fe9eb71114be5 779fbd7c8ebe4922a23d8e53de8b6f30--7cf2b808f17e4e909e9fe9eb71114be5 e753a5e25ec544338fd75a4eca51c8ca X 7cf2b808f17e4e909e9fe9eb71114be5--e753a5e25ec544338fd75a4eca51c8ca e753a5e25ec544338fd75a4eca51c8ca--cdc4844ab23a4f189619afa0d43ccbd2

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_7784b21ea4ff4236a4b1375be19defa7 cluster_2ba66ecd376e456eb1f3bd76d1f71324 7db956afd9f54248a92505b5b96a0b68 0 255bcbdb182c46f89e6738181b889f1d X 7db956afd9f54248a92505b5b96a0b68--255bcbdb182c46f89e6738181b889f1d 0771847b8f764b79a0300a63d435ae23 1 6d72c89f8d8c4e61b916b1da48504850 HamEvo 255bcbdb182c46f89e6738181b889f1d--6d72c89f8d8c4e61b916b1da48504850 4c5c222209704b61b9d76f39e8c0dce3 X 6d72c89f8d8c4e61b916b1da48504850--4c5c222209704b61b9d76f39e8c0dce3 9ea383a16aa24e92b60fde862454312a 4c5c222209704b61b9d76f39e8c0dce3--9ea383a16aa24e92b60fde862454312a 653fc76e1eb34de7afe59704d889e8ad HamEvo 9ea383a16aa24e92b60fde862454312a--653fc76e1eb34de7afe59704d889e8ad 6539619c6a24447e9f202fe63dcdf9ad 653fc76e1eb34de7afe59704d889e8ad--6539619c6a24447e9f202fe63dcdf9ad 032357a520024c52a993316f7caff3ba 6539619c6a24447e9f202fe63dcdf9ad--032357a520024c52a993316f7caff3ba d6392b848e0d4183a9b9c6578327eb78 03b7f13a36f64d989424a4c613f4bee9 0771847b8f764b79a0300a63d435ae23--03b7f13a36f64d989424a4c613f4bee9 aa7fda0968af41999eba376537d29c26 2 6d79f1a32c7141eea1791c8e2e8546c0 t = -500. 03b7f13a36f64d989424a4c613f4bee9--6d79f1a32c7141eea1791c8e2e8546c0 098721de99b84de1bc2d83fe83e3a0a2 6d79f1a32c7141eea1791c8e2e8546c0--098721de99b84de1bc2d83fe83e3a0a2 456f6a1bab7947c983a069a11b085409 X 098721de99b84de1bc2d83fe83e3a0a2--456f6a1bab7947c983a069a11b085409 f1713a48c3334cfe978653d4fac070bc t = -500. 456f6a1bab7947c983a069a11b085409--f1713a48c3334cfe978653d4fac070bc 54e851d75b424fa6872328ed63c62584 X f1713a48c3334cfe978653d4fac070bc--54e851d75b424fa6872328ed63c62584 54e851d75b424fa6872328ed63c62584--d6392b848e0d4183a9b9c6578327eb78 0191bfb0a92249a88b04d58c0783de04 ae4197cec28e4431b8d82fd7b46a03ef X aa7fda0968af41999eba376537d29c26--ae4197cec28e4431b8d82fd7b46a03ef 9ff691d9c6e14636a2f0bf4fe9d18f8b ae4197cec28e4431b8d82fd7b46a03ef--9ff691d9c6e14636a2f0bf4fe9d18f8b 50b633cdded74cd0998ac033478a2821 X 9ff691d9c6e14636a2f0bf4fe9d18f8b--50b633cdded74cd0998ac033478a2821 c7490df45f414c2a9bbc2b60f9528ec0 X 50b633cdded74cd0998ac033478a2821--c7490df45f414c2a9bbc2b60f9528ec0 cccb7aba1e34480cbf738dbfc8ba6e91 c7490df45f414c2a9bbc2b60f9528ec0--cccb7aba1e34480cbf738dbfc8ba6e91 fda6106c215a4f7292399e8bf851f86c X cccb7aba1e34480cbf738dbfc8ba6e91--fda6106c215a4f7292399e8bf851f86c fda6106c215a4f7292399e8bf851f86c--0191bfb0a92249a88b04d58c0783de04

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