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_cnot0(self): """Check implementation of ControlledU via Cnot0.""" # Check operator itself. x = ops.PauliX() * ops.Identity() self.assertTrue(ops.Cnot0(0, 1). is_close(x @ ops.Cnot(0, 1) @ x)) # Compute simplest case with Cnot0. psi = state.bitstring(1, 0) psi2 = ops.Cnot0(0, 1)(psi) self.assertTrue(psi.is_close(psi2)) # Compute via explicit constrution. psi2 = (x @ ops.Cnot(0, 1) @ x)(psi) self.assertTrue(psi.is_close(psi2)) # Different offsets. psi2 = ops.Cnot0(0, 1)(state.bitstring(0, 1)) self.assertTrue(psi2.is_close(state.bitstring(0, 0))) psi2 = ops.Cnot0(0, 3)(state.bitstring(0, 0, 0, 0, 1)) self.assertTrue(psi2.is_close(state.bitstring(0, 0, 0, 1, 1))) psi2 = ops.Cnot0(4, 0)(state.bitstring(1, 0, 0, 0, 0)) self.assertTrue(psi2.is_close(state.bitstring(0, 0, 0, 0, 0)))
def test_had_cnot_had(self): """Exercise 4.20 in Nielson, Chuang, H2.Cnot(0,1).H2==Cnot(1,0).""" h2 = ops.Hadamard(2) cnot = ops.Cnot(0, 1) op = h2(cnot(h2)) self.assertTrue(op.is_close(ops.Cnot(1, 0)))
def make_u(): """Make Simon's 2 (total 4) qubit Oracle.""" # We have to properly 'pad' the various gates to 4 qubits. # ident = ops.Identity() cnot0 = ops.Cnot(0, 2) * ident cnot1 = ops.Cnot(0, 3) cnot2 = ident * ops.Cnot(0, 1) * ident cnot3 = ident * ops.Cnot(0, 2) return cnot3 @ cnot2 @ cnot1 @ cnot0
def test_cnot(self): """Check implementation of ControlledU via Cnot.""" psi = state.bitstring(0, 1) psi2 = ops.Cnot(0, 1)(psi) self.assertTrue(psi.is_close(psi2)) psi2 = ops.Cnot(0, 1)(state.bitstring(1, 1)) self.assertTrue(psi2.is_close(state.bitstring(1, 0))) psi2 = ops.Cnot(0, 3)(state.bitstring(1, 0, 0, 0, 1)) self.assertTrue(psi2.is_close(state.bitstring(1, 0, 0, 1, 1))) psi2 = ops.Cnot(4, 0)(state.bitstring(1, 0, 0, 0, 1)) self.assertTrue(psi2.is_close(state.bitstring(0, 0, 0, 0, 1)))
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_padding(self): ident = ops.Identity(3) h = ops.Hadamard() op = ident(h, 0) op_manual = h * ops.Identity(2) self.assertTrue(op.is_close(op_manual)) op = ident(h, 1) op_manual = ops.Identity() * h * ops.Identity() self.assertTrue(op.is_close(op_manual)) op = ident(h, 2) op_manual = ops.Identity(2) * h self.assertTrue(op.is_close(op_manual)) ident = ops.Identity(4) cx = ops.Cnot(0, 1) op = ident(cx, 0) op_manual = cx * ops.Identity(2) self.assertTrue(op.is_close(op_manual)) op = ident(cx, 1) op_manual = ops.Identity(1) * cx * ops.Identity(1) self.assertTrue(op.is_close(op_manual)) op = ident(cx, 2) op_manual = ops.Identity(2) * cx self.assertTrue(op.is_close(op_manual))
def make_u(nbits: int, constant_c: Tuple[bool]) -> ops.Operator: """Make general Bernstein Oracle.""" # For each '1' at index i in the constant_c, build a Cnot from # bit 0 to the bottom bit. For example for string |101> # # |0> --- H --- o-------- # |0> --- H ----|-------- # |0> --- H ----|-- o --- # | | # |1> --- H --- X - X --- # op = ops.Identity(nbits) for idx in range(nbits - 1): if constant_c[idx]: op = ops.Identity(idx) * ops.Cnot(idx, nbits - 1) @ op # Note that the |+> basis, a cnot is the same as a single Z-gate. # This would also work: # op = (ops.Identity(idx) * ops.PauliZ() * # ops.Identity(nbits - 1 - idx)) @ op if not op.is_unitary(): raise AssertionError('Constructed non-unitary operator.') return op
def operator_order(): """Evaluate order of operations and corresponding matmuls.""" hi = ops.Hadamard() * ops.Identity() cx = ops.Cnot(0, 1) # Make sure that the order of evaluation is correct. For example, # this simple circuit: # # |0> --- H --- o --- # | # |0> ----------X --- # # p0 p1 p2 # # Can be evaluated step wise, applying each gate to psi: psi_0 = state.zeros(2) psi_1 = hi(psi_0) psi_2 = cx(psi_1) # Or via a combined operator. Yet, the order ot the ops # has to be reversed from above picture: combined_op = (cx @ hi) combined_psi = state.zeros(2) combined_psi_2 = combined_op(combined_psi) if not psi_2.is_close(combined_psi_2): raise AssertionError('Invalid order of operators from matmul') # This can also be expressed via the function call construct: combined_f = hi(cx) combined_f_psi = state.zeros(2) combined_f_psi_2 = combined_f(combined_f_psi) if not psi_2.is_close(combined_f_psi_2): raise AssertionError('Invalid order of operators from call construct')
def bell_state(a, b) -> state.State: """Make one of the four bell states with a, b from {0,1}.""" if a not in [0, 1] or b not in [0, 1]: raise ValueError('Bell state arguments are bits and must be 0 or 1.') psi = state.bitstring(a, b) psi = ops.Hadamard()(psi) return ops.Cnot()(psi)
def basis_kick1(): """Simple H-Cnot-H phase kick.""" psi = state.zeros(3) * state.ones(1) psi = ops.Hadamard(4)(psi) psi = ops.Cnot(2, 3)(psi, 2) psi = ops.Hadamard(4)(psi) if psi.prob(0, 0, 1, 1) < 0.9: raise AssertionError('Something is wrong with the phase kick')
def make_u(nbits, constant_c): """Make general Simon's Oracle.""" # Copy bits. op = ops.Identity(nbits*2) for idx in range(nbits): op = (ops.Identity(idx) * ops.Cnot(idx, idx+nbits) * ops.Identity(nbits - idx - 1)) @ op # Connect the xor's controlled by the msb(x). for idx in range(nbits): if constant_c[idx] == 1: op = (ops.Cnot(0, idx+nbits) * ops.Identity(nbits-idx-1)) @ op if not op.is_unitary(): raise AssertionError('Produced non-unitary Uf') return op
def test_measure(self): psi = state.zeros(2) psi = ops.Hadamard()(psi) psi = ops.Cnot(0, 1)(psi) p0, psi2 = ops.Measure(psi, 0) self.assertTrue(math.isclose(p0, 0.5, abs_tol=1e-5)) # Measure again - now state should have collapsed. p0, _ = ops.Measure(psi2, 0) self.assertTrue(math.isclose(p0, 1.0, abs_tol=1e-6))
def ghz_state(nbits) -> state.State: """Make a maximally entangled nbits state (GHZ State).""" # Simple construction via: # # |0> --- H --- o --------- # |0> ----------X --- o --- # |0> ----------------X --- ... # psi = state.zeros(nbits) psi = ops.Hadamard()(psi) for offset in range(nbits - 1): psi = ops.Cnot(0, 1)(psi, offset) return psi
def test_controlled_controlled(self): """Toffoli gate over 4 qubits to verify that controlling works.""" cnot = ops.Cnot(0, 3) toffoli = ops.ControlledU(0, 1, cnot) self.assertTrue(toffoli.is_close(ops.Toffoli(0, 1, 4))) psi = toffoli(state.bitstring(0, 1, 0, 0, 1)) self.assertTrue(psi.is_close(state.bitstring(0, 1, 0, 0, 1))) psi = toffoli(state.bitstring(1, 1, 0, 0, 1)) self.assertTrue(psi.is_close(state.bitstring(1, 1, 0, 0, 0))) psi = toffoli(state.bitstring(0, 0, 1, 1, 0, 0, 1), idx=2) self.assertTrue(psi.is_close(state.bitstring(0, 0, 1, 1, 0, 0, 0)))
def bob_measures(psi: state.State, expect0: int, expect1: int): """Bob measures both bits (in computational basis).""" # Change Hadamard basis back to computational basis. psi = ops.Cnot(0, 1)(psi) psi = ops.Hadamard()(psi) p0, _ = ops.Measure(psi, 0, tostate=expect1) p1, _ = ops.Measure(psi, 1, tostate=expect0) if (not math.isclose(p0, 1.0, abs_tol=1e-6) or not math.isclose(p1, 1.0, abs_tol=1e-6)): raise AssertionError(f'Invalid Result p0 {p0} p1 {p1}') print(f'Expected/matched: |{expect0}{expect1}>.')
def fulladder_matrix(psi: state.State): """Non-quantum-exploiting, classic full adder.""" psi = ops.Cnot(0, 3)(psi, 0) psi = ops.Cnot(1, 3)(psi, 1) psi = ops.ControlledU(0, 1, ops.Cnot(1, 4))(psi, 0) psi = ops.ControlledU(0, 2, ops.Cnot(2, 4))(psi, 0) psi = ops.ControlledU(1, 2, ops.Cnot(2, 4))(psi, 1) psi = ops.Cnot(2, 3)(psi, 2) return psi
def basis_kick2(): """Another way to look at this H-Cnot-H phase kick.""" # This produces the vector [0, 1, 0, 0] psi = state.bitstring(0, 1) # Applying Hadamard: [0.5, -0.5, 0.5, -0.5] h2 = ops.Hadamard(2) psi = h2(psi) # Acting Cnot on this vector: [0.5, -0.5, -0.5, 0.5] psi = ops.Cnot()(psi) # Final Hadamard: [0, 0, 0, 1] psi = h2(psi) # which is |11> p11 = state.bitstring(1, 1) if not psi.is_close(p11): raise AssertionError('Something is wrong with the phase kick')
def test_v_vdag_v(self): """Figure 4.8 Nielson, Chuang.""" # Make Toffoli out of V = sqrt(X). # v = ops.Vgate() # Could be any unitary, in principle! ident = ops.Identity() cnot = ops.Cnot(0, 1) o0 = ident * ops.ControlledU(1, 2, v) c2 = cnot * ident o2 = (ident * ops.ControlledU(1, 2, v.adjoint())) o4 = ops.ControlledU(0, 2, v) final = o4 @ c2 @ o2 @ c2 @ o0 v2 = v @ v cv1 = ops.ControlledU(1, 2, v2) cv0 = ops.ControlledU(0, 1, cv1) self.assertTrue(final.is_close(cv0))
def test_bell(self): """Check successful entanglement by computing the schmidt_number.""" b00 = bell.bell_state(0, 0) self.assertGreater(b00.schmidt_number([1]), 1.0) self.assertTrue( b00.is_close((state.zeros(2) + state.ones(2)) / math.sqrt(2))) # Note the order is reversed from pictorials. op_exp = (ops.Cnot(0, 1) @ (ops.Hadamard() * ops.Identity())) b00_exp = op_exp(state.zeros(2)) self.assertTrue(b00.is_close(b00_exp)) b01 = bell.bell_state(0, 1) self.assertGreater(b01.schmidt_number([1]), 1.0) b10 = bell.bell_state(1, 0) self.assertGreater(b10.schmidt_number([1]), 1.0) b11 = bell.bell_state(1, 1) self.assertGreater(b11.schmidt_number([1]), 1.0)
def test_control_equalities(self): """Exercise 4.31 Nielson, Chung.""" i, x, y, z = ops.Pauli() x1 = x * i x2 = i * x y1 = y * i y2 = i * y z1 = z * i z2 = i * z c = ops.Cnot(0, 1) theta = 25.0 * math.pi / 180.0 rx2 = i * ops.RotationX(theta) rz1 = ops.RotationZ(theta) * i self.assertTrue(c(x1(c)).is_close(x1(x2))) self.assertTrue((c @ x1 @ c).is_close(x1 @ x2)) self.assertTrue((c @ y1 @ c).is_close(y1 @ x2)) self.assertTrue((c @ z1 @ c).is_close(z1)) self.assertTrue((c @ x2 @ c).is_close(x2)) self.assertTrue((c @ y2 @ c).is_close(z1 @ y2)) self.assertTrue((c @ z2 @ c).is_close(z1 @ z2)) self.assertTrue((rz1 @ c).is_close(c @ rz1)) self.assertTrue((rx2 @ c).is_close(c @ rx2))