Ejemplo n.º 1
0
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')
Ejemplo n.º 2
0
    def test_density_to_cartesian(self):
        """Test density to cartesian conversion."""

        q0 = state.zeros(1)
        rho = q0.density()
        x, y, z = helper.density_to_cartesian(rho)
        self.assertEqual(x, 0.0)
        self.assertEqual(y, 0.0)
        self.assertEqual(z, 1.0)

        q1 = state.ones(1)
        rho = q1.density()
        x, y, z = helper.density_to_cartesian(rho)
        self.assertEqual(x, 0.0)
        self.assertEqual(y, 0.0)
        self.assertEqual(z, -1.0)

        qh = ops.Hadamard()(q0)
        rho = qh.density()
        x, y, z = helper.density_to_cartesian(rho)
        self.assertTrue(math.isclose(np.real(x), 1.0, abs_tol=1e-6))
        self.assertTrue(math.isclose(np.real(y), 0.0))
        self.assertTrue(math.isclose(np.real(z), 0.0, abs_tol=1e-6))

        qr = ops.RotationZ(90.0 * math.pi / 180.0)(qh)
        rho = qr.density()
        x, y, z = helper.density_to_cartesian(rho)
        self.assertTrue(math.isclose(np.real(x), 0.0, abs_tol=1e-6))
        self.assertTrue(math.isclose(np.real(y), -1.0, abs_tol=1e-6))
        self.assertTrue(math.isclose(np.real(z), 0.0, abs_tol=1e-6))
Ejemplo n.º 3
0
def run_experiment(nbits, t=8):
    """Run single phase estimation experiment."""

    # Make a unitary and find Eigen value/vector to estimate.
    #
    umat = scipy.stats.unitary_group.rvs(2**nbits)
    eigvals, eigvecs = np.linalg.eig(umat)
    u = ops.Operator(umat)

    # Pick Eigenvalue 'eigen_index' (any Eigenvalue / Eigenvector pair will work).
    eigen_index = 1
    phi = np.real(np.log(eigvals[eigen_index]) / (2j * np.pi))
    if phi < 0:
        phi += 1

    # Make state + circuit to estimate phi.
    # Pick Eigenvector 'eigen_index' to math the Eigenvalue.
    psi = state.zeros(t) * state.State(eigvecs[:, eigen_index])
    psi = phase1(psi, u, t)
    psi = ops.Qft(t).adjoint()(psi)

    # Find state with highest measurement probability and show results.
    #
    maxbits, maxprob = psi.maxprob()
    phi_estimate = sum(maxbits[i] * 2**(-i - 1) for i in range(t))

    delta = abs(phi - phi_estimate)
    print('Phase   : {:.4f}'.format(phi))
    print('Estimate: {:.4f} delta: {:.4f} probability: {:5.2f}%'.format(
        phi_estimate, delta, maxprob * 100.0))
    if delta > 0.02 and phi_estimate < 0.98:
        print('*** Warning: Delta is large')
Ejemplo n.º 4
0
    def with_matmul():
        psi = state.zeros(n)
        ident = ops.Identity(n)
        h = ops.Hadamard(n)

        psi = (ident @ h)(psi)
        return psi
Ejemplo n.º 5
0
def run_experiment():
    """Run single, defined experiment for secret 11."""

    psi = state.zeros(4)
    u = make_u()

    psi = ops.Hadamard(2)(psi)
    psi = u(psi)
    psi = ops.Hadamard(2)(psi)

    # Because of the xor patterns (Yanofski 6.64)
    # measurement will only find those qubit strings where
    # the scalar product of z (lower bits) and secret string:
    #    <z, c> = 0
    #
    # This should measure |00> and |11> with equal probability.
    # If true, than we can derive the secret string as being 11
    # because f(00) = f(11) and because f(00) = f(00 ^ c) -> c = 11
    #
    print('Measure likely states (want: pairs of 00 or 11):')
    for bits in helper.bitprod(4):
        if psi.prob(*bits) > 0.01:
            if (bits[0] == 0 and bits[1] == 1) or (bits[0] == 1
                                                   and bits[1] == 0):
                raise AssertionError('Invalid Results')
            print('|{}{} {}{}> = 0 : {:.2f}  dot % 2: {:.2f}'.format(
                bits[0], bits[1], bits[2], bits[3], psi.prob(*bits),
                dot2(bits)))
Ejemplo n.º 6
0
    def by_op():
        psi = state.zeros(n)
        ident = ops.Identity(n)
        h = ops.Hadamard(n)

        psi = ident(psi)
        psi = h(psi)
        return psi
Ejemplo n.º 7
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)))
Ejemplo n.º 8
0
    def test_schmidt(self):
        psi = state.zeros(2)
        self.assertEqual(psi.schmidt_number([1]), 1.0)

        psi = state.bitstring(0, 1, 1, 0, 1, 0, 1, 1)
        self.assertEqual(psi.schmidt_number([1]), 1.0)

        psi = state.State(np.array([1.0, 1.0, 0.0, 1.0]))
        self.assertNotEqual(psi.schmidt_number([1]), 1.0)
