def test_measure(self): # First, test measurement of a system in a pure state STATE = '01010' N = len(STATE) q = QubitSystem(N, int('0b' + STATE, 2)) self.assertEqual(q.measure(), int('0b' + STATE, 2)) self.assertEqual(q.smeasure(), STATE) for i in range(N): self.assertEqual(q.measure(i + 1), int(STATE[i])) # Test probabilistic measurement: repeatedly measure superpositions of # basis states and test that the outcome varies randomly. N = 2 NTRIALS = 100 # number of 1's in the first and second bit, respectively nsuccess1 = 0 nsuccess2 = 0 for i in range(NTRIALS): q = QubitSystem(N) # set the qubits to |00> hadamard_gate(N) * q # equal superposition of four basis states nsuccess1 += q.measure(1) nsuccess2 += q.measure(2) # Test that repeated measurement gives the same result state = q.measure() self.assertEqual(q.measure(), state) self.assertEqual(q.measure(), state) # Test that the number of 1's that appeared in the first and second # qubits is approximately half the total (within approx. 99% confidence # interval) CUTOFF = NTRIALS * 0.15 self.assertTrue(abs(nsuccess1 - NTRIALS / 2.) < CUTOFF) self.assertTrue(abs(nsuccess2 - NTRIALS / 2.) < CUTOFF)
def test_x_gate(self): X = x_gate() self.assertTrue((X.matrix() == array([[0., 1.], [1., 0.]])).all()) # Test that applying the X-gate to a qubit in state |0> converts it to # state |1>, and vice versa q = QubitSystem() X * q self.assertEqual(q.measure(), 1) X * q self.assertEqual(q.measure(), 0)
def test_tensor_product(self): # Test that |1> (x) |0> = |10> q0 = QubitSystem(1, 0) q1 = QubitSystem(1, 1) q1 * q0 self.assertEqual(q1.measure(), 0b10) # Test that |0100> (x) |101> = |0100101> q4 = QubitSystem(4, 0b0100) q5 = QubitSystem(3, 0b101) q4 * q5 self.assertEqual(q4.measure(), 0b0100101)
def grover_invert(f, y, n): """Grover's algorithm for inverting a general function f that maps a sequence of n bits (represented as an int whose binary representation is the bit sequence) to another sequence of bits. Args: f: Function to invert y: Value of the function at which to evaluate the inverse. Returns: The input x such that f(x) = y. If more than one input suffices, it returns one at random. If no input suffices, returns -1. """ if n <= 0: raise ValueError('n must be positive') Hn = hadamard_gate(n) Ui = _function_oracle(f, y, n) Ud = grover_diffusion_operator(n) MAX_ITER = 50 count = 0 x = None # Repeat until a solution is found or the iteration limit is reached while count < MAX_ITER and (x is None or f(x) != y): q = QubitSystem(n) # system of n bits in state |0> # apply Hadamard gate to create uniform superposition of basis states Hn * q for _ in range(_r(2**n)): Ui * q # apply operator that flips the sign of the matching index Ud * q # apply Grover's diffusion operator x = q.measure() count += 1 return x if f(x) == y else -1
def shor_factor(n): """Shor's factorization algorithm. Args: n: Integer >=2 to factor. Returns: If n is composite, a non-trivial factor of n. If n is prime, returns 1. Raises: ValueError if n is <= 1. """ if n <= 1: raise ValueError('n must be at least 2') if is_prime(n): return 1 if n % 2 == 0: return 2 # even numbers > 2 are trivial # Need to check that n is not a power of an integer for algorithm to work root = int_root(n) if root != -1: return root # choose m s.t. n^2 <= 2^m < 2*n^2 # log2(n^2) <= m <= log2(2 * n^2) = 1 + log2(n^2) m = ceil(log(n**2, 2)) ny = ceil(log(n - 1, 2)) # number of qubits in output of function f I = QuantumGate(eye(2**ny)) H = kron(hadamard_gate(m), I) MAX_ITER = 10 niter = 0 while True: a = n - 1 # arbitrary integer coprime to n # Initialize a system of qubits long enough to represent the integers 0 # to 2^m - 1 alongside an integer up to n - 1, then apply Hadamard gate # to the first m qubits to create a uniform superposition. q = QubitSystem(m + ny) H * q # Apply the function f(x) = a^x (mod n) to the system f = lambda x: pow(a, x, n) Uf = function_gate(f, m, ny) Uf * q # Find the period of f via quantum Fourier transform qft(q) r = 1. / q.measure() # period = 1 / frequency niter += 1 if niter >= MAX_ITER or (r % 2 == 0 and (a**(r / 2)) % n != -1): break return gcd(a**(r / 2) + 1, n)
def test_function_gate(self): f = lambda x: x >> 2 m, k = 4, 2 Uf = function_gate(f, m, k) # Initial state - M-bit binary string for 6 plus random K-bit register q = QubitSystem(m + k, 0b011010) # Expected output state: first M bits unchanged, followed by initial # string added to f(x) mod 2 (where x = first M bits) Uf * q self.assertEqual(q.measure(), 0b011011)
def test_controlled_gate(self): # gate that permutes the coefficients on a two-qubit system P = QuantumGate(array([[0., 0., 0., 1.], [1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.]])) q1 = QubitSystem(3, 0b011) q2 = QubitSystem(3, 0b101) q3 = QubitSystem(3, 0b101) # controlled gate permutes the second two bits iff the first bit is one CG = controlled_gate(P) CG * q1 self.assertEqual(q1.measure(), 0b011) CG * q2 self.assertEqual(q2.measure(), 0b110) # test Toffoli gate, a.k.a. controlled-controlled-not gate T = toffoli_gate() T * q1 self.assertEqual(q1.measure(), 0b011) T * q2 self.assertEqual(q2.measure(), 0b111) # Test Fredkin gate, a.k.a. controlled swap gate F = fredkin_gate() F * q1 self.assertEqual(q1.measure(), 0b011) F * q3 self.assertEqual(q3.measure(), 0b110)
def test_act(self): q1 = QubitSystem(2) q2 = QubitSystem(2, 0b10) SWAP = swap_gate() CNOT = cnot_gate() # SWAP * |00> = |00> SWAP * q1 self.assertEqual(q1.measure(), 0b00) # SWAP * |10> = |01>, and vice versa SWAP * q2 self.assertEqual(q2.measure(), 0b01) SWAP * q2 self.assertEqual(q2.measure(), 0b10) # CNOT * |00> = |00> CNOT * q1 self.assertEqual(q1.measure(), 0b00) # CNOT * |10> = |11> and vice versa CNOT * q2 self.assertEqual(q2.measure(), 0b11) CNOT * q2 self.assertEqual(q2.measure(), 0b10) # Test applying a gate to a subset of the qubits in the system q = QubitSystem(4) # state 0000 X = x_gate() X.act(q, 3) self.assertEqual(q.measure(), 0b0010) X.act(q, 4) self.assertEqual(q.measure(), 0b0011) SWAP.act(q, 2) self.assertEqual(q.measure(), 0b0101) SWAP * q self.assertEqual(q.measure(), 0b1001)
def grover_search(match_text, lst): """Grover's quantum algorithm for searching. Args: match_text: Text to find in the list lst. lst: List of strings to search to find a string matching match_text. Returns: The index i of the item such that lst[i] is the same string as match_text. The lines must match exactly; it is not enough for the text to be contained in the line. If two or more lines match, it will only return one of the line numbers. Returns -1 if no matching line is found, i.e. the algorithm fails to find a solution. """ if len(lst) <= 0: raise ValueError('List must be of positive length') n = len(lst) N = int(ceil(log(n, 2))) # number of qubits needed Hn = hadamard_gate(N) Ui = _search_oracle(match_text, lst) Ud = grover_diffusion_operator(N) MAX_ITER = 50 count = 0 index = n # Repeat until a solution is found or the iteration limit is reached while count < MAX_ITER and (index >= n or lst[index] != match_text): q = QubitSystem(N) # system of log2(n) bits in state |0> # apply Hadamard gate to create uniform superposition of basis states Hn * q for _ in range(_r(2**N)): Ui * q # apply operator that flips the sign of the matching index Ud * q # apply Grover's diffusion operator index = q.measure() count += 1 return index if index < n and lst[index] == match_text else -1