Source code for qrisp.algorithms.shor.shors_algorithm
"""\********************************************************************************* Copyright (c) 2025 the Qrisp authors** This program and the accompanying materials are made available under the* terms of the Eclipse Public License 2.0 which is available at* http://www.eclipse.org/legal/epl-2.0.** This Source Code may also be made available under the following Secondary* Licenses when the conditions for such availability set forth in the Eclipse* Public License, v. 2.0 are satisfied: GNU General Public License, version 2* with the GNU Classpath Exception which is* available at https://www.gnu.org/software/classpath/license.html.** SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0********************************************************************************/"""importnumpyasnpfromsympyimportcontinued_fraction_convergents,continued_fraction_iterator,Rationalfromqrisp.interfaceimportQiskitBackendfromqrisp.alg_primitives.arithmetic.modular_arithmeticimportfind_optimal_m,modinvfromqrispimportQuantumModulus,QuantumFloat,h,control,QFTdepths=[]cnot_count=[]qubits=[]deffind_optimal_a(N):n=int(np.ceil(np.log2(N)))proposals=[]# Search through the first O(1) possibilities to find a good aforainrange(2,min(100,N-1)):# We only append non-trivial proposalsifnp.gcd(a,N)==1:proposals.append(a)cost_dic={}forainproposals:m_values=[]forkinrange(2*n+1):inpl_multiplier=(a**(2**k))%Nifinpl_multiplier==1:continue# find_optimal_m is a function that determines the lowest possible# Montgomery shift for a given number. The higher the montgomery shift,# the more qubits and the more effort is needed.m_values.append(find_optimal_m(inpl_multiplier,N))m_values.append(find_optimal_m(modinv((-inpl_multiplier)%N,N),N))cost_dic[a]=sum(m_values)+max(m_values)*1E-5proposals.sort(key=lambdaa:cost_dic[a])optimal_a=proposals[0]m_values=[]forkinrange(2*n+1):inpl_multiplier=((optimal_a)**(2**k))%Nifinpl_multiplier==1:continuem_values.append(find_optimal_m(inpl_multiplier,N))returnproposalsdeffind_order(a,N,inpl_adder=None,mes_kwargs={}):qg=QuantumModulus(N,inpl_adder)qg[:]=1qpe_res=QuantumFloat(2*qg.size+1,exponent=-(2*qg.size+1))h(qpe_res)foriinrange(len(qpe_res)):withcontrol(qpe_res[i]):qg*=aa=(a*a)%NQFT(qpe_res,inv=True,inpl_adder=inpl_adder)mes_res=qpe_res.get_measurement(**mes_kwargs)returnextract_order(mes_res,a,N)defextract_order(mes_res,a,N):collected_r_values=[]approximations=list(mes_res.keys())try:approximations.remove(0)exceptValueError:passwhileTrue:r_values=get_r_values(approximations.pop(0))forrinr_values:if(a**r)%N==1:returnrcollected_r_values.append(r_values)fromitertoolsimportproductforcombinproduct(*collected_r_values):r=np.lcm.reduce(comb)if(a**r)%N==1:returnrdefget_r_values(approx):rationals=continued_fraction_convergents(continued_fraction_iterator(Rational(approx)))return[rat.qforratinrationalsif1<rat.q]
[docs]defshors_alg(N,inpl_adder=None,mes_kwargs={}):""" Performs `Shor's factorization algorithm <https://arxiv.org/abs/quant-ph/9508027>`_ on a given integer N. The adder used for factorization can be customized. To learn more about this feature, please read :ref:`QuantumModulus` Parameters ---------- N : integer The integer to be factored. inpl_adder : callable, optional A function that performs in-place addition. The default is None. mes_kwargs : dict, optional A dictionary of keyword arguments for :meth:`get_measurement <qrisp.QuantumVariable.get_measurement>`. This especially allows you to specify an execution backend. The default is {}. Returns ------- res : integer A factor of N. Examples -------- We factor 65: >>> from qrisp.shor import shors_alg >>> shors_alg(65) 5 """ifnotN%2:return2a_proposals=find_optimal_a(N)foraina_proposals:K=np.gcd(a,N)ifK!=1:res=Kbreakr=find_order(a,N,inpl_adder,mes_kwargs)ifr%2:continueg=int(np.gcd(a**(r//2)+1,N))ifgnotin[N,1]:res=gbreakreturnres
Get in touch!
If you are interested in Qrisp or high-level quantum algorithm research in general connect with us on our
Slack workspace.