---
title: "Grover's Algorithm"
author: "Carsten Urbach"
output:
  rmarkdown::html_vignette
    
vignette: >
  %\VignetteIndexEntry{Grover's Algorithm}
  %\VignetteEngine{knitr::rmarkdown}
  \usepackage[utf8]{inputenc}
---

```{r, echo=FALSE}
library(knitr)
library(qsimulatR)
knitr::opts_chunk$set(fig.align='center',
                      comment='')
```

# The Algorithm

Grover's quantum search algorithm is defined via the two following
unitary operations
\[
U\ =\ 1-2|x_s\rangle\langle x_s|\,,\quad V\ =\ 1-2|\psi\rangle\langle\psi|\,.
\]
Here
\[
|\psi\rangle\ =\ \frac{1}{\sqrt{N}}\sum_x |x\rangle\,,
\]
with states $|x\rangle$ in the computational basis and $N=2^n$ with
$n$ the number of qubits. $x_s$ is the index of the element sougth
for. 

The unitary operator $U$ is implemented via an oracle function
$f$ performing the following action
\[
|x\rangle|q\rangle\ \to\ |x\rangle|q\oplus f(x)\rangle
\]
with
\[
f(x)\ =\ 
\begin{cases}
1 & x=x_s\,,\\
0 & \mathrm{ortherwise}\,.\\
\end{cases}
\]
Thus, the qubit $q$ is flipped, if $f(x)=1$.

The quantum circuit for $U$ looks as follows

```{r, echo=FALSE}
x <- qstate(2)
x <- cqgate(c(1,2), sqgate(bit=2, M=array(as.complex(c(1, 0, 0, 1)), dim=c(2,2)), type="Oracle")) * x
x <- Z(2)*x
x <- cqgate(c(1,2), sqgate(bit=2, M=array(as.complex(c(1, 0, 0, 1)), dim=c(2,2)), type="Oracle")) * x
plot(x)
```

For $V$ it looks like

```{r, echo=FALSE}
x <- qstate(2)
x <- X(1) * (H(1) * x)
x <- CNOT(c(1,2)) * x
x <- Z(2) * x
x <- H(1) * (X(1) * (CNOT(c(1,2)) * x))
plot(x)
```



# Example case $N=4$

The case $n=2$ and $N=2^2=4$ can be implemented as follows: assume
$x_s=2$, thus we need a function $f(x) = 1$ for $x=2$ and $f(x) = 0$
otherwise. This is achieved as follows:

```{r}
## oracle for n=2 and x_s=2
oracle <- function(x) {
  x <- X(1) * (CCNOT(c(1,2,3)) *(X(1) * x))
  return(x)
}
```

The following test should return `1` only for $x=x_s$

```{r}
## case |00>=0
x <- oracle(qstate(3))
measure(x, 3)$value
## case |01>=1
x <- oracle(X(1)*qstate(3))
measure(x, 3)$value
## case |10>=2
x <- oracle(X(2)*qstate(3))
measure(x, 3)$value
## case |11>=3
x <- oracle(X(2)*(X(1)*qstate(3)))
measure(x, 3)$value
```

The unitaries $U$ and $V$ for the $n=2$ can then be implemented as follows

```{r}
U <- function(x) {
  x <- oracle(x)
  x <- Z(3) * x
  x <- oracle(x)
  return(x)
}
V <- function(x) {
  for(i in c(1:2)) {
    x <- H(i) * x
  }
  x <- X(1) * (X(2) * x)
  x <- CCNOT(c(1,2,3)) * x
  x <- Z(3) * x
  x <- CCNOT(c(1,2,3)) * x
  x <- X(1) * (X(2) * x)
  for(i in c(1:2)) {
    x <- H(i) * x
  }
  return(x)
}
```

One application of $V\cdot U$ looks as follows in the quantum circuit picture

```{r, echo=FALSE}
x <- qstate(3)
x <- U(x)
x <- V(x)
plot(x)
```

$N=4$ is the special case where the algorithms returns the correct
result with certainty after only a single application of $V\cdot
U$. This is demonstrated in the following example

```{r}
## prepare psi
psi <- H(1) * ( H(2) * qstate(3))
## apply VU
x <- U(psi)
x <- V(x)
x
```

As expected, the first two qubits (the two rightmost ones) of `x`
are equal to $x_s$ in binary representation. (The phase is not observable.)
