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_ee8fb21163704af79fc02422b8d857dd cluster_f7705633aa654d078ba967cad7827589 cluster_a054b01c9cbe40e6af7386fc2ed58cc6 cluster_ff71c2cf896a4a9c928ff8b03d4bf007 cluster_e8c7aacc6db44d11b2b37f6e93f3209c cluster_f8093b42bd9f4deca9afcff0151336f4 cluster_5e258da09e56477ca4c411048bf43168 3be62304adb24d7ca59e96dfeb6140cf 0 bd75fb6cb95e4f33b946c09ab82586ec HamEvo 3be62304adb24d7ca59e96dfeb6140cf--bd75fb6cb95e4f33b946c09ab82586ec f22acf0d2c0f4ecdac877f1e57534449 1 1fe6b78e048b47c6b65ad13618e0cf99 HamEvo bd75fb6cb95e4f33b946c09ab82586ec--1fe6b78e048b47c6b65ad13618e0cf99 4050f9f64d2542c99c0184095d001bb1 HamEvo 1fe6b78e048b47c6b65ad13618e0cf99--4050f9f64d2542c99c0184095d001bb1 2fb26e7d1d6a4f3d85adbb391bc59628 X 4050f9f64d2542c99c0184095d001bb1--2fb26e7d1d6a4f3d85adbb391bc59628 fbef780e4cf54103897b114fb71c9237 HamEvo 2fb26e7d1d6a4f3d85adbb391bc59628--fbef780e4cf54103897b114fb71c9237 73c92985b61d41798c10f719cf736cf6 HamEvo fbef780e4cf54103897b114fb71c9237--73c92985b61d41798c10f719cf736cf6 bc6e3d9cf38d49cea4a1cb4e91ffbd7a X 73c92985b61d41798c10f719cf736cf6--bc6e3d9cf38d49cea4a1cb4e91ffbd7a 82d8028eea4a4acc87297ac23cd98701 bc6e3d9cf38d49cea4a1cb4e91ffbd7a--82d8028eea4a4acc87297ac23cd98701 1fdcd437f91f45c69a543fd1725c1248 HamEvo 82d8028eea4a4acc87297ac23cd98701--1fdcd437f91f45c69a543fd1725c1248 2df71af8a57647408348e292e530eb26 HamEvo 1fdcd437f91f45c69a543fd1725c1248--2df71af8a57647408348e292e530eb26 b58690f5cb234d608bde07a30b937e42 2df71af8a57647408348e292e530eb26--b58690f5cb234d608bde07a30b937e42 eacd2eab2f69423e9779a898cbc65dec b58690f5cb234d608bde07a30b937e42--eacd2eab2f69423e9779a898cbc65dec e086fb89a11f4ccbbee401fe0666eb2b 58e6c55215664c389a3733a334478c9f t = -3.14 f22acf0d2c0f4ecdac877f1e57534449--58e6c55215664c389a3733a334478c9f 2391bc86a7d94388b4c0ceec1f3f49e7 2 6e5abec2055b48cfafec793663ef808d t = 3.142 58e6c55215664c389a3733a334478c9f--6e5abec2055b48cfafec793663ef808d 15d07820c25a4ce289175d592db04844 t = -3.14 6e5abec2055b48cfafec793663ef808d--15d07820c25a4ce289175d592db04844 bc15019791b1498b954b4d2b6dd467cd 15d07820c25a4ce289175d592db04844--bc15019791b1498b954b4d2b6dd467cd 7e63fbebb2424206857bef6449a59c96 t = 1.571 bc15019791b1498b954b4d2b6dd467cd--7e63fbebb2424206857bef6449a59c96 78d38147e46f45bd8444557a7055fba6 t = 1.571 7e63fbebb2424206857bef6449a59c96--78d38147e46f45bd8444557a7055fba6 bfcef536dda044ea9a2c8fdac93c23f4 78d38147e46f45bd8444557a7055fba6--bfcef536dda044ea9a2c8fdac93c23f4 657b2331235747ae8fbda6216baf3396 X bfcef536dda044ea9a2c8fdac93c23f4--657b2331235747ae8fbda6216baf3396 c3e373f329c0474d9e8a5edd8b2b2d24 t = 1.571 657b2331235747ae8fbda6216baf3396--c3e373f329c0474d9e8a5edd8b2b2d24 0110307b50384af1a0a56e04cfa16b0d t = 1.571 c3e373f329c0474d9e8a5edd8b2b2d24--0110307b50384af1a0a56e04cfa16b0d f954fb8c8c084d20a9e443c5f9305d0d X 0110307b50384af1a0a56e04cfa16b0d--f954fb8c8c084d20a9e443c5f9305d0d f954fb8c8c084d20a9e443c5f9305d0d--e086fb89a11f4ccbbee401fe0666eb2b 8771816bca194eb4a8f86f44d93e4f31 40288fcd11124690b94f39b6752d5e6e 2391bc86a7d94388b4c0ceec1f3f49e7--40288fcd11124690b94f39b6752d5e6e 203d15177500439d93bf178f6ca3737a 40288fcd11124690b94f39b6752d5e6e--203d15177500439d93bf178f6ca3737a eef3de83447a4f7c956bce0fa2619f28 203d15177500439d93bf178f6ca3737a--eef3de83447a4f7c956bce0fa2619f28 b0b0ce4d020c4f10b4e4d174ff060ecc X eef3de83447a4f7c956bce0fa2619f28--b0b0ce4d020c4f10b4e4d174ff060ecc 695c040226224458acad27365ac0a809 b0b0ce4d020c4f10b4e4d174ff060ecc--695c040226224458acad27365ac0a809 fe4da700b1de4712986455cc7c42f814 695c040226224458acad27365ac0a809--fe4da700b1de4712986455cc7c42f814 6fa1297117834054925fbc8850ac0f5a X fe4da700b1de4712986455cc7c42f814--6fa1297117834054925fbc8850ac0f5a 326ece75a3e940ea8c5ff30bb3ce124c X 6fa1297117834054925fbc8850ac0f5a--326ece75a3e940ea8c5ff30bb3ce124c 8abe0b7adf14410ca2aa39c9f80ab589 326ece75a3e940ea8c5ff30bb3ce124c--8abe0b7adf14410ca2aa39c9f80ab589 e7e116a6ed41473082904f8989b2e25c 8abe0b7adf14410ca2aa39c9f80ab589--e7e116a6ed41473082904f8989b2e25c 42329f6fef304838bbd675ddf545baf8 X e7e116a6ed41473082904f8989b2e25c--42329f6fef304838bbd675ddf545baf8 42329f6fef304838bbd675ddf545baf8--8771816bca194eb4a8f86f44d93e4f31

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_20ad55ad6fe34c1ca453f750469edd04 cluster_10a5cafd164e40788addd038d45c22d2 59e7f231fced4e58b922ebfc8bdb91f8 0 4545cee4aaf04f9689e139a62aa6dccc X 59e7f231fced4e58b922ebfc8bdb91f8--4545cee4aaf04f9689e139a62aa6dccc eba796732f8749049698650d8c4ef8fe 1 e913619795114ab3a5e24d9d620f1852 HamEvo 4545cee4aaf04f9689e139a62aa6dccc--e913619795114ab3a5e24d9d620f1852 e9bd81372dca4a33b9c702dad9093f3f X e913619795114ab3a5e24d9d620f1852--e9bd81372dca4a33b9c702dad9093f3f b244ad02444e442cb9fa6010cf7cf800 e9bd81372dca4a33b9c702dad9093f3f--b244ad02444e442cb9fa6010cf7cf800 20c37d5cddd545dea231f255d37d2595 HamEvo b244ad02444e442cb9fa6010cf7cf800--20c37d5cddd545dea231f255d37d2595 814f63c7dfb8476fa4442fbdaa3a6eb5 20c37d5cddd545dea231f255d37d2595--814f63c7dfb8476fa4442fbdaa3a6eb5 2cef06843d58473f9a4f0db1e1840683 814f63c7dfb8476fa4442fbdaa3a6eb5--2cef06843d58473f9a4f0db1e1840683 7abd9660ba984103a72b647d962d83fc 2b59f4d72afb45448f811b50b7cd0861 eba796732f8749049698650d8c4ef8fe--2b59f4d72afb45448f811b50b7cd0861 2545a16fdb3447aa8b98b550b8b33e7f 2 e0d0578e3509474c90072d7022729075 t = -0.50 2b59f4d72afb45448f811b50b7cd0861--e0d0578e3509474c90072d7022729075 84fdacc831434ab88566441ba058de3c e0d0578e3509474c90072d7022729075--84fdacc831434ab88566441ba058de3c 8dc01d44fbfa4f339380c05dfaa9d4a8 X 84fdacc831434ab88566441ba058de3c--8dc01d44fbfa4f339380c05dfaa9d4a8 d008a1d123d149979d90fa3b5cb59255 t = -0.50 8dc01d44fbfa4f339380c05dfaa9d4a8--d008a1d123d149979d90fa3b5cb59255 4715b2975dea415db810d63ff603c057 X d008a1d123d149979d90fa3b5cb59255--4715b2975dea415db810d63ff603c057 4715b2975dea415db810d63ff603c057--7abd9660ba984103a72b647d962d83fc de8f5026c14e4375b5b05be7b89c636e a75004532d424d4d8e944be14847a7b2 X 2545a16fdb3447aa8b98b550b8b33e7f--a75004532d424d4d8e944be14847a7b2 2f6e75da1bd84d029801d4601f1fe384 a75004532d424d4d8e944be14847a7b2--2f6e75da1bd84d029801d4601f1fe384 b3258ec1843b4f0ca88584281bd008af X 2f6e75da1bd84d029801d4601f1fe384--b3258ec1843b4f0ca88584281bd008af 0e90e95b876f430db4f41e7d90c43893 X b3258ec1843b4f0ca88584281bd008af--0e90e95b876f430db4f41e7d90c43893 2bc9261fd407431eba973da3bf9eb795 0e90e95b876f430db4f41e7d90c43893--2bc9261fd407431eba973da3bf9eb795 a820709ebecf442081e224b46391450b X 2bc9261fd407431eba973da3bf9eb795--a820709ebecf442081e224b46391450b a820709ebecf442081e224b46391450b--de8f5026c14e4375b5b05be7b89c636e

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_85c7e2aa710b4520877ddbff797bf437 cluster_fb239d3a7b7f44989a6e35917e3752bd cfad7cb2b4e24018b64a5b87f8beba3c 0 aeb287239f924ee2ad377b181255fa40 X cfad7cb2b4e24018b64a5b87f8beba3c--aeb287239f924ee2ad377b181255fa40 09826fe7fd8a445eb0bfb89c136939a7 1 e50fa9e19c934d6f9172b7d0c7b8d6f6 HamEvo aeb287239f924ee2ad377b181255fa40--e50fa9e19c934d6f9172b7d0c7b8d6f6 163df0e2c1944f89842b9a07745f6482 X e50fa9e19c934d6f9172b7d0c7b8d6f6--163df0e2c1944f89842b9a07745f6482 5abf1114ffb4414786bff5cb374722f5 163df0e2c1944f89842b9a07745f6482--5abf1114ffb4414786bff5cb374722f5 721e0458ebd14a70a318b1791d474de5 HamEvo 5abf1114ffb4414786bff5cb374722f5--721e0458ebd14a70a318b1791d474de5 ff566da8412e4453af56c2247a3eff3e 721e0458ebd14a70a318b1791d474de5--ff566da8412e4453af56c2247a3eff3e e7163e26cd7d4550a2b4152f91272f62 ff566da8412e4453af56c2247a3eff3e--e7163e26cd7d4550a2b4152f91272f62 2d69fa29d23d4356bdf10191eb57dbe0 d0116b4055a246a68c7b134b57a03907 09826fe7fd8a445eb0bfb89c136939a7--d0116b4055a246a68c7b134b57a03907 cb7397f8d648420196bccbfac4ec65ec 2 98858f3745b2436d8f269ae7d27196f7 t = -500. d0116b4055a246a68c7b134b57a03907--98858f3745b2436d8f269ae7d27196f7 af8010337098413f9d9df8c2452c29a1 98858f3745b2436d8f269ae7d27196f7--af8010337098413f9d9df8c2452c29a1 8f2b5264eb1e491bafd4d6657027ddb9 X af8010337098413f9d9df8c2452c29a1--8f2b5264eb1e491bafd4d6657027ddb9 ff99791aa83b4b5c8624a78cc63b33a2 t = -500. 8f2b5264eb1e491bafd4d6657027ddb9--ff99791aa83b4b5c8624a78cc63b33a2 2af59a7caa7140018d346cddc2600090 X ff99791aa83b4b5c8624a78cc63b33a2--2af59a7caa7140018d346cddc2600090 2af59a7caa7140018d346cddc2600090--2d69fa29d23d4356bdf10191eb57dbe0 312d47724a7e41cf9d47a1e06c295a03 bd13ff677f364f0cace09cbc736a19e8 X cb7397f8d648420196bccbfac4ec65ec--bd13ff677f364f0cace09cbc736a19e8 639888c0b60041b9a73656a45e22c4c9 bd13ff677f364f0cace09cbc736a19e8--639888c0b60041b9a73656a45e22c4c9 71634379bfa2488582a414bec913ea29 X 639888c0b60041b9a73656a45e22c4c9--71634379bfa2488582a414bec913ea29 2b93d0eee15c4e6998e672f766d80d71 X 71634379bfa2488582a414bec913ea29--2b93d0eee15c4e6998e672f766d80d71 d36a0ab33a0c4731970bb8cdc33291c0 2b93d0eee15c4e6998e672f766d80d71--d36a0ab33a0c4731970bb8cdc33291c0 64b3235a40a44398b8451aef5e7c4ba7 X d36a0ab33a0c4731970bb8cdc33291c0--64b3235a40a44398b8451aef5e7c4ba7 64b3235a40a44398b8451aef5e7c4ba7--312d47724a7e41cf9d47a1e06c295a03

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