def _partial_transpose_sparse(rho, mask): """ Implement the partial transpose using the CSR sparse matrix. """ data = sp.lil_matrix((rho.shape[0], rho.shape[1]), dtype=complex) for m in range(len(rho.data.indptr) - 1): n1 = rho.data.indptr[m] n2 = rho.data.indptr[m + 1] psi_A = state_index_number(rho.dims[0], m) for idx, n in enumerate(rho.data.indices[n1:n2]): psi_B = state_index_number(rho.dims[1], n) m_pt = state_number_index( rho.dims[1], np.choose(mask, [psi_A, psi_B])) n_pt = state_number_index( rho.dims[0], np.choose(mask, [psi_B, psi_A])) data[m_pt, n_pt] = rho.data.data[n1 + idx] return Qobj(data.tocsr(), dims=rho.dims)
def update_rho(self, rho): """ calculate probability distribution for quadrature measurement outcomes given a two-mode density matrix """ X1, X2 = np.meshgrid(self.xvecs[0], self.xvecs[1]) p = np.zeros((len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) N = rho.dims[0][0] M1 = np.zeros((N, N, len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) M2 = np.zeros((N, N, len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) for m in range(N): for n in range(N): M1[m,n] = exp(-1j * self.theta1 * (m - n)) / \ sqrt(pi * 2 ** (m + n) * factorial(n) * factorial(m)) * \ exp(-X1 ** 2) * np.polyval(hermite(m), X1) * np.polyval(hermite(n), X1) M2[m,n] = exp(-1j * self.theta2 * (m - n)) / \ sqrt(pi * 2 ** (m + n) * factorial(n) * factorial(m)) * \ exp(-X2 ** 2) * np.polyval(hermite(m), X2) * np.polyval(hermite(n), X2) for n1 in range(N): for n2 in range(N): i = state_number_index([N, N], [n1, n2]) for p1 in range(N): for p2 in range(N): j = state_number_index([N, N], [p1, p2]) p += M1[n1, p1] * M2[n2, p2] * rho.data[i, j] self.data = p
def swap(N=None, control=None, target=None, mask=None): """Quantum object representing the SWAP gate. Returns ------- swap_gate : qobj Quantum object representation of SWAP gate Examples -------- >>> swap() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]] """ if mask: warnings.warn("The mask argument to iswap is deprecated. " + "Use the N, control and target arguments instead.") if sum(mask) != 2: raise ValueError("mask must only have two ones, rest zeros") dims = [2] * len(mask) idx, = where(mask) N = prod(dims) data = sp.lil_matrix((N, N)) for s1 in state_number_enumerate(dims): i1 = state_number_index(dims, s1) if s1[idx[0]] == s1[idx[1]]: i2 = i1 else: s2 = array(s1).copy() s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]] i2 = state_number_index(dims, s2) data[i1, i2] = 1 return Qobj(data, dims=[dims, dims], shape=[N, N]) elif not N is None and not control is None and not target is None: return gate_expand_2toN(swap(), N, control, target) else: uu = qstate('uu') ud = qstate('ud') du = qstate('du') dd = qstate('dd') Q = uu * uu.dag() + ud * du.dag() + du * ud.dag() + dd * dd.dag() return Q
def iswap(N=None, control=None, target=None, mask=None): """Quantum object representing the iSWAP gate. Returns ------- iswap_gate : qobj Quantum object representation of iSWAP gate Examples -------- >>> iswap() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = False Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+1.j 0.+0.j] [ 0.+0.j 0.+1.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]] """ if mask: warnings.warn("The mask argument to iswap is deprecated. " + "Use the N, control and target arguments instead.") if sum(mask) != 2: raise ValueError("mask must only have two ones, rest zeros") dims = [2] * len(mask) idx, = where(mask) N = prod(dims) data = sp.lil_matrix((N, N), dtype=complex) for s1 in state_number_enumerate(dims): i1 = state_number_index(dims, s1) if s1[idx[0]] == s1[idx[1]]: i2 = i1 val = 1.0 else: s2 = s1.copy() s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]] i2 = state_number_index(dims, s2) val = 1.0j data[i1, i2] = val return Qobj(data, dims=[dims, dims], shape=[N, N]) elif not N is None and not control is None and not target is None: return gate_expand_2toN(iswap(), N, control, target) else: return Qobj(array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]])
def swap(mask=None): """Quantum object representing the SWAP gate. Returns ------- swap_gate : qobj Quantum object representation of SWAP gate Examples -------- >>> swap() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]] """ if mask is None: uu = qstate('uu') ud = qstate('ud') du = qstate('du') dd = qstate('dd') Q = uu * uu.dag() + ud * du.dag() + du * ud.dag() + dd * dd.dag() return Qobj(Q) else: if sum(mask) != 2: raise ValueError("mask must only have two ones, rest zeros") dims = [2] * len(mask) idx, = where(mask) N = prod(dims) data = sp.lil_matrix((N, N)) for s1 in state_number_enumerate(dims): i1 = state_number_index(dims, s1) if s1[idx[0]] == s1[idx[1]]: i2 = i1 else: s2 = array(s1).copy() s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]] i2 = state_number_index(dims, s2) data[i1, i2] = 1 return Qobj(data, dims=[dims, dims], shape=[N, N])
def iswap(mask=None): """Quantum object representing the iSWAP gate. Returns ------- iswap_gate : qobj Quantum object representation of iSWAP gate Examples -------- >>> iswap() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = False Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+1.j 0.+0.j] [ 0.+0.j 0.+1.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]] """ if mask is None: return Qobj(array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]]) else: if sum(mask) != 2: raise ValueError("mask must only have two ones, rest zeros") dims = [2] * len(mask) idx, = where(mask) N = prod(dims) data = sp.lil_matrix((N, N), dtype=complex) for s1 in state_number_enumerate(dims): i1 = state_number_index(dims, s1) if s1[idx[0]] == s1[idx[1]]: i2 = i1 val = 1.0 else: s2 = s1.copy() s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]] i2 = state_number_index(dims, s2) val = 1.0j data[i1, i2] = val return Qobj(data, dims=[dims, dims], shape=[N, N])
def _partial_transpose_reference(rho, mask): """ This is a reference implementation that explicitly loops over all states and performs the transpose. It's slow but easy to understand and useful for testing. """ A_pt = np.zeros(rho.shape, dtype=complex) for psi_A in state_number_enumerate(rho.dims[0]): m = state_number_index(rho.dims[0], psi_A) for psi_B in state_number_enumerate(rho.dims[1]): n = state_number_index(rho.dims[1], psi_B) m_pt = state_number_index( rho.dims[1], np.choose(mask, [psi_A, psi_B])) n_pt = state_number_index( rho.dims[0], np.choose(mask, [psi_B, psi_A])) A_pt[m_pt, n_pt] = rho.data[m, n] return Qobj(A_pt, dims=rho.dims)
def update_rho(self, rho): """ calculate probability distribution for quadrature measurement outcomes given a two-mode density matrix """ X1, X2 = np.meshgrid(self.xvecs[0], self.xvecs[1]) p = np.zeros((len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) N = rho.dims[0][0] M1 = np.zeros((N, N, len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) M2 = np.zeros((N, N, len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) for m in range(N): for n in range(N): M1[m, n] = exp(-1j * self.theta1 * (m - n)) / \ sqrt(pi * 2 ** (m + n) * factorial(n) * factorial(m)) * \ exp(-X1 ** 2) * np.polyval( hermite(m), X1) * np.polyval(hermite(n), X1) M2[m, n] = exp(-1j * self.theta2 * (m - n)) / \ sqrt(pi * 2 ** (m + n) * factorial(n) * factorial(m)) * \ exp(-X2 ** 2) * np.polyval( hermite(m), X2) * np.polyval(hermite(n), X2) for n1 in range(N): for n2 in range(N): i = state_number_index([N, N], [n1, n2]) for p1 in range(N): for p2 in range(N): j = state_number_index([N, N], [p1, p2]) p += M1[n1, p1] * M2[n2, p2] * rho.data[i, j] self.data = p
def update_psi(self, psi): """ calculate probability distribution for quadrature measurement outcomes given a two-mode wavefunction """ X1, X2 = np.meshgrid(self.xvecs[0], self.xvecs[1]) p = np.zeros((len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) N = psi.dims[0][0] for n1 in range(N): kn1 = exp(-1j * self.theta1 * n1) / \ sqrt(sqrt(pi) * 2 ** n1 * factorial(n1)) * \ exp(-X1 ** 2 / 2.0) * np.polyval(hermite(n1), X1) for n2 in range(N): kn2 = exp(-1j * self.theta2 * n2) / \ sqrt(sqrt(pi) * 2 ** n2 * factorial(n2)) * \ exp(-X2 ** 2 / 2.0) * np.polyval(hermite(n2), X2) i = state_number_index([N, N], [n1, n2]) p += kn1 * kn2 * psi.data[i, 0] self.data = abs(p)**2
def update_psi(self, psi): """ calculate probability distribution for quadrature measurement outcomes given a two-mode wavefunction """ X1, X2 = np.meshgrid(self.xvecs[0], self.xvecs[1]) p = np.zeros((len(self.xvecs[0]), len(self.xvecs[1])), dtype=complex) N = psi.dims[0][0] for n1 in range(N): kn1 = exp(-1j * self.theta1 * n1) / \ sqrt(sqrt(pi) * 2 ** n1 * factorial(n1)) * \ exp(-X1 ** 2 / 2.0) * np.polyval(hermite(n1), X1) for n2 in range(N): kn2 = exp(-1j * self.theta2 * n2) / \ sqrt(sqrt(pi) * 2 ** n2 * factorial(n2)) * \ exp(-X2 ** 2 / 2.0) * np.polyval(hermite(n2), X2) i = state_number_index([N, N], [n1, n2]) p += kn1 * kn2 * psi.data[i, 0] self.data = abs(p) ** 2