Source code for mermin_eval

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module is a SageMath module aimed at computing Mermin operators optimized 
to detect a specific quantum state.
"""
from sage.all import *

import csv

from opti import *
from run_circuit import *
import grover

[docs]def mermin_operator_opti(target_state_vector, precomputed_filename=None, verbose=False): r""" Computes the pseudo optimal operator used to perform the Mermin evaluation during Grover's algorithm. :param vector[int] target_state_vector: State searched by Grover's algorithm (only single item searches are supported for now). :param str precomputed_filename: File where the precomputed coefficients for optimal Mermin operator are stored, if left empty, precomputation will not be used. If precomputation is used and the searched state is not in this database, once the optimization done, the result will be added to the file. :param bool verbose: If *verbose* then extra run information will be displayed in terminal. :returns: matrix, real -- The Mermin operator satisfying the required conditions and the value reached. """ N = len(target_state_vector) n = log(N)/log(2) if precomputed_filename: target_state_string = grover.target_state_ket_vector_to_string(target_state_vector) if not os.path.exists(os.path.dirname(precomputed_filename)) and os.path.dirname(precomputed_filename) != '': os.makedirs(os.path.dirname(precomputed_filename)) try: precomputed_file = open(precomputed_filename, "a+b") except IOError: if verbose: print "Could not open file, falling back to default method" (a,b,c,m,p,q), _ = mermin_coef_opti(target_state_vector, verbose) with precomputed_file: reader = csv.DictReader(precomputed_file, delimiter=',', quotechar="\'") found = False for row in reader: if row['ket'] == target_state_string: found = True a,b,c,m,p,q = RR(row['a']), RR(row['b']), RR(row['c']), \ RR(row['m']), RR(row['p']), RR(row['q']), if not found: (a,b,c,m,p,q), _ = mermin_coef_opti(target_state_vector, verbose) writer = csv.DictWriter(precomputed_file, fieldnames=reader.fieldnames) writer.writerow({'ket':target_state_string, 'a':a, 'b':b, 'c':c, 'm':m, 'p':p, 'q':q}) else: (a,b,c,m,p,q), _ = mermin_coef_opti(target_state_vector, verbose) return M_from_coef(n,a,b,c,m,p,q)
[docs]def mermin_coef_opti(target_state, verbose=False): r""" Returns the Mermin operator maximizing the measure for a given input. :param vector[int] target_state_vector: State searched by Grover's algorithm (only single item searches are supported for now). :param bool verbose: If *verbose* then extra run information will be displayed in terminal. :returns: matrix, real -- Coefficients of the optimal Mermin operator for *target_state* in th Grover algorithm and the value reached. """ n = log(len(target_state))/log(2) plus = vector([1,1])/sqrt(2) plus_n = kronecker_power(plus, n) phi = (target_state + plus_n).normalized() def M_phi(_abcmpq): a,b,c,m,p,q = _abcmpq return M_eval(a,b,c,m,p,q, phi) abcmpq,v = optimize(M_phi, (1,1,1,1,1,1), 5, 10**(-2), 10**2) if verbose: print("Optimization completed result: optimum reached at (a,b,c,m," + \ "p,q) = " + str(abcmpq) + " with a value of v = " + \ str(CC(v).real())) return abcmpq,v
[docs]def M_eval(a, b, c, m, p, q, phi): r""" This function evaluates <*phi*|M_n|*phi*> with *(a,b,c,m,p,q)* describing M_n, the Mermin operator. M_n traditionally uses two families of operators, a_n and a'_n, in our case, a_n = a*X+b*Y+c*Z and a'_n = m*X+p*Y+q*Z. :param real a,b,c,m,p,q: Coefficients for the Mermin operator, used as described above. :param vector[complex] phi: Vector to be evaluated with M. :returns: complex -- <*phi*|M_n|*phi*> """ phi_matrix = matrix(phi).transpose() n = log(len(phi))/log(2) return abs((phi_matrix.transpose().conjugate() * M_from_coef(n,a,b,c,m,p,q) * phi_matrix)[0][0])
[docs]def M_from_coef(n,a,b,c,m,p,q): r""" Returns the Mermin operator for a given size *n* and coefficients *a* through *q*. M traditionally uses two families of operators, a_n and a'_n, in our case, a_n = a*X+b*Y+c*Z and a'_n = m*X+p*Y+q*Z. :param int n: Iteration for the Mermin operator (determines its size). :param real a,b,c,m,p,q: Coefficients for the Mermin operator, used as described above. :returns: matrix -- The Mermin operator M_n. """ X = matrix([[0, 1], [1, 0]]) Y = matrix([[0, -i], [i, 0]]) Z = matrix([[1, 0], [0, -1]]) a1 = vector([a,b,c]).normalized() a2 = vector([m,p,q]).normalized() A1 = a1[0]*X+a1[1]*Y+a1[2]*Z A2 = a2[0]*X+a2[1]*Y+a2[2]*Z return M(n, A1, A2)
[docs]def M(n, a, a_prime): r""" M_n is defined as such: M_n = (1/2)*(M_(n-1).tensor(a + a') + M'_(n-1).tensor(a - a')) :param int n: Iteration for the Mermin operator (determines its size). :param matrix a,a_prime: Size 2 hermitian operators, defining M as given above. :returns: matrix -- A size 2^n operator, following the definition given above. """ if n == 1: return a return (kronecker(M(n-1, a, a_prime), a + a_prime) + kronecker(M_prime(n-1, a, a_prime), a - a_prime))/2
[docs]def M_prime(n, a, a_prime): r""" M'_n is defined as such: M'_n = (1/2)*(M'_(n-1).tensor(a + a') + M_(n-1).tensor(a' - a)) :param int n: Iteration for the Mermin operator (determines its size). :param matrix a,a_prime: Size 2 hermitian operators, defining M as given above. :returns: matrix -- A size 2^n operator, following the definition given above. """ if n == 1: return a_prime return (kronecker(M(n-1, a, a_prime), a_prime - a) + kronecker(M_prime(n-1, a, a_prime), a + a_prime))/2
[docs]def mermin_coef_opti_all(phi, verbose=False): r""" Returns the Mermin operator' coefficients maximizing tr(M_n * rho) for a given input phi (where `rho = |phi><phi|` is the density matrix corresponding to the state phi). :param vector[complex] phi: State used for the optimization of tr(M_n * rho) (only single item searches are supported for now). :param bool verbose: If *verbose* then extra run information will be displayed in terminal. :returns: list[real], real -- Coefficients of the optimal Mermin operator for *target_state* in th Grover algorithm and the value reached. """ n = log(len(phi))/log(2) rho = (matrix(phi).transpose())*(matrix(phi).conjugate()) def M_func(_a_a_prime_coefs): _a_coefs, _a_prime_coefs = coefficients_packing(_a_a_prime_coefs) return M_eval_all(n, _a_coefs, _a_prime_coefs, rho) def normalizer_func(_a_a_prime_coefs): _a_coefs, _a_prime_coefs = coefficients_packing(_a_a_prime_coefs) _a_coefs_normalized = [] for _a_coef in _a_coefs: _a_coefs_normalized.append(list(vector(_a_coef).normalized())) _a_prime_coefs_normalized = [] for _a_prime_coef in _a_prime_coefs: _a_prime_coefs_normalized.append(list(vector(_a_prime_coef).normalized())) return coefficients_unpacking(_a_coefs_normalized,_a_prime_coefs_normalized) _a_a_prime_coefs_opti,v = optimize(M_func, [1]*3*n*2, 5, 10**(-2), 10**3) # _a_a_prime_coefs_opti,v = optimize_normalized(M_func, normalizer_func, [1]*3*n*2, 5, 10**(-2), 10**4) if verbose: print("Optimization completed result: optimum reached at (a, a') = " + \ str(_a_a_prime_coefs_opti) + " (packed coefficients) with a value of " + \ "v = " + str(v)) return _a_a_prime_coefs_opti,v
[docs]def M_eval_all(_n, _a_coefs, _a_prime_coefs, _rho): r""" This function evaluates tr(M_n * rho) with *a* and *a'* describing Mn, the Mermin operator. The coefficients must be given in the following shape: >>> [[a,b,c], [d,e,f], ...] and will result in the following family of observables: >>> a[0] = a*X + b*Y + c*Z >>> a[1] = d*X + e*Y + f*Z >>> ... :param int _n: Size of the system. :param list[list[real]] _a_coefs, _a_prime_coefs: Coefficients for the Mermin operator, used as described above. :param matrix[complex] rho: Density matrix of the state to be evaluated with M_n :returns: complex """ return abs((M_from_coef_all(_n, _a_coefs, _a_prime_coefs)*_rho).trace())
[docs]def M_from_coef_all(_n, _a_coefs, _a_prime_coefs): r""" Returns the Mermin operator for a given size *n* and coefficients of *a* and *a'* The coefficients must be given in the following shape: >>> [[a,b,c], [d,e,f], ...] and will result in the following family of observables: >>> a[0] = a*X + b*Y + c*Z >>> a[1] = d*X + e*Y + f*Z >>> ... :param int n: Iteration for the Mermin operator (determines its size). :param list[list[real]] _a_coefs, _a_prime_coefs: Coefficients for the Mermin operator, used as described above. :returns: matrix -- The Mermin operator M_n. """ X = matrix([[0, 1], [1, 0]]) Y = matrix([[0, -i], [i, 0]]) Z = matrix([[1, 0], [0, -1]]) _a = [] for _a_coef in _a_coefs: _a_n = vector(_a_coef).normalized() _a.append(_a_n[0]*X + _a_n[1]*Y + _a_n[2]*Z) _a_prime = [] for _a_prime_coef in _a_prime_coefs: _a_prime_n = vector(_a_prime_coef).normalized() _a_prime.append(_a_prime_n[0]*X + _a_prime_n[1]*Y + _a_prime_n[2]*Z) return M_all(_n, _a, _a_prime)
[docs]def M_all(_n, _a, _a_prime): r""" M_n is defined as such: M_n = (1/2)*(M_(n-1).tensor(a_n + a_n') + M'_(n-1).tensor(a-n - a-n')) :param int n: Iteration for the Mermin operator (determines its size). :param list[matrix] a,a_prime: List of size 2 hermitian operators, defining M as given above. :returns: matrix -- A size 2^n operator, following the definition given above. """ if _n == 1: return _a[0] return (kronecker(M_all(_n-1, _a, _a_prime), _a[_n-1] + _a_prime[_n-1]) + kronecker(M_prime_all(_n-1, _a, _a_prime), _a[_n-1] - _a_prime[_n-1]))/2
[docs]def M_prime_all(_n, _a, _a_prime): r""" M'_n is defined as such: M'_n = (1/2)*(M'_(n-1).tensor(a_n + a_n') + M_(n-1).tensor(a_n' - a_n)) :param int n: Iteration for the Mermin operator (determines its size). :param list[matrix] a,a_prime: List of size 2 hermitian operators, defining M' as given above. :returns: matrix -- A size 2^n operator, following the definition given above. """ if _n == 1: return _a_prime[0] return (kronecker(M_all(_n-1, _a, _a_prime), _a_prime[_n-1] - _a[_n-1]) + kronecker(M_prime_all(_n-1, _a, _a_prime), _a[_n-1] + _a_prime[_n-1]))/2
[docs]def coefficients_packing(_a_a_prime_coefs): r""" Packs a list of elements in two lists of lists of three elements Example: >>> coefficients_packing([1,2,3,4,5,6,7,8,9,10,11,12]) ([[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]) This function is used to interface above *..._all* functions and the *optimize* function. :param list[any] _a_a_prime_coefs: List of elements. :returns: tuple[list[list[any]]] -- Lists of lists of elements as described above. """ _a_a_prime_coefs_packed = [[_a_a_prime_coefs[3*_i], _a_a_prime_coefs[3*_i+1], _a_a_prime_coefs[3*_i+2]] for _i in range(len(_a_a_prime_coefs)/3)] _a_coefs = _a_a_prime_coefs_packed[:len(_a_a_prime_coefs_packed)/2] _a_prime_coefs = _a_a_prime_coefs_packed[len(_a_a_prime_coefs_packed)/2:] return _a_coefs, _a_prime_coefs
[docs]def coefficients_unpacking(_a_coefs, _a_prime_coefs): r""" Unpacks two lists of lists of three elements to one list of elements Example: >>> coefficients_unpacking([[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]) [1,2,3,4,5,6,7,8,9,10,11,12] This function is used to interface above *..._all* functions and the *optimize* function. :param tuple[list[list[any]]] _a_coefs, _a_prime_coefs: Lists of lists of elements as described above. :returns: list[any] -- List of elements. """ _a_a_prime_coefs = [k for element in _a_coefs+_a_prime_coefs for k in element] return _a_a_prime_coefs