Example #1
0
def shor_factor(n):
    """Shor's factorization algorithm.

    Args:
      n: Integer >=2 to factor.

    Returns:
      If n is composite, a non-trivial factor of n. If n is prime, returns 1.

    Raises:
      ValueError if n is <= 1.
    """
    if n <= 1:
        raise ValueError('n must be at least 2')
    if is_prime(n):
        return 1
    if n % 2 == 0:
        return 2 # even numbers > 2 are trivial

    # Need to check that n is not a power of an integer for algorithm to work
    root = int_root(n)
    if root != -1:
        return root

    # choose m s.t. n^2 <= 2^m < 2*n^2
    # log2(n^2) <= m <= log2(2 * n^2) = 1 + log2(n^2)
    m = ceil(log(n**2, 2))

    ny = ceil(log(n - 1, 2)) # number of qubits in output of function f
    I = QuantumGate(eye(2**ny))
    H = kron(hadamard_gate(m), I)

    MAX_ITER = 10
    niter = 0
    while True:
        a = n - 1 # arbitrary integer coprime to n

        # Initialize a system of qubits long enough to represent the integers 0
        # to 2^m - 1 alongside an integer up to n - 1, then apply Hadamard gate
        # to the first m qubits to create a uniform superposition.
        q = QubitSystem(m + ny)
        H * q

        # Apply the function f(x) = a^x (mod n) to the system
        f = lambda x: pow(a, x, n)
        Uf = function_gate(f, m, ny)
        Uf * q

        # Find the period of f via quantum Fourier transform
        qft(q)
        r = 1. / q.measure() # period = 1 / frequency

        niter += 1
        if niter >= MAX_ITER or (r % 2 == 0 and (a**(r / 2)) % n != -1):
            break
    return gcd(a**(r / 2) + 1, n)
    def test_function_gate(self):
        f = lambda x: x >> 2
        m, k = 4, 2
        Uf = function_gate(f, m, k)

        # Initial state - M-bit binary string for 6 plus random K-bit register
        q = QubitSystem(m + k, 0b011010)
        # Expected output state: first M bits unchanged, followed by initial
        # string added to f(x) mod 2 (where x = first M bits)
        Uf * q
        self.assertEqual(q.measure(), 0b011011)