示例#1
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')
示例#2
0
  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))
示例#3
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.')
示例#4
0
文件: bernstein.py 项目: qcc4cp/qcc
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
示例#5
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.')
示例#6
0
def random_gates(min_length, max_length, num_experiments):
  """Just create random sequences, find the best."""

  base = [to_su2(ops.Hadamard()), to_su2(ops.Tgate())]

  U = (ops.RotationX(2.0 * np.pi * random.random()) @
       ops.RotationY(2.0 * np.pi * random.random()) @
       ops.RotationZ(2.0 * np.pi * random.random()))

  min_dist = 1000
  for _ in range(num_experiments):
    seq_length = min_length + random.randint(0, max_length)
    U_approx = ops.Identity()

    for _ in range(seq_length):
      g = random.randint(0, 1)
      U_approx = U_approx @ base[g]

    dist = trace_dist(U, U_approx)
    min_dist = min(dist, min_dist)

  phi1 = U(state.zero)
  phi2 = U_approx(state.zero)
  print('Trace Dist: {:.4f} State: {:6.4f}%'.
        format(min_dist,
               100.0 * (1.0 - np.real(np.dot(phi1, phi2.conj())))))
示例#7
0
文件: tensor_math.py 项目: xbe/qcc
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')
示例#8
0
文件: tensor_math.py 项目: xbe/qcc
    def with_matmul():
        psi = state.zeros(n)
        ident = ops.Identity(n)
        h = ops.Hadamard(n)

        psi = (ident @ h)(psi)
        return psi
示例#9
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)))
示例#10
0
  def test_swap(self):
    """Test swap gate, various indices."""

    swap = ops.Swap(0, 4)
    psi = swap(state.bitstring(1, 0, 1, 0, 0))
    self.assertTrue(psi.is_close(state.bitstring(0, 0, 1, 0, 1)))

    swap = ops.Swap(2, 0)
    psi = swap(state.bitstring(1, 0, 0))
    self.assertTrue(psi.is_close(state.bitstring(0, 0, 1)))

    op_manual = ops.Identity()**2 * swap * ops.Identity()
    psi = op_manual(state.bitstring(1, 1, 0, 1, 1, 0))
    self.assertTrue(psi.is_close(state.bitstring(1, 1, 1, 1, 0, 0)))

    psi = swap(state.bitstring(1, 1, 0, 1, 1, 0), idx=2)
    self.assertTrue(psi.is_close(state.bitstring(1, 1, 1, 1, 0, 0)))
示例#11
0
文件: tensor_math.py 项目: xbe/qcc
    def by_op():
        psi = state.zeros(n)
        ident = ops.Identity(n)
        h = ops.Hadamard(n)

        psi = ident(psi)
        psi = h(psi)
        return psi
示例#12
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
示例#13
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
示例#14
0
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
示例#15
0
def graph_to_hamiltonian(n: int, nodes: List[int]) -> ops.Operator:
    """Compute Hamiltonian matrix from graph."""

    H = np.zeros((2**n, 2**n))
    for node in nodes:
        idx1 = node[0]
        idx2 = node[1]
        if idx1 > idx2:
            idx1, idx2 = idx2, idx1
        op = 1.0
        for _ in range(idx1):
            op = op * ops.Identity()
        op = op * (node[2] * ops.PauliZ())
        for _ in range(idx1 + 1, idx2):
            op = op * ops.Identity()
        op = op * (node[2] * ops.PauliZ())
        for _ in range(idx2 + 1, n):
            op = op * ops.Identity()
        H = H + op
    return ops.Operator(H)
示例#16
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
示例#17
0
def find_closest_u(gate_list, u):
  """Find the one gate in the list closest to u."""

  # Linear search over list of gates - is _very_ slow.
  # This can be optimized by using kd-trees.
  #
  min_dist, min_u = 10, ops.Identity()
  for gate in gate_list:
    tr_dist = trace_dist(gate, u)
    if tr_dist < min_dist:
      min_dist, min_u = tr_dist, gate
  return min_u
示例#18
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')
示例#19
0
  def test_dft(self):
    """Build 'manually' a 3 qubit gate, Nielsen/Chuang Box 5.1."""

    h = ops.Hadamard()

    op = ops.Identity(3)
    op = op(h, 0)
    op = op(ops.ControlledU(1, 0, ops.Rk(2)), 0)  # S-gate
    op = op(ops.ControlledU(2, 0, ops.Rk(3)), 0)  # T-gate
    op = op(h, 1)
    op = op(ops.ControlledU(1, 0, ops.Rk(2)), 1)  # S-gate
    op = op(h, 2)
    op = op(ops.Swap(0, 2), 0)

    op3 = ops.Qft(3)
    self.assertTrue(op3.is_close(op))
