--- title: "Quantum Fourier Trafo" author: "Carsten Urbach" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Quantum Fourier Trafo} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r echo=FALSE} library(knitr) library(qsimulatR) knitr::opts_chunk$set(fig.align='center', comment='') ``` # Three qubit QFT Let's take a normalised vector with eight components and Fourier transform it ```{r} N <- 3 v <- seq(1:2^N) v <- v/sqrt(sum(v^2)) w <- fft(v, inverse=TRUE)/sqrt(length(v)) ``` We have to use the \textit{inverse} Fast Fourier Trafo (FFT) here because `R` uses the convention where the phase is $\exp\left(-2\pi i jk/n\right)$ and the quantum Fourier Trafo uses the convention $\exp\left(2\pi i jk/n\right)$. The same using the quantum Fourier Trafo (QFT). Note that we have to start with the most significant bit, which in this case is qubit 3. ```{r} x <- qstate(N, coefs=as.complex(v)) x <- H(3) * x x <- cqgate(bits=c(2, 3), gate=S(3)) * x x <- cqgate(bits=c(1, 3), gate=Tgate(3)) * x x <- H(2) * x x <- cqgate(bits=c(1, 2), gate=S(2)) * x x <- H(1) * x x <- SWAP(c(1,3)) * x ``` The corresponding circuit looks as follows ```{r} plot(x) ``` Now the coefficients of the state `x` should be the Fourier transform of the coefficients of `y`. The QFT is unitary ```{r} sum(x@coefs*Conj(x@coefs)) ``` and the coefficients match the one from the classical FFT ```{r} sqrt(sum((w - x@coefs)*Conj(w - x@coefs))) ``` # The inverse Since the Hadamard gate is its own inverse, we need the hermitian conjugates for `T` and `S` ```{r} Tdagger <- function(bit) { return(methods::new("sqgate", bit=as.integer(bit), M=array(as.complex(c(1., 0, 0, exp(-1i*pi/4))), dim=c(2,2)), type="Tdag")) } Sdagger <- function(bit) { return(methods::new("sqgate", bit=as.integer(bit), M=array(as.complex(c(1,0,0,-1i)), dim=c(2,2)), type="Sdag")) } ``` ## Inverting the circuit With these we can write the inverse QFT as follows, again for three qubits ```{r} z <- qstate(N, coefs=x@coefs) z <- SWAP(c(1,3)) * z z <- H(1) * z z <- cqgate(bits=c(1, 2), gate=Sdagger(2)) * z z <- H(2) * z z <- cqgate(bits=c(1, 3), gate=Tdagger(2)) * z z <- cqgate(bits=c(2, 3), gate=Sdagger(2)) * z z <- H(3) * z ``` ```{r} plot(z) ``` The coefficients can be compared with the original vector we started from ```{r} sqrt(sum((v - z@coefs)*Conj(v - z@coefs))) ``` ## Inverting the phase Instead of inverting the circuit we can of course apply the usual inverse Fourier trafo, i.e. utilise the same circuit as for the original QFT with all phases reversed. ```{r} y <- qstate(N, coefs=x@coefs) y <- H(3) * y y <- cqgate(bits=c(2, 3), gate=Sdagger(3)) * y y <- cqgate(bits=c(1, 3), gate=Tdagger(3)) * y y <- H(2) * y y <- cqgate(bits=c(1, 2), gate=Sdagger(2)) * y y <- H(1) * y y <- SWAP(c(1,3)) * y plot(y) ``` Again we get the vector `v` back we started with. ```{r} sqrt(sum((v - y@coefs)*Conj(v - y@coefs))) ``` ## The general case Let define a function performing a quanturm Fourier trafo for general number of qubits. For this we need a gate representing \[ R_k = \begin{pmatrix} 1 & 0 \\ 0 & \exp(2\pi \mathrm{i}/2^k) \\ \end{pmatrix} \] Such a general gate is easily implemented in `qsimulatR` as follows ```{r} Ri <- function(bit, i, sign=+1) { type <- paste0("R", i) if(sign < 0) { type <- paste0("R", i, "dag") } return(methods::new("sqgate", bit=as.integer(bit), M=array(as.complex(c(1,0,0,exp(sign*2*pi*1i/2^i))), dim=c(2,2)), type=type)) } ``` With this gate we can implement the quantum Fourier trafo function (the following function is almost identical to the `qft` function included in `qsimulatR`, see `?qft` for details) ```{r, eval=FALSE} qft <- function(x, inverse=FALSE) { n <- x@nbits y <- x sign <- +1 if(inverse) sign <- -1 for(bit in c(n:1)) { y <- H(bit) * y if(bit > 1) { for(i in c((bit-1):1)) { y <- cqgate(bits=c(i, bit), gate=Ri(bit, bit-(i-1), sign=sign)) * y } } } ## reverse order for(k in c(1:floor(n/2))) { y <- SWAP(c(k, n-(k-1))) * y } return(invisible(y)) } ``` And we can plot and check the result again ```{r} y <- qstate(N, coefs=x@coefs) y <- qft(y, inverse=TRUE) plot(y) sqrt(sum((v - y@coefs)*Conj(v - y@coefs))) ```