QRAM definition¶
A QRAM is a unitary operator that operates as follow :
$$\displaystyle \large \textstyle\sum\limits_{i=0}^{2^n - 1}\displaystyle \alpha_i \lvert i \rangle \lvert 0^{\bigotimes k} \rangle \xrightarrow{\text{QRAM}} \large \textstyle\sum\limits_{i=0}^{2^n - 1}\displaystyle \frac{\alpha_i}{\lvert\lvert A_i\rvert\rvert} \lvert i \rangle \textstyle\sum\limits_{j=0}^{2^k - 1} A_{ij}\displaystyle | j \rangle $$
The first register is called the addresss register and the second is the data register. It is important to note that the data register must be set to 0. $A$ represent the matrix given in parameter of size $\normalsize 2^n \times 2^k$, with $n$ being the number of address qbits and $k$ the number of data qbits.
For instance, if we have the state vector $ \displaystyle \lvert \psi \rangle = \frac{1}{\sqrt{2}} (\lvert 00 \rangle + \lvert 10 \rangle)$, by applying a QRAM with the leftmost register being the address register and the following matrix $ A = \begin{pmatrix} \displaystyle\frac{1}{\sqrt{8}} & \displaystyle\frac{\displaystyle\sqrt{7}}{\sqrt{8}} \\ \displaystyle\frac{\sqrt{1}}{\sqrt{2}} & \displaystyle\frac{\sqrt{1}}{\sqrt{2}} \end{pmatrix} $, we obtain the state vector $ \displaystyle \lvert \psi \rangle = \frac{1}{4} \lvert 00 \rangle + \frac{\sqrt{7}}{4}\lvert 01 \rangle + \frac{1}{2} (\lvert 10 \rangle + \lvert 11 \rangle) $.
Creating and using a QRAM in pyAQASM¶
The QRAM gate is located in the oracles module.
The numbers $n$ of address qbits and $k$ of data qbits will be deduced by the size of the matrix given in parameter. The address register is considered to be the $n$ first qbits of arity of the gate, therefore, the next $k$ qbits of arity are part of the data register.
Just below, we apply our previous example in pyAQASM.
from qat.qpus import LinAlg
from qat.linalg.oracles import QRAM
from qat.lang.AQASM import *
from math import sqrt
import numpy as np
prog = Program()
qbits = prog.qalloc(2)
# Creating the matrix
A = np.array([[1/sqrt(8), sqrt(7)/sqrt(8)],
[1/sqrt(2), 1/sqrt(2)]])
# Hadamard gate on the address register to prepare the state vector
prog.apply(H, qbits[1])
# Applying the QRAM
prog.apply(QRAM(A), qbits[1], qbits[0])
# Print the results
circuit = prog.to_circ()
for result in LinAlg().submit(circuit.to_job()):
print("State %s has amplitude %s\n" % (result.state.lsb_int, result.amplitude))
State 0 has amplitude (0.24999999999999994+0j) State 2 has amplitude (0.5+0j) State 1 has amplitude (0.6614378277661476+0j) State 3 has amplitude (0.5+0j)