示例#20
0
文件: deutsch_jozsa.py 项目: xbe/qcc
def run_experiment(nbits, flavor):
    """Run full experiment for a given flavor of f()."""

    f = make_f(nbits - 1, flavor)
    u = ops.OracleUf(nbits, f)

    psi = (ops.Hadamard(nbits - 1)(state.zeros(nbits - 1)) *
           ops.Hadamard()(state.ones(1)))
    psi = u(psi)
    psi = (ops.Hadamard(nbits - 1) * ops.Identity(1))(psi)

    # Measure all of |0>. If all close to 1.0, f() is constant.
    for idx in range(nbits - 1):
        p0, _ = ops.Measure(psi, idx, tostate=0, collapse=False)
        if not math.isclose(p0, 1.0, abs_tol=1e-5):
            return exp_balanced
    return exp_constant
示例#21
0
  def test_rk(self):
    rk0 = ops.Rk(0)
    self.assertTrue(rk0.is_close(ops.Identity()))

    rk1 = ops.Rk(1)
    self.assertTrue(rk1.is_close(ops.PauliZ()))

    rk2 = ops.Rk(2)
    self.assertTrue(rk2.is_close(ops.Sgate()))

    rk3 = ops.Rk(3)
    self.assertTrue(rk3.is_close(ops.Tgate()))

    for idx in range(8):
      psi = state.zeros(2)
      psi = (ops.Rk(idx)**2 @ ops.Rk(-idx)**2)(psi)
      self.assertTrue(psi.is_close(state.zeros(2)))
示例#22
0
def create_unitaries(base, limit):
  """Create all combinations of all base gates, up to length 'limit'."""

  # Create bitstrings up to bitstring length limit-1:
  #  0, 1, 00, 01, 10, 11, 000, 001, 010, ...
  #
  # Multiply together the 2 base operators, according to their index.
  # Note: This can be optimized, by remembering the last 2^x results
  # and multiplying them with base gets 0, 1.
  #
  gate_list = []
  for width in range(limit):
    for bits in helper.bitprod(width):
      U = ops.Identity()
      for bit in bits:
        U = U @ base[bit]
      gate_list.append(U)
  return gate_list
示例#23
0
    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))
示例#24
0
    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)
示例#25
0
文件: grover.py 项目: qcc4cp/qcc
def run_experiment(nbits, solutions) -> None:
  """Run full experiment for a given flavor of f()."""

  # Note that op_zero multiplies the diagonal elements of the operator by -1,
  # except for element [0][0]. This can be interpreted as "rotating around
  # the |00..)>" state. More pragmatically, multiplying this op_zero with
  # a Hadamard from the left and right gives a matrix of this form:
  #
  # 2/N-1   2/N    2/N    ...   2/N
  # 2/N     2N-1   2/N    ...   2/N
  # 2/N     2/N    2/N-1  ...   2/N
  # 2/N     2/N    2/N    ...   2/N-1
  #
  # Multiplying this matrix with a state vector computes exactly:
  #     2u - c_x
  # for every vector element c_x, with u being the mean over the
  # state vector. This is the defintion of inversion about the mean.
  #
  zero_projector = np.zeros((2**nbits, 2**nbits))
  zero_projector[0, 0] = 1
  op_zero = ops.Operator(zero_projector)

  # Make f and Uf. Note:
  # We reserve space for an ancilla 'y', which is unused in
  # Grover's algorithm. This allows reuse of the Deutsch Uf builder.
  #
  # We use the Oracle construction for convenience. It is rather
  # slow (full matrix) for larger qubit counts. Once can construct
  # a 'regular' function for the grover search algorithms, but this
  # function is different for each bitstring and that quickly gets
  # confusing.
  #
  f = make_f(nbits, solutions)
  uf = ops.OracleUf(nbits+1, f)

  # Build state with 1 ancilla of |1>.
  #
  psi = state.zeros(nbits) * state.ones(1)
  for i in range(nbits + 1):
    psi.apply1(ops.Hadamard(), i)

  # Build Grover operator, note Id() for the ancilla.
  # The Grover operator is the combination of:
  #    - phase inversion via the u unitary
  #    - inversion about the mean (see matrix above)
  #
  hn = ops.Hadamard(nbits)
  reflection = op_zero * 2.0 - ops.Identity(nbits)
  inversion = hn(reflection(hn)) * ops.Identity()
  grover = inversion(uf)

  # Number of Grover iterations
  #
  # There are at least 2 ways to compute the required number of iterations.
  #
  # 1) Most text books, eg., page 157 of Kaye, Laflamme and Mosca, find
  #    that the highest probability of finding the right results occurs
  #    after pi/4 sqrt(n) rotations.
  #
  # 2) For grover specifically, with 1 solution the iteration count is:
  #        int(math.pi / 4 * math.sqrt(n))
  #
  # 3) For grover with multiple solutions:
  #        int(math.pi / 4 * math.sqrt(n / solutions))
  #
  # 4) For amplitude amplification, it's the probability of good
  #    solutions, which is trivial with the Grover equal
  #    superposition  here:
  #        int(math.sqrt(n / solutions))
  #
  iterations = int(math.pi / 4 * math.sqrt(2**nbits / solutions))

  for _ in range(iterations):
    psi = grover(psi)

  # Measurement - pick element with higher probability.
  #
  # Note: We constructed the Oracle with n+1 qubits, to allow
  # for the 'xor-ancillary'. To check the result, we need to
  # ignore this ancilla.
  #
  maxbits, maxprob = psi.maxprob()
  result = f(maxbits[:-1])
  print('Got f({}) = {}, want: 1, #: {:2d}, p: {:6.4f}'
        .format(maxbits[:-1], result, solutions, maxprob))
  if result != 1:
    raise AssertionError('something went wrong, measured invalid state')
