To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit a0344aed authored by Valerio's avatar Valerio
Browse files

partial solution lecture 7

parent 3aa42443
%% Cell type:markdown id: tags:
# Exercise Lecture 7
%% Cell type:code id: tags:
``` python
import numpy as np
import random
import copy
```
%% Cell type:code id: tags:
``` python
class QSimulator:
def binrep(self, var):
return ("{0:0" + str(self.n_) + "b}").format(var)
def __init__(self, n, verbose=False):
"""
Initialise quantum gate circuit simulator of n qubits, which can handle
up to 2^n input states.
"""
self.n_ = n
self.max_state = (1 << n) - 1
self.verbose = verbose
def CNOT(self, iwf, cqid, qid):
"""
Apply a NOT gate controlled by qubit cqid to the qubit qid of the
input state vector.
"""
owf = copy.deepcopy(iwf)
for st in range(self.max_state + 1):
if np.absolute(iwf[st]) > 0.: # skip unused states
if st & (1 << cqid): # control qubit is set
flipst = st ^ (1 << qid) # state with flipped qid
owf[flipst] = iwf[st]
owf[st] = iwf[flipst]
if self.verbose:
print("Wave function after CNOT gate:\n", owf, "\n")
return owf
def H(self, iwf, qid):
"""
Apply Hadamard gate on qubit qid of the input state vector iwf.
"""
owf = copy.deepcopy(iwf)
for st in range(self.max_state + 1):
if st & (1 << qid): # qubit contributes to state
flipst = st ^ (1 << qid) # state with flipped qid
if np.absolute(iwf[st]) == 0 and np.absolute(iwf[flipst]) == 0:
continue
owf[flipst] = (iwf[flipst] + iwf[st]) / np.sqrt(2)
owf[st] = (iwf[flipst] - iwf[st]) / np.sqrt(2)
if self.verbose:
print("Wave function after H gate:\n", owf, "\n")
return owf
def X(self, iwf, qid):
"""
Apply Pauli-X gate on qubit qid of the input state vector iwf.
"""
owf = copy.deepcopy(iwf)
for st in range(self.max_state + 1):
flipped = st ^ (1 << qid)
owf[st] = iwf[flipped]
owf[flipped] = iwf[st]
return owf
def Z(self, iwf, qid):
"""
Apply Pauli-Z gate on qubit qid of the input state vector iwf.
"""
owf = copy.deepcopy(iwf)
for st in range(self.max_state + 1):
if np.absolute(iwf[st]) > 0.0:
if st & (1 << qid):
owf[st] *= -1
return owf
def U(self, iwf, cqid, qid, theta):
"""
Apply controlled time evolution operator U to qid.
"""
owf = copy.deepcopy(iwf)
for st in range(self.max_state + 1):
if st & (1 << cqid):
flipst = st ^ (1 << qid)
owf[st] += 1.j * np.sin(theta) * iwf[st]
owf[flipst] += (np.cos(theta) - 1) * iwf[st]
if self.verbose:
print("Wave function after CU gate:\n", owf, "\n")
return owf
def tomography(self, wf, qid):
"""
Return probability of qubit qid of interest and accumulated
probabilities of the other qubits.
"""
alpha = 0
beta = 0
for st in range(self.max_state + 1):
if st & (1 << qid):
beta += (np.conj(wf[st]) * wf[st]).real
else:
alpha += (np.conj(wf[st]) * wf[st]).real
return (alpha, beta)
def measureQubit(self, iwf, qid):
"""
Measure qubit qid.
"""
probs_pair = self.tomography(iwf, qid)
rnd_num = random.uniform(0., 1.)
m = (rnd_num < probs_pair[1])
if self.verbose:
print("The probability to measure |0>: ", probs_pair[0],
", for |1>: ", probs_pair[1], "\n",
"Random number:", rnd_num,
", we measured 1: ", m, "\n")
for st in range(self.max_state + 1):
if np.abs(iwf[st]) != 0.0:
if st & (1 << qid):
if m:
iwf[st] /= np.sqrt(probs_pair[1])
else:
iwf[st] = 0
else:
if m:
iwf[st] = 0
else:
iwf[st] /= np.sqrt(probs_pair[0])
if self.verbose:
print("wavefunction after measurement:\n", iwf, "\n")
return (iwf, m)
```
%% Cell type:markdown id: tags:
## Sanity Check
%% Cell type:code id: tags:
``` python
def check_hadamard():
qsim = QSimulator(2)
iwf = np.zeros(qsim.max_state + 1, dtype=np.complex)
iwf[int('00', 2)] = 1. / np.sqrt(2)
iwf[int('10', 2)] = 1. / np.sqrt(2)
iwf = qsim.H(iwf, 0)
assert(np.allclose(iwf, 0.5 * np.ones(qsim.max_state + 1, dtype=np.complex)))
check_hadamard()
```
%% Cell type:markdown id: tags:
## Phase Estimation
%% Cell type:code id: tags:
``` python
def phase_estimate(alpha, beta, theta, verbose=False):
qsim = QSimulator(2, verbose)
iwf = np.zeros(qsim.max_state + 1, dtype=np.complex)
iwf[int('00', 2)] = alpha # qubit 1 real part
iwf[int('10', 2)] = beta # qubit 1 imag part
if qsim.verbose:
print("Initial wave function:", iwf, "\n")
iwf = qsim.H(iwf, 0)
iwf = qsim.U(iwf, 0, 1, theta)
iwf = qsim.H(iwf, 0)
# p(|0>) = 1/2 * (1 + cos\phi)
return np.arccos((2 * (qsim.tomography(iwf, 0)[0]) - 1))
alpha = 1. / np.sqrt(2)
beta = 1. / np.sqrt(2)
theta = np.pi / 5
theta2 = phase_estimate(alpha, beta, theta)
print("Phase estimation\ninput: {:.5f} -> output: {:.5f}"
.format(theta, theta2))
```
%% Cell type:markdown id: tags:
## Quantum Teleportation
%% Cell type:code id: tags:
``` python
def teleport(alpha, beta, verbose=False):
qsim = QSimulator(3, verbose)
iwf = np.zeros(qsim.max_state + 1, dtype=np.complex)
iwf[int('000', 2)] = alpha # qubit 0 real part
iwf[int('001', 2)] = beta # qubit 0 imag part
if qsim.verbose:
print("Initial wave function:", iwf, "\n")
# Generate Bell state:
iwf = qsim.H(iwf, 1)
iwf = qsim.CNOT(iwf, 1, 2)
# Bell basis measurement:
iwf = qsim.CNOT(iwf, 0, 1)
iwf = qsim.H(iwf, 0)
m0 = qsim.measureQubit(iwf, 0)
m1 = qsim.measureQubit(iwf, 1)
# Apply knowledge:
if m1[1]:
iwf = qsim.X(iwf, 2)
if m0[1]:
iwf = qsim.Z(iwf, 2)
prob_pair = qsim.tomography(iwf, 2)
return np.sqrt(prob_pair[0]), np.sqrt(prob_pair[1])
alpha = random.uniform(0, 1)
beta = np.sqrt(1 - alpha**2) # ensure |a|^2 + |b|^2 == 1
print("\nTeleportation")
print("State of Alices's qubit is {:.5f}*|0> + {:.5f}*|1>"
.format(alpha, beta))
alpha2, beta2 = teleport(alpha, beta)
print("State of Bob's qubit is {:.5f}*|0> + {:.5f}*|1>"
.format(alpha2, beta2))
```
%% Cell type:code id: tags:
``` python
```
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment