def test_xyx(self): """Exercise 4.7 in Nielson, Chuang, XYX == -Y.""" x = ops.PauliX() y = ops.PauliY() op = x(y(x)) self.assertTrue(op.is_close(-1.0 * ops.PauliY()))
def run_single_qubit_mult(): """Run experiments with single qubits.""" # Construct Hamiltonian. hamil = (random.random() * ops.PauliX() + random.random() * ops.PauliY() + random.random() * ops.PauliZ()) # Compute known minimum eigenvalue. eigvals = np.linalg.eigvalsh(hamil) # Brute force over the Bloch sphere. min_val = 1000.0 for i in range(0, 180, 10): for j in range(0, 180, 10): theta = np.pi * i / 180.0 phi = np.pi * j / 180.0 # Build the ansatz with two rotation gates. ansatz = single_qubit_ansatz(theta, phi) # Compute <psi ! H ! psi>. Find smallest one, which will be # the best approximation to the minimum eigenvalue from above. # In this version, we just multiply out the result. psi = np.dot(ansatz.psi.adjoint(), hamil(ansatz.psi)) if psi < min_val: min_val = psi # Result from brute force approach: print('Minimum: {:.4f}, Estimated: {:.4f}, Delta: {:.4f}'.format( eigvals[0], np.real(min_val), np.real(min_val - eigvals[0])))
def test_equalities(self): """Exercise 4.13 in Nielson, Chuang.""" _, x, y, z = ops.Pauli() h = ops.Hadamard() op = h(x(h)) self.assertTrue(op.is_close(ops.PauliZ())) op = h(y(h)) self.assertTrue(op.is_close(-1.0 * ops.PauliY())) op = h(z(h)) self.assertTrue(op.is_close(ops.PauliX())) op = x(z) self.assertTrue(op.is_close(1.0j * ops.PauliY()))
def test_bell_and_pauli(self): b00 = bell.bell_state(0, 0) bell_xz = ops.PauliX()(b00) bell_xz = ops.PauliZ()(bell_xz) bell_iy = (1j * ops.PauliY())(b00) self.assertTrue(np.allclose(bell_xz, bell_iy))
def single_qubit(): """Compute Pauli representation of single qubit.""" for i in range(10): # First we construct a circuit with just one, very random qubit. # qc = circuit.qc('random qubit') qc.qubit(random.random()) qc.rx(0, math.pi * random.random()) qc.ry(0, math.pi * random.random()) qc.rz(0, math.pi * random.random()) # Every qubit (rho) can be put in the Pauli Representation, # which is this Sum over i from 0 to 3 inclusive, representing # the four Pauli matrices (including the Identity): # # 3 # rho = 1/2 * Sum(c_i * Pauli_i) # i=0 # # To compute the various factors c_i, we multiply the Pauli # matrices with the density matrix and take the trace. This # trace is the computed factor: # rho = qc.psi.density() i = np.trace(ops.Identity() @ rho) x = np.trace(ops.PauliX() @ rho) y = np.trace(ops.PauliY() @ rho) z = np.trace(ops.PauliZ() @ rho) # Let's verify the result and construct a density matrix # from the Pauli matrices using the computed factors: # new_rho = 0.5 * (i * ops.Identity() + x * ops.PauliX() + y * ops.PauliY() + z * ops.PauliZ()) if not np.allclose(rho, new_rho): raise AssertionError('Invalid Pauli Representation') print(f'qubit({qc.psi[0]:11.2f}, {qc.psi[1]:11.2f}) = ', end='') print(f'{i:11.2f} I + {x:11.2f} X + {y:11.2f} Y + {z:11.2f} Z')
def test_acceleration(self): psi = state.bitstring(1, 0, 1, 0) qc = circuit.qc() qc.bitstring(1, 0, 1, 0) for i in range(4): qc.x(i) psi.apply(ops.PauliX(), i) qc.y(i) psi.apply(ops.PauliY(), i) qc.z(i) psi.apply(ops.PauliZ(), i) qc.h(i) psi.apply(ops.Hadamard(), i) if i: qc.cu1(0, i, 1.1) psi.apply_controlled(ops.U1(1.1), 0, i) if not psi.is_close(qc.psi): raise AssertionError('Numerical Problems') psi = state.bitstring(1, 0, 1, 0, 1) qc = circuit.qc() qc.bitstring(1, 0, 1, 0, 1) for n in range(5): qc.h(n) psi.apply(ops.Hadamard(), n) for i in range(0, 5): qc.cu1(n - (i + 1), n, math.pi / float(2**(i + 1))) psi.apply_controlled(ops.U1(math.pi / float(2**(i + 1))), n - (i + 1), n) for i in range(0, 5): qc.cu1(n - (i + 1), n, -math.pi / float(2**(i + 1))) psi.apply_controlled(ops.U1(-math.pi / float(2**(i + 1))), n - (i + 1), n) qc.h(n) psi.apply(ops.Hadamard(), n) if not psi.is_close(qc.psi): raise AssertionError('Numerical Problems')
def run_single_qubit_measure(): """Run measurement experiments with single qubits.""" # Construct Hamiltonian. a = random.random() b = random.random() c = random.random() hamil = (a * ops.PauliX() + b * ops.PauliY() + c * ops.PauliZ()) # Compute known minimum eigenvalue. eigvals = np.linalg.eigvalsh(hamil) min_val = 1000.0 for i in range(0, 360, 5): for j in range(0, 180, 5): theta = np.pi * i / 360.0 phi = np.pi * j / 180.0 # X Basis qc = single_qubit_ansatz(theta, phi) qc.h(0) val_a = a * qc.pauli_expectation(0) # Y Basis qc = single_qubit_ansatz(theta, phi) qc.sdag(0) qc.h(0) val_b = b * qc.pauli_expectation(0) # Z Basis qc = single_qubit_ansatz(theta, phi) val_c = c * qc.pauli_expectation(0) expectation = val_a + val_b + val_c if expectation < min_val: min_val = expectation print('Minimum eigenvalue: {:.3f}, Delta: {:.3f}'.format( eigvals[0], min_val - eigvals[0]))
def y(self, idx: int): self.apply1(ops.PauliY(), idx, 'y')
def cy(self, idx0: int, idx1: int): self.applyc(ops.PauliY(), idx0, idx1, 'cy')
def test_unitary(self): self.assertTrue(ops.PauliX().is_unitary()) self.assertTrue(ops.PauliY().is_unitary()) self.assertTrue(ops.PauliZ().is_unitary()) self.assertTrue(ops.Identity().is_unitary())
def test_yroot_gate(self): """Test that Yroot^2 == Y.""" t = ops.Yroot() self.assertTrue(t(t).is_close(ops.PauliY()))
def cy(self, idx0, idx1): self.apply_controlled(ops.PauliY(), idx0, idx1, 'cy')
def two_qubit(): """Compute Pauli representation for two-qubit system.""" for iteration in range(10): # First we construct a circuit with two, very random qubits. # qc = circuit.qc('random qubit') qc.qubit(random.random()) qc.qubit(random.random()) # Potentially entangle them. qc.h(0) qc.cx(0, 1) # Additionally rotate around randomly. for i in range(2): qc.rx(i, math.pi * random.random()) qc.ry(i, math.pi * random.random()) qc.rz(i, math.pi * random.random()) # Compute density matrix. rho = qc.psi.density() # Every rho can be put in the 2-qubit Pauli representation, # which is this Sum over i, j from 0 to 3 inclusive, representing # the four Pauli matrices (including the Identity): # # 3 # rho = 1/4 * Sum(c_ij * Pauli_i kron Pauli_j) # i,j=0 # # To compute the various factors c_ij, we multiply the Pauli # tensor products with the density matrix and take the trace. This # trace is the computed factor: # paulis = [ops.Identity(), ops.PauliX(), ops.PauliY(), ops.PauliZ()] c = np.zeros((4, 4), dtype=np.complex64) for i in range(4): for j in range(4): tprod = paulis[i] * paulis[j] c[i][j] = np.trace(rho @ tprod) # To test whether the two qubits are entangled, the diagonal factors # (without c[0][0]) are added up. If the sum is < 1.0, the qubit # states are still seperable. # diag = np.abs(c[1][1]) + np.abs(c[2][2]) + np.abs(c[3][3]) print(f'{iteration}: diag: {diag:5.2f} ', end='') if diag > 1.0: print('--> Entangled') else: print('Seperable') # Let's verify the result and construct a density matrix # from the Pauli matrices using the computed factors: # new_rho = np.zeros((4, 4), dtype=np.complex64) for i in range(4): for j in range(4): tprod = paulis[i] * paulis[j] new_rho = new_rho + c[i][j] * tprod if not np.allclose(rho, new_rho / 4, atol=1e-5): raise AssertionError('Invalid Pauli Representation')