def core(n, t=2): """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 ========== t : 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. References ========== .. [1] http://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core Examples ======== >>> from diofant.ntheory.factor_ import core >>> core(24, 2) 6 >>> core(9424, 3) 1178 >>> core(379238) 379238 >>> core(15**11, 10) 15 See Also ======== factorint """ 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
def __new__(cls, partition, integer=None): """ Generates a new IntegerPartition object from a list or dictionary. The partition can be given as a list of positive integers or a dictionary of (integer, multiplicity) items. If the partition is preceeded by an integer an error will be raised if the partition does not sum to that given integer. Examples ======== >>> from diofant.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([5, 4, 3, 1, 1]) >>> a IntegerPartition(14, (5, 4, 3, 1, 1)) >>> print(a) [5, 4, 3, 1, 1] >>> IntegerPartition({1:3, 2:1}) IntegerPartition(5, (2, 1, 1, 1)) If the value that the partion should sum to is given first, a check will be made to see n error will be raised if there is a discrepancy: >>> IntegerPartition(10, [5, 4, 3, 1]) Traceback (most recent call last): ... ValueError: The partition is not valid """ if integer is not None: integer, partition = partition, integer if isinstance(partition, (dict, Dict)): _ = [] for k, v in sorted(partition.items(), reverse=True): if not v: continue k, v = as_int(k), as_int(v) _.extend([k]*v) partition = tuple(_) else: partition = tuple(sorted(map(as_int, partition), reverse=True)) sum_ok = False if integer is None: integer = sum(partition) sum_ok = True else: integer = as_int(integer) if not sum_ok and sum(partition) != integer: raise ValueError("Partition did not add to %s" % integer) if any(i < 1 for i in partition): raise ValueError("The summands must all be positive.") obj = Basic.__new__(cls, integer, partition) obj.partition = list(partition) obj.integer = integer return obj
def give(a, b, seq=seed): a, b = as_int(a), as_int(b) w = b - a if w < 0: raise ValueError('_randint got empty range') try: x = seq.pop() except AttributeError: raise ValueError('_randint expects a list-like sequence') except IndexError: raise ValueError('_randint sequence was too short') if a <= x <= b: return x else: return give(a, b, seq)
def __init__(self, *args): if len(args) == 1 and isinstance(args[0], SparseMatrix): self.rows = args[0].rows self.cols = args[0].cols self._smat = dict(args[0]._smat) return self._smat = {} if len(args) == 3: self.rows = as_int(args[0]) self.cols = as_int(args[1]) if isinstance(args[2], collections.Callable): op = args[2] for i in range(self.rows): for j in range(self.cols): value = self._sympify( op(self._sympify(i), self._sympify(j))) if value: self._smat[(i, j)] = value elif isinstance(args[2], (dict, Dict)): # manual copy, copy.deepcopy() doesn't work for key in args[2].keys(): v = args[2][key] if v: self._smat[key] = self._sympify(v) elif is_sequence(args[2]): if len(args[2]) != self.rows * self.cols: raise ValueError('List length (%s) != rows*columns (%s)' % (len(args[2]), self.rows * self.cols)) flat_list = args[2] for i in range(self.rows): for j in range(self.cols): value = self._sympify(flat_list[i * self.cols + j]) if value: self._smat[(i, j)] = value else: # handle full matrix forms with _handle_creation_inputs r, c, _list = Matrix._handle_creation_inputs(*args) self.rows = r self.cols = c for i in range(self.rows): for j in range(self.cols): value = _list[self.cols * i + j] if value: self._smat[(i, j)] = value
def dict(self): n, p, succ, fail = self.n, self.p, self.succ, self.fail n = as_int(n) return { k * succ + (n - k) * fail: binomial(n, k) * p**k * (1 - p)**(n - k) for k in range(0, n + 1) }
def prime(nth): """Return the nth prime, with the primes indexed as prime(1) = 2, prime(2) = 3, etc.... The nth prime is approximately n*log(n) and can never be larger than 2**n. References ========== .. [1] http://primes.utm.edu/glossary/xpage/BertrandsPostulate.html Examples ======== >>> from diofant import prime >>> prime(10) 29 >>> prime(1) 2 See Also ======== diofant.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range primepi : Return the number of primes less than or equal to n """ n = as_int(nth) if n < 1: raise ValueError("nth must be a positive integer; prime(1) == 2") return sieve[n]
def antidivisor_count(n): """Return the number of antidivisors [1]_ of ``n``. References ========== .. [1] formula from https://oeis.org/A066272 Examples ======== >>> from diofant.ntheory.factor_ import antidivisor_count >>> antidivisor_count(13) 4 >>> antidivisor_count(27) 5 See Also ======== factorint, divisors, antidivisors, divisor_count, totient """ 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
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. References ========== .. [1] definition is described in http://oeis.org/A066272/a066272a.html Examples ======== >>> from diofant.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 """ n = as_int(abs(n)) if n <= 2: return [] rv = _antidivisors(n) if not generator: return sorted(rv) return rv
def primorial(n, nth=True): """Returns the product of the first n primes (default) or the primes less than or equal to n (when ``nth=False``). >>> from diofant.ntheory.generate import primorial, randprime, primerange >>> from diofant import factorint, Mul, primefactors, sqrt >>> primorial(4) # the first 4 primes are 2, 3, 5, 7 210 >>> primorial(4, nth=False) # primes <= 4 are 2 and 3 6 >>> primorial(1) 2 >>> primorial(1, nth=False) 1 >>> primorial(sqrt(101), nth=False) 210 One can argue that the primes are infinite since if you take a set of primes and multiply them together (e.g. the primorial) and then add or subtract 1, the result cannot be divided by any of the original factors, hence either 1 or more new primes must divide this product of primes. In this case, the number itself is a new prime: >>> factorint(primorial(4) + 1) {211: 1} In this case two new primes are the factors: >>> factorint(primorial(4) - 1) == {11: 1, 19: 1} True Here, some primes smaller and larger than the primes multiplied together are obtained: >>> p = list(primerange(10, 20)) >>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p))) [2, 5, 31, 149] See Also ======== primerange : Generate all primes in a given range """ if nth: n = as_int(n) else: n = int(n) if n < 1: raise ValueError("primorial argument must be >= 1") p = 1 if nth: for i in range(1, n + 1): p *= prime(i) else: for i in primerange(2, n + 1): p *= i return p
def nextprime(n, ith=1): """Return the ith prime greater than n. i must be an integer. Notes ===== Potential primes are located at 6*j +/- 1. This property is used during searching. >>> from diofant import nextprime >>> [(i, nextprime(i)) for i in range(10, 15)] [(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)] >>> nextprime(2, ith=2) # the 2nd prime after 2 5 See Also ======== prevprime : Return the largest prime smaller than n primerange : Generate all primes in a given range """ n = int(n) i = as_int(ith) if i > 1: pr = n j = 1 while 1: pr = nextprime(pr) j += 1 if j > i: break return pr if n < 2: return 2 if n < 7: return {2: 3, 3: 5, 4: 5, 5: 7, 6: 7}[n] nn = 6 * (n // 6) if nn == n: n += 1 if isprime(n): return n n += 4 elif n - nn == 5: n += 2 if isprime(n): return n n += 4 else: n = nn + 5 while 1: if isprime(n): return n n += 2 if isprime(n): return n n += 4
def unrank(cls, rank, n): """Finds the unranked Prufer sequence. Examples ======== >>> from diofant.combinatorics.prufer import Prufer >>> Prufer.unrank(0, 4) Prufer([0, 0]) """ n, rank = as_int(n), as_int(rank) L = defaultdict(int) for i in range(n - 3, -1, -1): L[i] = rank % n rank = (rank - L[i]) // n return Prufer([L[i] for i in range(len(L))])
def give(a, b=None, seq=seed): if b is None: a, b = 0, a a, b = as_int(a), as_int(b) w = b - a if w < 1: raise ValueError('_randrange got empty range') try: x = seq.pop() except AttributeError: raise ValueError('_randrange expects a list-like sequence') except IndexError: raise ValueError('_randrange sequence was too short') if a <= x < b: return x else: return give(a, b, seq)
def ones(r, c=None): """Returns a matrix of ones with ``r`` rows and ``c`` columns; if ``c`` is omitted a square matrix will be returned. See Also ======== diofant.matrices.dense.zeros diofant.matrices.dense.eye diofant.matrices.dense.diag """ from .dense import Matrix c = r if c is None else c r = as_int(r) c = as_int(c) return Matrix(r, c, [S.One] * r * c)
def __getitem__(self, n): """Return the nth prime number""" if isinstance(n, slice): self.extend_to_no(n.stop) return self._list[n.start - 1:n.stop - 1:n.step] else: n = as_int(n) self.extend_to_no(n) return self._list[n - 1]
def __contains__(self, n): try: n = as_int(n) assert n >= 2 except (ValueError, AssertionError): return False if n % 2 == 0: return n == 2 a, b = self.search(n) return a == b
def test_as_int(): pytest.raises(ValueError, lambda: as_int(1.1)) pytest.raises(ValueError, lambda: as_int([])) pytest.raises(ValueError, lambda: as_int(nan)) pytest.raises(ValueError, lambda: as_int(oo)) pytest.raises(ValueError, lambda: as_int(-oo)) pytest.raises(ValueError, lambda: as_int(zoo))
def test_as_int(): pytest.raises(ValueError, lambda: as_int(1.1)) pytest.raises(ValueError, lambda: as_int([])) pytest.raises(ValueError, lambda: as_int(S.NaN)) pytest.raises(ValueError, lambda: as_int(S.Infinity)) pytest.raises(ValueError, lambda: as_int(S.NegativeInfinity)) pytest.raises(ValueError, lambda: as_int(S.ComplexInfinity))
def test_as_int(): pytest.raises(ValueError, lambda: as_int(1.1)) pytest.raises(ValueError, lambda: as_int([])) pytest.raises(ValueError, lambda: as_int(nan)) pytest.raises(ValueError, lambda: as_int(oo)) pytest.raises(ValueError, lambda: as_int(-oo)) pytest.raises(ValueError, lambda: as_int(zoo))
def rs_pow(p1, n, x, prec): """ return ``p1**n`` modulo ``O(x**prec)`` Examples ======== >>> from diofant.polys.domains import QQ >>> from diofant.polys.rings import ring >>> R, x = ring('x', QQ) >>> p = x + 1 >>> rs_pow(p, 4, x, 3) 6*x**2 + 4*x + 1 """ R = p1.ring p = R.zero if isinstance(n, Rational): raise NotImplementedError('to be implemented') n = as_int(n) if n == 0: if p1: return R(1) else: raise ValueError('0**0 is undefined') if n < 0: p1 = rs_pow(p1, -n, x, prec) return rs_series_inversion(p1, x, prec) if n == 1: return rs_trunc(p1, x, prec) if n == 2: return rs_square(p1, x, prec) if n == 3: p2 = rs_square(p1, x, prec) return rs_mul(p1, p2, x, prec) p = R(1) while 1: if n & 1: p = rs_mul(p1, p, x, prec) n -= 1 if not n: break p1 = rs_square(p1, x, prec) n = n // 2 return p
def divisors(n, generator=False): r"""Return all divisors of n. Divisors are 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 diofant 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] See Also ======== primefactors, factorint, divisor_count References ========== .. [1] http://stackoverflow.com/questions/1010381/python-factorization """ n = as_int(abs(n)) if isprime(n): return [1, n] if n == 1: return [1] if n == 0: return [] rv = _divisors(n) if not generator: return sorted(rv) return rv
def extend_to_no(self, i): """Extend to include the ith prime number. i must be an integer. The list is extended by 50% if it is too short, so it is likely that it will be longer than requested. Examples ======== >>> from diofant import sieve >>> from array import array # this line and next for doctest only >>> sieve._list = array('l', [2, 3, 5, 7, 11, 13]) >>> sieve.extend_to_no(9) >>> sieve._list array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23]) """ i = as_int(i) while len(self._list) < i: self.extend(int(self._list[-1] * 1.5))
def jordan_cell(eigenval, n): """ Create matrix of Jordan cell kind: Examples ======== >>> from diofant.matrices import jordan_cell >>> from diofant.abc import x >>> jordan_cell(x, 4) Matrix([ [x, 1, 0, 0], [0, x, 1, 0], [0, 0, x, 1], [0, 0, 0, x]]) """ n = as_int(n) out = zeros(n) for i in range(n - 1): out[i, i] = eigenval out[i, i + 1] = S.One out[n - 1, n - 1] = eigenval return out
def __add__(self, other): """ Return permutation whose rank is ``other`` greater than current rank, (mod the maximum rank for the set). Examples ======== >>> from diofant.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3]) >>> a.rank 1 >>> (a + 1).rank 2 >>> (a + 100).rank 1 """ other = as_int(other) offset = self.rank + other result = RGS_unrank((offset) % RGS_enum(self.size), self.size) return Partition.from_rgs(result, self.members)
def random_integer_partition(n, seed=None): """ Generates a random integer partition summing to ``n`` as a list of reverse-sorted integers. Examples ======== >>> from diofant.combinatorics.partitions import random_integer_partition For the following, a seed is given so a known value can be shown; in practice, the seed would not be given. >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1]) [85, 12, 2, 1] >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1]) [5, 3, 1, 1] >>> random_integer_partition(1) [1] """ from diofant.utilities.randtest import _randint n = as_int(n) if n < 1: raise ValueError('n must be a positive integer') randint = _randint(seed) partition = [] while (n > 0): k = randint(1, n) mult = randint(1, n//k) partition.append((k, mult)) n -= k*mult partition.sort(reverse=True) partition = flatten([[k]*m for k, m in partition]) return partition
def __new__(cls, *args): from diofant.functions.elementary.integers import ceiling # expand range slc = slice(*args) start, stop, step = slc.start or 0, slc.stop, slc.step or 1 try: start, stop, step = [ w if w in [S.NegativeInfinity, S.Infinity] else Integer( as_int(w)) for w in (start, stop, step) ] except ValueError: raise ValueError("Inputs to Range must be Integer Valued\n" + "Use ImageSets of Ranges for other cases") if not step.is_finite: raise ValueError("Infinite step is not allowed") if start == stop: return S.EmptySet n = ceiling((stop - start) / step) if n <= 0: return S.EmptySet # normalize args: regardless of how they are entered they will show # canonically as Range(inf, sup, step) with step > 0 if n.is_finite: start, stop = sorted((start, start + (n - 1) * step)) else: start, stop = sorted((start, stop - step)) step = abs(step) if (start, stop) == (S.NegativeInfinity, S.Infinity): raise ValueError("Both the start and end value of " "Range cannot be unbounded") else: return Basic.__new__(cls, start, stop + step, step)
def zeros(cls, r, c=None): """Return an r x c matrix of zeros, square if c is omitted.""" c = r if c is None else c r = as_int(r) c = as_int(c) return cls._new(r, c, [cls._sympify(0)] * r * c)
def dict(self): sides = as_int(self.sides) return super(DieDistribution, self).dict
def nsimplify(expr, constants=[], tolerance=None, full=False, rational=None): """ Find a simple representation for a number or, if there are free symbols or if rational=True, then replace Floats with their Rational equivalents. If no change is made and rational is not False then Floats will at least be converted to Rationals. For numerical expressions, a simple formula that numerically matches the given numerical expression is sought (and the input should be possible to evalf to a precision of at least 30 digits). Optionally, a list of (rationally independent) constants to include in the formula may be given. A lower tolerance may be set to find less exact matches. If no tolerance is given then the least precise value will set the tolerance (e.g. Floats default to 15 digits of precision, so would be tolerance=10**-15). With full=True, a more extensive search is performed (this is useful to find simpler numbers when the tolerance is set low). Examples ======== >>> from diofant import nsimplify, sqrt, GoldenRatio, exp, I, exp, pi >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) -2 + 2*GoldenRatio >>> nsimplify((1/(exp(3*pi*I/5)+1))) 1/2 - I*sqrt(sqrt(5)/10 + 1/4) >>> nsimplify(I**I, [pi]) E**(-pi/2) >>> nsimplify(pi, tolerance=0.01) 22/7 See Also ======== diofant.core.function.nfloat """ try: return sympify(as_int(expr)) except (TypeError, ValueError): pass expr = sympify(expr) if rational or expr.free_symbols: return _real_to_rational(expr, tolerance) # Diofant's default tolerance for Rationals is 15; other numbers may have # lower tolerances set, so use them to pick the largest tolerance if None # was given if tolerance is None: tolerance = 10**-min([15] + [ mpmath.libmp.libmpf.prec_to_dps(n._prec) for n in expr.atoms(Float) ]) # XXX should prec be set independent of tolerance or should it be computed # from tolerance? prec = 30 bprec = int(prec * 3.33) constants_dict = {} for constant in constants: constant = sympify(constant) v = constant.evalf(prec) if not v.is_Float: raise ValueError("constants must be real-valued") constants_dict[str(constant)] = v._to_mpmath(bprec) exprval = expr.evalf(prec, chop=True) re, im = exprval.as_real_imag() # safety check to make sure that this evaluated to a number if not (re.is_Number and im.is_Number): return expr def nsimplify_real(x): orig = mpmath.mp.dps xv = x._to_mpmath(bprec) try: # We'll be happy with low precision if a simple fraction if not (tolerance or full): mpmath.mp.dps = 15 rat = mpmath.findpoly(xv, 1) if rat is not None: return Rational(-int(rat[1]), int(rat[0])) mpmath.mp.dps = prec newexpr = mpmath.identify(xv, constants=constants_dict, tol=tolerance, full=full) if not newexpr: raise ValueError if full: newexpr = newexpr[0] expr = sympify(newexpr) if x and not expr: # don't let x become 0 raise ValueError if expr.is_finite is False and xv not in [mpmath.inf, mpmath.ninf]: raise ValueError return expr finally: # even though there are returns above, this is executed # before leaving mpmath.mp.dps = orig try: if re: re = nsimplify_real(re) if im: im = nsimplify_real(im) except ValueError: if rational is None: return _real_to_rational(expr) return expr rv = re + im * S.ImaginaryUnit # if there was a change or rational is explicitly not wanted # return the value, else return the Rational representation if rv != expr or rational is False: return rv return _real_to_rational(expr)
def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True, verbose=False, visual=None): 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 diofant.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 diofant.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} Visual Factorization: If ``visual`` is set to ``True``, then it will return a visual factorization of the integer. For example: >>> from diofant import pprint >>> pprint(factorint(4200, visual=True), use_unicode=False) 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 diofant import Mul, Pow >>> regular = factorint(1764); regular {2: 2, 3: 2, 7: 2} >>> pprint(factorint(regular), use_unicode=False) 2 2 2 2 *3 *7 >>> visual = factorint(1764, visual=True); pprint(visual, use_unicode=False) 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 ===== 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. If ``verbose`` is set to ``True``, detailed progress is printed. See Also ======== smoothness, smoothness_p, divisors """ factordict = {} if visual and not isinstance(n, Mul) and not isinstance(n, 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 list(n.as_powers_dict().items()) } elif isinstance(n, dict): factordict = n if factordict and (isinstance(n, Mul) or isinstance(n, dict)): # check it for k in list(factordict.keys()): if isprime(k): continue e = factordict.pop(k) d = factorint(k, 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) or isinstance(n, Mul): return factordict assert use_trial or use_rho or use_pm1 n = as_int(n) if limit: limit = int(limit) # 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) factors.update(facs) 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 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, 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, 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 low, high = high, high * 2
def multiplicity(p, n): """Find the greatest integer m such that p**m divides n. Examples ======== >>> from diofant.ntheory import multiplicity >>> from diofant.core.numbers import Rational as R >>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]] [0, 1, 2, 3, 3] >>> multiplicity(3, R(1, 9)) -2 """ try: p, n = as_int(p), as_int(n) except ValueError: if all(isinstance(i, (DIOFANT_INTS, Rational)) for i in (p, n)): try: p = Rational(p) n = Rational(n) if p.q == 1: if n.p == 1: return -multiplicity(p.p, n.q) return S.Zero 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 except AttributeError: pass raise ValueError('expecting ints or fractions, got %s and %s' % (p, n)) if n == 0: raise ValueError('multiplicity of 0 is not defined') 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 eye(cls, n): """Return an n x n identity matrix.""" n = as_int(n) mat = [cls._sympify(0)] * n * n mat[::n + 1] = [cls._sympify(1)] * n return cls._new(n, n, mat)