示例#26
0
def run_experiment(nbits_phase, nbits_grover, solutions) -> None:
  """Run full experiment for a given number of solutions."""

  # Building the Grover Operator, see grover.py
  n = 2**nbits_grover
  zero_projector = np.zeros((n, n))
  zero_projector[0, 0] = 1
  op_zero = ops.Operator(zero_projector)

  f = make_f(nbits_grover, solutions)
  u = ops.OracleUf(nbits_grover + 1, f)

  # The state for the counting algorithm.
  # We reserve nbits for the phase estimation.
  # We also reserve nbits for the Oracle.
  # These numbers could be adjusted to achieve better
  # accuracy. Yet, this keeps the code a little bit simpler,
  # while trading off a few off-by-1 estimation errors.
  #
  # We also add the |1> for the Oracle.
  #
  psi = (state.zeros(nbits_phase) * state.zeros(nbits_grover) * state.ones(1))

  # Apply Hadamard to all the qubits.
  for i in range(nbits_phase + nbits_grover + 1):
    psi.apply(ops.Hadamard(), i)

  # Construct the Grover Operator.
  reflection = op_zero * 2.0 - ops.Identity(nbits_grover)
  hn = ops.Hadamard(nbits_grover)
  inversion = hn(reflection(hn)) * ops.Identity()
  grover = inversion(u)

  # Now that we have the Grover Operator, we have to perform
  # phase estimation. This loop is a copy from phase_estimation.py
  # with more comments there.
  #
  for idx, inv in enumerate(range(nbits_phase - 1, -1, -1)):
    u2 = grover
    for _ in range(idx):
      u2 = u2(u2)
    psi = ops.ControlledU(inv, nbits_phase, u2)(psi, inv)

  # Reverse QFT gives us the phase as a fraction of 2*Pi
  psi = ops.Qft(nbits_phase).adjoint()(psi)

  # Get the state with highest probability and compute the phase
  # as a binary fraction. Note that the probability increases
  # as M, the number of solutions, gets closer and closer to N,
  # the total mnumber of states.
  maxbits, maxprob = psi.maxprob()
  phi_estimate = sum(maxbits[i] * 2**(-i - 1) for i in range(nbits_phase))

  # We know that after phase estimation, this holds:
  #
  #    sin(phi/2) = sqrt(M/N)
  #             M = N * sin(phi/2)^2
  #
  # Hence we can compute M. We keep the result to 2 digit to visualize
  # the errors. Note that the phi_estimate is a fraction of 2*PI, hence
  # the 1/2 in above formula cancels out against the 2 and we compute:
  M = round(n * math.sin(phi_estimate * math.pi)**2, 2)

  print('Estimate: {:.4f} prob: {:5.2f}% --> M: {:5.2f}, want: {:2d}'.format(
      phi_estimate, maxprob * 100.0, M, solutions))
