示例#1
0
文件: tensor_math.py 项目: xbe/qcc
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.')
示例#2
0
def incr_mod_9(qc, aux):
    """Increment-by-1 modulo 9 circuit."""

    # We achieve this with help of an ancilla:
    #
    #  -X------------ o  X  0
    #  -o--X--------- 0  |  0
    #  -o--o--X------ 0  |  0
    #  -o--o--o--X--- o  X  0
    #                 |  |  |
    #  needs an extra ancillary:
    #                 |  |  |
    #  ...            X--o--X  -> |0>
    #
    for i in range(4):
        ctl = []
        for j in range(4 - 1, i, -1):
            ctl.append(j)
        qc.multi_control(ctl, i, aux, ops.PauliX(), 'multi-X')

    qc.multi_control([0, [1], [2], 3], aux[4], aux, ops.PauliX(), 'multi-X')
    qc.cx(aux[4], 0)
    qc.cx(aux[4], 3)
    qc.multi_control([[0], [1], [2], [3]], aux[4], aux, ops.PauliX(),
                     'multi-X')
示例#3
0
文件: tensor_math.py 项目: xbe/qcc
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')
示例#4
0
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])))
示例#5
0
 def test_multi1(self):
     c = circuit.qc('multi', eager=False)
     comp = c.reg(6)
     aux = c.reg(6)
     ctl = [0, 1, 2, 3, 4]
     c.multi_control(ctl, 5, aux, ops.PauliX(), f'multi-x({ctl}, 5)')
     self.assertEqual(41, c.ir.ngates)
示例#6
0
 def test_multi0(self):
     c = circuit.qc('multi', eager=True)
     comp = c.reg(4, (1, 0, 0, 1))
     aux = c.reg(4)
     ctl = [0, [1], [2]]
     c.multi_control(ctl, 3, aux, ops.PauliX(), f'multi-x({ctl}, 5)')
     self.assertGreater(c.psi.prob(1, 0, 0, 0, 0, 0, 0, 0), 0.99)
示例#7
0
    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()))
示例#8
0
  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)))
示例#9
0
文件: superdense.py 项目: qcc4cp/qcc
def alice_manipulates(psi: state.State, bit0: int, bit1: int) -> state.State:
    """Alice encodes 2 classical bits in her 1 qubit."""

    ret = ops.Identity(2)(psi)
    if bit0:
        ret = ops.PauliX()(ret)
    if bit1:
        ret = ops.PauliZ()(ret)
    return ret
示例#10
0
文件: superdense.py 项目: xbe/qcc
def alice_manipulates(psi, bit0, bit1):
    """Alice encodes 2 classical bits in her 1 qubit."""

    ret = ops.Identity(2)(psi)
    if bit0:
        ret = ops.PauliZ()(ret)
    if bit1:
        ret = ops.PauliX()(ret)
    return ret
示例#11
0
    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))
示例#12
0
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')
示例#13
0
def alice_measures(alice: state.State, expect0: np.complexfloating,
                   expect1: np.complexfloating, qubit0: np.complexfloating,
                   qubit1: np.complexfloating):
    """Force measurement and get teleported qubit."""

    # Alices measure her state and get a collapsed |qubit0 qubit1>.
    # She let's Bob know which one of the 4 combinations she obtained.

    # We force measurement here, collapsing to a state with the
    # first two qubits collapsed. Bob's qubit is still unmeasured.
    _, alice0 = ops.Measure(alice, 0, tostate=qubit0)
    _, alice1 = ops.Measure(alice0, 1, tostate=qubit1)

    # Depending on what was measured and communicated, Bob has to
    # one of these things to his qubit2:
    if qubit0 == 0 and qubit1 == 0:
        pass
    if qubit0 == 0 and qubit1 == 1:
        alice1 = ops.PauliX()(alice1, idx=2)
    if qubit0 == 1 and qubit1 == 0:
        alice1 = ops.PauliZ()(alice1, idx=2)
    if qubit0 == 1 and qubit1 == 1:
        alice1 = ops.PauliX()(ops.PauliZ()(alice1, idx=2), idx=2)

    # Now Bob measures his qubit (2) (without collapse, so we can
    # 'measure' it twice. This is not necessary, but good to double check
    # the maths).
    p0, _ = ops.Measure(alice1, 2, tostate=0, collapse=False)
    p1, _ = ops.Measure(alice1, 2, tostate=1, collapse=False)

    # Alice should now have 'teleported' the qubit in state 'x'.
    # We sqrt() the probability, we want to show (original) amplitudes.
    bob_a = math.sqrt(p0.real)
    bob_b = math.sqrt(p1.real)
    print('Teleported (|{:d}{:d}>)   a={:.2f}, b={:.2f}'.format(
        qubit0, qubit1, bob_a, bob_b))

    if (not math.isclose(expect0, bob_a, abs_tol=1e-6)
            or not math.isclose(expect1, bob_b, abs_tol=1e-6)):
        raise AssertionError('Invalid result.')
