def run_experiment(a1: np.complexfloating, a2: np.complexfloating, target: float) -> None: """Construct swap test circuit and measure.""" # The circuit is quite simple: # # |0> --- H --- o --- H --- Measure # | # a1 --------- x --------- # | # a2 ----------x --------- psi = state.bitstring(0) * state.qubit(a1) * state.qubit(a2) psi = ops.Hadamard()(psi, 0) psi = ops.ControlledU(0, 1, ops.Swap(1, 2))(psi) psi = ops.Hadamard()(psi, 0) # Measure once. p0, _ = ops.Measure(psi, 0) if abs(p0 - target) > 0.05: raise AssertionError( 'Probability {:.2f} off more than 5% from target {:.2f}'.format( p0, target)) print('Similarity of a1: {:.2f}, a2: {:.2f} ==> %: {:.2f}'.format( a1, a2, 100.0 * p0))
def operator_per_state(): """First foray into more effective math for 1-qubit operators.""" # Make product state q0 = state.qubit(alpha=0.5) q1 = state.qubit(alpha=0.9) psi = q0 * q1 # Compute via combined operator. op = ops.PauliX() * ops.Identity(1) psi1 = op(psi) # Combine via 1-qubit on q0 * q1 psi2 = ops.PauliX()(q0) * q1 if not psi1.is_close(psi2): raise AssertionError( 'Wrong tensor math and application of 1-qubit gate.') # Same thing, but apply to qubit 1. op = ops.Identity() * ops.PauliX() psi1 = op(psi) psi2 = q0 * ops.PauliX()(q1) if not psi1.is_close(psi2): raise AssertionError( 'Wrong tensor math and application of 1-qubit gate.')
def test_mult_conjugates(self): a = state.qubit(0.6) b = state.qubit(0.8) psi = a * b psi_adj = np.conj(a) * np.conj(b) self.assertTrue(np.allclose(psi_adj, np.conj(psi))) i1 = np.conj(np.inner(a, b)) i2 = np.inner(b, a) self.assertTrue(np.allclose(i1, i2))
def hipster_multi(): """Multi-qubit, optimized application.""" nbits = 7 for bits in helper.bitprod(nbits): psi = state.bitstring(*bits) for target in range(1, nbits): # Full matrix (O(n*n). op = (ops.Identity(target - 1) * ops.Cnot(target - 1, target) * ops.Identity(nbits - target - 1)) psi1 = op(psi) # Single Qubit (O(n)) psi = apply_controlled_gate(ops.PauliX(), target - 1, target, psi) if not psi.is_close(psi1): raise AssertionError('Invalid Single Gate Application.') psi = state.bitstring(1, 1, 0, 0, 1) pn = ops.Cnot(1, 4)(psi, 1) if not pn.is_close(apply_controlled_gate(ops.PauliX(), 1, 4, psi)): raise AssertionError('Invalid Cnot') pn = ops.Cnot(4, 1)(psi, 1) if not pn.is_close(apply_controlled_gate(ops.PauliX(), 4, 1, psi)): raise AssertionError('Invalid Cnot') pn = ops.ControlledU(0, 1, ops.ControlledU(1, 4, ops.PauliX()))(psi) psi = state.qubit(alpha=0.6) * state.ones(2) pn = ops.Cnot(0, 2)(psi) if not pn.is_close(apply_controlled_gate(ops.PauliX(), 0, 2, psi)): raise AssertionError('Invalid Cnot')
def test_inner_tensor_product(self): p1 = state.qubit(random.random()) p2 = state.qubit(random.random()) x1 = state.qubit(random.random()) x2 = state.qubit(random.random()) psi1 = p1 * x1 psi2 = p2 * x2 inner1 = np.inner(psi1.conj(), psi2) inner2 = np.inner(p1.conj(), p2) * np.inner(x1.conj(), x2) self.assertTrue(np.allclose(inner1, inner2)) self.assertTrue(np.allclose(np.inner(psi1.conj(), psi1), 1.0)) self.assertTrue( np.allclose( np.inner(p1.conj(), p1) * np.inner(x1.conj(), x1), 1.0))
def main(argv): if len(argv) > 1: raise app.UsageError('Too many command-line arguments.') # Step 1: Alice and Bob share an entangled pair, and separate. psi = bell.bell_state(0, 0) # Step 2: Alice wants to teleport a qubit |x> to Bob, # which is in the state: # |x> = a|0> + b|1> (with a^2 + b^2 == 1) a = 0.6 b = math.sqrt(1.0 - a * a) x = state.qubit(a, b) print('Quantum Teleportation') print('Start with EPR Pair a={:.2f}, b={:.2f}'.format(a, b)) # Produce combined state. alice = x * psi # Alice lets the 1st qubit interact with the 2nd qubit, which is her # part of the entangle state with Bob. alice = ops.Cnot(0, 1)(alice) # Now she applies a Hadamard to qubit 0. Bob still owns qubit 2. alice = ops.Hadamard()(alice, idx=0) # Alices measures and communicates the result (|00>, |01>, ...) to Bob. alice_measures(alice, a, b, 0, 0) alice_measures(alice, a, b, 0, 1) alice_measures(alice, a, b, 1, 0) alice_measures(alice, a, b, 1, 1)
def test_partial(self): """Test partial trace.""" psi = bell.bell_state(0, 0) reduced = ops.TraceOut(psi.density(), [0]) self.assertTrue( math.isclose(np.real(np.trace(reduced)), 1.0, abs_tol=1e-6)) self.assertTrue(math.isclose(np.real(reduced[0, 0]), 0.5, abs_tol=1e-6)) self.assertTrue(math.isclose(np.real(reduced[1, 1]), 0.5, abs_tol=1e-6)) q0 = state.qubit(alpha=0.5) q1 = state.qubit(alpha=0.8660254) psi = q0 * q1 reduced = ops.TraceOut(psi.density(), [0]) self.assertTrue(math.isclose(np.real(np.trace(reduced)), 1.0)) self.assertTrue( math.isclose(np.real(reduced[0, 0]), 0.75, abs_tol=1e-6)) self.assertTrue( math.isclose(np.real(reduced[1, 1]), 0.25, abs_tol=1e-6)) reduced = ops.TraceOut(psi.density(), [1]) self.assertTrue(math.isclose(np.real(np.trace(reduced)), 1.0)) self.assertTrue( math.isclose(np.real(reduced[0, 0]), 0.25, abs_tol=1e-6)) self.assertTrue( math.isclose(np.real(reduced[1, 1]), 0.75, abs_tol=1e-6)) psi = q1 * q0 * state.qubit(alpha=(0.8660254)) reduced = ops.TraceOut(psi.density(), [2]) reduced = ops.TraceOut(reduced, [0]) self.assertTrue(math.isclose(np.real(np.trace(reduced)), 1.0)) self.assertTrue(math.isclose(np.real(reduced[0, 0]), 0.25)) self.assertTrue(math.isclose(np.real(reduced[1, 1]), 0.75)) psi = q1 * q0 * state.qubit(alpha=(0.8660254)) reduced = ops.TraceOut(psi.density(), [0, 2]) self.assertTrue(math.isclose(np.real(np.trace(reduced)), 1.0)) self.assertTrue(math.isclose(np.real(reduced[0, 0]), 0.25)) self.assertTrue(math.isclose(np.real(reduced[1, 1]), 0.75))
def qubit(self, alpha: np.complexfloating = None, beta: np.complexfloating = None) -> None: self.psi = self.psi * state.qubit(alpha, beta) self.global_reg = self.global_reg + 1
def qubit(self, alpha=None, beta=None): self.psi = self.psi * state.qubit(alpha, beta)