def test_single_qubit_operation(self): N = 6 # Test single qubit operation psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0][0] = 1 # Apply sigma_y on the second qubit to get 1j|020000> psi0 = rydberg.multiply(psi0, [1], rydberg.Y) self.assertTrue(psi0[(rydberg.d - 1) * rydberg.d**(N - 2), 0] == 1j) # Apply sigma_z on the second qubit, codes is -1j|010000> psi0 = rydberg.multiply(psi0, [1], rydberg.Z) self.assertTrue(psi0[(rydberg.d - 1) * rydberg.d**(N - 2), 0] == -1j) # Apply sigma_x on qubits psi0 = rydberg.multiply(psi0, [0, 2, 3, 4, 5], tools.tensor_product([rydberg.X] * (N - 1))) # Vector is still normalized self.assertTrue(np.vdot(psi0, psi0) == 1) # Should be -1j|111111> self.assertTrue(psi0[-1, 0] == -1j) # Test rydberg operations with density matrices psi1 = np.array([ tools.tensor_product([np.array([1, 0, 1]), np.array([1, 0, 0])]) / 2**(1 / 2) ]).T psi1 = State(tools.outer_product(psi1, psi1), code=rydberg) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1, 0, -1], [1, 0, 0]) * -1j / 2**(1 / 2)]).T rho2 = tools.outer_product(psi2, psi2) psi1 = rydberg.multiply(psi1, [0], ['Y']) self.assertTrue(np.linalg.norm(psi1 - rho2) <= 1e-10) psi0 = np.array([ tools.tensor_product([np.array([1, 0, 1]), np.array([1, 0, 0])]) / 2**(1 / 2) ]).T psi0 = State(tools.outer_product(psi0, psi0), code=rydberg) psi1 = State(psi0.copy(), code=rydberg) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1, 0, -1], [1, 0, 0]) * -1j / 2**(1 / 2)]).T psi2 = tools.outer_product(psi2, psi2) # Apply single qubit operation to dmatrix psi0 = rydberg.multiply(psi0, [0], rydberg.Y) self.assertTrue(np.linalg.norm(psi0 - psi2) <= 1e-10) # Test on ket psi1 = rydberg.multiply(psi1, [0], rydberg.Y) self.assertTrue(np.linalg.norm(psi1 - psi2) <= 1e-10)
def test_multi_qubit(self): n = 5 psi0 = State( tools.tensor_product([jordan_farhi_shor.logical_basis[0]] * n)) psi1 = psi0.copy() op = tools.tensor_product( [jordan_farhi_shor.X, jordan_farhi_shor.Y, jordan_farhi_shor.Z]) psi0 = jordan_farhi_shor.multiply(psi0, [1, 3, 4], op) psi1 = jordan_farhi_shor.multiply(psi1, [1, 3, 4], ['X', 'Y', 'Z']) self.assertTrue(np.allclose(psi0, psi1))
def rotation(state: State, apply_to: Union[int, list], angle: float, op, is_involutary=False, is_idempotent=False): """ Apply a single qubit rotation :math:`e^{-i \\alpha A}` to the input ``codes``. :param apply_to: :param is_idempotent: :param is_involutary: :param state: input wavefunction or density matrix :type state: np.ndarray :param angle: The angle :math:`\\alpha`` to rotate by. :type angle: float :param op: Operator to act with. :type op: np.ndarray """ if isinstance(apply_to, int): apply_to = [apply_to] if not isinstance(op, list): op = [op] # Type handling: to determine if Pauli, check if a list of strings pauli = False if isinstance(op, list): if all(isinstance(elem, str) for elem in op): pauli = True else: op = tools.tensor_product(op) if pauli: # Construct operator to use temp = [] for i in range(len(op)): if op[i] == 'X': temp.append(X) elif op[i] == 'Y': temp.append(Y) elif op[i] == 'Z': temp.append(Z) temp = tools.tensor_product(temp) temp = np.cos(angle) * np.identity( temp.shape[0]) - temp * 1j * np.sin(angle) return multiply(state, apply_to, temp) else: if is_involutary: op = np.cos(angle) * np.identity( op.shape[0]) - op * 1j * np.sin(angle) return multiply(state, apply_to, op) elif is_idempotent: op = (np.exp(-1j * angle) - 1) * op + np.identity(op.shape[0]) return multiply(state, apply_to, op) else: return multiply(state, apply_to, expm(-1j * angle * op))
def test_multi_qubit(self): N = 5 psi0 = State( tools.tensor_product([two_qubit_code.logical_basis[0]] * N)) psi1 = psi0.copy() op = tools.tensor_product( [two_qubit_code.X, two_qubit_code.Y, two_qubit_code.Z]) psi0 = two_qubit_code.multiply(psi0, [1, 3, 4], op) psi1 = two_qubit_code.multiply(psi1, [1, 3, 4], ['X', 'Y', 'Z']) self.assertTrue(np.allclose(psi0, psi1))
def test_single_qubit_multiply_pauli(self): # Tests single qubit operation given a pauli index N = 6 # Initialize in |000000> psi0 = State(np.zeros((2 ** N, 1))) psi0[0,0] = 1 # Apply sigma_y on the second qubit to get 1j|010000> # Check Typing psi0 = qubit.multiply(psi0, 1, 'Y') self.assertTrue(psi0[2 ** (N - 2), 0] == 1j) # Apply sigma_z on the second qubit, codes is -1j|010000> psi0 = qubit.multiply(psi0, [1], 'Z') self.assertTrue(psi0[2 ** (N - 2), 0] == -1j) # Apply sigma_x on all qubits but 1 psi0 = qubit.multiply(psi0, [0, 2, 3, 4, 5], ['X'] * (N - 1)) # Vector is still normalized self.assertTrue(np.vdot(psi0, psi0) == 1) # Should be -1j|111111> self.assertTrue(psi0[-1, 0] == -1j) # Density matrix test psi1 = np.array([tools.tensor_product([np.array([1, 1]), np.array([1, 0])]) / 2 ** (1 / 2)]).T psi1 = State(tools.outer_product(psi1, psi1)) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1j, -1j], [1, 0]) / 2 ** (1 / 2)]).T rho2 = tools.outer_product(psi2, psi2) psi1 = qubit.multiply(psi1, [0], 'Y') self.assertTrue(np.linalg.norm(psi1 - rho2) <= 1e-10)
def cost_function(G, penalty): global N sigma_plus = np.array([1, 0]) rr = np.array([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) C = np.zeros([2**N]) myeye = lambda n: np.ones(np.asarray(sigma_plus.shape[0])**n) for i, j in G.edges: temp = tools.tensor_product([rr, tools.identity(N - 2)]) temp = np.reshape(temp, 2 * np.ones(2 * N, dtype=int)) temp = np.moveaxis(temp, [0, 1, N, N + 1], [i, j, N + i, N + j]) temp = np.reshape(temp, (2**N, 2**N)) C = C + np.diagonal(temp) * penalty * -1 for c in G.nodes: C = C + tools.tensor_product([myeye(c), sigma_plus, myeye(N - c - 1)]) return C
def test_single_qubit(self): psi0 = State( tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[0] ])) psi1 = psi0.copy() # Density matrix test psi2 = State(tools.outer_product(psi1, psi1)) psi0 = three_qubit_code.multiply(psi0, [1], ['Y']) # Test non-pauli operation psi1 = three_qubit_code.multiply(psi1, [1], three_qubit_code.Y) psi2 = three_qubit_code.multiply(psi2, [1], three_qubit_code.Y) res = 1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[1] ]) # Should get out 1j|0L>|1L> self.assertTrue(np.allclose(psi0, res)) self.assertTrue(np.allclose(psi1, res)) self.assertTrue(np.allclose(psi2, tools.outer_product(res, res))) self.assertTrue( np.allclose( three_qubit_code.multiply(psi0, [1], ['Z']), -1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[1] ]))) psi0 = three_qubit_code.multiply(psi0, [0], ['X']) # Should get out -1j|1L>|1L> self.assertTrue( np.allclose( psi0, 1j * tools.tensor_product([ three_qubit_code.logical_basis[1], three_qubit_code.logical_basis[1] ]))) # Rotate all qubits for i in range(2): psi0 = three_qubit_code.rotation(psi0, [i], np.pi / 2, three_qubit_code.X) self.assertTrue( np.allclose( psi0, -1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[0] ])))
def __init__(self, graph: nx.Graph, IS_penalty=1, code=None): self.graph = graph if code is None: code = qubit self.code = code self.N = self.graph.number_of_nodes() self.IS_penalty = IS_penalty # Construct jump operators for edges and nodes # node = (np.identity(self.code.d * self.code.n) - self.code.Z) / 2 # edge = self.IS_penalty * tools.tensor_product([self.code.U, self.code.U]) node = self.code.X @ (np.identity(self.code.d * self.code.n) - self.code.Z) / 2 edge = self.IS_penalty * (tools.tensor_product([ self.code.X, np.identity(self.code.d * self.code.n) ]) + tools.tensor_product([ np.identity(self.code.d * self.code.n), self.code.X ])) @ tools.tensor_product([self.code.U, self.code.U]) / 2 self.jump_operators = [node, edge]
def test_multi_qubit_operation(self): N = 6 psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0, 0] = 1 psi1 = psi0.copy() op = tools.tensor_product([rydberg.X, rydberg.Y, rydberg.Z]) psi0 = rydberg.multiply(psi0, [1, 3, 4], op) psi1 = rydberg.multiply(psi1, [1], 'X') psi1 = rydberg.multiply(psi1, [3], 'Y') psi1 = rydberg.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1))
def IS_projector(G): global N rr = np.array([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) C = np.identity(2**N) for i, j in G.edges: temp = tools.tensor_product([rr, tools.identity(N - 2)]) temp = np.reshape(temp, 2 * np.ones(2 * N, dtype=int)) temp = np.moveaxis(temp, [0, 1, N, N + 1], [i, j, N + i, N + j]) temp = np.reshape(temp, (2**N, 2**N)) C = C @ (np.identity(2**N) - temp) return C
def test_multi_qubit_pauli(self): N = 6 psi0 = np.zeros((2 ** N, 1), dtype=np.complex128) psi0[0, 0] = 1 psi1 = State(psi0) psi2 = State(psi0) psi3 = State(psi0) psi4 = State(psi0) psi0 = State(psi0) psi0 = qubit.multiply(psi0, [1, 3, 4], ['X', 'Y', 'Z']) psi2 = qubit.multiply(psi2, [4, 1, 3], ['Z', 'X', 'Y']) psi3 = qubit.multiply(psi3, [1, 3, 4], tools.tensor_product([qubit.X, qubit.Y, qubit.Z])) psi4 = qubit.multiply(psi4, [4, 1, 3], tools.tensor_product([qubit.Z, qubit.X, qubit.Y])) psi1 = qubit.multiply(psi1, [1], 'X') psi1 = qubit.multiply(psi1, [3], 'Y') psi1 = qubit.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1)) self.assertTrue(np.allclose(psi1, psi2)) self.assertTrue(np.allclose(psi2, psi3)) self.assertTrue(np.allclose(psi3, psi4))
def test_multi_qubit_multiply(self): N = 6 psi0 = np.zeros((2 ** N, 1), dtype=np.complex128) psi0[0, 0] = 1 psi1 = State(psi0) psi0 = State(psi0) op = tools.tensor_product([qubit.X, qubit.Y, qubit.Z]) psi0 = qubit.multiply(psi0, [1, 3, 4], op) psi1 = qubit.multiply(psi1, [1], 'X') psi1 = qubit.multiply(psi1, [3], 'Y') psi1 = qubit.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1))
def ham_term(*argv): def decode(code): if code == 'i': return np.identity(2) if code == 'x': return tools.X() if code == 'y': return tools.Y() if code == 'z': return tools.Z() return tools.tensor_product([decode(arg) for arg in argv])
def adiabatic_hamiltonian(t, tf): graph, mis = line_graph(n=n) ham = np.zeros((2**n, 2**n)) coefficients = adiabatic_schedule(t, tf) rydberg_energy = 50 rydberg_hamiltonian = hamiltonian.HamiltonianMIS(graph, energy=rydberg_energy, code=qubit) # TODO: generalize this! if n == 3: ham = ham + coefficients[1] * tools.tensor_product( [qubit.Z, np.identity(2), np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), qubit.Z, np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), np.identity(2), qubit.Z]) ham = ham + coefficients[0] * tools.tensor_product( [qubit.X, np.identity(2), np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), qubit.X, np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), np.identity(2), qubit.X]) ham = ham + np.diag(rydberg_hamiltonian.hamiltonian.T[0]) elif n == 2: ham = ham + coefficients[1] * tools.tensor_product( [qubit.Z, np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), qubit.Z]) ham = ham + coefficients[0] * tools.tensor_product( [qubit.X, np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), qubit.X]) ham = ham + np.diag(rydberg_hamiltonian.hamiltonian.T[0]) return np.linalg.eig(ham)
def test_multi_qubit_pauli(self): N = 6 psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0, 0] = 1 psi1 = psi0.copy() psi2 = psi0.copy() psi3 = psi0.copy() psi4 = psi0.copy() psi0 = rydberg.multiply(psi0, [1, 3, 4], ['X', 'Y', 'Z']) psi1 = rydberg.multiply(psi1, [1], 'X') psi1 = rydberg.multiply(psi1, [3], 'Y') psi1 = rydberg.multiply(psi1, [4], 'Z') psi2 = rydberg.multiply(psi2, [4, 1, 3], ['Z', 'X', 'Y']) psi3 = rydberg.multiply( psi3, [1, 3, 4], tools.tensor_product([rydberg.X, rydberg.Y, rydberg.Z])) psi4 = rydberg.multiply( psi4, [4, 1, 3], tools.tensor_product([rydberg.Z, rydberg.X, rydberg.Y])) self.assertTrue(np.allclose(psi0, psi1)) self.assertTrue(np.allclose(psi1, psi2)) self.assertTrue(np.allclose(psi2, psi3)) self.assertTrue(np.allclose(psi3, psi4))
def multiply(state: State, apply_to: Union[int, list], op): """ Apply a multi-qubit operator on several qubits (indexed in apply_to) of the input codes. :param state: input wavefunction or density matrix :type state: np.ndarray :param apply_to: zero-based indices of qudit locations to apply the operator :type apply_to: list of int :param op: Operator to act with. :type op: np.ndarray (2-dimensional) """ if isinstance(apply_to, int): apply_to = [apply_to] if not isinstance(op, list): op = [op] # Type handling: to determine if Pauli, check if a list of strings pauli = False if isinstance(op, list): if all(isinstance(elem, str) for elem in op): pauli = True else: op = tools.tensor_product(op) if not state.is_ket: if pauli: out = state.copy() for i in range(len(apply_to)): # Note index start from the right (sN,...,s3,s2,s1) # Note index start from the right (sN,...,s3,s2,s1) if op[i] == 'X': # Sigma_X out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 2], ['Y', 'Y']) elif op[i] == 'Y': # Sigma_Y out = -1 * qubit.left_multiply( out, [n * apply_to[i] + 1, n * apply_to[i] + 2], ['X', 'X']) elif op[i] == 'Z': # Sigma_Z out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 1], ['Z', 'Z']) return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code) else: return right_multiply(left_multiply(state, apply_to, op), apply_to, op) else: return left_multiply(state, apply_to, op)
def multiply(state: State, apply_to: Union[int, list], op): """ Apply a multi-qubit operator on several qubits (indexed in apply_to) of the input codes. :param state: input wavefunction or density matrix :type state: np.ndarray :param apply_to: zero-based indices of qudit locations to apply the operator :type apply_to: list of int :param op: Operator to act with. :type op: np.ndarray (2-dimensional) """ if isinstance(apply_to, int): apply_to = [apply_to] if not isinstance(op, list): op = [op] # Type handling: to determine if Pauli, check if a list of strings pauli = False if isinstance(op, list): if all(isinstance(elem, str) for elem in op): pauli = True else: op = tools.tensor_product(op) if not state.is_ket: if pauli: out = state.copy() for i in range(len(apply_to)): ind = d ** apply_to[i] out = out.reshape((-1, d, d ** (state.number_physical_qudits - 1), d, ind), order='F') if op[i] == 'X': # Sigma_X out = np.flip(out, axis=(1, 3)) elif op[i] == 'Y': # Sigma_Y out = np.flip(out, axis=(1, 3)) out[:, d - 1, :, 0, :] = -out[:, d - 1, :, 0, :] out[:, 0, :, d - 1, :] = -out[:, 0, :, d - 1, :] elif op[i] == 'Z': # Sigma_Z out[:, d - 1, :, 0, :] = -out[:, d - 1, :, 0, :] out[:, 0, :, d - 1, :] = -out[:, 0, :, d - 1, :] out = out.reshape(state.shape, order='F') return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code) else: return right_multiply(left_multiply(state, apply_to, op), apply_to, op) else: return left_multiply(state, apply_to, op)
def __init__(self, graph: nx.Graph, rate): super().__init__(jump_operators=[ np.array([[0, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]), np.array([[0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0]]), np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0]]) ], weights=rate) # Construct the right jump_operators operators self.code = qubit self.graph = graph self.N = self.graph.number_of_nodes() jump_operators = [] for (i, j) in graph.edges: for p in range(len(self.jump_operators)): temp = tools.tensor_product( [self.jump_operators[p], tools.identity(self.N - 2)]) temp = np.reshape(temp, 2 * np.ones(2 * self.N, dtype=int)) temp = np.moveaxis(temp, [0, 1, self.N, self.N + 1], [i, j, self.N + i, self.N + j]) temp = np.reshape(temp, (2**self.N, 2**self.N)) jump_operators.append(temp) self.jump_operators = jump_operators
import numpy as np from qsim.codes import qubit from qsim.codes.quantum_state import State from qsim import tools import time from scipy.linalg import expm from scipy.sparse.linalg import expm_multiply from scipy.sparse import csr_matrix n = 10 print('Timer test with', n, 'qubits') Hb = np.zeros((2**n, 2**n), dtype=int) for i in range(n): Hb = Hb + tools.tensor_product( [tools.identity(i), qubit.X, tools.identity(n - i - 1)]) # Make sparse matrix for Hb Hb_sparse = csr_matrix(Hb) psi0 = State(np.zeros((2**n, 1))) psi0[-1, -1] = 1 t0 = time.perf_counter() res = expm_multiply(Hb, psi0) t1 = time.perf_counter() print('scipy expm_multiply with non-sparse matrix: ', t1 - t0) res = expm(Hb) @ psi0 t2 = time.perf_counter() print('numpy expm with non-spares matrix: ', t2 - t1) res = expm_multiply(Hb_sparse, psi0) t3 = time.perf_counter()
def left_multiply(state: State, apply_to: Union[int, list], op): """ Apply a multi-qubit operator on several qubits (indexed in apply_to) of the input codes. :param state: input wavefunction or density matrix :type state: np.ndarray :param apply_to: zero-based indices of qudit locations to apply the operator :type apply_to: list of int :param op: Operator to act with. :type op: np.ndarray (2-dimensional) """ if isinstance(apply_to, int): apply_to = [apply_to] if not isinstance(op, list): op = [op] # Type handling: to determine if Pauli, check if a list of strings pauli = False if isinstance(op, list): if all(isinstance(elem, str) for elem in op): pauli = True else: op = tools.tensor_product(op) n_op = len(apply_to) if not pauli: if tools.is_sorted(apply_to): # Generate all shapes for left multiplication preshape = (d**n) * np.ones((2, n_op), dtype=int) preshape[1, 0] = int(state.dimension / ((d**n)**(1 + apply_to[n_op - 1]))) if n_op > 1: preshape[1, 1:] = np.flip((d**n)**np.diff(apply_to)) / (d**n) shape1 = np.zeros(2 * n_op + 1, dtype=int) shape2 = np.zeros(2 * n_op + 1, dtype=int) order1 = np.zeros(2 * n_op + 1, dtype=int) order2 = np.zeros(2 * n_op + 1, dtype=int) shape1[:-1] = np.flip(preshape, axis=0).reshape((2 * n_op), order='F') shape1[-1] = -1 shape2[:-1] = preshape.reshape((-1), order='C') shape2[-1] = -1 preorder = np.arange(2 * n_op) order1[:-1] = np.flip(preorder.reshape((-1, 2), order='C'), axis=1).reshape((-1), order='F') order2[:-1] = np.flip(preorder.reshape((2, -1), order='C'), axis=0).reshape((-1), order='F') order1[-1] = 2 * n_op order2[-1] = 2 * n_op # Now left multiply out = state.reshape(shape1, order='F').transpose(order1) out = np.dot(op, out.reshape(((d**n)**n_op, -1), order='F')) out = out.reshape(shape2, order='F').transpose(order2) out = out.reshape(state.shape, order='F') return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code) else: # Need to reshape the operator given new_shape = (d**n) * np.ones(2 * n_op, dtype=int) permut = np.argsort(apply_to) transpose_ord = np.zeros(2 * n_op, dtype=int) transpose_ord[:n_op] = permut transpose_ord[n_op:] = n_op * np.ones(n_op, dtype=int) + permut sorted_op = np.reshape(np.transpose(np.reshape(op, new_shape, order='F'), axes=transpose_ord), ((d**n)**n_op, (d**n)**n_op), order='F') sorted_apply_to = apply_to[permut] return left_multiply(state, sorted_apply_to, sorted_op) else: # op should be a list of Pauli operators, or out = state.copy() for i in range(len(apply_to)): if op[i] == 'X': # Sigma_X out = qubit.left_multiply(out, [n * apply_to[i]], ['X']) elif op[i] == 'Y': # Sigma_Y out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 1], ['Y', 'Z']) elif op[i] == 'Z': # Sigma_Z out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 1], ['Z', 'Z']) return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code)
def right_multiply(state: State, apply_to: Union[int, list], op): """ Apply a multi-qubit operator on several qubits (indexed in apply_to) of the input codes. :param state: input wavefunction or density matrix :type state: np.ndarray :param apply_to: zero-based indices of qudit locations to apply the operator :type apply_to: list of int :param op: Operator to act with. :type op: np.ndarray (2-dimensional) """ if isinstance(apply_to, int): apply_to = [apply_to] if not isinstance(op, list): op = [op] # Type handling: to determine if Pauli, check if a list of strings pauli = False if isinstance(op, list): if all(isinstance(elem, str) for elem in op): pauli = True else: op = tools.tensor_product(op) if state.is_ket: print( 'Warning: right multiply functionality currently applies the operator and daggers the s.' ) n_op = len(apply_to) if not pauli: if tools.is_sorted(apply_to): # generate necessary shapes preshape = (d**n) * np.ones((2, n_op), dtype=int) preshape[0, 0] = int(state.dimension / ((d**n)**(1 + apply_to[n_op - 1]))) if n_op > 1: preshape[0, 1:] = np.flip((d**n)**np.diff(apply_to)) / (d**n) shape3 = np.zeros(2 * n_op + 2, dtype=int) shape3[0] = state.dimension shape3[1:-1] = np.reshape(preshape, (2 * n_op), order='F') shape3[-1] = -1 shape4 = np.zeros(2 * n_op + 2, dtype=int) shape4[0] = state.dimension shape4[1:n_op + 1] = preshape[0] shape4[n_op + 1] = -1 shape4[n_op + 2:] = preshape[1] order3 = np.zeros(2 * n_op + 2, dtype=int) order3[0] = 0 order3[1:n_op + 2] = 2 * np.arange(n_op + 1) + np.ones(n_op + 1) order3[n_op + 2:] = 2 * np.arange(1, n_op + 1) order4 = np.zeros(2 * n_op + 2, dtype=int) order4[0] = 0 order4[1] = 1 order4[2:] = np.flip(np.arange(2, 2 * n_op + 2).reshape((2, -1), order='C'), axis=0).reshape((-1), order='F') # right multiply out = state.reshape(shape3, order='F').transpose(order3) out = np.dot(out.reshape((-1, (d**n)**n_op), order='F'), op.conj().T) out = out.reshape(shape4, order='F').transpose(order4) out = out.reshape(state.shape, order='F') return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code) else: new_shape = 2 * np.ones(2 * n_op, dtype=int) permut = np.argsort(apply_to) transpose_ord = np.zeros(2 * n_op, dtype=int) transpose_ord[:n_op] = permut transpose_ord[n_op:] = n_op * np.ones(n_op, dtype=int) + permut sorted_op = np.reshape(np.transpose(np.reshape(op, new_shape, order='F'), axes=transpose_ord), ((d**n)**n_op, (d**n)**n_op), order='F') sorted_apply_to = apply_to[permut] return right_multiply(state, sorted_apply_to, sorted_op) else: out = state.copy() for i in range(len(apply_to)): # Note index start from the right (sN,...,s3,s2,s1) if op[i] == 'X': # Sigma_X out = qubit.left_multiply(out, [n * apply_to[i]], ['X']) elif op[i] == 'Y': # Sigma_Y out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 1], ['Y', 'Z']) elif op[i] == 'Z': # Sigma_Z out = qubit.left_multiply( out, [n * apply_to[i], n * apply_to[i] + 1], ['Z', 'Z']) return State(out, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code)
import numpy as np from qsim import tools from . import qubit from scipy.linalg import expm from qsim.codes.quantum_state import State from typing import Union __all__ = ['multiply', 'right_multiply', 'left_multiply', 'rotation'] logical_code = True X = tools.tensor_product([tools.X(), tools.identity()]) Y = tools.tensor_product([tools.Y(), tools.Z()]) Z = tools.tensor_product([tools.Z(), tools.Z()]) n = 2 d = 2 logical_basis = np.array([[[1], [0], [0], [1]], [[0], [1], [1], [0]]]).astype( np.complex128) / np.sqrt(2) Q = 1 / 2 * (np.identity(d**n) + Z) P = 1 / 2 * (np.identity(d**n) - Z) code_space_projector = tools.outer_product( logical_basis[0], logical_basis[0]) + tools.outer_product( logical_basis[1], logical_basis[1]) def rotation(state: State, apply_to: Union[int, list], angle: float, op, is_involutary=False,
def ground_overlap(state): g = np.array([[0, 0], [0, 1]]) op = tools.tensor_product([g] * graph.number_of_nodes()) return np.real(np.trace(op @ state))
import numpy as np from qsim import tools from . import qubit from scipy.linalg import expm from qsim.codes.quantum_state import State from typing import Union """ :class:`ThreeQubitCode` is an error correcting code which can correct bit flip (X-type) errors. """ __all__ = ['multiply', 'right_multiply', 'left_multiply', 'rotation'] logical_code = True X = tools.tensor_product([tools.X(), tools.X(), tools.X()]) Y = -1 * tools.tensor_product([tools.Y(), tools.Y(), tools.Y()]) Z = tools.tensor_product([tools.Z(), tools.Z(), tools.Z()]) n = 3 d = 2 logical_basis = np.array([[[1], [0], [0], [0], [0], [0], [0], [0]], [[0], [0], [0], [0], [0], [0], [0], [1]]], dtype=np.complex128) Q = 1/2*(np.identity(d**n)+Z) P = 1/2*(np.identity(d**n)-Z) code_space_projector = tools.outer_product(logical_basis[0], logical_basis[0]) + tools.outer_product(logical_basis[1], logical_basis[1]) stabilizers = np.array( [tools.tensor_product([tools.Z(2), tools.identity()]), tools.tensor_product([tools.identity(), tools.Z(2)])]) def rotation(state: State, apply_to: Union[int, list], angle: float, op, is_involutary=False, is_idempotent=False): """