def test_pauli_sgn_prod(self): p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) self.log.info("sign product:") p3, sgn = sgn_prod(p1, p2) self.log.info("p1: %s", p1.to_label()) self.log.info("p2: %s", p2.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p1, p2): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, 1j) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info("p2: %s", p2.to_label()) self.log.info("p1: %s", p1.to_label()) self.log.info("p3: %s", p3.to_label()) self.log.info("sgn_prod(p2, p1): %s", str(sgn)) self.assertEqual(p1.to_label(), 'X') self.assertEqual(p2.to_label(), 'Y') self.assertEqual(p3.to_label(), 'Z') self.assertEqual(sgn, -1j)
def _two_body_mapping(h2_ijkm, a_i, a_j, a_k, a_m, threshold): """ Subroutine for two body mapping. Args: h1_ijkm (complex): value of h2 at index (i,j,k,m) a_i (Pauli): pauli at index i a_j (Pauli): pauli at index j a_k (Pauli): pauli at index k a_m (Pauli): pauli at index m threshold: (float): threshold to remove a pauli Returns: Operator: Operator for those paulis """ pauli_list = [] for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): pauli_prod_1 = sgn_prod(a_i[alpha], a_k[beta]) pauli_prod_2 = sgn_prod(pauli_prod_1[0], a_m[gamma]) pauli_prod_3 = sgn_prod(pauli_prod_2[0], a_j[delta]) phase1 = pauli_prod_1[1] * pauli_prod_2[ 1] * pauli_prod_3[1] phase2 = np.power(-1j, alpha + beta) * np.power( 1j, gamma + delta) pauli_term = [ h2_ijkm / 16 * phase1 * phase2, pauli_prod_3[0] ] if np.absolute(pauli_term[0]) > threshold: pauli_list.append(pauli_term) return Operator(paulis=pauli_list)
def test_pauli(self): v = np.zeros(3) w = np.zeros(3) v[0] = 1 w[1] = 1 v[2] = 1 w[2] = 1 p = Pauli(v, w) self.log.info(p) self.log.info("In label form:") self.log.info(p.to_label()) self.log.info("In matrix form:") self.log.info(p.to_matrix()) q = random_pauli(2) self.log.info(q) r = inverse_pauli(p) self.log.info("In label form:") self.log.info(r.to_label()) self.log.info("Group in tensor order:") grp = pauli_group(3, case=1) for j in grp: self.log.info(j.to_label()) self.log.info("Group in weight order:") grp = pauli_group(3) for j in grp: self.log.info(j.to_label()) self.log.info("sign product:") p1 = Pauli(np.array([0]), np.array([1])) p2 = Pauli(np.array([1]), np.array([1])) p3, sgn = sgn_prod(p1, p2) self.log.info(p1.to_label()) self.log.info(p2.to_label()) self.log.info(p3.to_label()) self.log.info(sgn) self.log.info("sign product reverse:") p3, sgn = sgn_prod(p2, p1) self.log.info(p2.to_label()) self.log.info(p1.to_label()) self.log.info(p3.to_label()) self.log.info(sgn)
def _one_body_mapping(h1_ij, a_i, a_j, threshold): """ Subroutine for one body mapping. Args: h1_ij (complex): value of h1 at index (i,j) a_i (Pauli): pauli at index i a_j (Pauli): pauli at index j threshold: (float): threshold to remove a pauli Returns: Operator: Operator for those paulis """ pauli_list = [] for alpha in range(2): for beta in range(2): pauli_prod = sgn_prod(a_i[alpha], a_j[beta]) coeff = h1_ij / 4 * pauli_prod[1] * np.power(-1j, alpha) * np.power(1j, beta) pauli_term = [coeff, pauli_prod[0]] if np.absolute(pauli_term[0]) > threshold: pauli_list.append(pauli_term) return Operator(paulis=pauli_list)
def fermionic_maps(h1, h2, map_type, out_file=None, threshold=0.000000000001): """Creates a list of Paulis with coefficients from fermionic one and two-body operator. Args: h1 (list): second-quantized fermionic one-body operator h2 (list): second-quantized fermionic two-body operator map_type (str): "JORDAN_WIGNER", "PARITY", "BINARY_TREE" out_file (str): name of the optional file to write the Pauli list on threshold (float): threshold for Pauli simplification Returns: list: A list of Paulis with coefficients """ # pylint: disable=invalid-name #################################################################### # ########### DEFINING MAPPED FERMIONIC OPERATORS ############# #################################################################### pauli_list = [] n = len(h1) # number of fermionic modes / qubits a = [] if map_type == 'JORDAN_WIGNER': for i in range(n): xv = np.append(np.append(np.ones(i), 0), np.zeros(n - i - 1)) xw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) yv = np.append(np.append(np.ones(i), 1), np.zeros(n - i - 1)) yw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(xv, xw), Pauli(yv, yw))) if map_type == 'PARITY': for i in range(n): if i > 1: Xv = np.append(np.append(np.zeros(i - 1), [1, 0]), np.zeros(n - i - 1)) Xw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) Yv = np.append(np.append(np.zeros(i - 1), [0, 1]), np.zeros(n - i - 1)) Yw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) elif i > 0: Xv = np.append((1, 0), np.zeros(n - i - 1)) Xw = np.append([0, 1], np.ones(n - i - 1)) Yv = np.append([0, 1], np.zeros(n - i - 1)) Yw = np.append([0, 1], np.ones(n - i - 1)) else: Xv = np.append(0, np.zeros(n - i - 1)) Xw = np.append(1, np.ones(n - i - 1)) Yv = np.append(1, np.zeros(n - i - 1)) Yw = np.append(1, np.ones(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, # a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) if map_type == 'BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup = 1 while n > np.power(2, bin_sup): bin_sup += 1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets = [] update_pauli = [] parity_sets = [] parity_pauli = [] flip_sets = [] remainder_sets = [] remainder_pauli = [] for j in range(n): update_sets.append(update_set(j, np.power(2, bin_sup))) update_sets[j] = update_sets[j][update_sets[j] < n] parity_sets.append(parity_set(j, np.power(2, bin_sup))) parity_sets[j] = parity_sets[j][parity_sets[j] < n] flip_sets.append(flip_set(j, np.power(2, bin_sup))) flip_sets[j] = flip_sets[j][flip_sets[j] < n] remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) update_pauli.append(Pauli(np.zeros(n), np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n), np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n), np.zeros(n))) for k in range(n): if np.in1d(k, update_sets[j]): update_pauli[j].w[k] = 1 if np.in1d(k, parity_sets[j]): parity_pauli[j].v[k] = 1 if np.in1d(k, remainder_sets[j]): remainder_pauli[j].v[k] = 1 x_j = Pauli(np.zeros(n), np.zeros(n)) x_j.w[j] = 1 y_j = Pauli(np.zeros(n), np.zeros(n)) y_j.v[j] = 1 y_j.w[j] = 1 # defines the two mapped Pauli components of a_i and a_i^\dag, # according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> # (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j] * x_j * parity_pauli[j], update_pauli[j] * y_j * remainder_pauli[j])) #################################################################### # ########### BUILDING THE MAPPED HAMILTONIAN ############### #################################################################### # ###################### One-body ############################# for i in range(n): for j in range(n): if h1[i, j] != 0: for alpha in range(2): for beta in range(2): pauli_prod = sgn_prod(a[i][alpha], a[j][beta]) pauli_term = [h1[i, j] * 1 / 4 * pauli_prod[1] * np.power(-1j, alpha) * np.power(1j, beta), pauli_prod[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) # ###################### Two-body ############################ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i, j, k, m] != 0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): # Note: chemists' notation for the # labeling, # h2(i,j,k,m) adag_i adag_k a_m a_j pauli_prod_1 = sgn_prod( a[i][alpha], a[k][beta]) pauli_prod_2 = sgn_prod( pauli_prod_1[0], a[m][gamma]) pauli_prod_3 = sgn_prod( pauli_prod_2[0], a[j][delta]) phase1 = pauli_prod_1[1] *\ pauli_prod_2[1] * pauli_prod_3[1] phase2 = np.power(-1j, alpha + beta) *\ np.power(1j, gamma + delta) pauli_term = [ h2[i, j, k, m] * 1 / 16 * phase1 * phase2, pauli_prod_3[0]] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) #################################################################### # ################ WRITE TO FILE ################## #################################################################### if out_file is not None: out_stream = open(out_file, 'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label() + '\n') out_stream.write('%.15f' % pauli_term[0].real + '\n') out_stream.close() return pauli_list
def fermionic_maps(h1,h2,map_type,out_file=None,threshold=0.000000000001): """ Takes fermionic one and two-body operators in the form of numpy arrays with real entries, e.g. h1=np.zeros((n,n)) h2=np.zeros((n,n,n,n)) where n is the number of fermionic modes, and gives a pauli_list of mapped pauli terms and coefficients, according to the map_type specified, with values map_type: JORDAN_WIGNER PARITY BINARY_TREE the notation for the two-body operator is the chemists' one, h2(i,j,k,m) a^dag_i a^dag_k a_m a_j Options: - writes the mapped pauli_list to a file named out_file given as an input (does not do this as default) - neglects mapped terms below a threshold defined by the user (default is 10^-12) """ pauli_list=[] n=len(h1) # number of fermionic modes / qubits """ #################################################################### ############ DEFINING MAPPED FERMIONIC OPERATORS ############## #################################################################### """ a=[] if map_type=='JORDAN_WIGNER': for i in range(n): Xv=np.append(np.append(np.ones(i),0),np.zeros(n-i-1)) Xw=np.append(np.append(np.zeros(i),1),np.zeros(n-i-1)) Yv=np.append(np.append(np.ones(i),1),np.zeros(n-i-1)) Yw=np.append(np.append(np.zeros(i),1),np.zeros(n-i-1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv,Xw),Pauli(Yv,Yw))) if map_type=='PARITY': for i in range(n): if i>1: Xv=np.append(np.append(np.zeros(i-1),[1,0]),np.zeros(n-i-1)) Xw=np.append(np.append(np.zeros(i-1),[0,1]),np.ones(n-i-1)) Yv=np.append(np.append(np.zeros(i-1),[0,1]),np.zeros(n-i-1)) Yw=np.append(np.append(np.zeros(i-1),[0,1]),np.ones(n-i-1)) elif i>0: Xv=np.append((1,0),np.zeros(n-i-1)) Xw=np.append([0,1],np.ones(n-i-1)) Yv=np.append([0,1],np.zeros(n-i-1)) Yw=np.append([0,1],np.ones(n-i-1)) else: Xv=np.append(0,np.zeros(n-i-1)) Xw=np.append(1,np.ones(n-i-1)) Yv=np.append(1,np.zeros(n-i-1)) Yw=np.append(1,np.ones(n-i-1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv,Xw),Pauli(Yv,Yw))) if map_type=='BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup=1 while n>np.power(2,bin_sup): bin_sup+=1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets=[] update_pauli=[] parity_sets=[] parity_pauli=[] flip_sets=[] flip_pauli=[] remainder_sets=[] remainder_pauli=[] for j in range(n): update_sets.append(update_set(j,np.power(2,bin_sup))) update_sets[j]=update_sets[j][update_sets[j]<n] parity_sets.append(parity_set(j,np.power(2,bin_sup))) parity_sets[j]=parity_sets[j][parity_sets[j]<n] flip_sets.append(flip_set(j,np.power(2,bin_sup))) flip_sets[j]=flip_sets[j][flip_sets[j]<n] remainder_sets.append(np.setdiff1d(parity_sets[j],flip_sets[j])) update_pauli.append(Pauli(np.zeros(n),np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n),np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n),np.zeros(n))) for k in range(n): if np.in1d(k,update_sets[j]): update_pauli[j].w[k]=1 if np.in1d(k,parity_sets[j]): parity_pauli[j].v[k]=1 if np.in1d(k,remainder_sets[j]): remainder_pauli[j].v[k]=1 Xj=Pauli(np.zeros(n),np.zeros(n)) Xj.w[j]=1 Yj=Pauli(np.zeros(n),np.zeros(n)) Yj.v[j]=1 Yj.w[j]=1 # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j]*Xj*parity_pauli[j],update_pauli[j]*Yj*remainder_pauli[j])) """ #################################################################### ############ BUILDING THE MAPPED HAMILTONIAN ################ #################################################################### """ """ ####################### One-body ############################# """ for i in range(n): for j in range(n): if h1[i,j]!=0: for alpha in range(2): for beta in range(2): pauli_prod=sgn_prod(a[i][alpha],a[j][beta]) pauli_term=[ h1[i,j]*1/4*pauli_prod[1]*np.power(-1j,alpha)*np.power(1j,beta), pauli_prod[0] ] pauli_list=pauli_term_append(pauli_term,pauli_list,threshold) """ ####################### Two-body ############################# """ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i,j,k,m]!=0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): """ # Note: chemists' notation for the labeling, h2(i,j,k,m) adag_i adag_k a_m a_j """ pauli_prod_1=sgn_prod(a[i][alpha],a[k][beta]) pauli_prod_2=sgn_prod(pauli_prod_1[0],a[m][gamma]) pauli_prod_3=sgn_prod(pauli_prod_2[0],a[j][delta]) phase1=pauli_prod_1[1]*pauli_prod_2[1]*pauli_prod_3[1] phase2=np.power(-1j,alpha+beta)*np.power(1j,gamma+delta) pauli_term=[h2[i,j,k,m]*1/16*phase1*phase2,pauli_prod_3[0]] pauli_list=pauli_term_append(pauli_term,pauli_list,threshold) """ #################################################################### ################# WRITE TO FILE ################### #################################################################### """ if out_file!= None: out_stream=open(out_file,'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label()+'\n') out_stream.write('%.15f' % pauli_term[0].real+'\n') out_stream.close() return pauli_list
def fermionic_maps(h1, h2, map_type, out_file=None, threshold=0.000000000001): """ Takes fermionic one and two-body operators in the form of numpy arrays with real entries, e.g. h1=np.zeros((n,n)) h2=np.zeros((n,n,n,n)) where n is the number of fermionic modes, and gives a pauli_list of mapped pauli terms and coefficients, according to the map_type specified, with values map_type: JORDAN_WIGNER PARITY BINARY_TREE the notation for the two-body operator is the chemists' one, h2(i,j,k,m) a^dag_i a^dag_k a_m a_j Options: - writes the mapped pauli_list to a file named out_file given as an input (does not do this as default) - neglects mapped terms below a threshold defined by the user (default is 10^-12) """ pauli_list = [] n = len(h1) # number of fermionic modes / qubits """ #################################################################### ############ DEFINING MAPPED FERMIONIC OPERATORS ############## #################################################################### """ a = [] if map_type == 'JORDAN_WIGNER': for i in range(n): Xv = np.append(np.append(np.ones(i), 0), np.zeros(n - i - 1)) Xw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) Yv = np.append(np.append(np.ones(i), 1), np.zeros(n - i - 1)) Yw = np.append(np.append(np.zeros(i), 1), np.zeros(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) if map_type == 'PARITY': for i in range(n): if i > 1: Xv = np.append(np.append(np.zeros(i - 1), [1, 0]), np.zeros(n - i - 1)) Xw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) Yv = np.append(np.append(np.zeros(i - 1), [0, 1]), np.zeros(n - i - 1)) Yw = np.append(np.append(np.zeros(i - 1), [0, 1]), np.ones(n - i - 1)) elif i > 0: Xv = np.append((1, 0), np.zeros(n - i - 1)) Xw = np.append([0, 1], np.ones(n - i - 1)) Yv = np.append([0, 1], np.zeros(n - i - 1)) Yw = np.append([0, 1], np.ones(n - i - 1)) else: Xv = np.append(0, np.zeros(n - i - 1)) Xw = np.append(1, np.ones(n - i - 1)) Yv = np.append(1, np.zeros(n - i - 1)) Yw = np.append(1, np.ones(n - i - 1)) # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((Pauli(Xv, Xw), Pauli(Yv, Yw))) if map_type == 'BINARY_TREE': # FIND BINARY SUPERSET SIZE bin_sup = 1 while n > np.power(2, bin_sup): bin_sup += 1 # DEFINE INDEX SETS FOR EVERY FERMIONIC MODE update_sets = [] update_pauli = [] parity_sets = [] parity_pauli = [] flip_sets = [] flip_pauli = [] remainder_sets = [] remainder_pauli = [] for j in range(n): update_sets.append(update_set(j, np.power(2, bin_sup))) update_sets[j] = update_sets[j][update_sets[j] < n] parity_sets.append(parity_set(j, np.power(2, bin_sup))) parity_sets[j] = parity_sets[j][parity_sets[j] < n] flip_sets.append(flip_set(j, np.power(2, bin_sup))) flip_sets[j] = flip_sets[j][flip_sets[j] < n] remainder_sets.append(np.setdiff1d(parity_sets[j], flip_sets[j])) update_pauli.append(Pauli(np.zeros(n), np.zeros(n))) parity_pauli.append(Pauli(np.zeros(n), np.zeros(n))) remainder_pauli.append(Pauli(np.zeros(n), np.zeros(n))) for k in range(n): if np.in1d(k, update_sets[j]): update_pauli[j].w[k] = 1 if np.in1d(k, parity_sets[j]): parity_pauli[j].v[k] = 1 if np.in1d(k, remainder_sets[j]): remainder_pauli[j].v[k] = 1 Xj = Pauli(np.zeros(n), np.zeros(n)) Xj.w[j] = 1 Yj = Pauli(np.zeros(n), np.zeros(n)) Yj.v[j] = 1 Yj.w[j] = 1 # defines the two mapped Pauli components of a_i and a_i^\dag, according to a_i -> (a[i][0]+i*a[i][1])/2, a_i^\dag -> (a_[i][0]-i*a[i][1])/2 a.append((update_pauli[j] * Xj * parity_pauli[j], update_pauli[j] * Yj * remainder_pauli[j])) """ #################################################################### ############ BUILDING THE MAPPED HAMILTONIAN ################ #################################################################### """ """ ####################### One-body ############################# """ for i in range(n): for j in range(n): if h1[i, j] != 0: for alpha in range(2): for beta in range(2): pauli_prod = sgn_prod(a[i][alpha], a[j][beta]) pauli_term = [ h1[i, j] * 1 / 4 * pauli_prod[1] * np.power(-1j, alpha) * np.power(1j, beta), pauli_prod[0] ] pauli_list = pauli_term_append(pauli_term, pauli_list, threshold) """ ####################### Two-body ############################# """ for i in range(n): for j in range(n): for k in range(n): for m in range(n): if h2[i, j, k, m] != 0: for alpha in range(2): for beta in range(2): for gamma in range(2): for delta in range(2): """ # Note: chemists' notation for the labeling, h2(i,j,k,m) adag_i adag_k a_m a_j """ pauli_prod_1 = sgn_prod( a[i][alpha], a[k][beta]) pauli_prod_2 = sgn_prod( pauli_prod_1[0], a[m][gamma]) pauli_prod_3 = sgn_prod( pauli_prod_2[0], a[j][delta]) phase1 = pauli_prod_1[1] * pauli_prod_2[ 1] * pauli_prod_3[1] phase2 = np.power( -1j, alpha + beta) * np.power( 1j, gamma + delta) pauli_term = [ h2[i, j, k, m] * 1 / 16 * phase1 * phase2, pauli_prod_3[0] ] pauli_list = pauli_term_append( pauli_term, pauli_list, threshold) """ #################################################################### ################# WRITE TO FILE ################### #################################################################### """ if out_file != None: out_stream = open(out_file, 'w') for pauli_term in pauli_list: out_stream.write(pauli_term[1].to_label() + '\n') out_stream.write('%.15f' % pauli_term[0].real + '\n') out_stream.close() return pauli_list