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_qft(self): N = 4 q = QubitSystem(N) # put q into a non-uniform mixed state hadamard_gate(N) * q tensor_power(phase_shift_gate(pi), N) * q # classical FFT of coefficients, normalized to be unitary like the QFT yhat = fft(q._QubitSystem__coeffs) / sqrt(2 ** N) qft(q) self.assertTrue(numpy.max(numpy.abs(q._QubitSystem__coeffs - yhat)) < EPS)
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_hadamard_gate(self): N = 3 # Matrix with 1's for all positive entries of three-qubit Hadamard gate is_pos = array([[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0], [1, 1, 0, 0, 1, 1, 0, 0], [1, 0, 0, 1, 1, 0, 0, 1], [1, 1, 1, 1, 0, 0, 0, 0], [1, 0, 1, 0, 0, 1, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1], [1, 0, 0, 1, 0, 1, 1, 0]]) H = hadamard_gate(N) ENTRY_VAL = 2.**(-N / 2.) # abs val of each entry H_exp = ENTRY_VAL * (2 * is_pos - 1) # expected H self.assertTrue((abs(H.matrix() - H_exp) < EPS).all())
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