def npartitions(n, verbose=False): """ Calculate the partition function P(n), i.e. the number of ways that n can be written as a sum of positive integers. P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_. The correctness of this implementation has been tested through 10**10. Examples ======== >>> from sympy.ntheory import npartitions >>> npartitions(25) 1958 References ========== .. [1] http://mathworld.wolfram.com/PartitionFunctionP.html """ n = int(n) if n < 0: return 0 if n <= 5: return [1, 1, 2, 3, 5, 7][n] if '_factor' not in globals(): _pre() # Estimate number of bits in p(n). This formula could be tidied pbits = int(( math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ math.log(10, 2) prec = p = int(pbits * 1.1 + 100) s = fzero M = max(6, int(0.24 * n**0.5 + 4)) if M > 10**5: raise ValueError("Input too big") # Corresponds to n > 1.7e11 sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): a = _a(n, q, p) d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) if verbose: print("step", q, "of", M, to_str(a, 10), to_str(d, 10)) # On average, the terms decrease rapidly in magnitude. # Dynamically reducing the precision greatly improves # performance. p = bitcount(abs(to_int(d))) + 50 return int(to_int(mpf_add(s, fhalf, prec)))
def npartitions(n, verbose=False): """ Calculate the partition function P(n), i.e. the number of ways that n can be written as a sum of positive integers. P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_. The correctness of this implementation has been tested through 10**10. Examples ======== >>> from sympy.ntheory import npartitions >>> npartitions(25) 1958 References ========== .. [1] http://mathworld.wolfram.com/PartitionFunctionP.html """ n = int(n) if n < 0: return 0 if n <= 5: return [1, 1, 2, 3, 5, 7][n] if '_factor' not in globals(): _pre() # Estimate number of bits in p(n). This formula could be tidied pbits = int(( math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ math.log(10, 2) prec = p = int(pbits*1.1 + 100) s = fzero M = max(6, int(0.24*n**0.5 + 4)) if M > 10**5: raise ValueError("Input too big") # Corresponds to n > 1.7e11 sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): a = _a(n, q, p) d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) if verbose: print("step", q, "of", M, to_str(a, 10), to_str(d, 10)) # On average, the terms decrease rapidly in magnitude. # Dynamically reducing the precision greatly improves # performance. p = bitcount(abs(to_int(d))) + 50 return int(to_int(mpf_add(s, fhalf, prec)))
def _d(n, j, prec, sq23pi, sqrt8): """ Compute the sinh term in the outer sum of the HRR formula. The constants sqrt(2/3*pi) and sqrt(8) must be precomputed. """ j = from_int(j) pi = mpf_pi(prec) a = mpf_div(sq23pi, j, prec) b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec) c = mpf_sqrt(b, prec) ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec) D = mpf_div(mpf_sqrt(j, prec), mpf_mul(mpf_mul(sqrt8, b), pi), prec) E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec) return mpf_mul(D, E)
def npartitions(n): """Calculate the partition function P(n), i.e. the number of ways that n can be written as a sum of positive integers. P(n) is computed using the Hardy-Ramanujan-Rademacher formula. The correctness of this implementation has been tested for 10**n up to n = 8. Examples ======== >>> npartitions(25) 1958 References ========== * https://mathworld.wolfram.com/PartitionFunctionP.html """ n = int(n) if n < 0: return 0 if n <= 5: return [1, 1, 2, 3, 5, 7][n] # Estimate number of bits in p(n). This formula could be tidied pbits = int((math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ math.log(10, 2) prec = p = int(pbits * 1.1 + 100) s = fzero M = max(6, int(0.24 * n**0.5 + 4)) sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): a = _a(n, q, p) d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) debug('step', q, 'of', M, to_str(a, 10), to_str(d, 10)) # On average, the terms decrease rapidly in magnitude. Dynamically # reducing the precision greatly improves performance. p = bitcount(abs(to_int(d))) + 50 return int(to_int(mpf_add(s, fhalf, prec)))
def npartitions(n): """Calculate the partition function P(n), i.e. the number of ways that n can be written as a sum of positive integers. P(n) is computed using the Hardy-Ramanujan-Rademacher formula. The correctness of this implementation has been tested for 10**n up to n = 8. Examples ======== >>> npartitions(25) 1958 References ========== * http://mathworld.wolfram.com/PartitionFunctionP.html """ n = int(n) if n < 0: return 0 if n <= 5: return [1, 1, 2, 3, 5, 7][n] # Estimate number of bits in p(n). This formula could be tidied pbits = int((math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ math.log(10, 2) prec = p = int(pbits*1.1 + 100) s = fzero M = max(6, int(0.24*n**0.5 + 4)) sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): a = _a(n, q, p) d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) debug("step", q, "of", M, to_str(a, 10), to_str(d, 10)) # On average, the terms decrease rapidly in magnitude. Dynamically # reducing the precision greatly improves performance. p = bitcount(abs(to_int(d))) + 50 return int(to_int(mpf_add(s, fhalf, prec)))
def evalf_pow(v, prec, options): target_prec = prec base, exp = v.args # We handle x**n separately. This has two purposes: 1) it is much # faster, because we avoid calling evalf on the exponent, and 2) it # allows better handling of real/imaginary parts that are exactly zero if exp.is_Integer: p = exp.p # Exact if not p: return fone, None, prec, None # Exponentiation by p magnifies relative error by |p|, so the # base must be evaluated with increased precision if p is large prec += int(math.log(abs(p), 2)) re, im, re_acc, im_acc = evalf(base, prec + 5, options) # Real to integer power if re and not im: return mpf_pow_int(re, p, target_prec), None, target_prec, None # (x*I)**n = I**n * x**n if im and not re: z = mpf_pow_int(im, p, target_prec) case = p % 4 if case == 0: return z, None, target_prec, None if case == 1: return None, z, None, target_prec if case == 2: return mpf_neg(z), None, target_prec, None if case == 3: return None, mpf_neg(z), None, target_prec # Zero raised to an integer power if not re: return None, None, None, None # General complex number to arbitrary integer power re, im = libmp.mpc_pow_int((re, im), p, prec) # Assumes full accuracy in input return finalize_complex(re, im, target_prec) # Pure square root if exp is S.Half: xre, xim, _, _ = evalf(base, prec + 5, options) # General complex square root if xim: re, im = libmp.mpc_sqrt((xre or fzero, xim), prec) return finalize_complex(re, im, prec) if not xre: return None, None, None, None # Square root of a negative real number if mpf_lt(xre, fzero): return None, mpf_sqrt(mpf_neg(xre), prec), None, prec # Positive square root return mpf_sqrt(xre, prec), None, prec, None # We first evaluate the exponent to find its magnitude # This determines the working precision that must be used prec += 10 yre, yim, _, _ = evalf(exp, prec, options) # Special cases: x**0 if not (yre or yim): return fone, None, prec, None ysize = fastlog(yre) # Restart if too big # XXX: prec + ysize might exceed maxprec if ysize > 5: prec += ysize yre, yim, _, _ = evalf(exp, prec, options) # Pure exponential function; no need to evalf the base if base is S.Exp1: if yim: re, im = libmp.mpc_exp((yre or fzero, yim), prec) return finalize_complex(re, im, target_prec) return mpf_exp(yre, target_prec), None, target_prec, None xre, xim, _, _ = evalf(base, prec + 5, options) # 0**y if not (xre or xim): return None, None, None, None # (real ** complex) or (complex ** complex) if yim: re, im = libmp.mpc_pow((xre or fzero, xim or fzero), (yre or fzero, yim), target_prec) return finalize_complex(re, im, target_prec) # complex ** real if xim: re, im = libmp.mpc_pow_mpf((xre or fzero, xim), yre, target_prec) return finalize_complex(re, im, target_prec) # negative ** real elif mpf_lt(xre, fzero): re, im = libmp.mpc_pow_mpf((xre, fzero), yre, target_prec) return finalize_complex(re, im, target_prec) # positive ** real else: return mpf_pow(xre, yre, target_prec), None, target_prec, None
def _a(n, k, prec): """ Compute the inner sum in HRR formula [1]_ References ========== .. [1] http://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf """ if k == 1: return fone k1 = k e = 0 p = _factor[k] while k1 % p == 0: k1 //= p e += 1 k2 = k//k1 # k2 = p^e v = 1 - 24*n pi = mpf_pi(prec) if k1 == 1: # k = p^e if p == 2: mod = 8*k v = mod + v % mod v = (v*pow(9, k - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 2, e + 3)[0] arg = mpf_div(mpf_mul( from_int(4*m), pi, prec), from_int(mod), prec) return mpf_mul(mpf_mul( from_int((-1)**e*jacobi_symbol(m - 1, m)), mpf_sqrt(from_int(k), prec), prec), mpf_sin(arg, prec), prec) if p == 3: mod = 3*k v = mod + v % mod if e > 1: v = (v*pow(64, k//3 - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 3, e + 1)[0] arg = mpf_div(mpf_mul(from_int(4*m), pi, prec), from_int(mod), prec) return mpf_mul(mpf_mul( from_int(2*(-1)**(e + 1)*legendre_symbol(m, 3)), mpf_sqrt(from_int(k//3), prec), prec), mpf_sin(arg, prec), prec) v = k + v % k if v % p == 0: if e == 1: return mpf_mul( from_int(jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec) return fzero if not is_quad_residue(v, p): return fzero _phi = p**(e - 1)*(p - 1) v = (v*pow(576, _phi - 1, k)) m = _sqrt_mod_prime_power(v, p, e)[0] arg = mpf_div( mpf_mul(from_int(4*m), pi, prec), from_int(k), prec) return mpf_mul(mpf_mul( from_int(2*jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec), mpf_cos(arg, prec), prec) if p != 2 or e >= 3: d1, d2 = igcd(k1, 24), igcd(k2, 24) e = 24//(d1*d2) n1 = ((d2*e*n + (k2**2 - 1)//d1)* pow(e*k2*k2*d2, _totient[k1] - 1, k1)) % k1 n2 = ((d1*e*n + (k1**2 - 1)//d2)* pow(e*k1*k1*d1, _totient[k2] - 1, k2)) % k2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) if e == 2: n1 = ((8*n + 5)*pow(128, _totient[k1] - 1, k1)) % k1 n2 = (4 + ((n - 2 - (k1**2 - 1)//8)*(k1**2)) % 4) % 4 return mpf_mul(mpf_mul( from_int(-1), _a(n1, k1, prec), prec), _a(n2, k2, prec)) n1 = ((8*n + 1)*pow(32, _totient[k1] - 1, k1)) % k1 n2 = (2 + (n - (k1**2 - 1)//8) % 2) % 2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
def _a(n, k, prec): """ Compute the inner sum in HRR formula [1]_ References ========== .. [1] http://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf """ if k == 1: return fone k1 = k e = 0 p = _factor[k] while k1 % p == 0: k1 //= p e += 1 k2 = k // k1 # k2 = p^e v = 1 - 24 * n pi = mpf_pi(prec) if k1 == 1: # k = p^e if p == 2: mod = 8 * k v = mod + v % mod v = (v * pow(9, k - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 2, e + 3)[0] arg = mpf_div(mpf_mul(from_int(4 * m), pi, prec), from_int(mod), prec) return mpf_mul( mpf_mul(from_int((-1)**e * jacobi_symbol(m - 1, m)), mpf_sqrt(from_int(k), prec), prec), mpf_sin(arg, prec), prec) if p == 3: mod = 3 * k v = mod + v % mod if e > 1: v = (v * pow(64, k // 3 - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 3, e + 1)[0] arg = mpf_div(mpf_mul(from_int(4 * m), pi, prec), from_int(mod), prec) return mpf_mul( mpf_mul(from_int(2 * (-1)**(e + 1) * legendre_symbol(m, 3)), mpf_sqrt(from_int(k // 3), prec), prec), mpf_sin(arg, prec), prec) v = k + v % k if v % p == 0: if e == 1: return mpf_mul(from_int(jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec) return fzero if not is_quad_residue(v, p): return fzero _phi = p**(e - 1) * (p - 1) v = (v * pow(576, _phi - 1, k)) m = _sqrt_mod_prime_power(v, p, e)[0] arg = mpf_div(mpf_mul(from_int(4 * m), pi, prec), from_int(k), prec) return mpf_mul( mpf_mul(from_int(2 * jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec), mpf_cos(arg, prec), prec) if p != 2 or e >= 3: d1, d2 = igcd(k1, 24), igcd(k2, 24) e = 24 // (d1 * d2) n1 = ((d2 * e * n + (k2**2 - 1) // d1) * pow(e * k2 * k2 * d2, _totient[k1] - 1, k1)) % k1 n2 = ((d1 * e * n + (k1**2 - 1) // d2) * pow(e * k1 * k1 * d1, _totient[k2] - 1, k2)) % k2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) if e == 2: n1 = ((8 * n + 5) * pow(128, _totient[k1] - 1, k1)) % k1 n2 = (4 + ((n - 2 - (k1**2 - 1) // 8) * (k1**2)) % 4) % 4 return mpf_mul(mpf_mul(from_int(-1), _a(n1, k1, prec), prec), _a(n2, k2, prec)) n1 = ((8 * n + 1) * pow(32, _totient[k1] - 1, k1)) % k1 n2 = (2 + (n - (k1**2 - 1) // 8) % 2) % 2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
def evalf_pow(v, prec, options): target_prec = prec base, exp = v.args # We handle x**n separately. This has two purposes: 1) it is much # faster, because we avoid calling evalf on the exponent, and 2) it # allows better handling of real/imaginary parts that are exactly zero if exp.is_Integer: p = exp.p # Exact if not p: return fone, None, prec, None # Exponentiation by p magnifies relative error by |p|, so the # base must be evaluated with increased precision if p is large prec += int(math.log(abs(p), 2)) re, im, re_acc, im_acc = evalf(base, prec + 5, options) # Real to integer power if re and not im: return mpf_pow_int(re, p, target_prec), None, target_prec, None # (x*I)**n = I**n * x**n if im and not re: z = mpf_pow_int(im, p, target_prec) case = p % 4 if case == 0: return z, None, target_prec, None if case == 1: return None, z, None, target_prec if case == 2: return mpf_neg(z), None, target_prec, None if case == 3: return None, mpf_neg(z), None, target_prec # Zero raised to an integer power if not re: return None, None, None, None # General complex number to arbitrary integer power re, im = libmp.mpc_pow_int((re, im), p, prec) # Assumes full accuracy in input return finalize_complex(re, im, target_prec) # Pure square root if exp is S.Half: xre, xim, _, _ = evalf(base, prec + 5, options) # General complex square root if xim: re, im = libmp.mpc_sqrt((xre or fzero, xim), prec) return finalize_complex(re, im, prec) if not xre: return None, None, None, None # Square root of a negative real number if mpf_lt(xre, fzero): return None, mpf_sqrt(mpf_neg(xre), prec), None, prec # Positive square root return mpf_sqrt(xre, prec), None, prec, None # We first evaluate the exponent to find its magnitude # This determines the working precision that must be used prec += 10 yre, yim, _, _ = evalf(exp, prec, options) # Special cases: x**0 if not (yre or yim): return fone, None, prec, None ysize = fastlog(yre) # Restart if too big # XXX: prec + ysize might exceed maxprec if ysize > 5: prec += ysize yre, yim, _, _ = evalf(exp, prec, options) # Pure exponential function; no need to evalf the base if base is S.Exp1: if yim: re, im = libmp.mpc_exp((yre or fzero, yim), prec) return finalize_complex(re, im, target_prec) return mpf_exp(yre, target_prec), None, target_prec, None xre, xim, _, _ = evalf(base, prec + 5, options) # 0**y if not (xre or xim): return None, None, None, None # (real ** complex) or (complex ** complex) if yim: re, im = libmp.mpc_pow( (xre or fzero, xim or fzero), (yre or fzero, yim), target_prec) return finalize_complex(re, im, target_prec) # complex ** real if xim: re, im = libmp.mpc_pow_mpf((xre or fzero, xim), yre, target_prec) return finalize_complex(re, im, target_prec) # negative ** real elif mpf_lt(xre, fzero): re, im = libmp.mpc_pow_mpf((xre, fzero), yre, target_prec) return finalize_complex(re, im, target_prec) # positive ** real else: return mpf_pow(xre, yre, target_prec), None, target_prec, None