def output(self): # to get output state if self.state is None: msg = 'please input somthing' raise TypeError(msg) else: dim = self.state.shape[0] if self.evol is None: self.evol = eyex(dim) if typex(self.state) == 'bra': msg = 'state should not a bra vector' raise TypeError(msg) elif typex(self.state) == 'ket': if self.post is None: return (dotx(self.evol, self.state)) else: # with post-selected if typex(self.post) != 'bra': msg = 'post state must be a bra vector' raise TypeError(msg) else: return (dotx(self.post, self.evol, self.state)) else: # state is an oper if self.post is None: return (dotx(self.evol, self.state, daggx(self.evol))) else: # with post-selected if typex(self.post) != 'bra': msg = 'post state must be a bra vector' raise TypeError(msg) else: pp = dotx(self.evol, self.state, dagg(self.evol)) return (dotx(self.post, pp, dagg(self.post)))
def operx(x): """ to convert a bra or ket vector into oper """ if typex(x) == 'oper': return qx(x) elif typex(x) == 'bra': return qx(dotx(daggx(x), x)) else: return qx(dotx(x, daggx(x)))
def _sic_d(d): """ construct sic povm for d ≥ 5 a set of povm elements can be calculated by acting the Displacement operateros on the fiducial vectors """ pov = [] for i in _Dd_(d): dat = dotx(i,_f_vectors_(d)) pov.append(dotx(dat,daggx(dat))) return pov
def position(d, x): """ to generate position state ie., X|x> = x|x> Parameters ----------- x: position coordinate, real number d: number of dimensions """ ground = obasis(d, 0) power = -0.5 * dotx(raising(d),raising(d)) + \ sqrt(2) * x * raising(d) exponential = expx(power) position = exp(-x**2 / 2) / (pi**(1. / 4)) * dotx(exponential, ground) position = normx(position) return qx(position)
def gtrace(a,b): """ To get trace distance between a and b See: Nielsen & Chuang, "Quantum Computation and Quantum Information" Input --------- a : density matrix or state vector b : the same as a Result --------- fidelity : float """ # check if they are quantum object if isqx(a) and isqx(b): a = operx(a) b = operx(b) if a.shape != b.shape: raise TypeError('a and b do not have the same dimensions.') diff = a - b diff = dotx(daggx(diff),diff) # get eigenvalues of sparse matrix vals, vecs= eigh(diff) return float(real(0.5 * np.sum(sqrt(np.abs(vals))))) else: msg = 'a or b is not a quantum object' raise TypeError(msg)
def l2normx(x): """ to calculate norm 2 of a vector or trace operater >>> l2norm = <psi|psi> >>> l2morm = √tr(Aˆ†*A) """ if typex(x) != 'oper': x = operx(x) #get oper x return np.sqrt(tracex(dotx(daggx(x), x)))
def _Djkd_(j,k,d): # a displacement opertator Djk # PRX 5, 041006 (2015) w = np.exp(2*np.pi*1j/float(d)) data = 0.0 for m in range (d): data += w**(j*k/2.)*w**(j*m)*\ dotx(obasis(d,(k+m) % d),daggx(obasis(d,m))) return data
def _stoke_base(): """ to define four stock parameters there are defined to be H, V, D, R see: PRA.64.052312 Return: ------- stoke povm """ # default u = obasis(2,0) d = obasis(2,1) h = dotx(u,daggx(u)) v = dotx(d,daggx(d)) d = dotx(normx(u-d),daggx(normx(u-d))) r = dotx(normx(u-1j*d),daggx(normx(u-1j*d))) m = [h,v,d,r] return m
def squeezed(d, alpha, beta): """ to generate squeezed state Parameters ---------- alpha: complex number d: number of dimensions """ ground = obasis(d, 0) squeezed = dotx(displacement(d, alpha), squeezing(d, beta), ground) squeezed = normx(squeezed) return qx(squeezed)
def coherent(d, alpha): """ to generate coherent state Parameters ---------- alpha: complex number d: number of dimensions """ ground = obasis(d, 0) coherent = dotx(displacement(d, alpha), ground) coherent = normx(coherent) return qx(coherent)
def _sic_2(): u = obasis(2,0) d = obasis(2,1) p1 = u p2 = 1/sqrt(3.)*u + sqrt(2/3.)*d p3 = 1/sqrt(3.)*u + sqrt(2/3.)*exp(1j*2*pi/3.)*d p4 = 1/sqrt(3.)*u + sqrt(2/3.)*exp(1j*4*pi/3.)*d p = [p1,p2,p3,p4] pp = [] for i in p: pp.append(dotx(i,daggx(i))) return pp
def _pro_time_(self): if self.state is None: msg = 'please input somthing' raise TypeError(msg) else: # turn state into oper if typex(self.state) != 'oper': instate = operx(self.state) else: instate = self.state dims = shapex(instate)[0] # check args if self.args == None: return tracex(dotx(instate, self.args)) elif self.args[0] == 'Pauli': pov = _pauli(int(np.log2(dims))) elif self.args[0] == 'Stoke': pov = _stoke(int(np.log2(dims))) elif self.args[0] == 'MUB': pov = _mub(dims) elif self.args[0] == 'SIC': pov = _sic(dims) else: #arbitary POVMs if len(self.args) == 1 and \ isinstance(self.args[0],(list,np.ndarray)): # e.g. args = [m1,m2,...mn] pov = self.args[0] else: pov = self.args # now calculate probability pr = [] start = time.time() # starting time for i in range(len(pov)): pr.append(tracex(dotx(instate, pov[i]))) end = time.time() # stoping time dtime = (end - start) # time need to calcualte all proba. return pr, dtime
def normx(x): """ to normalize x use the Frobeius norm >>> |psi>/sqrt(<psi|psi>) # for vector states >>> (Aˆ†*A)/tr(Aˆ†*A) # for oper """ if typex(x) != 'oper': return x / np.sqrt(l2normx(x)) else: if x.shape[0] == x.shape[1]: return dotx(daggx(x), x) / l2normx(x)**2 else: raise TypeError('not a square matrix')
def get_pqurec(state, post_state, p0, theta, niter, dim): """ to get pure quantum state Eqs. (16,17) in the main text >>> (P+ - P- + 2P1) Re[psi]_n = --------------- (16) psi_til(1+delta_n) >>> PL - PR Im[psi]_n = --------------- (17) psi_til(1+deta_n) """ #p0 = abs(sum(state))**2/dim niter = int(niter * p0 / 3.) temp_rs = np.zeros((niter, 6, dim)) psi_til = abs(np.sum(dotx(post_state, state))) prob = get_prob(state, post_state, theta, dim) for i in range(niter): temp_rs[i, :, :] = get_bisection(state, prob, dim) ave_rs = np.zeros((6, dim)) for i in range(6): for j in range(dim): ave_rs[i, j] = cdf(temp_rs[:, i, j]) rtemp = np.zeros(dim) itemp = np.zeros(dim) rnorm = 0.0 for i in range(dim): rtemp[i] = (ave_rs[2,i]-ave_rs[3,i]+2*ave_rs[1,i])/\ (psi_til*post_state[0,i]) itemp[i] = (ave_rs[4,i]-ave_rs[5,i])/\ (psi_til*post_state[0,i]) rnorm += rtemp[i]**2 + itemp[i]**2 rtemp /= sqrt(rnorm) itemp /= sqrt(rnorm) restate = np.zeros((dim, dim), dtype=complex) for i in range(dim): for j in range(dim): restate[i,j] = (rtemp[i]+1j*itemp[i])*\ (rtemp[j]-1j*itemp[j]) return restate
def _sic_3(): b0 = obasis(3,0) b1 = obasis(3,1) b2 = obasis(3,2) p1 = b0 p2 = 0.5*b0 + 1j*sqrt(3.)/2.*b1 p3 = 0.5*b0 - 1j*sqrt(3.)/2.*b1 p4 = 0.5*b0 + 0.5*b1 + 1/sqrt(2.)*b2 p5 = 0.5*b0 + 0.5*b1 + exp(2j*pi/3.)/sqrt(2.)*b2 p6 = 0.5*b0 + 0.5*b1 + exp(-2j*pi/3.)/sqrt(2.)*b2 p7 = 0.5*b0 - 0.5*b1 + 1/sqrt(2.)*b2 p8 = 0.5*b0 - 0.5*b1 + exp(2j*pi/3.)/sqrt(2.)*b2 p9 = 0.5*b0 - 0.5*b1 + exp(-2j*pi/3.)/sqrt(2.)*b2 p = [p1,p2,p3,p4,p5,p6,p7,p8,p9] pp = [] for i in p: pp.append(dotx(i,daggx(i))) return pp
def random(d): """ to generate a random state Parameters: ---------- d: dimension Return: random state """ rpsi = np.zeros((d, 1)) ipsi = np.zeros((d, 1)) for i in range(d): rpsi[i, 0] = randunit() ipsi[i, 0] = randunit() ppsi = rpsi + 1j * ipsi ppsi = normx(ppsi) M = haar(d) prime = dotx((eyex(d) + M), ppsi) prime = normx(prime) return qx(prime)
def add_random_noise(psi, m=0.0, st=0.0): """ to generate 1 perturbed random state from psi Parameters: ---------- d: dims m: mean st: standard derivative """ if isqx(psi): dim = psi.shape[0] per = [randnormal(m, st, dim) + 1j * randnormal(m, st, dim)] if typex(psi) == 'ket': per = daggx(per) #to get ket elif typex(psi) == 'oper': per = dotx(daggx(per), per) psi = psi + per psi = normx(psi) return qx(psi) else: msg = 'psi is not a quantum object' raise TypeError(msg)
def gfide(a,b): """ To get fidelity of a and b See: Nielsen & Chuang, "Quantum Computation and Quantum Information" Input --------- a : density matrix or state vector b : the same as a Result --------- fidelity : float """ # check if they are quantum onject if isqx(a) and isqx(b): if typex(a) != 'oper': sqrtma = operx(a) if typex(b) != 'oper': b = operx(b) else: if typex(b) != 'oper': #swap a and b return gfide(b,a) sqrtma = sqrtx(a) if sqrtma.shape != b.shape: raise TypeError('Density matrices do not have same dimensions.') eig_vals, eig_vecs = eigh(dotx(sqrtma,b,sqrtma)) return float(real(sum(sqrt(eig_vals[eig_vals > 0])))) else: msg = ' a or b is not a quantum object' raise TypeError(msg)
def _pauli_eigens(): """ to get eigenstate of pauli matrices there are 3 bases: {0, 1}, {plus, minus}, {L, R} Return: ------- Pauli eigenstate POVM set """ u = obasis(2,0) d = obasis(2,1) h = dotx(u,daggx(u)) v = dotx(d,daggx(d)) p = dotx(normx(u+d),daggx(normx(u+d))) m = dotx(normx(u-d),daggx(normx(u-d))) l = dotx(normx(u+1j*d),daggx(normx(u+1j*d))) r = dotx(normx(u-1j*d),daggx(normx(u-1j*d))) m = [h,v,p,m,l,r] return m
def squeezing(d, beta): power = 0.5 * (conj(beta)*dotx(lowering(d),lowering(d))\ - beta*dotx(raising(d),raising(d))) M = expx(power) return M
def get_prob(state, post_state, theta, dim): """ to get probabilities P0,P1,....PL,PR >>> P_k = trace(rho_out * POVM_k) Parameters ---------- state (oper or ket): input state post_state (bra): post-selected state theta (real): angle dim(int): dimesion """ if typex(state) == 'oper': e_theta = 1 - np.cos(pi * theta) temp_prob = np.zeros((3, dim, dim), dtype=complex) rho = np.zeros((4, dim, dim), dtype=complex) prob = np.zeros((6, dim, dim), dtype=complex) for x in range(dim): for p in range(dim): # temp_prob_0: sum_{x,y} for tx in range(dim): for y in range(dim): temp_prob[0,x,p] += state[tx,y]*\ np.exp(1j*2.0*pi*(y-tx)*p/dim)*\ post_state[0,y]*post_state[0,tx] # temp_prob_1: sum_y for y in range(dim): temp_prob[1,x,p] += state[x,y]*\ np.exp(1j*2.0*pi*(y-x)*p/dim)*\ post_state[0,x]*post_state[0,y] # temp_prob_2: sum_{x,x} temp_prob[2, x, p] = state[x, x] * post_state[0, x]**2 # rho_00: pointer_state_00 rho[0,:,:] = (temp_prob[0,:,:] - \ e_theta*2*np.real(temp_prob[1,:,:]) + \ e_theta**2 * temp_prob[2,:,:]) / 2.0 # rho_10: pointer_state_10 rho[1,:,:] = (temp_prob[1,:,:] - \ e_theta * temp_prob[2,:,:]) * \ np.sin(pi * theta) / 2.0 # rho_01 rho[2, :, :] = np.conj(rho[1, :, :]) # rho_11 rho[3, :, :] = temp_prob[2, :, :] * np.sin(pi * theta)**2 / 2.0 #probabilities prob[0,:,:] = np.real((rho[0,:,:]+rho[1,:,:]\ +rho[2,:,:]+rho[3,:,:])/2.0) #Prob.+ prob[1,:,:] = (rho[0,:,:]-rho[1,:,:]\ -rho[2,:,:]+rho[3,:,:])/2.0 #Prob.- prob[2,:,:] = (rho[0,:,:]-1j*rho[1,:,:]\ +1j*rho[2,:,:]+rho[3,:,:])/2.0 #Prob.L prob[3,:,:] = (rho[0,:,:]+1j*rho[1,:,:]\ -1j*rho[2,:,:]+rho[3,:,:])/2.0 #Prob.R prob[4, :, :] = rho[0, :, :] #Prob. 0 prob[5, :, :] = rho[3, :, :] #Prob. 1 return np.real(prob) else: #for pure state prob = np.zeros((6, dim), dtype=complex) rpsi = np.real(state) ipsi = np.imag(state) psi_til = abs(dotx(post_state, state)[0, 0]) #scala psi_abs2 = abs(state)**2 #ket: calculate |\psi'_n|^2 #calculate probabilities prob[0,:]= (psi_til**2 - 2.0*post_state[0,:]*psi_til*rpsi[:,0]+\ post_state[0,:]**2*psi_abs2[:,0])/(2.0) #P(0) prob[1, :] = (post_state[0, :]**2 * psi_abs2[:, 0]) / (2.0) #P(1) prob[2, :] = (psi_til**2) / (4.0) #P(+) prob[3,:]= (psi_til**2-4.0*psi_til*post_state[0,:]*rpsi[:,0]+\ 4.0*post_state[0,:]**2*psi_abs2[:,0])/(4.0) #P(-) prob[4,:]= (psi_til**2 - 2.0*psi_til*post_state[0,:]*rpsi[:,0]+\ 2.0*psi_til*post_state[0,:]*ipsi[:,0]+\ 2.0*post_state[0,:]**2*psi_abs2[:,0])/(4.0) #P(L) prob[5,:]= (psi_til**2 - 2.0*psi_til*post_state[0,:]*rpsi[:,0]-\ 2.0*psi_til*post_state[0,:]*ipsi[:,0]+\ 2.0*post_state[0,:]**2*psi_abs2[:,0])/(4.0) #P(R) return np.real(prob)
def _sic_4(): b0 = obasis(4,0) b1 = obasis(4,1) b2 = obasis(4,2) b3 = obasis(4,3) c5 = sqrt(5.) mcc5 = 1.0/c5 ct110 = sqrt(-110.+50.*c5) ct290 = sqrt(-290.+130.*c5) c5t2c5 = sqrt(5.-2.*c5) p1 = b0 p2 = mcc5*b0 + 2.0*mcc5*b1 p3 = mcc5*b0 + 2.0/(5.+sqrt(5.))*b1 + sqrt(0.5+0.5*mcc5)*b2 p4 = mcc5*b0 + 2.0/(5.+sqrt(5.))*b1 + \ sqrt(2.5-5.5*mcc5)*b2 + sqrt(6.0/c5-2.)*b3 t5c4c5 = -5.+4.*c5 mt4c5 = 10.-4.*c5 ct10 = sqrt(-10.+10.*c5) sq1 = sqrt(t5c4c5-2.*ct110)+1j*c5t2c5 sq2 = sqrt(mt4c5-ct290)-1j*sqrt(2.*c5+ct10) p5 = mcc5*b0 + (1j/2.-0.5/c5)*b1 + 0.5/c5*sq1*b2 + 0.5/c5*sq2*b3 sq3 = -sqrt(t5c4c5+2.*ct110)+1j*c5t2c5 sq4 = sqrt(mt4c5+ct290)+1j*sqrt(2.*c5-ct10) p6 = mcc5*b0 + (1j/2.-0.5/c5)*b1 + 0.5/c5*sq3*b2 + 0.5/c5*sq4*b3 p7 = conjx(p6) p8 = conjx(p5) mc2c10 = 1./(2.*sqrt(10.)) btc5 = 3.-c5 c5tc5 = sqrt(5.-c5) nc3c5 = 5.+3.*c5 nb1 = btc5 + 1j*ct10 nb2 = -c5tc5 -1j*sqrt(nc3c5+4.*ct110) nb3 = sqrt(2.*c5-ct10)-1j*sqrt(mt4c5+ct290) p9 = mcc5*b0 + 1./(4.*c5)*nb1*b1 + mc2c10*nb2*b2 + 0.5/c5*nb3*b3 nb2 = -c5tc5 +1j*sqrt(nc3c5-4.*ct110) nb3 = -sqrt(2.*c5+ct10)+1j*sqrt(mt4c5-ct290) p10 = mcc5*b0 + 1./(4.*c5)*nb1*b1 + mc2c10*nb2*b2 + 0.5/c5*nb3*b3 p11 = conjx(p9) p12 = conjx(p10) t5c3c5 = -5.+3.*c5 ncc5 = 5.+c5 ct58 = sqrt(-58.+26.*c5) nb1 = -2.-ct10+1j*(c5tc5)**2 nb2 = sqrt(t5c3c5+2.*ct290)+1j*sqrt(ncc5-4.*ct290) nb3 = -sqrt(mt4c5-ct290)+1j*sqrt(2.*c5-5.*ct58) p13 = mcc5*b0 + 1./(4.*c5)*nb1*b1 + mc2c10*nb2*b2 + 0.5/c5*nb3*b3 nb1 = -2.+ct10+1j*c5tc5**2 nb2 = sqrt(t5c3c5-2.*ct290)-1j*sqrt(ncc5+4.*ct290)### nb3 = -sqrt(mt4c5+ct290)+1j*sqrt(2.*c5+5.*ct58) p14 = mcc5*b0 + 1./(4.*c5)*nb1*b1 + mc2c10*nb2*b2 + 0.5/c5*nb3*b3 p15 = conjx(p14) p16 = conjx(p13) p = [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,\ p12,p13,p14,p15,p16] pp = [] for i in p: pp.append(dotx(i,daggx(i))) return pp