Path: blob/master/src/sage/combinat/combinat_cython.pyx
8817 views
"""1Fast computation of combinatorial functions (Cython + mpz).23Currently implemented:4- Stirling numbers of the second kind56AUTHORS:7- Fredrik Johansson (2010-10): Stirling numbers of second kind89"""1011include "sage/ext/stdsage.pxi"121314from sage.libs.gmp.all cimport *15from sage.rings.integer cimport Integer1617cdef void mpz_addmul_alt(mpz_t s, mpz_t t, mpz_t u, unsigned long parity):18"""19Set s = s + t*u * (-1)^parity20"""21if parity & 1:22mpz_submul(s, t, u)23else:24mpz_addmul(s, t, u)252627cdef mpz_stirling_s2(mpz_t s, unsigned long n, unsigned long k):28"""29Set s = S(n,k) where S(n,k) denotes a Stirling number of the30second kind.3132Algorithm: S(n,k) = (sum_{j=0}^k (-1)^(k-j) C(k,j) j^n) / k!3334TODO: compute S(n,k) efficiently for large n when n-k is small35(e.g. when k > 20 and n-k < 20)36"""37cdef mpz_t t, u38cdef mpz_t *bc39cdef unsigned long j, max_bc40# Some important special cases41if k+1 >= n:42# Upper triangle of n\k table43if k > n:44mpz_set_ui(s, 0)45elif n == k:46mpz_set_ui(s, 1)47elif k+1 == n:48# S(n,n-1) = C(n,2)49mpz_set_ui(s, n)50mpz_mul_ui(s, s, n-1)51mpz_tdiv_q_2exp(s, s, 1)52elif k <= 2:53# Leftmost three columns of n\k table54if k == 0:55mpz_set_ui(s, 0)56elif k == 1:57mpz_set_ui(s, 1)58elif k == 2:59# 2^(n-1)-160mpz_set_ui(s, 1)61mpz_mul_2exp(s, s, n-1)62mpz_sub_ui(s, s, 1)63# Direct sequential evaluation of the sum64elif n < 200:65mpz_init(t)66mpz_init(u)67mpz_set_ui(t, 1)68mpz_set_ui(s, 0)69for j in range(1, k//2+1):70mpz_mul_ui(t, t, k+1-j)71mpz_tdiv_q_ui(t, t, j)72mpz_set_ui(u, j)73mpz_pow_ui(u, u, n)74mpz_addmul_alt(s, t, u, k+j)75if 2*j != k:76# Use the fact that C(k,j) = C(k,k-j)77mpz_set_ui(u, k-j)78mpz_pow_ui(u, u, n)79mpz_addmul_alt(s, t, u, j)80# Last term not included because loop starts from 181mpz_set_ui(u, k)82mpz_pow_ui(u, u, n)83mpz_add(s, s, u)84mpz_fac_ui(t, k)85mpz_tdiv_q(s, s, t)86mpz_clear(t)87mpz_clear(u)88# Only compute odd powers, saving about half of the time for large n.89# We need to precompute binomial coefficients since they will be accessed90# out of order, adding overhead that makes this slower for small n.91else:92mpz_init(t)93mpz_init(u)94max_bc = (k+1)//295bc = <mpz_t*> sage_malloc((max_bc+1) * sizeof(mpz_t))96mpz_init_set_ui(bc[0], 1)97for j in range(1, max_bc+1):98mpz_init_set(bc[j], bc[j-1])99mpz_mul_ui(bc[j], bc[j], k+1-j)100mpz_tdiv_q_ui(bc[j], bc[j], j)101mpz_set_ui(s, 0)102for j in range(1, k+1, 2):103mpz_set_ui(u, j)104mpz_pow_ui(u, u, n)105# Process each 2^p * j, where j is odd106while 1:107if j > max_bc:108mpz_addmul_alt(s, bc[k-j], u, k+j)109else:110mpz_addmul_alt(s, bc[j], u, k+j)111j *= 2112if j > k:113break114mpz_mul_2exp(u, u, n)115for j in range(max_bc+1): # careful: 0 ... max_bc116mpz_clear(bc[j])117sage_free(bc)118mpz_fac_ui(t, k)119mpz_tdiv_q(s, s, t)120mpz_clear(t)121mpz_clear(u)122123def _stirling_number2(n, k):124"""125Python wrapper of mpz_stirling_s2.126127sage: from sage.combinat.combinat_cython import _stirling_number2128sage: _stirling_number2(3, 2)1293130131This is wrapped again by stirling_number2 in combinat.py.132"""133cdef Integer s134s = PY_NEW(Integer)135mpz_stirling_s2(s.value, n, k)136return s137138139