Ejemplo n.º 9
0
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')
Ejemplo n.º 10
0
    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))
Ejemplo n.º 11
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)
Ejemplo n.º 12
0
def run_experiment(nbits: int) -> None:
    """Run full experiment for a given number of bits."""

    c = make_c(nbits - 1)
    u = make_u(nbits, c)

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

    check_result(nbits, c, psi)
Ejemplo n.º 13
0
def run_oracle_experiment(nbits) -> None:
    """Run full experiment for a given number of bits."""

    c = make_c(nbits - 1)
    f = make_oracle_f(c)
    u = ops.OracleUf(nbits, f)

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

    check_result(nbits, c, psi)
Ejemplo n.º 14
0
  def test_double_hadamard(self):
    """Check that Hadamard is fully reversible."""

    psi = state.zeros(2)

    psi2 = ops.Hadamard(2)(ops.Hadamard(2)(psi))
    self.assertEqual(psi2.nbits, 2)
    self.assertTrue(psi.is_close(psi2))

    combo = ops.Hadamard(2) @ ops.Hadamard(2)
    psi3 = combo(psi)
    self.assertEqual(psi3.nbits, 2)
    self.assertTrue(psi.is_close(psi3))
    self.assertTrue(psi.density().is_pure())
Ejemplo n.º 15
0
Archivo: bell.py Proyecto: xbe/qcc
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
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))
Ejemplo n.º 18
0
    def test_simple_state(self):
        psi = state.zero
        self.assertEqual(psi[0], 1)
        self.assertEqual(psi[1], 0)

        psi = state.one
        self.assertEqual(psi[0], 0)
        self.assertEqual(psi[1], 1)

        psi = state.zeros(8)
        self.assertEqual(psi[0], 1)
        for i in range(1, 2**8 - 1):
            self.assertEqual(psi[i], 0)

        psi = state.ones(8)
        for i in range(0, 2**8 - 2):
            self.assertEqual(psi[i], 0)
        self.assertEqual(psi[2**8 - 1], 1)

        psi = state.rand(8)
        self.assertEqual(psi.nbits, 8)
Ejemplo n.º 19
0
def run_experiment(nbits):
    """Run single, defined experiment for secret 11."""

    psi = state.zeros(nbits * 2)
    c = make_c(nbits)
    u = make_u(nbits, c)

    psi = ops.Hadamard(nbits)(psi)
    psi = u(psi)
    psi = ops.Hadamard(nbits)(psi)

    # Because of the xor patterns (Yanofski 6.64)
    # measurement will only find those qubit strings where
    # the scalar product of z (lower bits) and secret string:
    #    <z, c> = 0
    #
    print('Measure likely states:')
    for bits in helper.bitprod(nbits * 2):
        if psi.prob(*bits) > 0.0 and dot2(bits, nbits) < 1.0:
            print('|{}> = 0 : {:.2f}  dot % 2: {:.2f}'.format(
                bits, psi.prob(*bits), dot2(bits, nbits)))
Ejemplo n.º 20
0
def ControlledU(idx0, idx1, u):
    """Control qubit at idx1 via controlling qubit at idx0."""

    if idx0 == idx1:
        raise ValueError('Control and controlled qubit must not be equal.')

    p0 = Projector(state.zeros(1))
    p1 = Projector(state.ones(1))
    ifill = Identity(int(math.fabs(idx1 - idx0)) - 1)  # space between qubits
    ufill = Identity()**u.nbits  # 'width' of U in terms of Identity matrices

    if idx1 > idx0:
        if idx1 - idx0 > 1:
            op = p0 * ifill * ufill + p1 * ifill * u
        else:
            op = p0 * ufill + p1 * u
    else:
        if idx0 - idx1 > 1:
            op = ufill * ifill * p0 + u * ifill * p1
        else:
            op = ufill * p0 + u * p1
    return op
Ejemplo n.º 21
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')
Ejemplo n.º 22
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.')
Ejemplo n.º 23
0
 def apply_single():
     psi = state.zeros(nbits)
     psi = apply_single_gate(gate, qubit, psi)
Ejemplo n.º 24
0
Archivo: grover.py Proyecto: 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')
Ejemplo n.º 25
0
 def zeros(self, n: int) -> None:
     self.psi = self.psi * state.zeros(n)
     self.global_reg = self.global_reg + n
Ejemplo n.º 26
0
Archivo: grover.py Proyecto: 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')
Ejemplo n.º 27
0
 def with_matmul():
     psi = state.zeros(nbits)
     op = ops.Identity(qubit) * gate * ops.Identity(nbits - qubit - 1)
     psi = op(psi)
Ejemplo n.º 28
0
 def with_matrix():
     psi = state.zeros(nbits)
     psi = ops.Hadamard(nbits)(psi)
Ejemplo n.º 29
0
 def bench():
     psi = state.zeros(nbits)
     for i in range(nbits):
         psi = apply_single_gate(h, i, psi)
Ejemplo n.º 30
0
 def individual():
     psi = state.zeros(nbits)
     h = ops.Hadamard()
     for i in range(nbits):
         psi = apply_single_gate(h, i, psi)