Source code for qolumbina.programs.shor_algorithm._common.shor_postprocessing

from fractions import Fraction
from math import gcd

[docs] def shor_classical_postprocess( counts: dict[str, int], a: int, N: int, num_control: int ): r""" Classical post-processing stage of Shor's algorithm. Args: counts: Qiskit backend measurement counts of the phase register. Format: {bitstring: shots} a: The base used in modular exponentiation. Must be coprime to :math:`N`. N: The integer :math:`N` to be factorized num_control: Number of control (phase) qubits. Returns: A non-trivial factor of N if found, otherwise None. """ FACTOR_FOUND = False num_attempt = 0 while not FACTOR_FOUND: print(f"\nATTEMPT {num_attempt}:") # Here, we get the bitstring by iterating over outcomes # of a previous hardware run with multiple shots. # Instead, we can also perform a single-shot measurement # here in the loop. bitstring = list(counts.keys())[num_attempt] num_attempt += 1 # Find the phase from measurement decimal = int(bitstring, 2) phase = decimal / (2**num_control) # phase = k / r print(f"Phase: theta = {phase}") # Guess the order from phase frac = Fraction(phase).limit_denominator(N) r = frac.denominator # order = r print(f"Order of {a} modulo {N} estimated as: r = {r}") if phase != 0: # Guesses for factors are gcd(a^{r / 2} +/- 1, N) if r % 2 == 0: x = pow(a, r // 2, N) - 1 d = gcd(x, N) if d > 1: FACTOR_FOUND = True print(f"*** Non-trivial factor found: {x} ***") return d