示例#14
0
文件: tensor_math.py 项目: xbe/qcc
def hipster_single():
    """Single-qubit Hipster Technique."""

    # This is a nice trick, outlined in this paper on "Hipster":
    #    https://arxiv.org/pdf/1601.07195.pdf
    #
    # The observation is that to apply a single-qubit gate to a
    # gubit with index i, take the binary representation of inidices and
    # apply the transformation matrix to the elements according
    # to the power of 2 index. Generally:
    # "Performing a single-qubit gate on qubit k of n-qubit quantum
    # register applies G to pairs of amplitudes whose indices differ in
    # k-th bits of their binary index".
    #
    # For example, for a 2-qubit system, to apply a gate to qubit 0:
    #    apply G to
    #    q11, q12   psi[0], psi[1]
    #    q21, q22   psi[2], psi[3]
    #
    # To apply to qubit 1:
    #    q11, q12   psi[0], psi[2]
    #    q21, q22   psi[1], psi[3]
    #
    # 'Outer loop' jumps by 2**(nbits+1)
    # 'Inner loop' jumps by 2**k
    #
    # To maintain the qubit / index ordering of this infrastructure,
    # the qubit index in the paper is reversed to the qubit index here.
    # (Hence the (nbits - qubit - 1) above)
    #

    # Make sure that for sample gates and all states the transformations
    # are identical.
    #
    for gate in (ops.PauliX(), ops.PauliZ(), ops.Hadamard(),
                 ops.RotationX(0.5)):
        nbits = 5
        for bits in helper.bitprod(nbits):
            psi = state.bitstring(*bits)
            qubit = random.randint(0, nbits - 1)

            # Full matrix (O(n*n).
            op = ops.Identity(qubit) * gate * ops.Identity(nbits - qubit - 1)
            psi1 = op(psi)

            # Single Qubit (O(n))
            psi = apply_single_gate(gate, qubit, psi)

            if not psi.is_close(psi1):
                raise AssertionError('Invalid Single Gate Application.')
示例#15
0
  def test_multi_n(self):
    c = circuit.qc('multi', eager=True)
    c.reg(4, (1, 0, 0, 1))
    aux = c.reg(4)
    ctl = []
    c.multi_control(ctl, 3, aux, ops.PauliX(), 'single')
    self.assertGreater(c.psi.prob(1, 0, 0, 0, 0, 0, 0, 0), 0.99)

    ctl = [0]
    c.multi_control(ctl, 3, aux, ops.PauliX(), 'single')
    self.assertGreater(c.psi.prob(1, 0, 0, 1, 0, 0, 0, 0), 0.99)

    ctl = [1]
    c.multi_control(ctl, 3, aux, ops.PauliX(), 'single')
    self.assertGreater(c.psi.prob(1, 0, 0, 1, 0, 0, 0, 0), 0.99)

    ctl = [[1]]
    c.multi_control(ctl, 3, aux, ops.PauliX(), 'single')
    self.assertGreater(c.psi.prob(1, 0, 0, 0, 0, 0, 0, 0), 0.99)

    ctl = [0, [1], [2]]
    c.multi_control(ctl, 3, aux, ops.PauliX(), 'single')
    self.assertGreater(c.psi.prob(1, 0, 0, 1, 0, 0, 0, 0), 0.99)
示例#16
0
def incr(qc, idx, nbits, aux, controller=[]):
  """Increment-by-1 circuit."""

  # See "Efficient Quantum Circuit Implementation of
  # Quantum Walks" by Douglas, Wang.
  #
  #  -X--
  #  -o--X--
  #  -o--o--X--
  #  -o--o--o--X--
  #  ...
  for i in range(0, nbits):
    ctl=controller.copy()
    for j in range(nbits-1, i, -1):
      ctl.append(j+idx)
    qc.multi_control(ctl, i+idx, aux, ops.PauliX(), "multi-1-X")
