12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654 |
- """
- Integer factorization
- """
- from collections import defaultdict
- from functools import reduce
- import random
- import math
- from sympy.core import sympify
- from sympy.core.containers import Dict
- from sympy.core.evalf import bitcount
- from sympy.core.expr import Expr
- from sympy.core.function import Function
- from sympy.core.logic import fuzzy_and
- from sympy.core.mul import Mul
- from sympy.core.numbers import igcd, ilcm, Rational, Integer
- from sympy.core.power import integer_nthroot, Pow, integer_log
- from sympy.core.singleton import S
- from sympy.external.gmpy import SYMPY_INTS
- from .primetest import isprime
- from .generate import sieve, primerange, nextprime
- from .digits import digits
- from sympy.utilities.iterables import flatten
- from sympy.utilities.misc import as_int, filldedent
- from .ecm import _ecm_one_factor
- # Note: This list should be updated whenever new Mersenne primes are found.
- # Refer: https://www.mersenne.org/
- MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
- 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
- 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
- 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933)
- # compute more when needed for i in Mersenne prime exponents
- PERFECT = [6] # 2**(i-1)*(2**i-1)
- MERSENNES = [3] # 2**i - 1
- def _ismersenneprime(n):
- global MERSENNES
- j = len(MERSENNES)
- while n > MERSENNES[-1] and j < len(MERSENNE_PRIME_EXPONENTS):
- # conservatively grow the list
- MERSENNES.append(2**MERSENNE_PRIME_EXPONENTS[j] - 1)
- j += 1
- return n in MERSENNES
- def _isperfect(n):
- global PERFECT
- if n % 2 == 0:
- j = len(PERFECT)
- while n > PERFECT[-1] and j < len(MERSENNE_PRIME_EXPONENTS):
- # conservatively grow the list
- t = 2**(MERSENNE_PRIME_EXPONENTS[j] - 1)
- PERFECT.append(t*(2*t - 1))
- j += 1
- return n in PERFECT
- small_trailing = [0] * 256
- for j in range(1,8):
- small_trailing[1<<j::1<<(j+1)] = [j] * (1<<(7-j))
- def smoothness(n):
- """
- Return the B-smooth and B-power smooth values of n.
- The smoothness of n is the largest prime factor of n; the power-
- smoothness is the largest divisor raised to its multiplicity.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import smoothness
- >>> smoothness(2**7*3**2)
- (3, 128)
- >>> smoothness(2**4*13)
- (13, 16)
- >>> smoothness(2)
- (2, 2)
- See Also
- ========
- factorint, smoothness_p
- """
- if n == 1:
- return (1, 1) # not prime, but otherwise this causes headaches
- facs = factorint(n)
- return max(facs), max(m**facs[m] for m in facs)
- def smoothness_p(n, m=-1, power=0, visual=None):
- """
- Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...]
- where:
- 1. p**M is the base-p divisor of n
- 2. sm(p + m) is the smoothness of p + m (m = -1 by default)
- 3. psm(p + m) is the power smoothness of p + m
- The list is sorted according to smoothness (default) or by power smoothness
- if power=1.
- The smoothness of the numbers to the left (m = -1) or right (m = 1) of a
- factor govern the results that are obtained from the p +/- 1 type factoring
- methods.
- >>> from sympy.ntheory.factor_ import smoothness_p, factorint
- >>> smoothness_p(10431, m=1)
- (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
- >>> smoothness_p(10431)
- (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
- >>> smoothness_p(10431, power=1)
- (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])
- If visual=True then an annotated string will be returned:
- >>> print(smoothness_p(21477639576571, visual=1))
- p**i=4410317**1 has p-1 B=1787, B-pow=1787
- p**i=4869863**1 has p-1 B=2434931, B-pow=2434931
- This string can also be generated directly from a factorization dictionary
- and vice versa:
- >>> factorint(17*9)
- {3: 2, 17: 1}
- >>> smoothness_p(_)
- 'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16'
- >>> smoothness_p(_)
- {3: 2, 17: 1}
- The table of the output logic is:
- ====== ====== ======= =======
- | Visual
- ------ ----------------------
- Input True False other
- ====== ====== ======= =======
- dict str tuple str
- str str tuple dict
- tuple str tuple str
- n str tuple tuple
- mul str tuple tuple
- ====== ====== ======= =======
- See Also
- ========
- factorint, smoothness
- """
- # visual must be True, False or other (stored as None)
- if visual in (1, 0):
- visual = bool(visual)
- elif visual not in (True, False):
- visual = None
- if isinstance(n, str):
- if visual:
- return n
- d = {}
- for li in n.splitlines():
- k, v = [int(i) for i in
- li.split('has')[0].split('=')[1].split('**')]
- d[k] = v
- if visual is not True and visual is not False:
- return d
- return smoothness_p(d, visual=False)
- elif not isinstance(n, tuple):
- facs = factorint(n, visual=False)
- if power:
- k = -1
- else:
- k = 1
- if isinstance(n, tuple):
- rv = n
- else:
- rv = (m, sorted([(f,
- tuple([M] + list(smoothness(f + m))))
- for f, M in list(facs.items())],
- key=lambda x: (x[1][k], x[0])))
- if visual is False or (visual is not True) and (type(n) in [int, Mul]):
- return rv
- lines = []
- for dat in rv[1]:
- dat = flatten(dat)
- dat.insert(2, m)
- lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat))
- return '\n'.join(lines)
- def trailing(n):
- """Count the number of trailing zero digits in the binary
- representation of n, i.e. determine the largest power of 2
- that divides n.
- Examples
- ========
- >>> from sympy import trailing
- >>> trailing(128)
- 7
- >>> trailing(63)
- 0
- """
- n = abs(int(n))
- if not n:
- return 0
- low_byte = n & 0xff
- if low_byte:
- return small_trailing[low_byte]
- # 2**m is quick for z up through 2**30
- z = bitcount(n) - 1
- if isinstance(z, SYMPY_INTS):
- if n == 1 << z:
- return z
- if z < 300:
- # fixed 8-byte reduction
- t = 8
- n >>= 8
- while not n & 0xff:
- n >>= 8
- t += 8
- return t + small_trailing[n & 0xff]
- # binary reduction important when there might be a large
- # number of trailing 0s
- t = 0
- p = 8
- while not n & 1:
- while not n & ((1 << p) - 1):
- n >>= p
- t += p
- p *= 2
- p //= 2
- return t
- def multiplicity(p, n):
- """
- Find the greatest integer m such that p**m divides n.
- Examples
- ========
- >>> from sympy import multiplicity, Rational
- >>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]]
- [0, 1, 2, 3, 3]
- >>> multiplicity(3, Rational(1, 9))
- -2
- Note: when checking for the multiplicity of a number in a
- large factorial it is most efficient to send it as an unevaluated
- factorial or to call ``multiplicity_in_factorial`` directly:
- >>> from sympy.ntheory import multiplicity_in_factorial
- >>> from sympy import factorial
- >>> p = factorial(25)
- >>> n = 2**100
- >>> nfac = factorial(n, evaluate=False)
- >>> multiplicity(p, nfac)
- 52818775009509558395695966887
- >>> _ == multiplicity_in_factorial(p, n)
- True
- """
- try:
- p, n = as_int(p), as_int(n)
- except ValueError:
- from sympy.functions.combinatorial.factorials import factorial
- if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)):
- p = Rational(p)
- n = Rational(n)
- if p.q == 1:
- if n.p == 1:
- return -multiplicity(p.p, n.q)
- return multiplicity(p.p, n.p) - multiplicity(p.p, n.q)
- elif p.p == 1:
- return multiplicity(p.q, n.q)
- else:
- like = min(
- multiplicity(p.p, n.p),
- multiplicity(p.q, n.q))
- cross = min(
- multiplicity(p.q, n.p),
- multiplicity(p.p, n.q))
- return like - cross
- elif (isinstance(p, (SYMPY_INTS, Integer)) and
- isinstance(n, factorial) and
- isinstance(n.args[0], Integer) and
- n.args[0] >= 0):
- return multiplicity_in_factorial(p, n.args[0])
- raise ValueError('expecting ints or fractions, got %s and %s' % (p, n))
- if n == 0:
- raise ValueError('no such integer exists: multiplicity of %s is not-defined' %(n))
- if p == 2:
- return trailing(n)
- if p < 2:
- raise ValueError('p must be an integer, 2 or larger, but got %s' % p)
- if p == n:
- return 1
- m = 0
- n, rem = divmod(n, p)
- while not rem:
- m += 1
- if m > 5:
- # The multiplicity could be very large. Better
- # to increment in powers of two
- e = 2
- while 1:
- ppow = p**e
- if ppow < n:
- nnew, rem = divmod(n, ppow)
- if not rem:
- m += e
- e *= 2
- n = nnew
- continue
- return m + multiplicity(p, n)
- n, rem = divmod(n, p)
- return m
- def multiplicity_in_factorial(p, n):
- """return the largest integer ``m`` such that ``p**m`` divides ``n!``
- without calculating the factorial of ``n``.
- Examples
- ========
- >>> from sympy.ntheory import multiplicity_in_factorial
- >>> from sympy import factorial
- >>> multiplicity_in_factorial(2, 3)
- 1
- An instructive use of this is to tell how many trailing zeros
- a given factorial has. For example, there are 6 in 25!:
- >>> factorial(25)
- 15511210043330985984000000
- >>> multiplicity_in_factorial(10, 25)
- 6
- For large factorials, it is much faster/feasible to use
- this function rather than computing the actual factorial:
- >>> multiplicity_in_factorial(factorial(25), 2**100)
- 52818775009509558395695966887
- """
- p, n = as_int(p), as_int(n)
- if p <= 0:
- raise ValueError('expecting positive integer got %s' % p )
- if n < 0:
- raise ValueError('expecting non-negative integer got %s' % n )
- factors = factorint(p)
- # keep only the largest of a given multiplicity since those
- # of a given multiplicity will be goverened by the behavior
- # of the largest factor
- test = defaultdict(int)
- for k, v in factors.items():
- test[v] = max(k, test[v])
- keep = set(test.values())
- # remove others from factors
- for k in list(factors.keys()):
- if k not in keep:
- factors.pop(k)
- mp = S.Infinity
- for i in factors:
- # multiplicity of i in n! is
- mi = (n - (sum(digits(n, i)) - i))//(i - 1)
- # multiplicity of p in n! depends on multiplicity
- # of prime `i` in p, so we floor divide by factors[i]
- # and keep it if smaller than the multiplicity of p
- # seen so far
- mp = min(mp, mi//factors[i])
- return mp
- def perfect_power(n, candidates=None, big=True, factor=True):
- """
- Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a unique
- perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a
- perfect power). A ValueError is raised if ``n`` is not Rational.
- By default, the base is recursively decomposed and the exponents
- collected so the largest possible ``e`` is sought. If ``big=False``
- then the smallest possible ``e`` (thus prime) will be chosen.
- If ``factor=True`` then simultaneous factorization of ``n`` is
- attempted since finding a factor indicates the only possible root
- for ``n``. This is True by default since only a few small factors will
- be tested in the course of searching for the perfect power.
- The use of ``candidates`` is primarily for internal use; if provided,
- False will be returned if ``n`` cannot be written as a power with one
- of the candidates as an exponent and factoring (beyond testing for
- a factor of 2) will not be attempted.
- Examples
- ========
- >>> from sympy import perfect_power, Rational
- >>> perfect_power(16)
- (2, 4)
- >>> perfect_power(16, big=False)
- (4, 2)
- Negative numbers can only have odd perfect powers:
- >>> perfect_power(-4)
- False
- >>> perfect_power(-8)
- (-2, 3)
- Rationals are also recognized:
- >>> perfect_power(Rational(1, 2)**3)
- (1/2, 3)
- >>> perfect_power(Rational(-3, 2)**3)
- (-3/2, 3)
- Notes
- =====
- To know whether an integer is a perfect power of 2 use
- >>> is2pow = lambda n: bool(n and not n & (n - 1))
- >>> [(i, is2pow(i)) for i in range(5)]
- [(0, False), (1, True), (2, True), (3, False), (4, True)]
- It is not necessary to provide ``candidates``. When provided
- it will be assumed that they are ints. The first one that is
- larger than the computed maximum possible exponent will signal
- failure for the routine.
- >>> perfect_power(3**8, [9])
- False
- >>> perfect_power(3**8, [2, 4, 8])
- (3, 8)
- >>> perfect_power(3**8, [4, 8], big=False)
- (9, 4)
- See Also
- ========
- sympy.core.power.integer_nthroot
- sympy.ntheory.primetest.is_square
- """
- if isinstance(n, Rational) and not n.is_Integer:
- p, q = n.as_numer_denom()
- if p is S.One:
- pp = perfect_power(q)
- if pp:
- pp = (n.func(1, pp[0]), pp[1])
- else:
- pp = perfect_power(p)
- if pp:
- num, e = pp
- pq = perfect_power(q, [e])
- if pq:
- den, _ = pq
- pp = n.func(num, den), e
- return pp
- n = as_int(n)
- if n < 0:
- pp = perfect_power(-n)
- if pp:
- b, e = pp
- if e % 2:
- return -b, e
- return False
- if n <= 3:
- # no unique exponent for 0, 1
- # 2 and 3 have exponents of 1
- return False
- logn = math.log(n, 2)
- max_possible = int(logn) + 2 # only check values less than this
- not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8
- min_possible = 2 + not_square
- if not candidates:
- candidates = primerange(min_possible, max_possible)
- else:
- candidates = sorted([i for i in candidates
- if min_possible <= i < max_possible])
- if n%2 == 0:
- e = trailing(n)
- candidates = [i for i in candidates if e%i == 0]
- if big:
- candidates = reversed(candidates)
- for e in candidates:
- r, ok = integer_nthroot(n, e)
- if ok:
- return (r, e)
- return False
- def _factors():
- rv = 2 + n % 2
- while True:
- yield rv
- rv = nextprime(rv)
- for fac, e in zip(_factors(), candidates):
- # see if there is a factor present
- if factor and n % fac == 0:
- # find what the potential power is
- if fac == 2:
- e = trailing(n)
- else:
- e = multiplicity(fac, n)
- # if it's a trivial power we are done
- if e == 1:
- return False
- # maybe the e-th root of n is exact
- r, exact = integer_nthroot(n, e)
- if not exact:
- # Having a factor, we know that e is the maximal
- # possible value for a root of n.
- # If n = fac**e*m can be written as a perfect
- # power then see if m can be written as r**E where
- # gcd(e, E) != 1 so n = (fac**(e//E)*r)**E
- m = n//fac**e
- rE = perfect_power(m, candidates=divisors(e, generator=True))
- if not rE:
- return False
- else:
- r, E = rE
- r, e = fac**(e//E)*r, E
- if not big:
- e0 = primefactors(e)
- if e0[0] != e:
- r, e = r**(e//e0[0]), e0[0]
- return r, e
- # Weed out downright impossible candidates
- if logn/e < 40:
- b = 2.0**(logn/e)
- if abs(int(b + 0.5) - b) > 0.01:
- continue
- # now see if the plausible e makes a perfect power
- r, exact = integer_nthroot(n, e)
- if exact:
- if big:
- m = perfect_power(r, big=big, factor=factor)
- if m:
- r, e = m[0], e*m[1]
- return int(r), e
- return False
- def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None):
- r"""
- Use Pollard's rho method to try to extract a nontrivial factor
- of ``n``. The returned factor may be a composite number. If no
- factor is found, ``None`` is returned.
- The algorithm generates pseudo-random values of x with a generator
- function, replacing x with F(x). If F is not supplied then the
- function x**2 + ``a`` is used. The first value supplied to F(x) is ``s``.
- Upon failure (if ``retries`` is > 0) a new ``a`` and ``s`` will be
- supplied; the ``a`` will be ignored if F was supplied.
- The sequence of numbers generated by such functions generally have a
- a lead-up to some number and then loop around back to that number and
- begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 -- this leader
- and loop look a bit like the Greek letter rho, and thus the name, 'rho'.
- For a given function, very different leader-loop values can be obtained
- so it is a good idea to allow for retries:
- >>> from sympy.ntheory.generate import cycle_length
- >>> n = 16843009
- >>> F = lambda x:(2048*pow(x, 2, n) + 32767) % n
- >>> for s in range(5):
- ... print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s)))
- ...
- loop length = 2489; leader length = 42
- loop length = 78; leader length = 120
- loop length = 1482; leader length = 99
- loop length = 1482; leader length = 285
- loop length = 1482; leader length = 100
- Here is an explicit example where there is a two element leadup to
- a sequence of 3 numbers (11, 14, 4) that then repeat:
- >>> x=2
- >>> for i in range(9):
- ... x=(x**2+12)%17
- ... print(x)
- ...
- 16
- 13
- 11
- 14
- 4
- 11
- 14
- 4
- 11
- >>> next(cycle_length(lambda x: (x**2+12)%17, 2))
- (3, 2)
- >>> list(cycle_length(lambda x: (x**2+12)%17, 2, values=True))
- [16, 13, 11, 14, 4]
- Instead of checking the differences of all generated values for a gcd
- with n, only the kth and 2*kth numbers are checked, e.g. 1st and 2nd,
- 2nd and 4th, 3rd and 6th until it has been detected that the loop has been
- traversed. Loops may be many thousands of steps long before rho finds a
- factor or reports failure. If ``max_steps`` is specified, the iteration
- is cancelled with a failure after the specified number of steps.
- Examples
- ========
- >>> from sympy import pollard_rho
- >>> n=16843009
- >>> F=lambda x:(2048*pow(x,2,n) + 32767) % n
- >>> pollard_rho(n, F=F)
- 257
- Use the default setting with a bad value of ``a`` and no retries:
- >>> pollard_rho(n, a=n-2, retries=0)
- If retries is > 0 then perhaps the problem will correct itself when
- new values are generated for a:
- >>> pollard_rho(n, a=n-2, retries=1)
- 257
- References
- ==========
- .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
- A Computational Perspective", Springer, 2nd edition, 229-231
- """
- n = int(n)
- if n < 5:
- raise ValueError('pollard_rho should receive n > 4')
- prng = random.Random(seed + retries)
- V = s
- for i in range(retries + 1):
- U = V
- if not F:
- F = lambda x: (pow(x, 2, n) + a) % n
- j = 0
- while 1:
- if max_steps and (j > max_steps):
- break
- j += 1
- U = F(U)
- V = F(F(V)) # V is 2x further along than U
- g = igcd(U - V, n)
- if g == 1:
- continue
- if g == n:
- break
- return int(g)
- V = prng.randint(0, n - 1)
- a = prng.randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2
- F = None
- return None
- def pollard_pm1(n, B=10, a=2, retries=0, seed=1234):
- """
- Use Pollard's p-1 method to try to extract a nontrivial factor
- of ``n``. Either a divisor (perhaps composite) or ``None`` is returned.
- The value of ``a`` is the base that is used in the test gcd(a**M - 1, n).
- The default is 2. If ``retries`` > 0 then if no factor is found after the
- first attempt, a new ``a`` will be generated randomly (using the ``seed``)
- and the process repeated.
- Note: the value of M is lcm(1..B) = reduce(ilcm, range(2, B + 1)).
- A search is made for factors next to even numbers having a power smoothness
- less than ``B``. Choosing a larger B increases the likelihood of finding a
- larger factor but takes longer. Whether a factor of n is found or not
- depends on ``a`` and the power smoothness of the even number just less than
- the factor p (hence the name p - 1).
- Although some discussion of what constitutes a good ``a`` some
- descriptions are hard to interpret. At the modular.math site referenced
- below it is stated that if gcd(a**M - 1, n) = N then a**M % q**r is 1
- for every prime power divisor of N. But consider the following:
- >>> from sympy.ntheory.factor_ import smoothness_p, pollard_pm1
- >>> n=257*1009
- >>> smoothness_p(n)
- (-1, [(257, (1, 2, 256)), (1009, (1, 7, 16))])
- So we should (and can) find a root with B=16:
- >>> pollard_pm1(n, B=16, a=3)
- 1009
- If we attempt to increase B to 256 we find that it does not work:
- >>> pollard_pm1(n, B=256)
- >>>
- But if the value of ``a`` is changed we find that only multiples of
- 257 work, e.g.:
- >>> pollard_pm1(n, B=256, a=257)
- 1009
- Checking different ``a`` values shows that all the ones that did not
- work had a gcd value not equal to ``n`` but equal to one of the
- factors:
- >>> from sympy import ilcm, igcd, factorint, Pow
- >>> M = 1
- >>> for i in range(2, 256):
- ... M = ilcm(M, i)
- ...
- >>> set([igcd(pow(a, M, n) - 1, n) for a in range(2, 256) if
- ... igcd(pow(a, M, n) - 1, n) != n])
- {1009}
- But does aM % d for every divisor of n give 1?
- >>> aM = pow(255, M, n)
- >>> [(d, aM%Pow(*d.args)) for d in factorint(n, visual=True).args]
- [(257**1, 1), (1009**1, 1)]
- No, only one of them. So perhaps the principle is that a root will
- be found for a given value of B provided that:
- 1) the power smoothness of the p - 1 value next to the root
- does not exceed B
- 2) a**M % p != 1 for any of the divisors of n.
- By trying more than one ``a`` it is possible that one of them
- will yield a factor.
- Examples
- ========
- With the default smoothness bound, this number cannot be cracked:
- >>> from sympy.ntheory import pollard_pm1
- >>> pollard_pm1(21477639576571)
- Increasing the smoothness bound helps:
- >>> pollard_pm1(21477639576571, B=2000)
- 4410317
- Looking at the smoothness of the factors of this number we find:
- >>> from sympy.ntheory.factor_ import smoothness_p, factorint
- >>> print(smoothness_p(21477639576571, visual=1))
- p**i=4410317**1 has p-1 B=1787, B-pow=1787
- p**i=4869863**1 has p-1 B=2434931, B-pow=2434931
- The B and B-pow are the same for the p - 1 factorizations of the divisors
- because those factorizations had a very large prime factor:
- >>> factorint(4410317 - 1)
- {2: 2, 617: 1, 1787: 1}
- >>> factorint(4869863-1)
- {2: 1, 2434931: 1}
- Note that until B reaches the B-pow value of 1787, the number is not cracked;
- >>> pollard_pm1(21477639576571, B=1786)
- >>> pollard_pm1(21477639576571, B=1787)
- 4410317
- The B value has to do with the factors of the number next to the divisor,
- not the divisors themselves. A worst case scenario is that the number next
- to the factor p has a large prime divisisor or is a perfect power. If these
- conditions apply then the power-smoothness will be about p/2 or p. The more
- realistic is that there will be a large prime factor next to p requiring
- a B value on the order of p/2. Although primes may have been searched for
- up to this level, the p/2 is a factor of p - 1, something that we do not
- know. The modular.math reference below states that 15% of numbers in the
- range of 10**15 to 15**15 + 10**4 are 10**6 power smooth so a B of 10**6
- will fail 85% of the time in that range. From 10**8 to 10**8 + 10**3 the
- percentages are nearly reversed...but in that range the simple trial
- division is quite fast.
- References
- ==========
- .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
- A Computational Perspective", Springer, 2nd edition, 236-238
- .. [2] https://web.archive.org/web/20150716201437/http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/node81.html
- .. [3] https://www.cs.toronto.edu/~yuvalf/Factorization.pdf
- """
- n = int(n)
- if n < 4 or B < 3:
- raise ValueError('pollard_pm1 should receive n > 3 and B > 2')
- prng = random.Random(seed + B)
- # computing a**lcm(1,2,3,..B) % n for B > 2
- # it looks weird, but it's right: primes run [2, B]
- # and the answer's not right until the loop is done.
- for i in range(retries + 1):
- aM = a
- for p in sieve.primerange(2, B + 1):
- e = int(math.log(B, p))
- aM = pow(aM, pow(p, e), n)
- g = igcd(aM - 1, n)
- if 1 < g < n:
- return int(g)
- # get a new a:
- # since the exponent, lcm(1..B), is even, if we allow 'a' to be 'n-1'
- # then (n - 1)**even % n will be 1 which will give a g of 0 and 1 will
- # give a zero, too, so we set the range as [2, n-2]. Some references
- # say 'a' should be coprime to n, but either will detect factors.
- a = prng.randint(2, n - 2)
- def _trial(factors, n, candidates, verbose=False):
- """
- Helper function for integer factorization. Trial factors ``n`
- against all integers given in the sequence ``candidates``
- and updates the dict ``factors`` in-place. Returns the reduced
- value of ``n`` and a flag indicating whether any factors were found.
- """
- if verbose:
- factors0 = list(factors.keys())
- nfactors = len(factors)
- for d in candidates:
- if n % d == 0:
- m = multiplicity(d, n)
- n //= d**m
- factors[d] = m
- if verbose:
- for k in sorted(set(factors).difference(set(factors0))):
- print(factor_msg % (k, factors[k]))
- return int(n), len(factors) != nfactors
- def _check_termination(factors, n, limitp1, use_trial, use_rho, use_pm1,
- verbose):
- """
- Helper function for integer factorization. Checks if ``n``
- is a prime or a perfect power, and in those cases updates
- the factorization and raises ``StopIteration``.
- """
- if verbose:
- print('Check for termination')
- # since we've already been factoring there is no need to do
- # simultaneous factoring with the power check
- p = perfect_power(n, factor=False)
- if p is not False:
- base, exp = p
- if limitp1:
- limit = limitp1 - 1
- else:
- limit = limitp1
- facs = factorint(base, limit, use_trial, use_rho, use_pm1,
- verbose=False)
- for b, e in facs.items():
- if verbose:
- print(factor_msg % (b, e))
- factors[b] = exp*e
- raise StopIteration
- if isprime(n):
- factors[int(n)] = 1
- raise StopIteration
- if n == 1:
- raise StopIteration
- trial_int_msg = "Trial division with ints [%i ... %i] and fail_max=%i"
- trial_msg = "Trial division with primes [%i ... %i]"
- rho_msg = "Pollard's rho with retries %i, max_steps %i and seed %i"
- pm1_msg = "Pollard's p-1 with smoothness bound %i and seed %i"
- ecm_msg = "Elliptic Curve with B1 bound %i, B2 bound %i, num_curves %i"
- factor_msg = '\t%i ** %i'
- fermat_msg = 'Close factors satisying Fermat condition found.'
- complete_msg = 'Factorization is complete.'
- def _factorint_small(factors, n, limit, fail_max):
- """
- Return the value of n and either a 0 (indicating that factorization up
- to the limit was complete) or else the next near-prime that would have
- been tested.
- Factoring stops if there are fail_max unsuccessful tests in a row.
- If factors of n were found they will be in the factors dictionary as
- {factor: multiplicity} and the returned value of n will have had those
- factors removed. The factors dictionary is modified in-place.
- """
- def done(n, d):
- """return n, d if the sqrt(n) was not reached yet, else
- n, 0 indicating that factoring is done.
- """
- if d*d <= n:
- return n, d
- return n, 0
- d = 2
- m = trailing(n)
- if m:
- factors[d] = m
- n >>= m
- d = 3
- if limit < d:
- if n > 1:
- factors[n] = 1
- return done(n, d)
- # reduce
- m = 0
- while n % d == 0:
- n //= d
- m += 1
- if m == 20:
- mm = multiplicity(d, n)
- m += mm
- n //= d**mm
- break
- if m:
- factors[d] = m
- # when d*d exceeds maxx or n we are done; if limit**2 is greater
- # than n then maxx is set to zero so the value of n will flag the finish
- if limit*limit > n:
- maxx = 0
- else:
- maxx = limit*limit
- dd = maxx or n
- d = 5
- fails = 0
- while fails < fail_max:
- if d*d > dd:
- break
- # d = 6*i - 1
- # reduce
- m = 0
- while n % d == 0:
- n //= d
- m += 1
- if m == 20:
- mm = multiplicity(d, n)
- m += mm
- n //= d**mm
- break
- if m:
- factors[d] = m
- dd = maxx or n
- fails = 0
- else:
- fails += 1
- d += 2
- if d*d > dd:
- break
- # d = 6*i - 1
- # reduce
- m = 0
- while n % d == 0:
- n //= d
- m += 1
- if m == 20:
- mm = multiplicity(d, n)
- m += mm
- n //= d**mm
- break
- if m:
- factors[d] = m
- dd = maxx or n
- fails = 0
- else:
- fails += 1
- # d = 6*(i + 1) - 1
- d += 4
- return done(n, d)
- def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True,
- use_ecm=True, verbose=False, visual=None, multiple=False):
- r"""
- Given a positive integer ``n``, ``factorint(n)`` returns a dict containing
- the prime factors of ``n`` as keys and their respective multiplicities
- as values. For example:
- >>> from sympy.ntheory import factorint
- >>> factorint(2000) # 2000 = (2**4) * (5**3)
- {2: 4, 5: 3}
- >>> factorint(65537) # This number is prime
- {65537: 1}
- For input less than 2, factorint behaves as follows:
- - ``factorint(1)`` returns the empty factorization, ``{}``
- - ``factorint(0)`` returns ``{0:1}``
- - ``factorint(-n)`` adds ``-1:1`` to the factors and then factors ``n``
- Partial Factorization:
- If ``limit`` (> 3) is specified, the search is stopped after performing
- trial division up to (and including) the limit (or taking a
- corresponding number of rho/p-1 steps). This is useful if one has
- a large number and only is interested in finding small factors (if
- any). Note that setting a limit does not prevent larger factors
- from being found early; it simply means that the largest factor may
- be composite. Since checking for perfect power is relatively cheap, it is
- done regardless of the limit setting.
- This number, for example, has two small factors and a huge
- semi-prime factor that cannot be reduced easily:
- >>> from sympy.ntheory import isprime
- >>> a = 1407633717262338957430697921446883
- >>> f = factorint(a, limit=10000)
- >>> f == {991: 1, int(202916782076162456022877024859): 1, 7: 1}
- True
- >>> isprime(max(f))
- False
- This number has a small factor and a residual perfect power whose
- base is greater than the limit:
- >>> factorint(3*101**7, limit=5)
- {3: 1, 101: 7}
- List of Factors:
- If ``multiple`` is set to ``True`` then a list containing the
- prime factors including multiplicities is returned.
- >>> factorint(24, multiple=True)
- [2, 2, 2, 3]
- Visual Factorization:
- If ``visual`` is set to ``True``, then it will return a visual
- factorization of the integer. For example:
- >>> from sympy import pprint
- >>> pprint(factorint(4200, visual=True))
- 3 1 2 1
- 2 *3 *5 *7
- Note that this is achieved by using the evaluate=False flag in Mul
- and Pow. If you do other manipulations with an expression where
- evaluate=False, it may evaluate. Therefore, you should use the
- visual option only for visualization, and use the normal dictionary
- returned by visual=False if you want to perform operations on the
- factors.
- You can easily switch between the two forms by sending them back to
- factorint:
- >>> from sympy import Mul
- >>> regular = factorint(1764); regular
- {2: 2, 3: 2, 7: 2}
- >>> pprint(factorint(regular))
- 2 2 2
- 2 *3 *7
- >>> visual = factorint(1764, visual=True); pprint(visual)
- 2 2 2
- 2 *3 *7
- >>> print(factorint(visual))
- {2: 2, 3: 2, 7: 2}
- If you want to send a number to be factored in a partially factored form
- you can do so with a dictionary or unevaluated expression:
- >>> factorint(factorint({4: 2, 12: 3})) # twice to toggle to dict form
- {2: 10, 3: 3}
- >>> factorint(Mul(4, 12, evaluate=False))
- {2: 4, 3: 1}
- The table of the output logic is:
- ====== ====== ======= =======
- Visual
- ------ ----------------------
- Input True False other
- ====== ====== ======= =======
- dict mul dict mul
- n mul dict dict
- mul mul dict dict
- ====== ====== ======= =======
- Notes
- =====
- Algorithm:
- The function switches between multiple algorithms. Trial division
- quickly finds small factors (of the order 1-5 digits), and finds
- all large factors if given enough time. The Pollard rho and p-1
- algorithms are used to find large factors ahead of time; they
- will often find factors of the order of 10 digits within a few
- seconds:
- >>> factors = factorint(12345678910111213141516)
- >>> for base, exp in sorted(factors.items()):
- ... print('%s %s' % (base, exp))
- ...
- 2 2
- 2507191691 1
- 1231026625769 1
- Any of these methods can optionally be disabled with the following
- boolean parameters:
- - ``use_trial``: Toggle use of trial division
- - ``use_rho``: Toggle use of Pollard's rho method
- - ``use_pm1``: Toggle use of Pollard's p-1 method
- ``factorint`` also periodically checks if the remaining part is
- a prime number or a perfect power, and in those cases stops.
- For unevaluated factorial, it uses Legendre's formula(theorem).
- If ``verbose`` is set to ``True``, detailed progress is printed.
- See Also
- ========
- smoothness, smoothness_p, divisors
- """
- if isinstance(n, Dict):
- n = dict(n)
- if multiple:
- fac = factorint(n, limit=limit, use_trial=use_trial,
- use_rho=use_rho, use_pm1=use_pm1,
- verbose=verbose, visual=False, multiple=False)
- factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p])
- for p in sorted(fac)), [])
- return factorlist
- factordict = {}
- if visual and not isinstance(n, (Mul, dict)):
- factordict = factorint(n, limit=limit, use_trial=use_trial,
- use_rho=use_rho, use_pm1=use_pm1,
- verbose=verbose, visual=False)
- elif isinstance(n, Mul):
- factordict = {int(k): int(v) for k, v in
- n.as_powers_dict().items()}
- elif isinstance(n, dict):
- factordict = n
- if factordict and isinstance(n, (Mul, dict)):
- # check it
- for key in list(factordict.keys()):
- if isprime(key):
- continue
- e = factordict.pop(key)
- d = factorint(key, limit=limit, use_trial=use_trial, use_rho=use_rho,
- use_pm1=use_pm1, verbose=verbose, visual=False)
- for k, v in d.items():
- if k in factordict:
- factordict[k] += v*e
- else:
- factordict[k] = v*e
- if visual or (type(n) is dict and
- visual is not True and
- visual is not False):
- if factordict == {}:
- return S.One
- if -1 in factordict:
- factordict.pop(-1)
- args = [S.NegativeOne]
- else:
- args = []
- args.extend([Pow(*i, evaluate=False)
- for i in sorted(factordict.items())])
- return Mul(*args, evaluate=False)
- elif isinstance(n, (dict, Mul)):
- return factordict
- assert use_trial or use_rho or use_pm1 or use_ecm
- from sympy.functions.combinatorial.factorials import factorial
- if isinstance(n, factorial):
- x = as_int(n.args[0])
- if x >= 20:
- factors = {}
- m = 2 # to initialize the if condition below
- for p in sieve.primerange(2, x + 1):
- if m > 1:
- m, q = 0, x // p
- while q != 0:
- m += q
- q //= p
- factors[p] = m
- if factors and verbose:
- for k in sorted(factors):
- print(factor_msg % (k, factors[k]))
- if verbose:
- print(complete_msg)
- return factors
- else:
- # if n < 20!, direct computation is faster
- # since it uses a lookup table
- n = n.func(x)
- n = as_int(n)
- if limit:
- limit = int(limit)
- use_ecm = False
- # special cases
- if n < 0:
- factors = factorint(
- -n, limit=limit, use_trial=use_trial, use_rho=use_rho,
- use_pm1=use_pm1, verbose=verbose, visual=False)
- factors[-1] = 1
- return factors
- if limit and limit < 2:
- if n == 1:
- return {}
- return {n: 1}
- elif n < 10:
- # doing this we are assured of getting a limit > 2
- # when we have to compute it later
- return [{0: 1}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1},
- {2: 1, 3: 1}, {7: 1}, {2: 3}, {3: 2}][n]
- factors = {}
- # do simplistic factorization
- if verbose:
- sn = str(n)
- if len(sn) > 50:
- print('Factoring %s' % sn[:5] + \
- '..(%i other digits)..' % (len(sn) - 10) + sn[-5:])
- else:
- print('Factoring', n)
- if use_trial:
- # this is the preliminary factorization for small factors
- small = 2**15
- fail_max = 600
- small = min(small, limit or small)
- if verbose:
- print(trial_int_msg % (2, small, fail_max))
- n, next_p = _factorint_small(factors, n, small, fail_max)
- else:
- next_p = 2
- if factors and verbose:
- for k in sorted(factors):
- print(factor_msg % (k, factors[k]))
- if next_p == 0:
- if n > 1:
- factors[int(n)] = 1
- if verbose:
- print(complete_msg)
- return factors
- # continue with more advanced factorization methods
- # first check if the simplistic run didn't finish
- # because of the limit and check for a perfect
- # power before exiting
- try:
- if limit and next_p > limit:
- if verbose:
- print('Exceeded limit:', limit)
- _check_termination(factors, n, limit, use_trial, use_rho, use_pm1,
- verbose)
- if n > 1:
- factors[int(n)] = 1
- return factors
- else:
- # Before quitting (or continuing on)...
- # ...do a Fermat test since it's so easy and we need the
- # square root anyway. Finding 2 factors is easy if they are
- # "close enough." This is the big root equivalent of dividing by
- # 2, 3, 5.
- sqrt_n = integer_nthroot(n, 2)[0]
- a = sqrt_n + 1
- a2 = a**2
- b2 = a2 - n
- for i in range(3):
- b, fermat = integer_nthroot(b2, 2)
- if fermat:
- break
- b2 += 2*a + 1 # equiv to (a + 1)**2 - n
- a += 1
- if fermat:
- if verbose:
- print(fermat_msg)
- if limit:
- limit -= 1
- for r in [a - b, a + b]:
- facs = factorint(r, limit=limit, use_trial=use_trial,
- use_rho=use_rho, use_pm1=use_pm1,
- verbose=verbose)
- for k, v in facs.items():
- factors[k] = factors.get(k, 0) + v
- raise StopIteration
- # ...see if factorization can be terminated
- _check_termination(factors, n, limit, use_trial, use_rho, use_pm1,
- verbose)
- except StopIteration:
- if verbose:
- print(complete_msg)
- return factors
- # these are the limits for trial division which will
- # be attempted in parallel with pollard methods
- low, high = next_p, 2*next_p
- limit = limit or sqrt_n
- # add 1 to make sure limit is reached in primerange calls
- limit += 1
- iteration = 0
- while 1:
- try:
- high_ = high
- if limit < high_:
- high_ = limit
- # Trial division
- if use_trial:
- if verbose:
- print(trial_msg % (low, high_))
- ps = sieve.primerange(low, high_)
- n, found_trial = _trial(factors, n, ps, verbose)
- if found_trial:
- _check_termination(factors, n, limit, use_trial, use_rho,
- use_pm1, verbose)
- else:
- found_trial = False
- if high > limit:
- if verbose:
- print('Exceeded limit:', limit)
- if n > 1:
- factors[int(n)] = 1
- raise StopIteration
- # Only used advanced methods when no small factors were found
- if not found_trial:
- if (use_pm1 or use_rho):
- high_root = max(int(math.log(high_**0.7)), low, 3)
- # Pollard p-1
- if use_pm1:
- if verbose:
- print(pm1_msg % (high_root, high_))
- c = pollard_pm1(n, B=high_root, seed=high_)
- if c:
- # factor it and let _trial do the update
- ps = factorint(c, limit=limit - 1,
- use_trial=use_trial,
- use_rho=use_rho,
- use_pm1=use_pm1,
- use_ecm=use_ecm,
- verbose=verbose)
- n, _ = _trial(factors, n, ps, verbose=False)
- _check_termination(factors, n, limit, use_trial,
- use_rho, use_pm1, verbose)
- # Pollard rho
- if use_rho:
- max_steps = high_root
- if verbose:
- print(rho_msg % (1, max_steps, high_))
- c = pollard_rho(n, retries=1, max_steps=max_steps,
- seed=high_)
- if c:
- # factor it and let _trial do the update
- ps = factorint(c, limit=limit - 1,
- use_trial=use_trial,
- use_rho=use_rho,
- use_pm1=use_pm1,
- use_ecm=use_ecm,
- verbose=verbose)
- n, _ = _trial(factors, n, ps, verbose=False)
- _check_termination(factors, n, limit, use_trial,
- use_rho, use_pm1, verbose)
- except StopIteration:
- if verbose:
- print(complete_msg)
- return factors
- #Use subexponential algorithms if use_ecm
- #Use pollard algorithms for finding small factors for 3 iterations
- #if after small factors the number of digits of n is >= 20 then use ecm
- iteration += 1
- if use_ecm and iteration >= 3 and len(str(n)) >= 25:
- break
- low, high = high, high*2
- B1 = 10000
- B2 = 100*B1
- num_curves = 50
- while(1):
- if verbose:
- print(ecm_msg % (B1, B2, num_curves))
- while(1):
- try:
- factor = _ecm_one_factor(n, B1, B2, num_curves)
- ps = factorint(factor, limit=limit - 1,
- use_trial=use_trial,
- use_rho=use_rho,
- use_pm1=use_pm1,
- use_ecm=use_ecm,
- verbose=verbose)
- n, _ = _trial(factors, n, ps, verbose=False)
- _check_termination(factors, n, limit, use_trial,
- use_rho, use_pm1, verbose)
- except ValueError:
- break
- except StopIteration:
- if verbose:
- print(complete_msg)
- return factors
- B1 *= 5
- B2 = 100*B1
- num_curves *= 4
- def factorrat(rat, limit=None, use_trial=True, use_rho=True, use_pm1=True,
- verbose=False, visual=None, multiple=False):
- r"""
- Given a Rational ``r``, ``factorrat(r)`` returns a dict containing
- the prime factors of ``r`` as keys and their respective multiplicities
- as values. For example:
- >>> from sympy import factorrat, S
- >>> factorrat(S(8)/9) # 8/9 = (2**3) * (3**-2)
- {2: 3, 3: -2}
- >>> factorrat(S(-1)/987) # -1/789 = -1 * (3**-1) * (7**-1) * (47**-1)
- {-1: 1, 3: -1, 7: -1, 47: -1}
- Please see the docstring for ``factorint`` for detailed explanations
- and examples of the following keywords:
- - ``limit``: Integer limit up to which trial division is done
- - ``use_trial``: Toggle use of trial division
- - ``use_rho``: Toggle use of Pollard's rho method
- - ``use_pm1``: Toggle use of Pollard's p-1 method
- - ``verbose``: Toggle detailed printing of progress
- - ``multiple``: Toggle returning a list of factors or dict
- - ``visual``: Toggle product form of output
- """
- if multiple:
- fac = factorrat(rat, limit=limit, use_trial=use_trial,
- use_rho=use_rho, use_pm1=use_pm1,
- verbose=verbose, visual=False, multiple=False)
- factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p])
- for p, _ in sorted(fac.items(),
- key=lambda elem: elem[0]
- if elem[1] > 0
- else 1/elem[0])), [])
- return factorlist
- f = factorint(rat.p, limit=limit, use_trial=use_trial,
- use_rho=use_rho, use_pm1=use_pm1,
- verbose=verbose).copy()
- f = defaultdict(int, f)
- for p, e in factorint(rat.q, limit=limit,
- use_trial=use_trial,
- use_rho=use_rho,
- use_pm1=use_pm1,
- verbose=verbose).items():
- f[p] += -e
- if len(f) > 1 and 1 in f:
- del f[1]
- if not visual:
- return dict(f)
- else:
- if -1 in f:
- f.pop(-1)
- args = [S.NegativeOne]
- else:
- args = []
- args.extend([Pow(*i, evaluate=False)
- for i in sorted(f.items())])
- return Mul(*args, evaluate=False)
- def primefactors(n, limit=None, verbose=False):
- """Return a sorted list of n's prime factors, ignoring multiplicity
- and any composite factor that remains if the limit was set too low
- for complete factorization. Unlike factorint(), primefactors() does
- not return -1 or 0.
- Examples
- ========
- >>> from sympy.ntheory import primefactors, factorint, isprime
- >>> primefactors(6)
- [2, 3]
- >>> primefactors(-5)
- [5]
- >>> sorted(factorint(123456).items())
- [(2, 6), (3, 1), (643, 1)]
- >>> primefactors(123456)
- [2, 3, 643]
- >>> sorted(factorint(10000000001, limit=200).items())
- [(101, 1), (99009901, 1)]
- >>> isprime(99009901)
- False
- >>> primefactors(10000000001, limit=300)
- [101]
- See Also
- ========
- divisors
- """
- n = int(n)
- factors = sorted(factorint(n, limit=limit, verbose=verbose).keys())
- s = [f for f in factors[:-1:] if f not in [-1, 0, 1]]
- if factors and isprime(factors[-1]):
- s += [factors[-1]]
- return s
- def _divisors(n, proper=False):
- """Helper function for divisors which generates the divisors."""
- factordict = factorint(n)
- ps = sorted(factordict.keys())
- def rec_gen(n=0):
- if n == len(ps):
- yield 1
- else:
- pows = [1]
- for j in range(factordict[ps[n]]):
- pows.append(pows[-1] * ps[n])
- for q in rec_gen(n + 1):
- for p in pows:
- yield p * q
- if proper:
- for p in rec_gen():
- if p != n:
- yield p
- else:
- yield from rec_gen()
- def divisors(n, generator=False, proper=False):
- r"""
- Return all divisors of n sorted from 1..n by default.
- If generator is ``True`` an unordered generator is returned.
- The number of divisors of n can be quite large if there are many
- prime factors (counting repeated factors). If only the number of
- factors is desired use divisor_count(n).
- Examples
- ========
- >>> from sympy import divisors, divisor_count
- >>> divisors(24)
- [1, 2, 3, 4, 6, 8, 12, 24]
- >>> divisor_count(24)
- 8
- >>> list(divisors(120, generator=True))
- [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60, 120]
- Notes
- =====
- This is a slightly modified version of Tim Peters referenced at:
- https://stackoverflow.com/questions/1010381/python-factorization
- See Also
- ========
- primefactors, factorint, divisor_count
- """
- n = as_int(abs(n))
- if isprime(n):
- if proper:
- return [1]
- return [1, n]
- if n == 1:
- if proper:
- return []
- return [1]
- if n == 0:
- return []
- rv = _divisors(n, proper)
- if not generator:
- return sorted(rv)
- return rv
- def divisor_count(n, modulus=1, proper=False):
- """
- Return the number of divisors of ``n``. If ``modulus`` is not 1 then only
- those that are divisible by ``modulus`` are counted. If ``proper`` is True
- then the divisor of ``n`` will not be counted.
- Examples
- ========
- >>> from sympy import divisor_count
- >>> divisor_count(6)
- 4
- >>> divisor_count(6, 2)
- 2
- >>> divisor_count(6, proper=True)
- 3
- See Also
- ========
- factorint, divisors, totient, proper_divisor_count
- """
- if not modulus:
- return 0
- elif modulus != 1:
- n, r = divmod(n, modulus)
- if r:
- return 0
- if n == 0:
- return 0
- n = Mul(*[v + 1 for k, v in factorint(n).items() if k > 1])
- if n and proper:
- n -= 1
- return n
- def proper_divisors(n, generator=False):
- """
- Return all divisors of n except n, sorted by default.
- If generator is ``True`` an unordered generator is returned.
- Examples
- ========
- >>> from sympy import proper_divisors, proper_divisor_count
- >>> proper_divisors(24)
- [1, 2, 3, 4, 6, 8, 12]
- >>> proper_divisor_count(24)
- 7
- >>> list(proper_divisors(120, generator=True))
- [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60]
- See Also
- ========
- factorint, divisors, proper_divisor_count
- """
- return divisors(n, generator=generator, proper=True)
- def proper_divisor_count(n, modulus=1):
- """
- Return the number of proper divisors of ``n``.
- Examples
- ========
- >>> from sympy import proper_divisor_count
- >>> proper_divisor_count(6)
- 3
- >>> proper_divisor_count(6, modulus=2)
- 1
- See Also
- ========
- divisors, proper_divisors, divisor_count
- """
- return divisor_count(n, modulus=modulus, proper=True)
- def _udivisors(n):
- """Helper function for udivisors which generates the unitary divisors."""
- factorpows = [p**e for p, e in factorint(n).items()]
- for i in range(2**len(factorpows)):
- d, j, k = 1, i, 0
- while j:
- if (j & 1):
- d *= factorpows[k]
- j >>= 1
- k += 1
- yield d
- def udivisors(n, generator=False):
- r"""
- Return all unitary divisors of n sorted from 1..n by default.
- If generator is ``True`` an unordered generator is returned.
- The number of unitary divisors of n can be quite large if there are many
- prime factors. If only the number of unitary divisors is desired use
- udivisor_count(n).
- Examples
- ========
- >>> from sympy.ntheory.factor_ import udivisors, udivisor_count
- >>> udivisors(15)
- [1, 3, 5, 15]
- >>> udivisor_count(15)
- 4
- >>> sorted(udivisors(120, generator=True))
- [1, 3, 5, 8, 15, 24, 40, 120]
- See Also
- ========
- primefactors, factorint, divisors, divisor_count, udivisor_count
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Unitary_divisor
- .. [2] https://mathworld.wolfram.com/UnitaryDivisor.html
- """
- n = as_int(abs(n))
- if isprime(n):
- return [1, n]
- if n == 1:
- return [1]
- if n == 0:
- return []
- rv = _udivisors(n)
- if not generator:
- return sorted(rv)
- return rv
- def udivisor_count(n):
- """
- Return the number of unitary divisors of ``n``.
- Parameters
- ==========
- n : integer
- Examples
- ========
- >>> from sympy.ntheory.factor_ import udivisor_count
- >>> udivisor_count(120)
- 8
- See Also
- ========
- factorint, divisors, udivisors, divisor_count, totient
- References
- ==========
- .. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html
- """
- if n == 0:
- return 0
- return 2**len([p for p in factorint(n) if p > 1])
- def _antidivisors(n):
- """Helper function for antidivisors which generates the antidivisors."""
- for d in _divisors(n):
- y = 2*d
- if n > y and n % y:
- yield y
- for d in _divisors(2*n-1):
- if n > d >= 2 and n % d:
- yield d
- for d in _divisors(2*n+1):
- if n > d >= 2 and n % d:
- yield d
- def antidivisors(n, generator=False):
- r"""
- Return all antidivisors of n sorted from 1..n by default.
- Antidivisors [1]_ of n are numbers that do not divide n by the largest
- possible margin. If generator is True an unordered generator is returned.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import antidivisors
- >>> antidivisors(24)
- [7, 16]
- >>> sorted(antidivisors(128, generator=True))
- [3, 5, 15, 17, 51, 85]
- See Also
- ========
- primefactors, factorint, divisors, divisor_count, antidivisor_count
- References
- ==========
- .. [1] definition is described in https://oeis.org/A066272/a066272a.html
- """
- n = as_int(abs(n))
- if n <= 2:
- return []
- rv = _antidivisors(n)
- if not generator:
- return sorted(rv)
- return rv
- def antidivisor_count(n):
- """
- Return the number of antidivisors [1]_ of ``n``.
- Parameters
- ==========
- n : integer
- Examples
- ========
- >>> from sympy.ntheory.factor_ import antidivisor_count
- >>> antidivisor_count(13)
- 4
- >>> antidivisor_count(27)
- 5
- See Also
- ========
- factorint, divisors, antidivisors, divisor_count, totient
- References
- ==========
- .. [1] formula from https://oeis.org/A066272
- """
- n = as_int(abs(n))
- if n <= 2:
- return 0
- return divisor_count(2*n - 1) + divisor_count(2*n + 1) + \
- divisor_count(n) - divisor_count(n, 2) - 5
- class totient(Function):
- r"""
- Calculate the Euler totient function phi(n)
- ``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n
- that are relatively prime to n.
- Parameters
- ==========
- n : integer
- Examples
- ========
- >>> from sympy.ntheory import totient
- >>> totient(1)
- 1
- >>> totient(25)
- 20
- >>> totient(45) == totient(5)*totient(9)
- True
- See Also
- ========
- divisor_count
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function
- .. [2] https://mathworld.wolfram.com/TotientFunction.html
- """
- @classmethod
- def eval(cls, n):
- if n.is_Integer:
- if n < 1:
- raise ValueError("n must be a positive integer")
- factors = factorint(n)
- return cls._from_factors(factors)
- elif not isinstance(n, Expr) or (n.is_integer is False) or (n.is_positive is False):
- raise ValueError("n must be a positive integer")
- def _eval_is_integer(self):
- return fuzzy_and([self.args[0].is_integer, self.args[0].is_positive])
- @classmethod
- def _from_distinct_primes(self, *args):
- """Subroutine to compute totient from the list of assumed
- distinct primes
- Examples
- ========
- >>> from sympy.ntheory.factor_ import totient
- >>> totient._from_distinct_primes(5, 7)
- 24
- """
- return reduce(lambda i, j: i * (j-1), args, 1)
- @classmethod
- def _from_factors(self, factors):
- """Subroutine to compute totient from already-computed factors
- Examples
- ========
- >>> from sympy.ntheory.factor_ import totient
- >>> totient._from_factors({5: 2})
- 20
- """
- t = 1
- for p, k in factors.items():
- t *= (p - 1) * p**(k - 1)
- return t
- class reduced_totient(Function):
- r"""
- Calculate the Carmichael reduced totient function lambda(n)
- ``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that
- `k^m \equiv 1 \mod n` for all k relatively prime to n.
- Examples
- ========
- >>> from sympy.ntheory import reduced_totient
- >>> reduced_totient(1)
- 1
- >>> reduced_totient(8)
- 2
- >>> reduced_totient(30)
- 4
- See Also
- ========
- totient
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Carmichael_function
- .. [2] https://mathworld.wolfram.com/CarmichaelFunction.html
- """
- @classmethod
- def eval(cls, n):
- if n.is_Integer:
- if n < 1:
- raise ValueError("n must be a positive integer")
- factors = factorint(n)
- return cls._from_factors(factors)
- @classmethod
- def _from_factors(self, factors):
- """Subroutine to compute totient from already-computed factors
- """
- t = 1
- for p, k in factors.items():
- if p == 2 and k > 2:
- t = ilcm(t, 2**(k - 2))
- else:
- t = ilcm(t, (p - 1) * p**(k - 1))
- return t
- @classmethod
- def _from_distinct_primes(self, *args):
- """Subroutine to compute totient from the list of assumed
- distinct primes
- """
- args = [p - 1 for p in args]
- return ilcm(*args)
- def _eval_is_integer(self):
- return fuzzy_and([self.args[0].is_integer, self.args[0].is_positive])
- class divisor_sigma(Function):
- r"""
- Calculate the divisor function `\sigma_k(n)` for positive integer n
- ``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])``
- If n's prime factorization is:
- .. math ::
- n = \prod_{i=1}^\omega p_i^{m_i},
- then
- .. math ::
- \sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots
- + p_i^{m_ik}).
- Parameters
- ==========
- n : integer
- k : integer, optional
- power of divisors in the sum
- for k = 0, 1:
- ``divisor_sigma(n, 0)`` is equal to ``divisor_count(n)``
- ``divisor_sigma(n, 1)`` is equal to ``sum(divisors(n))``
- Default for k is 1.
- Examples
- ========
- >>> from sympy.ntheory import divisor_sigma
- >>> divisor_sigma(18, 0)
- 6
- >>> divisor_sigma(39, 1)
- 56
- >>> divisor_sigma(12, 2)
- 210
- >>> divisor_sigma(37)
- 38
- See Also
- ========
- divisor_count, totient, divisors, factorint
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Divisor_function
- """
- @classmethod
- def eval(cls, n, k=S.One):
- k = sympify(k)
- if n.is_prime:
- return 1 + n**k
- if n.is_Integer:
- if n <= 0:
- raise ValueError("n must be a positive integer")
- elif k.is_Integer:
- k = int(k)
- return Integer(math.prod(
- (p**(k*(e + 1)) - 1)//(p**k - 1) if k != 0
- else e + 1 for p, e in factorint(n).items()))
- else:
- return Mul(*[(p**(k*(e + 1)) - 1)/(p**k - 1) if k != 0
- else e + 1 for p, e in factorint(n).items()])
- if n.is_integer: # symbolic case
- args = []
- for p, e in (_.as_base_exp() for _ in Mul.make_args(n)):
- if p.is_prime and e.is_positive:
- args.append((p**(k*(e + 1)) - 1)/(p**k - 1) if
- k != 0 else e + 1)
- else:
- return
- return Mul(*args)
- def core(n, t=2):
- r"""
- Calculate core(n, t) = `core_t(n)` of a positive integer n
- ``core_2(n)`` is equal to the squarefree part of n
- If n's prime factorization is:
- .. math ::
- n = \prod_{i=1}^\omega p_i^{m_i},
- then
- .. math ::
- core_t(n) = \prod_{i=1}^\omega p_i^{m_i \mod t}.
- Parameters
- ==========
- n : integer
- t : integer
- core(n, t) calculates the t-th power free part of n
- ``core(n, 2)`` is the squarefree part of ``n``
- ``core(n, 3)`` is the cubefree part of ``n``
- Default for t is 2.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import core
- >>> core(24, 2)
- 6
- >>> core(9424, 3)
- 1178
- >>> core(379238)
- 379238
- >>> core(15**11, 10)
- 15
- See Also
- ========
- factorint, sympy.solvers.diophantine.diophantine.square_factor
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core
- """
- n = as_int(n)
- t = as_int(t)
- if n <= 0:
- raise ValueError("n must be a positive integer")
- elif t <= 1:
- raise ValueError("t must be >= 2")
- else:
- y = 1
- for p, e in factorint(n).items():
- y *= p**(e % t)
- return y
- class udivisor_sigma(Function):
- r"""
- Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n
- ``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])``
- If n's prime factorization is:
- .. math ::
- n = \prod_{i=1}^\omega p_i^{m_i},
- then
- .. math ::
- \sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}).
- Parameters
- ==========
- k : power of divisors in the sum
- for k = 0, 1:
- ``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)``
- ``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))``
- Default for k is 1.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import udivisor_sigma
- >>> udivisor_sigma(18, 0)
- 4
- >>> udivisor_sigma(74, 1)
- 114
- >>> udivisor_sigma(36, 3)
- 47450
- >>> udivisor_sigma(111)
- 152
- See Also
- ========
- divisor_count, totient, divisors, udivisors, udivisor_count, divisor_sigma,
- factorint
- References
- ==========
- .. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html
- """
- @classmethod
- def eval(cls, n, k=S.One):
- k = sympify(k)
- if n.is_prime:
- return 1 + n**k
- if n.is_Integer:
- if n <= 0:
- raise ValueError("n must be a positive integer")
- else:
- return Mul(*[1+p**(k*e) for p, e in factorint(n).items()])
- class primenu(Function):
- r"""
- Calculate the number of distinct prime factors for a positive integer n.
- If n's prime factorization is:
- .. math ::
- n = \prod_{i=1}^k p_i^{m_i},
- then ``primenu(n)`` or `\nu(n)` is:
- .. math ::
- \nu(n) = k.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import primenu
- >>> primenu(1)
- 0
- >>> primenu(30)
- 3
- See Also
- ========
- factorint
- References
- ==========
- .. [1] https://mathworld.wolfram.com/PrimeFactor.html
- """
- @classmethod
- def eval(cls, n):
- if n.is_Integer:
- if n <= 0:
- raise ValueError("n must be a positive integer")
- else:
- return len(factorint(n).keys())
- class primeomega(Function):
- r"""
- Calculate the number of prime factors counting multiplicities for a
- positive integer n.
- If n's prime factorization is:
- .. math ::
- n = \prod_{i=1}^k p_i^{m_i},
- then ``primeomega(n)`` or `\Omega(n)` is:
- .. math ::
- \Omega(n) = \sum_{i=1}^k m_i.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import primeomega
- >>> primeomega(1)
- 0
- >>> primeomega(20)
- 3
- See Also
- ========
- factorint
- References
- ==========
- .. [1] https://mathworld.wolfram.com/PrimeFactor.html
- """
- @classmethod
- def eval(cls, n):
- if n.is_Integer:
- if n <= 0:
- raise ValueError("n must be a positive integer")
- else:
- return sum(factorint(n).values())
- def mersenne_prime_exponent(nth):
- """Returns the exponent ``i`` for the nth Mersenne prime (which
- has the form `2^i - 1`).
- Examples
- ========
- >>> from sympy.ntheory.factor_ import mersenne_prime_exponent
- >>> mersenne_prime_exponent(1)
- 2
- >>> mersenne_prime_exponent(20)
- 4423
- """
- n = as_int(nth)
- if n < 1:
- raise ValueError("nth must be a positive integer; mersenne_prime_exponent(1) == 2")
- if n > 51:
- raise ValueError("There are only 51 perfect numbers; nth must be less than or equal to 51")
- return MERSENNE_PRIME_EXPONENTS[n - 1]
- def is_perfect(n):
- """Returns True if ``n`` is a perfect number, else False.
- A perfect number is equal to the sum of its positive, proper divisors.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import is_perfect, divisors, divisor_sigma
- >>> is_perfect(20)
- False
- >>> is_perfect(6)
- True
- >>> 6 == divisor_sigma(6) - 6 == sum(divisors(6)[:-1])
- True
- References
- ==========
- .. [1] https://mathworld.wolfram.com/PerfectNumber.html
- .. [2] https://en.wikipedia.org/wiki/Perfect_number
- """
- n = as_int(n)
- if _isperfect(n):
- return True
- # all perfect numbers for Mersenne primes with exponents
- # less than or equal to 43112609 are known
- iknow = MERSENNE_PRIME_EXPONENTS.index(43112609)
- if iknow <= len(PERFECT) - 1 and n <= PERFECT[iknow]:
- # there may be gaps between this and larger known values
- # so only conclude in the range for which all values
- # are known
- return False
- if n%2 == 0:
- last2 = n % 100
- if last2 != 28 and last2 % 10 != 6:
- return False
- r, b = integer_nthroot(1 + 8*n, 2)
- if not b:
- return False
- m, x = divmod(1 + r, 4)
- if x:
- return False
- e, b = integer_log(m, 2)
- if not b:
- return False
- else:
- if n < 10**2000: # https://www.lirmm.fr/~ochem/opn/
- return False
- if n % 105 == 0: # not divis by 105
- return False
- if not any(n%m == r for m, r in [(12, 1), (468, 117), (324, 81)]):
- return False
- # there are many criteria that the factor structure of n
- # must meet; since we will have to factor it to test the
- # structure we will have the factors and can then check
- # to see whether it is a perfect number or not. So we
- # skip the structure checks and go straight to the final
- # test below.
- rv = divisor_sigma(n) - n
- if rv == n:
- if n%2 == 0:
- raise ValueError(filldedent('''
- This even number is perfect and is associated with a
- Mersenne Prime, 2^%s - 1. It should be
- added to SymPy.''' % (e + 1)))
- else:
- raise ValueError(filldedent('''In 1888, Sylvester stated: "
- ...a prolonged meditation on the subject has satisfied
- me that the existence of any one such [odd perfect number]
- -- its escape, so to say, from the complex web of conditions
- which hem it in on all sides -- would be little short of a
- miracle." I guess SymPy just found that miracle and it
- factors like this: %s''' % factorint(n)))
- def is_mersenne_prime(n):
- """Returns True if ``n`` is a Mersenne prime, else False.
- A Mersenne prime is a prime number having the form `2^i - 1`.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import is_mersenne_prime
- >>> is_mersenne_prime(6)
- False
- >>> is_mersenne_prime(127)
- True
- References
- ==========
- .. [1] https://mathworld.wolfram.com/MersennePrime.html
- """
- n = as_int(n)
- if _ismersenneprime(n):
- return True
- if not isprime(n):
- return False
- r, b = integer_log(n + 1, 2)
- if not b:
- return False
- raise ValueError(filldedent('''
- This Mersenne Prime, 2^%s - 1, should
- be added to SymPy's known values.''' % r))
- def abundance(n):
- """Returns the difference between the sum of the positive
- proper divisors of a number and the number.
- Examples
- ========
- >>> from sympy.ntheory import abundance, is_perfect, is_abundant
- >>> abundance(6)
- 0
- >>> is_perfect(6)
- True
- >>> abundance(10)
- -2
- >>> is_abundant(10)
- False
- """
- return divisor_sigma(n, 1) - 2 * n
- def is_abundant(n):
- """Returns True if ``n`` is an abundant number, else False.
- A abundant number is smaller than the sum of its positive proper divisors.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import is_abundant
- >>> is_abundant(20)
- True
- >>> is_abundant(15)
- False
- References
- ==========
- .. [1] https://mathworld.wolfram.com/AbundantNumber.html
- """
- n = as_int(n)
- if is_perfect(n):
- return False
- return n % 6 == 0 or bool(abundance(n) > 0)
- def is_deficient(n):
- """Returns True if ``n`` is a deficient number, else False.
- A deficient number is greater than the sum of its positive proper divisors.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import is_deficient
- >>> is_deficient(20)
- False
- >>> is_deficient(15)
- True
- References
- ==========
- .. [1] https://mathworld.wolfram.com/DeficientNumber.html
- """
- n = as_int(n)
- if is_perfect(n):
- return False
- return bool(abundance(n) < 0)
- def is_amicable(m, n):
- """Returns True if the numbers `m` and `n` are "amicable", else False.
- Amicable numbers are two different numbers so related that the sum
- of the proper divisors of each is equal to that of the other.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import is_amicable, divisor_sigma
- >>> is_amicable(220, 284)
- True
- >>> divisor_sigma(220) == divisor_sigma(284)
- True
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Amicable_numbers
- """
- if m == n:
- return False
- a, b = (divisor_sigma(i) for i in (m, n))
- return a == b == (m + n)
- def dra(n, b):
- """
- Returns the additive digital root of a natural number ``n`` in base ``b``
- which is a single digit value obtained by an iterative process of summing
- digits, on each iteration using the result from the previous iteration to
- compute a digit sum.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import dra
- >>> dra(3110, 12)
- 8
- References
- ==========
- .. [1] https://en.wikipedia.org/wiki/Digital_root
- """
- num = abs(as_int(n))
- b = as_int(b)
- if b <= 1:
- raise ValueError("Base should be an integer greater than 1")
- if num == 0:
- return 0
- return (1 + (num - 1) % (b - 1))
- def drm(n, b):
- """
- Returns the multiplicative digital root of a natural number ``n`` in a given
- base ``b`` which is a single digit value obtained by an iterative process of
- multiplying digits, on each iteration using the result from the previous
- iteration to compute the digit multiplication.
- Examples
- ========
- >>> from sympy.ntheory.factor_ import drm
- >>> drm(9876, 10)
- 0
- >>> drm(49, 10)
- 8
- References
- ==========
- .. [1] https://mathworld.wolfram.com/MultiplicativeDigitalRoot.html
- """
- n = abs(as_int(n))
- b = as_int(b)
- if b <= 1:
- raise ValueError("Base should be an integer greater than 1")
- while n > b:
- mul = 1
- while n > 1:
- n, r = divmod(n, b)
- if r == 0:
- return 0
- mul *= r
- n = mul
- return n
|