def do_measurement(self, qubit: int) -> int: """ Measure a qubit, collapse the wavefunction, and return the measurement result. :param qubit: Index of the qubit to measure. :return: measured bit """ if self.rs is None: raise ValueError( "You have tried to perform a stochastic operation without setting the " "random state of the simulator. Might I suggest using a PyQVM object?" ) # lift projective measure operator to Hilbert space # prob(0) = <psi P0 | P0 psi> = psi* . P0* . P0 . psi measure_0 = lifted_gate_matrix(matrix=P0, qubit_inds=[qubit], n_qubits=self.n_qubits) proj_psi = measure_0 @ self.wf prob_zero = np.conj(proj_psi).T @ proj_psi # generate random number to 'roll' for measure if self.rs.uniform() < prob_zero: # decohere state using the measure_0 operator unitary = measure_0 @ (np.eye(2**self.n_qubits) / np.sqrt(prob_zero)) self.wf = unitary.dot(self.wf) return 0 else: # measure one measure_1 = lifted_gate_matrix(matrix=P1, qubit_inds=[qubit], n_qubits=self.n_qubits) unitary = measure_1 @ (np.eye(2**self.n_qubits) / np.sqrt(1 - prob_zero)) self.wf = unitary.dot(self.wf) return 1
def do_measurement(self, qubit: int) -> int: """ Measure a qubit and collapse the wavefunction :return: The measurement result. A 1 or a 0. """ if self.rs is None: raise ValueError( "You have tried to perform a stochastic operation without setting the " "random state of the simulator. Might I suggest using a PyQVM object?" ) measure_0 = lifted_gate_matrix(matrix=P0, qubit_inds=[qubit], n_qubits=self.n_qubits) prob_zero = np.trace(measure_0 @ self.density) # generate random number to 'roll' for measurement if self.rs.uniform() < prob_zero: # decohere state using the measure_0 operator unitary = measure_0 @ (np.eye(2**self.n_qubits) / np.sqrt(prob_zero)) self.density = unitary.dot(self.density).dot(np.conj(unitary.T)) return 0 else: # measure one measure_1 = lifted_gate_matrix(matrix=P1, qubit_inds=[qubit], n_qubits=self.n_qubits) unitary = measure_1 @ (np.eye(2**self.n_qubits) / np.sqrt(1 - prob_zero)) self.density = unitary.dot(self.density).dot(np.conj(unitary.T)) return 1
def test_lifted_gate_two_qubit(): test_unitary = lifted_gate(CNOT(0, 1), 4) true_unitary = lifted_gate_matrix(mat.CNOT, [0, 1], 4) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate(CNOT(1, 0), 4) true_unitary = lifted_gate_matrix(mat.CNOT, [1, 0], 4) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate(CNOT(1, 3), 4) true_unitary = lifted_gate_matrix(mat.CNOT, [1, 3], 4) assert np.allclose(test_unitary, true_unitary)
def test_two_qubit_gates_15(): unitary_test = lifted_gate_matrix(mat.SWAP, [3, 1], 4) swap_12 = np.kron(np.eye(2), np.kron(mat.SWAP, np.eye(2))) swapper = swap_12 V = np.kron(mat.SWAP, np.eye(4)) unitary_true = np.dot(np.conj(swapper.T), np.dot(V, swapper)) assert np.allclose(unitary_test, unitary_true)
def do_gate_matrix(self, matrix: np.ndarray, qubits: Sequence[int]): """ Apply an arbitrary unitary; not necessarily a named gate. :param matrix: The unitary matrix to apply. No checks are done. :param qubits: The qubits to apply the unitary to. :return: ``self`` to support method chaining. """ unitary = lifted_gate_matrix(matrix, list(qubits), n_qubits=self.n_qubits) self.wf = unitary.dot(self.wf) return self
def _term_expectation(wf, term: PauliTerm, n_qubits): # Computes <psi|XYZ..XXZ|psi> wf2 = wf for qubit_i, op_str in term._ops.items(): # Re-use QUANTUM_GATES since it has X, Y, Z op_mat = QUANTUM_GATES[op_str] op_mat = lifted_gate_matrix(matrix=op_mat, qubit_inds=[qubit_i], n_qubits=n_qubits) wf2 = op_mat @ wf2 # `wf2` is XYZ..XXZ|psi> # hit it with a <psi| i.e. `wf.dag` return term.coefficient * (wf.conj().T @ wf2)
def do_gate_matrix(self, matrix: np.ndarray, qubits: Sequence[int]) -> 'AbstractQuantumSimulator': """ Apply an arbitrary unitary; not necessarily a named gate. :param matrix: The unitary matrix to apply. No checks are done :param qubits: A list of qubits to apply the unitary to. :return: ``self`` to support method chaining. """ unitary = lifted_gate_matrix(matrix=matrix, qubit_inds=qubits, n_qubits=self.n_qubits) self.density = unitary.dot(self.density).dot(np.conj(unitary).T) return self
def do_post_gate_noise(self, noise_type: str, noise_prob: float, qubits: List[int]): kraus_ops = KRAUS_OPS[noise_type](p=noise_prob) if np.isclose(noise_prob, 0.0): warnings.warn(f"Skipping {noise_type} post-gate noise because noise_prob is close to 0") return self for q in qubits: new_density = np.zeros_like(self.density) for kraus_op in kraus_ops: lifted_kraus_op = lifted_gate_matrix(matrix=kraus_op, qubit_inds=[q], n_qubits=self.n_qubits) new_density += lifted_kraus_op.dot(self.density).dot(np.conj(lifted_kraus_op.T)) self.density = new_density return self
def test_two_qubit_gates_6(): unitary_test = lifted_gate_matrix(mat.ISWAP, [1, 0], 3) unitary_true = np.kron(np.eye(2), mat.ISWAP) assert np.allclose(unitary_test, unitary_true)
def test_single_qubit_gates_9(): test_unitary = lifted_gate_matrix(mat.H, [4], 5) true_unitary = np.kron(np.eye(2**0), np.kron(mat.H, np.eye(2**4))) assert np.allclose(test_unitary, true_unitary)
def test_single_qubit_gates_5(): test_unitary = lifted_gate_matrix(mat.H, [0], 5) true_unitary = np.kron(np.eye(2**4), mat.H) assert np.allclose(test_unitary, true_unitary)
def test_single_qubit_gates_4(): test_unitary = lifted_gate_matrix(mat.H, [3], 4) true_unitary = np.kron(mat.H, np.eye(8)) assert np.allclose(test_unitary, true_unitary)
def test_two_qubit_gates_1(): unitary_test = lifted_gate_matrix(mat.CNOT, [1, 0], 2) unitary_true = np.kron(mat.P0, np.eye(2)) + \ np.kron(mat.P1, mat.X) assert np.allclose(unitary_test, unitary_true)
def test_two_qubit_gates_9(): unitary_test = lifted_gate_matrix(mat.ISWAP, [2, 3], 4) unitary_true = np.kron(mat.ISWAP, np.eye(4)) assert np.allclose(unitary_test, unitary_true)
def test_two_qubit_gates_2(): unitary_test = lifted_gate_matrix(mat.CNOT, [0, 1], 2) unitary_true = np.kron(np.eye(2), mat.P0) + \ np.kron(mat.X, mat.P1) assert np.allclose(unitary_test, unitary_true)
def test_two_qubit_gates_4(): with pytest.raises(IndexError): lifted_gate_matrix(mat.CNOT, [2, 1], 2)
def test_two_qubit_gates_3(): unitary_test = lifted_gate_matrix(mat.CNOT, [2, 1], 3) unitary_true = np.kron(mat.CNOT, np.eye(2**1)) assert np.allclose(unitary_test, unitary_true)
def test_multiqubit_decay_bellstate(): program = Program(RY(np.pi / 3, 0), CNOT(0, 1)) # commence manually dotting the above program initial_density = np.zeros((4, 4), dtype=complex) initial_density[0, 0] = 1.0 gate_time_1q = 50e-9 T1 = 30e-6 T2 = 15e-6 p1 = 1 - np.exp(-gate_time_1q / T1) p2 = 1 - np.exp(-gate_time_1q / T2) # RY gate_1 = np.kron(np.eye(2), qmats.RY(np.pi / 3)) state = gate_1.dot(initial_density).dot(np.conj(gate_1).T) for ii in range(2): new_density = np.zeros_like(state) for kop in qmats.relaxation_operators(p1): operator = lifted_gate_matrix(matrix=kop, qubit_inds=[ii], n_qubits=2) new_density += operator.dot(state).dot(np.conj(operator).T) state = new_density for ii in range(2): new_density = np.zeros_like(state) for kop in qmats.dephasing_operators(p2): operator = lifted_gate_matrix(matrix=kop, qubit_inds=[ii], n_qubits=2) new_density += operator.dot(state).dot(np.conj(operator).T) state = new_density # CNOT # TODO: different 1q, 2q noise probabilities cnot_01 = np.kron(qmats.I, qmats.P0) + np.kron(qmats.X, qmats.P1) state = cnot_01.dot(state).dot(cnot_01.T) gate_time_2q = 150e-9 p1 = 1 - np.exp(-gate_time_2q / T1) p2 = 1 - np.exp(-gate_time_2q / T2) for ii in range(2): new_density = np.zeros_like(state) for kop in qmats.relaxation_operators(p1): operator = lifted_gate_matrix(matrix=kop, qubit_inds=[ii], n_qubits=2) new_density += operator.dot(state).dot(np.conj(operator).T) state = new_density for ii in range(2): new_density = np.zeros_like(state) for kop in qmats.dephasing_operators(p2): operator = lifted_gate_matrix(matrix=kop, qubit_inds=[ii], n_qubits=2) new_density += operator.dot(state).dot(np.conj(operator).T) state = new_density qam = PyQVM(n_qubits=2, quantum_simulator_type=ReferenceDensitySimulator, post_gate_noise_probabilities={ 'relaxation': p1, 'dephasing': p2 }) qam.execute(program) assert np.allclose(qam.wf_simulator.density, state)
def test_two_qubit_gates_7(): unitary_test = lifted_gate_matrix(mat.ISWAP, [1, 2], 4) unitary_true = np.kron(np.eye(2), np.kron(mat.ISWAP, np.eye(2))) assert np.allclose(unitary_test, unitary_true)