Source code for qft

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module is aimed to provide the user means to study the QFT and especially 
how entanglement changes during its execution using the Mermin evaluation.
"""
from sage.all import *

import csv
import time

from mermin_eval import *
from run_circuit import *


[docs]def qft_main(state, verbose=False, file_name=None): r""" Prints in terminal or in file ``file_name`` the Mermin evaluation of each step of the QFT. Example: >>> grover(periodic_state(0,11,4))0,1.99823485241887 1.99933058720672 1.99761683801972 1.84600827724524 1.66149864543535 1.66010335826574 1.66127978203391 2.17163453049907 2.17187381801221 1.54230165695219 1.54129902140376 1.54169705834015 :param vector[int] state: State on which the operator wants the QFT performed of, this is usually a periodic state. :param bool verbose: If *verbose* then extra run information will be displayed in terminal. :param str file_name: File name for the registration of the Mermin evaluation for each step of the algorithm, in csv format. :returns: any -- Result of this function depends on file_name. If a file name is given `qft_main` returns None, otherwise, it returns an array with the evaluation values . """ states = qft_run(state, verbose) return qft_evaluate(states, verbose, file_name)
[docs]def qft_run(state, verbose=False): r""" Runs a simulation of the QFT. Example: >>> qft_run(periodic_state(2,1,3)) [(0, 0, 1/6*sqrt(6), 1/6*sqrt(6), 1/6*sqrt(6), 1/6*sqrt(6), 1/6*sqrt(6), 1/6*sqrt(6)), (1/12*sqrt(6)*sqrt(2), 1/12*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), -1/12*sqrt(6)*sqrt(2), -1/12*sqrt(6)*sqrt(2), 0, 0), (1/12*sqrt(6)*sqrt(2), 1/12*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), -1/12*sqrt(6)*sqrt(2), -1/12*sqrt(6)*sqrt(2), 0, 0), (1/12*sqrt(6)*sqrt(2), 1/12*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), 1/6*sqrt(6)*sqrt(2), -1/12*sqrt(6)*sqrt(2), -(1/12*I + 1/12)*sqrt(6), 0, 0), (1/4*sqrt(6), 1/4*sqrt(6), -1/12*sqrt(6), -1/12*sqrt(6), -1/12*sqrt(6), -(1/24*I + 1/24)*sqrt(6)*sqrt(2), -1/12*sqrt(6), -(1/24*I + 1/24)*sqrt(6)*sqrt(2)), (1/4*sqrt(6), 1/4*sqrt(6), -1/12*sqrt(6), -1/12*I*sqrt(6), -1/12*sqrt(6), -(1/24*I + 1/24)*sqrt(6)*sqrt(2), -1/12*sqrt(6), -(1/24*I - 1/24)*sqrt(6)*sqrt(2)), (1/4*sqrt(6)*sqrt(2), 0, -(1/24*I + 1/24)*sqrt(6)*sqrt(2), (1/24*I - 1/24)*sqrt(6)*sqrt(2), -1/24*sqrt(6)*sqrt(2) - (1/24*I + 1/24)*sqrt(6), -1/24*sqrt(6)*sqrt(2) + (1/24*I + 1/24)*sqrt(6), -1/24*sqrt(6)*sqrt(2) - (1/24*I - 1/24)*sqrt(6), -1/24*sqrt(6)*sqrt(2) + (1/24*I - 1/24)*sqrt(6)), (1/4*sqrt(6)*sqrt(2), -1/24*sqrt(6)*sqrt(2) - (1/24*I + 1/24)*sqrt(6), -(1/24*I + 1/24)*sqrt(6)*sqrt(2), -1/24*sqrt(6)*sqrt(2) - (1/24*I - 1/24)*sqrt(6), 0, -1/24*sqrt(6)*sqrt(2) + (1/24*I + 1/24)*sqrt(6), (1/24*I - 1/24)*sqrt(6)*sqrt(2), -1/24*sqrt(6)*sqrt(2) + (1/24*I - 1/24)*sqrt(6))] :param vector[int] state: State on which the operator wants the QFT performed of, this is usually a periodic state. :param bool verbose: If ``verbose`` then extra run information will be displayed in terminal. :returns: list[vectors] -- the list of states after each step. """ layers = qft_layers(state) if verbose: print "Layers completed" states, _ = run(layers, state) if verbose: print "Run completed" return states
[docs]def qft_layers(state): r""" Computes the circuit for the QFT using the circuit format used for the ``run`` function from ``run_circuit.sage``. Example: >>> qft_layers(periodic_state(2,1,3)) [ [ [ 1/2*sqrt(2) 1/2*sqrt(2)] [1 0] [1 0] [ 1/2*sqrt(2) -1/2*sqrt(2)], [0 1], [0 1] ],[ [1 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 I 0] [0 0 0 0 0 0 0 I] ],[ [1 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 (1/2*I + 1/2)*sqrt(2) 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 (1/2*I + 1/2)*sqrt(2)] ],[ [1 0] [ 1/2*sqrt(2) 1/2*sqrt(2)] [1 0] [0 1], [ 1/2*sqrt(2) -1/2*sqrt(2)], [0 1] ],[ [1 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 I 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 I] ],[ [1 0] [1 0] [ 1/2*sqrt(2) 1/2*sqrt(2)] [0 1], [0 1], [ 1/2*sqrt(2) -1/2*sqrt(2)] ],[ [1 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 1] ] ] :param vector[int] state: State on which the operator wants the QFT performed of, this is usually a periodic state. :returns: (list[list[matrix]],int) -- Circuit for the QFT. """ H = matrix(field, [[1, 1], [1, -1]])/sqrt(2) I2 = matrix.identity(field, 2) def swap(wire1=0,wire2=1,size=2): result = matrix(field, 2**size) # matrix uses little endian and bit values modification uses big endian so # we need to convert between the two w1_big = size-1-wire1 w2_big = size-1-wire2 for i in range(2**size): # we exchange the bit corresponding to each wire result[ set_bit_value( set_bit_value(i,w1_big,bit_value(i,w2_big)), w2_big,bit_value(i,w1_big) ),i] = 1 return result def R(k,target,control,size): cR = matrix.identity(field, 4) cR[3,3] = exp(2*i*pi/(2**k)) result = kronecker(cR, matrix.identity(field, 2**(size-2))) result = \ swap(target, 0, size) * swap(control, 1, size) * \ result *\ swap(1, control, size) * swap(0, target, size) return result nWires = log(len(state))/log(2) layers = [] for wire in range(nWires): layers.append([I2]*wire + [H] + [I2]*(nWires-wire-1)) for k in range(2, nWires-(wire-1)): layers.append([R(k, wire, k+(wire-1), nWires)]) global_swap = matrix.identity(field, 2**nWires) for wire in range(nWires/2): global_swap *= swap(wire, nWires-1-wire, nWires) layers.append([global_swap]) return layers
[docs]def qft_evaluate(states, verbose=False, file_name=None): r""" Computes the Mermin Evaluation for each state in ``states``. Example: >>> qft_evaluate([periodic_state(1,5,4)]) [1.33201398251237] :param list[vector] states: The states after each step of the QFT. :param bool verbose: If `verbose` then extra run information will be displayed in terminal. :param str file_name: File name for the registration of the Mermin evaluation for each step of the algorithm, in csv format. :returns: any -- Result of this function depends on file_name. If a file name is given `qft_main` returns None, otherwise, it returns an array with the evaluation values. """ result = [] for state in states: # we are setting the calculations in floating numbers (instead on symbolic # to speed them up) result.append(mermin_coef_opti_all(vector(CC,state), verbose)[1]) if file_name == None: return result else : lines, i = [["iteration", "intricationValue"]], 0 for value in result: lines.append([i, value]) i += 1 if not os.path.exists(os.path.dirname(file_name)) and os.path.dirname(file_name) != '': os.makedirs(os.path.dirname(file_name)) with open(file_name, 'w') as writeFile: writer = csv.writer(writeFile) writer.writerows(lines) writeFile.close() return None
[docs]def qft_matrix(size): r""" This function should compute a matrix equivalent to the whole QFT operation. It has not been tester much though and should not be relied on for now. Example: >>> qft_matrix(3) [ 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2) 1/4*sqrt(2)] [ 1/4*sqrt(2) 1/4*I + 1/4 1/4*I*sqrt(2) 1/4*I - 1/4 -1/4*sqrt(2) -1/4*I - 1/4 -1/4*I*sqrt(2) -1/4*I + 1/4] [ 1/4*sqrt(2) 1/4*I*sqrt(2) -1/4*sqrt(2) -1/4*I*sqrt(2) 1/4*sqrt(2) 1/4*I*sqrt(2) -1/4*sqrt(2) -1/4*I*sqrt(2)] [ 1/4*sqrt(2) 1/4*I - 1/4 -1/4*I*sqrt(2) 1/4*I + 1/4 -1/4*sqrt(2) -1/4*I + 1/4 1/4*I*sqrt(2) -1/4*I - 1/4] [ 1/4*sqrt(2) -1/4*sqrt(2) 1/4*sqrt(2) -1/4*sqrt(2) 1/4*sqrt(2) -1/4*sqrt(2) 1/4*sqrt(2) -1/4*sqrt(2)] [ 1/4*sqrt(2) -1/4*I - 1/4 1/4*I*sqrt(2) -1/4*I + 1/4 -1/4*sqrt(2) 1/4*I + 1/4 -1/4*I*sqrt(2) 1/4*I - 1/4] [ 1/4*sqrt(2) -1/4*I*sqrt(2) -1/4*sqrt(2) 1/4*I*sqrt(2) 1/4*sqrt(2) -1/4*I*sqrt(2) -1/4*sqrt(2) 1/4*I*sqrt(2)] [ 1/4*sqrt(2) -1/4*I + 1/4 -1/4*I*sqrt(2) -1/4*I - 1/4 -1/4*sqrt(2) 1/4*I - 1/4 1/4*I*sqrt(2) 1/4*I + 1/4] :param int size: The size of the QFT (number of qubits). :returns: matrix -- The matrix corresponding to the QFT. """ N = 2**size w = exp(2*i*pi/N) result = matrix(SR, N) for k in range(N): for l in range(N): result[k,l] = w**(k*l) return result/sqrt(N)
[docs]def periodic_state(l,r,nWires): r""" Returns the periodic state `|\varphi^{l,r}>` of size `2^{nWires}`. We have: `|\varphi^{l,r}> = \sum_{i=0}^{A-1}|l+ir>/sqrt(A)` with `A = floor((2^{nWires}-l)/r)+1` In this definition, ``l`` is the shift of the state, and ``r`` is the period of the state. Example: Since `|\varphi^{1,5}> = (|1>+|6>+|11>)/sqrt(3)=(|0001>+|0110>+|1011>)/sqrt(3)`, >>> periodic_state(1,5,4) (0, 1/3*sqrt(3), 0, 0, 0, 0, 1/3*sqrt(3), 0, 0, 0, 0, 1/3*sqrt(3), 0, 0, 0, 0) :param int l: The shift of the state. :param int r: The period of the state. :param int nWires: The size of the system (number of qubits). :returns: vector -- The state defined by ``l``, ``r`` and ``nWires`` according to the definition given above. """ N = 2**nWires result = vector(SR, N) for k in range(ceil((N-l)/r)): result[l+k*r] = 1 return result.normalized()
[docs]def bit_value(n, k, base=2): """ Returns the value of the ``k`` `^{th}` digit of the integer ``n`` given in base ``base``. Example: >>> bit_value(5, 0) 1 >>> bit_value(5, 1) 0 >>> bit_value(15, 0, base=10) 5 :param int n: Integer studied. :param int k: Digit desired. :param int base: Base in which ``n`` is studied. :returns: int -- Value of the ``k`` `^{th}` digit of the integer ``n`` given in base ``base``. """ return floor(abs(n)/base**(k)) - floor(abs(n)/base**(k+1))*base
[docs]def set_bit_value(n, k, value, base=2): """ Returns ``n`` with its ``k`` `^{th}` bit set to ``value`` in base ``base``. Example: >>> set_bit_value(5, 0, 0) 4 >>> set_bit_value(5, 1, 0) 5 >>> set_bit_value(15, 0, 9, base=10) 19 :param int n: Integer modified. :param int k: Digit to change. :param int value: Value wanted for the ``k`` `^{th}` digit of ``n`` (must be between 0 and ``base-1``). :param int base: Base in which ``n`` is modified. :returns: int -- ``n`` with its ``k`` `^{th}` bit set to ``value`` in base ``base``. """ return n - bit_value(n, k, base)*(2**k) + value*(2**k)