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_6839549c6f884777bae65227a7a636e0 cluster_db6baa9ff4164ca4baca37e6b4658a37 cluster_fc73cac0ca014f1d9a6aa091ea25eef8 cluster_2960c63efbdd4e73aec0cff230cecadb cluster_34154b0ac4c54b118afd722affdc548e cluster_c76f70f41b9d45be836318ae6c54f7e5 cluster_98483d1a40d24d6bb5f653bf7c906470 4f5572073d1941248b7adac4bb2d4073 0 517f455723fb473a8a1b618992b33fe0 HamEvo 4f5572073d1941248b7adac4bb2d4073--517f455723fb473a8a1b618992b33fe0 bc441ca822cf4c4590c40cfe5effdaf4 1 e43b6a4830c140ca8387ea45d4ccc094 HamEvo 517f455723fb473a8a1b618992b33fe0--e43b6a4830c140ca8387ea45d4ccc094 445c03d7f2624f72baa513592b108b73 HamEvo e43b6a4830c140ca8387ea45d4ccc094--445c03d7f2624f72baa513592b108b73 f6dedb824a7142c3a69737fac972a2f7 X 445c03d7f2624f72baa513592b108b73--f6dedb824a7142c3a69737fac972a2f7 56471f3376dd4a62bf632767ce2abd7c HamEvo f6dedb824a7142c3a69737fac972a2f7--56471f3376dd4a62bf632767ce2abd7c d9c2ca2556a946afb878b4e8423d0cc7 HamEvo 56471f3376dd4a62bf632767ce2abd7c--d9c2ca2556a946afb878b4e8423d0cc7 a9da39f982c7463c9f21c36a76175a3b X d9c2ca2556a946afb878b4e8423d0cc7--a9da39f982c7463c9f21c36a76175a3b dc82246c827744b0883e85a522885c61 a9da39f982c7463c9f21c36a76175a3b--dc82246c827744b0883e85a522885c61 1343a55f012947e98d0081e7baa602a8 HamEvo dc82246c827744b0883e85a522885c61--1343a55f012947e98d0081e7baa602a8 d11701280e1e413bba0f994dac3820ae HamEvo 1343a55f012947e98d0081e7baa602a8--d11701280e1e413bba0f994dac3820ae 65fd25500be8451087ce1c161b266d0b d11701280e1e413bba0f994dac3820ae--65fd25500be8451087ce1c161b266d0b 86b243f7ada843b6a1f9baf45841fcba 65fd25500be8451087ce1c161b266d0b--86b243f7ada843b6a1f9baf45841fcba b632350f138c4b3b91e956483e2c06c6 9e87847f51bd4e16b9a07ad2a060db9f t = -3.142 bc441ca822cf4c4590c40cfe5effdaf4--9e87847f51bd4e16b9a07ad2a060db9f e3ab1c3290f64464a6146d3cac8642c2 2 c4a5ef8a9fbc4ba1b3b9453d9dad7415 t = 3.142 9e87847f51bd4e16b9a07ad2a060db9f--c4a5ef8a9fbc4ba1b3b9453d9dad7415 d14188d1699c422dbb1ee39b9bd5d76e t = -3.142 c4a5ef8a9fbc4ba1b3b9453d9dad7415--d14188d1699c422dbb1ee39b9bd5d76e 46611899c46b488f9e355876cb99879f d14188d1699c422dbb1ee39b9bd5d76e--46611899c46b488f9e355876cb99879f c4ef0698f5c4474bafe50a0684e1183b t = 1.571 46611899c46b488f9e355876cb99879f--c4ef0698f5c4474bafe50a0684e1183b e2f4179e291a440bbc9931a827ea9245 t = 1.571 c4ef0698f5c4474bafe50a0684e1183b--e2f4179e291a440bbc9931a827ea9245 098cb710ec7d49f0892ffde867fbd84e e2f4179e291a440bbc9931a827ea9245--098cb710ec7d49f0892ffde867fbd84e 6ece77f493c749adbd1fff4c8eef4136 X 098cb710ec7d49f0892ffde867fbd84e--6ece77f493c749adbd1fff4c8eef4136 072c5443ff064a02928a129b45fb647e t = 1.571 6ece77f493c749adbd1fff4c8eef4136--072c5443ff064a02928a129b45fb647e c19e5bee9a904e1bb6bda946832b0b54 t = 1.571 072c5443ff064a02928a129b45fb647e--c19e5bee9a904e1bb6bda946832b0b54 6680fc566bcf4cdfac8a36e55ebd0c5d X c19e5bee9a904e1bb6bda946832b0b54--6680fc566bcf4cdfac8a36e55ebd0c5d 6680fc566bcf4cdfac8a36e55ebd0c5d--b632350f138c4b3b91e956483e2c06c6 0cd32ede015244348b6d390d0f17a93b 3fd2c45aa8b246619754f07d60946189 e3ab1c3290f64464a6146d3cac8642c2--3fd2c45aa8b246619754f07d60946189 81c60501580545a89f5100ef8f915d6b 3fd2c45aa8b246619754f07d60946189--81c60501580545a89f5100ef8f915d6b 8f2afdda03a64d46a4cf08fb6506d804 81c60501580545a89f5100ef8f915d6b--8f2afdda03a64d46a4cf08fb6506d804 ff1012a1b2e4477a96abea5a35d041aa X 8f2afdda03a64d46a4cf08fb6506d804--ff1012a1b2e4477a96abea5a35d041aa 074b2b76569b4e87b98d0d72c1c9610e ff1012a1b2e4477a96abea5a35d041aa--074b2b76569b4e87b98d0d72c1c9610e cc5abd97963b41fb8282eab0943e9cd8 074b2b76569b4e87b98d0d72c1c9610e--cc5abd97963b41fb8282eab0943e9cd8 5b01d7a33a2e4a9d8ef8081b29faab9f X cc5abd97963b41fb8282eab0943e9cd8--5b01d7a33a2e4a9d8ef8081b29faab9f 95049487eae24c96a1b4e18d48c90d23 X 5b01d7a33a2e4a9d8ef8081b29faab9f--95049487eae24c96a1b4e18d48c90d23 3c56a7fc293245a5adeecd31552ed455 95049487eae24c96a1b4e18d48c90d23--3c56a7fc293245a5adeecd31552ed455 dc7f76b3eec844e49211f1c01a176805 3c56a7fc293245a5adeecd31552ed455--dc7f76b3eec844e49211f1c01a176805 2e5de85f538d4a7cb0f6b536880d44f5 X dc7f76b3eec844e49211f1c01a176805--2e5de85f538d4a7cb0f6b536880d44f5 2e5de85f538d4a7cb0f6b536880d44f5--0cd32ede015244348b6d390d0f17a93b

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_5e592853a47545fbbe28df8b3613ffeb cluster_5531fe6882d8441fa5027c94dc91c3aa 0dd4ee3f49834ba8b73190bc7ce15842 0 466214fd0ce149bf8fe34f16fcc7f4b6 X 0dd4ee3f49834ba8b73190bc7ce15842--466214fd0ce149bf8fe34f16fcc7f4b6 60de69bf25f348d19f5ab8d5d00628db 1 cf70bd37393443998e1210e8df645e6c HamEvo 466214fd0ce149bf8fe34f16fcc7f4b6--cf70bd37393443998e1210e8df645e6c 4052147935c8452f9f68b950afb6e7c8 X cf70bd37393443998e1210e8df645e6c--4052147935c8452f9f68b950afb6e7c8 394f340a54354beab22d3f2678267896 4052147935c8452f9f68b950afb6e7c8--394f340a54354beab22d3f2678267896 1554561404a4477c8d11b64392259e33 HamEvo 394f340a54354beab22d3f2678267896--1554561404a4477c8d11b64392259e33 37b5f27d42264050b6b28fdf2ecf0c3a 1554561404a4477c8d11b64392259e33--37b5f27d42264050b6b28fdf2ecf0c3a 8f1f8d6f756a441ebda1e9ea25da2517 37b5f27d42264050b6b28fdf2ecf0c3a--8f1f8d6f756a441ebda1e9ea25da2517 cf65c36cc8c44878b76f716d73906c0b 816c7fa54d5248c3971efc1a30fd2abc 60de69bf25f348d19f5ab8d5d00628db--816c7fa54d5248c3971efc1a30fd2abc 128892d5118a4c5abfc5efcfa574e72e 2 902b13028d3e4465b2ce594d5aedd88c t = -0.500 816c7fa54d5248c3971efc1a30fd2abc--902b13028d3e4465b2ce594d5aedd88c fce0695904cb4c68b762b3e2b13fd834 902b13028d3e4465b2ce594d5aedd88c--fce0695904cb4c68b762b3e2b13fd834 856ba0ddccdd49e1b0506e4e548273bd X fce0695904cb4c68b762b3e2b13fd834--856ba0ddccdd49e1b0506e4e548273bd e1a2d77450ac4c2498f5d428b596d6e9 t = -0.500 856ba0ddccdd49e1b0506e4e548273bd--e1a2d77450ac4c2498f5d428b596d6e9 4f35ed084d0d46ca9086651a3463d33d X e1a2d77450ac4c2498f5d428b596d6e9--4f35ed084d0d46ca9086651a3463d33d 4f35ed084d0d46ca9086651a3463d33d--cf65c36cc8c44878b76f716d73906c0b 143704b3196e4dec8d149a6b52900958 b73f5aa1b01a4ea88ac7585c3999398c X 128892d5118a4c5abfc5efcfa574e72e--b73f5aa1b01a4ea88ac7585c3999398c 598e090b5aa541f782efa07582a5627d b73f5aa1b01a4ea88ac7585c3999398c--598e090b5aa541f782efa07582a5627d 2b820437972f4bd09bfb2e39eddcdcbb X 598e090b5aa541f782efa07582a5627d--2b820437972f4bd09bfb2e39eddcdcbb bacc31459a804196b581e85440b8fd8c X 2b820437972f4bd09bfb2e39eddcdcbb--bacc31459a804196b581e85440b8fd8c 16c40584c1844e1bbb10501b77a5806d bacc31459a804196b581e85440b8fd8c--16c40584c1844e1bbb10501b77a5806d 83b6a9af3922472089ab98f308ade8a5 X 16c40584c1844e1bbb10501b77a5806d--83b6a9af3922472089ab98f308ade8a5 83b6a9af3922472089ab98f308ade8a5--143704b3196e4dec8d149a6b52900958

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_fb7cea927eda4922bf12bffbd3d55c3b cluster_e6263a1f82ea4003aa65863369dd465d 657f4232206440deae4f328a3a07b11b 0 a49935977f6143c4802b0cf60f576bcd X 657f4232206440deae4f328a3a07b11b--a49935977f6143c4802b0cf60f576bcd 4576f1640deb4783a69c888ea0f5a661 1 166a4a8db08f4a0e8a9e4424731eb9d5 HamEvo a49935977f6143c4802b0cf60f576bcd--166a4a8db08f4a0e8a9e4424731eb9d5 32324d4d93be4cb49831cf529d91e40a X 166a4a8db08f4a0e8a9e4424731eb9d5--32324d4d93be4cb49831cf529d91e40a 7f8636eb777944529d90988f283b3b39 32324d4d93be4cb49831cf529d91e40a--7f8636eb777944529d90988f283b3b39 6e5280a6ce88436489dc10a3658a6f08 HamEvo 7f8636eb777944529d90988f283b3b39--6e5280a6ce88436489dc10a3658a6f08 0dccf9f86579430b878b7e316db9ec17 6e5280a6ce88436489dc10a3658a6f08--0dccf9f86579430b878b7e316db9ec17 c52015cc06364e3a8c560b9f67d33f77 0dccf9f86579430b878b7e316db9ec17--c52015cc06364e3a8c560b9f67d33f77 647c42e428344468bc2f3572b2a41110 469e5c7457854005b9010f6a7ea7fde5 4576f1640deb4783a69c888ea0f5a661--469e5c7457854005b9010f6a7ea7fde5 70af0a3449034436bbd210d865bd39d5 2 344c9c8d1ffc4db79a1d16699606cc8f t = -500.000000000000 469e5c7457854005b9010f6a7ea7fde5--344c9c8d1ffc4db79a1d16699606cc8f 1ed8ab9a2a8f4099833feeef8e732063 344c9c8d1ffc4db79a1d16699606cc8f--1ed8ab9a2a8f4099833feeef8e732063 be6dda365e5242d4a0ce0944b80e68a6 X 1ed8ab9a2a8f4099833feeef8e732063--be6dda365e5242d4a0ce0944b80e68a6 3aa4307853714c24827730fbc8d05814 t = -500.000000000000 be6dda365e5242d4a0ce0944b80e68a6--3aa4307853714c24827730fbc8d05814 17dfb88f9c5248a9b865da43503d934d X 3aa4307853714c24827730fbc8d05814--17dfb88f9c5248a9b865da43503d934d 17dfb88f9c5248a9b865da43503d934d--647c42e428344468bc2f3572b2a41110 4e407e21a33a4203ace644a53a471109 1ebf29e1601f455a9c7d338b1d22fb46 X 70af0a3449034436bbd210d865bd39d5--1ebf29e1601f455a9c7d338b1d22fb46 75f0f4b0d2f44ab79833e047fafd7232 1ebf29e1601f455a9c7d338b1d22fb46--75f0f4b0d2f44ab79833e047fafd7232 236bdf729433437fad2bf3dda1732bc3 X 75f0f4b0d2f44ab79833e047fafd7232--236bdf729433437fad2bf3dda1732bc3 1be76d2220bc49ed96081c18f4ba5738 X 236bdf729433437fad2bf3dda1732bc3--1be76d2220bc49ed96081c18f4ba5738 6f632bc2715b4fe5b5b33bedca4e554e 1be76d2220bc49ed96081c18f4ba5738--6f632bc2715b4fe5b5b33bedca4e554e 18c02b38748e40b093e6b1700a9e6668 X 6f632bc2715b4fe5b5b33bedca4e554e--18c02b38748e40b093e6b1700a9e6668 18c02b38748e40b093e6b1700a9e6668--4e407e21a33a4203ace644a53a471109

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