示例#17
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()))
示例#18
0
  def test_bloch(self):
    psi = state.zeros(1)
    x, y, z = helper.density_to_cartesian(psi.density())
    self.assertEqual(x, 0.0)
    self.assertEqual(y, 0.0)
    self.assertEqual(z, 1.0)

    psi = ops.PauliX()(psi)
    x, y, z = helper.density_to_cartesian(psi.density())
    self.assertEqual(x, 0.0)
    self.assertEqual(y, 0.0)
    self.assertEqual(z, -1.0)

    psi = ops.Hadamard()(psi)
    x, y, z = helper.density_to_cartesian(psi.density())
    self.assertTrue(math.isclose(x, -1.0, abs_tol=1e-6))
    self.assertTrue(math.isclose(y, 0.0, abs_tol=1e-6))
    self.assertTrue(math.isclose(z, 0.0, abs_tol=1e-6))
示例#19
0
def decr(qc, idx, nbits, aux, controller=[]):
  """Decrement-by-1 circuit."""

  # See "Efficient Quantum Circuit Implementation of
  # Quantum Walks" by Douglas, Wang.
  #
  # Similar to incr, except controlled-by-0's are being used.
  #
  #  -X--
  #  -0--X--
  #  -0--0--X--
  #  -0--0--0--X--
  #  ...
  for i in range(0, nbits):
    ctl=controller.copy()
    for j in range(nbits-1, i, -1):
      ctl.append([j+idx])
    qc.multi_control(ctl, i+idx, aux, ops.PauliX(), "multi-0-X")
示例#20
0
文件: tensor_math.py 项目: xbe/qcc
def single_gate_complexity():
    """Compare times for full matmul vs single-gate."""

    nbits = 12
    qubit = random.randint(0, nbits - 1)
    gate = ops.PauliX()

    def with_matmul():
        psi = state.zeros(nbits)
        op = ops.Identity(qubit) * gate * ops.Identity(nbits - qubit - 1)
        psi = op(psi)

    def apply_single():
        psi = state.zeros(nbits)
        psi = apply_single_gate(gate, qubit, psi)

    print('Time with full matmul: {:.3f} secs'.format(
        timeit.timeit(with_matmul, number=1)))
    print('Time with single gate: {:.3f} secs'.format(
        timeit.timeit(apply_single, number=1)))
示例#21
0
    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')
示例#22
0
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]))
示例#23
0
def basis_changes():
    """Explore basis changes via Hadamard."""

    # Generate [1, 0]
    psi = state.zeros(1)

    # Hadamard will result in 1/sqrt(2) [1, 1] (|+>)
    psi = ops.Hadamard()(psi)

    # Generate [0, 1]
    psi = state.ones(1)

    # Hadamard on |1> will result in 1/sqrt(2) [1, -1] (|->)
    psi = ops.Hadamard()(psi)

    # Simple PauliX will result in 1/sqrt(2) [-1, 1]
    psi = ops.PauliX()(psi)

    # But back to computational, will result in -|1>, but phases
    # can be ignored.
    psi = ops.Hadamard()(psi)
    if psi[1] > -0.95:
        raise AssertionError('Invalid Basis Changes')
示例#24
0
def basis_changes():
  """Explore basis changes via Hadamard."""

  # Generate [1, 0]
  psi = state.zeros(1)

  # Hadamard will result in 1/sqrt(2) [1, 1] (|+>)
  psi = ops.Hadamard()(psi)

  # Generate [0, 1]
  psi = state.ones(1)

  # Hadamard on |1> will result in 1/sqrt(2) [1, -1] (|->)
  psi = ops.Hadamard()(psi)

  # Simple PauliX will result in 1/sqrt(2) [-1, 1]
  psi = ops.PauliX()(psi)

  # But back to computational, will result in -|1>.
  # Global phases can be ignored.
  psi = ops.Hadamard()(psi)
  if not np.allclose(psi[1], -1.0):
    raise AssertionError('Invalid basis change.')
示例#25
0
    def test_v_gate(self):
        """V^2 == X."""

        s = ops.Vgate() @ ops.Vgate()
        self.assertTrue(s.is_close(ops.PauliX()))
示例#26
0
  def test_v_gate(self):
    """Test that V^2 == X."""

    t = ops.Vgate()
    self.assertTrue(t(t).is_close(ops.PauliX()))
示例#27
0
 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())
示例#28
0
 def decr(qc, idx, nbits, aux, controller=[]):
     for i in range(0, nbits):
         ctl = controller.copy()
         for j in range(nbits - 1, i, -1):
             ctl.append([j + idx])
     qc.multi_control(ctl, i + idx, aux, ops.PauliX(), "multi-0-X")
示例#29
0
 def cx(self, idx0: int, idx1: int):
     self.applyc(ops.PauliX(), idx0, idx1, 'cx')
示例#30
0
 def x(self, idx: int):
     self.apply1(ops.PauliX(), idx, 'x')