예제 #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
파일: helper_test.py 프로젝트: xbe/qcc
    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))
예제 #3
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')
예제 #4
0
파일: bernstein.py 프로젝트: qcc4cp/qcc
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)
예제 #5
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)
예제 #6
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
예제 #7
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)
예제 #8
0
파일: state_test.py 프로젝트: qcc4cp/qcc
    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)
예제 #9
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
예제 #10
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.')
예제 #11
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')
예제 #12
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')
예제 #13
0
 def ones(self, n: int) -> None:
     self.psi = self.psi * state.ones(n)
     self.global_reg = self.global_reg + n
예제 #14
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')
예제 #15
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))
예제 #16
0
 def ones(self, n):
     self.psi = self.psi * state.ones(n)