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

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

## Rotation Matrix

We use a rotation matrix
\[
U\ =\ \begin{pmatrix}
c & s \\
-s & c \\
\end{pmatrix}
\]
with $c=\cos(\alpha)$, $s=\sin(\alpha)$ and a real-valued angle
$\alpha$ as an example. $U$ has eigenvalues
\[
\lambda_\pm\ =\ c\pm \mathrm{i} s\ =\ e^{\pm i \alpha}\,.
\]
Thus, $\phi=\alpha/(2\pi)$. 
The corresponding eigenvectors are of the form
\[
u_\pm\ =\
\begin{pmatrix}
1 \\
\pm\mathrm{i}\\
\end{pmatrix}\,.
\]

## Phase Estimation

We use

```{r}
t=6
```

in the second register which allows us with probability $1-\epsilon$ to get the 
correct phase up to $t-\left\lceil \log\left(2+\frac{1}{2\epsilon}\right)\right\rceil$
digits. Let us choose

```{r}
epsilon <- 1/4
## note the log in base-2
digits <- t-ceiling(log(2+1/(2*epsilon))/log(2)) 
digits
```

and therefore expect an error of less than

```{r}
2^(-digits)
```

We start with qubit 1 in state $u_+$

```{r}
x <- S(1) * (H(1) * qstate(t+1, basis=""))
```

and we define the gate corresponding to $U$

```{r}
alpha <- pi*3/7
s <- sin(alpha)
c <- cos(alpha)
## note that R fills the matrix columns first
M <- array(as.complex(c(c, -s, s, c)), dim=c(2,2)) 
Uf <- sqgate(bit=1, M=M, type=paste0("Uf"))
```

Now we apply the Hadamard gate to qubits 2,\dots,t+1

```{r}
for(i in c(2:(t+1))) {
  x <- H(i) * x
}
```

and the controlled $U_f$

```{r}
for(i in c(2:(t+1))) {
  x <- cqgate(bits=c(i, 1),
              gate=sqgate(bit=1,
                          M=M, type=paste0("Uf", 2^(i-2)))) * x
  M <- M %*% M
}
plot(x)
```

Next we apply the inverse Fourier transform

```{r, fig.width=9, fig.height=4}
x <- qft(x, inverse=TRUE, bits=c(2:(t+1)))
plot(x)
```

$x$ is now the state
$|\tilde\varphi\rangle|u\rangle$. $|\tilde\varphi\rangle$ is not necessarily
a pure state. The next step is a projective measurement of
$|\tilde\varphi\rangle$

```{r}
xtmp <- measure(x)
cbits <- genStateNumber(which(xtmp$value==1)-1, t+1)
phi <- sum(cbits[1:t]/2^(1:t))

cbits[1:t]
phi
```

Note that we can measure the complete state, because $|u\rangle$ is not entangled to the rest.
We find that usually

```{r}
phi-alpha/(2*pi)
```

is indeed smaller than the maximal deviation $2^{-\mathrm{digits}}=$
`r 2^(-digits)` we expect. The distribution of probabilities over the
states in $|\tilde\varphi\rangle$ is given as follows (factor 2 from
dropping $|u\rangle$)

```{r}
plot(2*abs(x@coefs[seq(1,128,2)])^2, type="l",
     ylab="p", xlab="state index")
```

## Starting from a random state

The algorithm also works in case the specific eigenvector cannot be
prepared. Starting with a random initial state $|\psi\rangle = \sum_u
c_u |u\rangle$, we may apply the very same algorithm and we will find
the approximation to the phase $\varphi_u$ with probability
$|c_u|^2(1-\epsilon)$. 

We prepare the second register in the state
\[
\begin{pmatrix}
1\\
1\\
\end{pmatrix}\ =\
(1-i) u_+ + (1+i) u_-\,.
\]

```{r}
x <- (H(1) * qstate(t+1, basis=""))
```

This implies that we will find both $\varphi_u$ with equal probability.

```{r}
for(i in c(2:(t+1))) {
  x <- H(i) * x
}
M <- array(as.complex(c(c, -s, s, c)), dim=c(2,2)) 
for(i in c(2:(t+1))) {
  x <- cqgate(bits=c(i, 1),
              gate=sqgate(bit=1,
                          M=M, type=paste0("Uf", 2^(i-2)))) * x
  M <- M %*% M
}
x <- qft(x, inverse=TRUE, bits=c(2:(t+1)))

measurephi <- function(x, t) {
  xtmp <- measure(x)
  cbits <- genStateNumber(which(xtmp$value==1)-1, t+1)
  phi <- sum(cbits[1:t]/2^(1:t))
  return(invisible(phi))
}
phi <- measurephi(x, t=t)
2*pi*phi
phi-c(+alpha, 2*pi-alpha)/2/pi
```

We can draw the probability distribution again and observe the two
peaks corresponding to the two eigenvalues

```{r}
plot(abs(x@coefs)^2, type="l",
     ylab="p", xlab="state index")
```

Let's measure `r N=1000` `r N` times, which is easily possible in our simulator

```{r}
phi <- c()
for(i in c(1:N)) {
  phi[i] <- measurephi(x, t)
}
hist(phi, breaks=2^t, xlim=c(0,1))
abline(v=c(alpha/2/pi, 1-alpha/2/pi), lwd=2, col="red")
```

The red vertical lines indicate the _true_ values.