示例#27
0
文件: grover.py 项目: xbe/qcc
def run_experiment(nbits) -> None:
    """Run full experiment for a given flavor of f()."""

    hn = ops.Hadamard(nbits)
    h = ops.Hadamard()
    n = 2**nbits

    # Note that op_zero multiplies the diagonal elements of the operator by -1,
    # except for element [0][0]. This can be interpreted as "rotating around
    # the |00..)>" state. More pragmatically, multiplying this op_zero with
    # a Hadamard from the left and right gives a matrix of this form:
    #
    # 2/N-1   2/N    2/N    ...   2/N
    # 2/N     2N-1   2/N    ...   2/N
    # 2/N     2/N    2/N-1  ...   2/N
    # 2/N     2/N    2/N    ...   2/N-1
    #
    # Multiplying this matrix with a state vector computes exactly:
    #     2u - c_x
    # for every vector element c_x, with u being the mean over the
    # state vector. This is the defintion of inversion about the mean.
    #
    zero_projector = np.zeros((n, n))
    zero_projector[0, 0] = 1
    op_zero = ops.Operator(zero_projector)

    # Make f and Uf. Note: We reserve space for an ancilla 'y', which is unused
    # in Grover's algorithm. This allows reuse of the Deutsch Uf builder.
    #
    # We use the Oracle construction for convenience. It is rather slow (full
    # matrix) for larger qubit counts. Once can construct a 'regular' function
    # for the grover search algorithms, but this function is different for
    # each bitstring and that quickly gets quite confusing.
    #
    # Good examples for 2-qubit and 3-qubit functions can be found here:
    #    https://qiskit.org/textbook/ch-algorithms/grover.html#3qubits
    #
    f = make_f(nbits)
    u = ops.OracleUf(nbits + 1, f)

    # Build state with 1 ancilla of |1>.
    #
    psi = state.zeros(nbits) * state.ones(1)
    for i in range(nbits + 1):
        psi.apply(h, i)

    # Build Grover operator, note Id() for the ancilla.
    # The Grover operator is the combination of:
    #    - phase inversion via the u unitary
    #    - inversion about the mean (see matrix above)
    #
    reflection = op_zero * 2.0 - ops.Identity(nbits)
    inversion = hn(reflection(hn)) * ops.Identity()
    grover = inversion(u)

    # Number of Grover iterations
    #
    # There are at least 2 ways to compute the required number of iterations.
    #
    # 1) Most text books, eg., page 157 of Kaye, Laflamme and Mosca, find
    #    that the highest probability of finding the right results occurs
    #    after pi/4 sqrt(n) rotations.
    #
    # 2) I found this computation in qcircuits:
    #    angle_to_rotate = np.arccos(np.sqrt(1 / n))
    #    rotation_angle = 2 * np.arcsin(np.sqrt(1 / n))
    #    iterations = int(round(angle_to_rotate / rotation_angle))
    #
    # Both produce identical results.
    #
    iterations = int(math.pi / 4 * math.sqrt(n))

    for _ in range(iterations):
        psi = grover(psi)

    # Measurement - pick element with higher probability.
    #
    # Note: We constructed the Oracle with n+1 qubits, to allow
    # for the 'xor-ancillary'. To check the result, we need to
    # ignore this ancilla.
    #
    maxbits, maxprobs = psi.maxprob()
    result = f(maxbits[:-1])
    print(f'Got f({maxbits[:-1]}) = {result}, want: 1')
    if result != 1:
        raise AssertionError('something went wrong, measured invalid state')
示例#28
0
    def test_reversible_hadamard(self):
        """H*H = I."""

        h2 = ops.Hadamard(2)
        i2 = ops.Identity(2)
        self.assertTrue((h2 @ h2).is_close(i2))
示例#29
0
文件: tensor_math.py 项目: xbe/qcc
 def with_matmul():
     psi = state.zeros(nbits)
     op = ops.Identity(qubit) * gate * ops.Identity(nbits - qubit - 1)
     psi = op(psi)
示例#30
0
    def test_swap(self):
        """Swap(Swap) == I."""

        swap = ops.Swap(0, 3)
        self.assertTrue((swap @ swap).is_close(ops.Identity(4)))