# QRNG - a basic form of quantum random number genrator
from projectq.ops import H, Measure
from projectq import MainEngine
# create a main compiler engine
eng = MainEngine()
# allocate one qubit
q1 = eng.allocate_qubit()
# put it in superposition
H | q1
# measure
Measure | q1
eng.flush()
# print the result:
print("Measured: {}".format(int(q1)))
Measured: 0
import projectq.setups.default
from projectq.ops import H, X, Z, Rz, CNOT, Measure
from projectq import MainEngine
from projectq.meta import Dagger, Control
def create_bell_pair(eng):
b1 = eng.allocate_qubit()
b2 = eng.allocate_qubit()
H | b1
CNOT | (b1, b2)
return b1, b2
def run_teleport(eng, state_creation_function, verbose=False):
# make a Bell-pair
b1, b2 = create_bell_pair(eng)
# Alice creates a nice state to send
psi = eng.allocate_qubit()
if verbose:
print("Alice is creating her state from scratch, i.e., |0>.")
state_creation_function(eng, psi)
# entangle it with Alice's b1
CNOT | (psi, b1)
if verbose:
print("Alice entangled her qubit with her share of the Bell-pair.")
# measure two values (once in Hadamard basis) and send the bits to Bob
H | psi
Measure | (psi, b1)
msg_to_bob = [int(psi), int(b1)]
if verbose:
print("Alice is sending the message {} to Bob.".format(msg_to_bob))
# Bob may have to apply up to two operation depending on the message sent
# by Alice:
with Control(eng, b1):
X | b2
with Control(eng, psi):
Z | b2
# try to uncompute the psi state
if verbose:
print("Bob is trying to uncompute the state.")
with Dagger(eng):
state_creation_function(eng, b2)
# check whether the uncompute was successful. The simulator only allows to
# delete qubits which are in a computational basis state.
del b2
eng.flush()
if verbose:
print("Bob successfully arrived at |0>")
if __name__ == "__main__":
# create a main compiler engine with a simulator backend:
eng = MainEngine()
# define our state-creation routine, which transforms a |0> to the state
# we would like to send. Bob can then try to uncompute it and, if he
# arrives back at |0>, we know that the teleportation worked.
def create_state(eng, qb):
H | qb
Rz(1.21) | qb
# run the teleport and then, let Bob try to uncompute his qubit:
run_teleport(eng, create_state, verbose=True)
Alice is creating her state from scratch, i.e., |0>. Alice entangled her qubit with her share of the Bell-pair. Alice is sending the message [1, 1] to Bob. Bob is trying to uncompute the state. Bob successfully arrived at |0>
As a third example, consider Shor’s algorithm for factoring, which for a given (large) number N determines the two prime factor $p_1$ and $p_2$, such that $p1⋅p2=N$ in polynomial time!
This is a superpolynomial speed-up over the best known classical algorithm (which is the number field sieve) and enables the breaking of modern encryption schemes such as RSA on a future quantum computer.
A tiny bit of number theory
There is a small amount of number theory involved, which reduces the problem of factoring to period-finding of the function $$f(x)=a^xmodN$$
for some a (relative prime to N, otherwise we get a factor right away anyway by calling $gcd(a,N))$. The period r for a function f(x) is the number for which $f(x)=f(x+r)∀x$ holds. In this case, this means that ax=ax+r(modN)∀x . Therefore, ar=1+qN for some integer q and hence, ar−1=(ar/2−1)(ar/2+1)=qN . This suggests that using the gcd on N and ar/2±1 we may find a factor of N!
Factoring on a quantum computer: An example At the heart of Shor’s algorithm lies modular exponentiation of a classically known constant (denoted by a in the code) by a quantum superposition of numbers x , i.e.,
$$|x⟩|0⟩↦|x⟩|axmodN⟩$$Using N=15 and a=2 , and applying this operation to the uniform superposition over all x leads to the superposition (modulo renormalization)
$$|0⟩|1⟩+|1⟩|2⟩+|2⟩|4⟩+|3⟩|8⟩+|4⟩|1⟩+|5⟩|2⟩+|6⟩|4⟩+⋯$$In Shor’s algorithm, the second register will not be touched again before the end of the quantum program, which means it might as well be measured now. Let’s assume we measure 2; this collapses the state above to
|1⟩|2⟩+|5⟩|2⟩+|9⟩|2⟩+⋯ The period of a modulo N can now be read off. On a quantum computer, this information can be accessed by applying an inverse quantum Fourier transform to the x-register, followed by a measurement of x.
# Running Shor.py file here
! python shor.py 15