def __init__( self, N: int = 15, a: int = 2, quantum_instance: Optional[Union[QuantumInstance, BaseBackend, Backend]] = None ) -> None: """ Args: N: The integer to be factored, has a min. value of 3. a: Any integer that satisfies 1 < a < N and gcd(a, N) = 1. quantum_instance: Quantum Instance or Backend Raises: ValueError: Invalid input """ validate_min('N', N, 3) validate_min('a', a, 2) super().__init__(quantum_instance) self._n = None # type: Optional[int] self._up_qreg = None self._down_qreg = None # type: Optional[QuantumRegister] self._aux_qreg = None # type: Optional[QuantumRegister] # check the input integer if N < 1 or N % 2 == 0: raise ValueError( 'The input needs to be an odd integer greater than 1.') self._N = N if a >= N or math.gcd(a, self._N) != 1: raise ValueError( 'The integer a needs to satisfy a < N and gcd(a, N) = 1.') self._a = a self._ret = AlgorithmResult({ "factors": [], "total_counts": 0, "successful_counts": 0 }) # check if the input integer is a power tf, b, p = is_power(N, return_decomposition=True) if tf: logger.info('The input integer is a power: %s=%s^%s.', N, b, p) self._ret['factors'].append(b) self._qft = QFT(do_swaps=False).to_instruction() self._iqft = self._qft.inverse() self._phi_add_N = None # type: Optional[Gate] self._iphi_add_N = None
def factor( self, N: int, a: int = 2, ) -> 'ShorResult': """Execute the algorithm. The input integer :math:`N` to be factored is expected to be odd and greater than 2. Even though this implementation is general, its capability will be limited by the capacity of the simulator/hardware. Another input integer :math:`a` can also be supplied, which needs to be a co-prime smaller than :math:`N` . Args: N: The integer to be factored, has a min. value of 3. a: Any integer that satisfies 1 < a < N and gcd(a, N) = 1. Returns: ShorResult: results of the algorithm. Raises: ValueError: Invalid input AlgorithmError: If a quantum instance or backend has not been provided """ validate_min('N', N, 3) validate_min('a', a, 2) # check the input integer if N < 1 or N % 2 == 0: raise ValueError( 'The input needs to be an odd integer greater than 1.') if a >= N or math.gcd(a, N) != 1: raise ValueError( 'The integer a needs to satisfy a < N and gcd(a, N) = 1.') if self.quantum_instance is None: raise AlgorithmError( "A QuantumInstance or Backend " "must be supplied to run the quantum algorithm.") result = ShorResult() # check if the input integer is a power tf, b, p = is_power(N, return_decomposition=True) if tf: logger.info('The input integer is a power: %s=%s^%s.', N, b, p) result.factors.append(b) if not result.factors: logger.debug('Running with N=%s and a=%s.', N, a) if self._quantum_instance.is_statevector: circuit = self.construct_circuit(N=N, a=a, measurement=False) logger.warning('The statevector_simulator might lead to ' 'subsequent computation using too much memory.') result = self._quantum_instance.execute(circuit) complete_state_vec = result.get_statevector(circuit) # TODO: this uses too much memory up_qreg_density_mat = partial_trace( complete_state_vec, range(2 * self._n, 4 * self._n + 2)) up_qreg_density_mat_diag = np.diag(up_qreg_density_mat) counts = dict() for i, v in enumerate(up_qreg_density_mat_diag): if not v == 0: counts[bin(int(i))[2:].zfill(2 * self._n)] = v**2 else: circuit = self.construct_circuit(N=N, a=a, measurement=True) counts = self._quantum_instance.execute(circuit).get_counts( circuit) result.total_counts = len(counts) # For each simulation result, print proper info to user # and try to calculate the factors of N for measurement in list(counts.keys()): # Get the x_final value from the final state qubits logger.info("------> Analyzing result %s.", measurement) factors = self._get_factors(N, a, measurement) if factors: logger.info('Found factors %s from measurement %s.', factors, measurement) result.successful_counts = result.successful_counts + 1 if factors not in result.factors: result.factors.append(factors) return result