--- title: "Deutsch-Jozsa Algorithm" author: "Carsten Urbach" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Deutsch-Sozsa Algorithm} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r echo=FALSE} library(knitr) library(qsimulatR) ``` # The Deutsch-Jozsa Algorithm This is an example implementation of the Deutsch-Jozsa algorithm for the special case of $2$ qubits. The algorithm allows to distinguish between a constant or balanced function $f$ with a single application of $f$, relying on what is called quantum parallelism. We first prepare a state $|\psi_0\rangle = |x, y\rangle = |0, 1\rangle$ with only 2 qubits as follows ```{r} x <- X(1) * qstate(nbits=2, basis=genComputationalBasis(2, collapse=",")) x ``` Note that we count the qubits from one to number of qubits, and the **least significant bit** (the right most one) is counted **first**. Using the Hadamard gate on both qubits results in a superposition in both qubits ```{r} y <- H(2) * (H(1) * x) y ``` The next step is to apply the uniform transformation $U_f$ to the state $|x\rangle(|0\rangle - |1\rangle)$. The action of $U_f$ was defined as $|x,y\rangle \to |x, y\oplus f(x)\rangle$, where $\oplus$ is addition modulo $2$. The function $f$ is a function $\{0,1\}\to\{0,1\}$. We first consider a so-called balanced function $f(x)$, i.e.\ it is equal to $1$ for exactly half of the possible $x$. In our case with a single qubit $x$ this could be $f(0)=0$ and $f(1) = 1$. $U_f$ is realised in this case by CNOT$(2,1)$, where we consider the second qubit as the control qubit. For $|x, y\oplus f(x)\rangle$, there are four different possibilities * $x=0, y=0$, $U_f(|0,0\rangle) = |0, 0\oplus f(0)\rangle = |0, 0\rangle$ * $x=1, y=0$, $U_f(|1,0\rangle) = |1, 0\oplus f(1)\rangle = |1, 1\rangle$ * $x=0, y=1$, $U_f(|0,1\rangle) = |0, 1\oplus f(0)\rangle = |0, 1\rangle$ * $x=1, y=1$, $U_f(|1,1\rangle) = |1, 1\oplus f(1)\rangle = |1, 0\rangle$ Now, * CNOT$(2,1)|0,0\rangle = |0,0\rangle$ * CNOT$(2,1)|1,0\rangle = |1,1\rangle$ * CNOT$(2,1)|0,1\rangle = |0,1\rangle$ * CNOT$(2,1)|1,1\rangle = |1,0\rangle$ which is what we wanted to archive. Thus, we apply it: ```{r} z <- CNOT(c(2, 1)) * y z ``` Now apply the Hadamard gate again on $x$ (the query register), i.e. the second qubit ```{r} u <- H(2) * z u ``` Now qubit $2$ equals $1$, thus, if we measure, ```{r} value <- measure(u, 2)$value ``` we obtain $`r value`$. We can also plot the corresponding circuit ```{r, fig.align='center'} plot(u, qubitnames=c("|y>", "|x>"), cbitnames="c") ``` On the other hand, a constant function $f(x) = 1$ leads to * $x=0, y=0$, $U_f(|0,0\rangle) = |0, 0\oplus f(0)\rangle = |0, 1\rangle$ * $x=1, y=0$, $U_f(|1,0\rangle) = |1, 0\oplus f(1)\rangle = |1, 1\rangle$ * $x=0, y=1$, $U_f(|0,1\rangle) = |0, 1\oplus f(0)\rangle = |0, 0\rangle$ * $x=1, y=1$, $U_f(|1,1\rangle) = |1, 1\oplus f(1)\rangle = |1, 0\rangle$ which can be realised with a NOT operation on the first qubit * X$(1)|0,0\rangle = |0,1\rangle$ * X$(1)|1,0\rangle = |1,1\rangle$ * X$(1)|0,1\rangle = |0,0\rangle$ * X$(1)|1,1\rangle = |1,0\rangle$ So, the same algorithm again, now with the constant $f$ ```{r} x <- X(1) * qstate(nbits=2, basis=genComputationalBasis(2, collapse=",")) y <- H(2) * (H(1) * x) z <- X(1) * y z u <- H(2) * z u v <- measure(u, 2) v plot(v$psi) value <- v$value ``` and we obtain $`r value`$ for the second qubit. ## Export to Qiskit In principle the code in Qiskit could look somehow like this: ```{r comment=''} filename <- paste0(tempdir(), "/circuit.py") export2qiskit(u, filename=filename) cat(readLines(filename), sep = '\n') ``` But this does not include the measurement and the measurement cannot simply be added as an additional command. If a measurement is to be performed, one has to add corresponding classical bits. To do so export the state including the measurement: ```{r comment=''} export2qiskit(v$psi, filename=filename, import=TRUE) cat(readLines(filename), sep = '\n') ``` Then the results from the Quiskit simulation can be obtained with ``` qc.draw() res = execute(qc, simulator, shots=1) res.result().get_counts(qc) ```