164
164
def bell_number (n , algorithm = 'dobinski' , ** options ):
165
165
r"""
166
166
Return the `n`-th Bell number (the number of ways to partition a set
167
- of n elements into pairwise disjoint nonempty subsets). If `n \leq 0`,
168
- return `1`.
167
+ of `n` elements into pairwise disjoint nonempty subsets).
169
168
170
169
INPUT:
171
170
172
171
- ``n`` -- a positive integer
173
172
174
- - ``algorithm`` -- (Default ``'dobinski'``) Can be any one of the
175
- following:
173
+ - ``algorithm`` -- (Default: ``'dobinski'``) any one of the following:
176
174
177
175
- ``'dobinski'`` -- Use Dobinski's summation formula
178
- (when `n < 200`, this just wraps GAP)
179
- - ``'gap'`` -- Wrap GAP's ``Bell``
176
+
177
+ - ``'gap'`` -- Wrap libGAP's ``Bell``
178
+
180
179
- ``'mpmath'`` -- Wrap mpmath's ``bell``
181
180
182
181
.. WARNING::
183
182
184
- When using the mpmath algorithm to compute bell numbers and you specify
183
+ When using the mpmath algorithm to compute Bell numbers and you specify
185
184
``prec``, it can return incorrect results due to low precision. See
186
185
the examples section.
187
186
@@ -191,20 +190,23 @@ def bell_number(n, algorithm='dobinski', **options):
191
190
192
191
B_n = e^{-1} \sum_{k=0}^{\infty} \frac{k^n}{k!}.
193
192
194
- To show our implementation of Dobinski's method works, suppose that `n > 8 `
195
- and let `k_0` be the smallest integer for that `\frac{k_0^n}{k_0!} < 1`.
193
+ To show our implementation of Dobinski's method works, suppose that `n \geq 5 `
194
+ and let `k_0` be the smallest positive integer such that `\frac{k_0^n}{k_0!} < 1`.
196
195
Note that `k_0 > n` and `k_0 \leq 2n` because we can prove that
197
196
`\frac{(2n)^n}{(2n)!} < 1` by Stirling.
198
197
199
- Next if `k > k_0`, then we have `\frac{k^n}{k!} < \frac{1}{2^{k-k_0}}`, and
200
- the proof is by induction. Let `c_k = \frac{k^n}{k!}`, if `k > n` then
198
+ If `k > k_0`, then we have `\frac{k^n}{k!} < \frac{1}{2^{k-k_0}}`.
199
+ We show this by induction:
200
+ let `c_k = \frac{k^n}{k!}`, if `k > n` then
201
201
202
202
.. MATH::
203
203
204
204
\frac{c_{k+1}}{c_k} = \frac{(1+k^{-1})^n}{k+1} < \frac{(1+n^{-1})^n}{n}
205
- < \frac{4}{n} < \frac{ 1}{2}.
205
+ < \frac{1}{2}.
206
206
207
- By using this, we can see that `\frac{c_k}{c_{k_0}} < \frac{1}{2^{k-k_0}}`
207
+ The last inequality can easily be checked numerically for `n \geq 5`.
208
+
209
+ Using this, we can see that `\frac{c_k}{c_{k_0}} < \frac{1}{2^{k-k_0}}`
208
210
for `k > k_0 > n`. So summing this it gives that `\sum_{k=k_0+1}^{\infty}
209
211
\frac{k^n}{k!} < 1`, and hence
210
212
@@ -213,61 +215,75 @@ def bell_number(n, algorithm='dobinski', **options):
213
215
B_n = e^{-1} \left( \sum_{k=0}^{k_0} \frac{k^n}{k!} + E_1 \right)
214
216
= e^{-1} \sum_{k=0}^{k_0} \frac{k^n}{k!} + E_2,
215
217
216
- where `0 < E_1 < 1` and `0 < E_2 < e^{-1}`. Next we have:
217
-
218
- .. MATH::
219
-
220
- \sum_{k=0}^{k_0} \frac{k^n}{k!} = \sum_{k=0}^{k_0} n^{-2} \left\lfloor
221
- \frac{n^2 k^n}{k!} \right\rfloor + \frac{E_3}{n^2}
222
-
223
- where `0 \leq E_3 \leq k_0 + 1 \leq 2n + 1 \leq 3n`, so
218
+ where `0 < E_1 < 1` and `0 < E_2 < e^{-1}`. Next we have for any `q > 0`
224
219
225
220
.. MATH::
226
221
227
- \sum_{k=0}^{k_0} \frac{k^n}{k!} = \sum_{k=0}{k_0} n^{-2 } \left\lfloor
228
- \frac{n^2 k^n}{k!} \right\rfloor + E_4,
222
+ \sum_{k=0}^{k_0} \frac{k^n}{k!} = \frac{1}{q} \ sum_{k=0}^{k_0 } \left\lfloor
223
+ \frac{q k^n}{k!} \right\rfloor + \frac{E_3}{q}
229
224
230
- where `0 \leq E_4 \leq \frac{3}{n}`. These two bounds gives:
225
+ where `0 \leq E_3 \leq k_0 + 1 \leq 2n + 1`. Let `E_4 = \frac{E_3}{q}`
226
+ and let `q = 2n + 1`. We find `0 \leq E_4 \leq 1`. These two bounds give:
231
227
232
228
.. MATH::
233
229
234
230
\begin{aligned}
235
- B_n & = e^{-1} \sum_{k=0}^{k_0} n^{-2 } \left\lfloor
236
- \frac{n^2 k^n}{k!} \right\rfloor + e^{-1} E_4 + E_2 \\
237
- & = e^{-1} \sum_{k=0}^{k_0} n^{-2} \left\lfloor \frac{n^2 k^n}{k!}
231
+ B_n & = \frac{ e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor
232
+ \frac{q k^n}{k!} \right\rfloor + e^{-1} E_4 + E_2 \\
233
+ & = \frac{ e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor \frac{q k^n}{k!}
238
234
\right\rfloor + E_5
239
235
\end{aligned}
240
236
241
237
where
242
238
243
239
.. MATH::
244
240
245
- 0 \leq E_5 < e^{-1} + \frac{3e^{-1}}{n} \leq e^{-1} \left(1 +
246
- \frac{3}{9}\right) < \frac{1}{2}.
241
+ 0 < E_5 = e^{-1} E_4 + E_2 \leq e^{-1} + e^{-1} < \frac{3}{4}.
247
242
248
- Note `E_5` can be close to 0, so to avoid this, we subtract `\frac{1}{4}`
249
- from the sum:
243
+ It follows that
250
244
251
245
.. MATH::
252
246
253
- \begin{aligned}
254
- B_n & = e^{-1} \sum_{k=0}^{k_0} n^{-2} \left\lfloor \ frac{n^2 k^n}{k!}
255
- \right\rfloor - \frac{1}{4} + E, \\
256
- B_n & = \left\lceil e^{-1} \sum_{k=0}^{k_0} n^{-2} \left\lfloor
257
- \frac{n^2 k^n}{k!} \right\rfloor -1/4 \right\rceil
258
- \end{aligned}
247
+ B_n = \left\lceil \frac{e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor
248
+ \ frac{q k^n}{k!} \right\rfloor \right\rceil.
249
+
250
+ Now define
251
+
252
+ .. MATH::
259
253
260
- where `\frac{1}{4 } \leq E < \frac{3}{4}` .
254
+ b = \sum_{k=0}^{k_0 } \left\lfloor \frac{q k^n}{k!} \right\rfloor .
261
255
262
- Lastly, to avoid the costly integer division by `k!`, in one step collect
263
- more terms and do only one division, say collect 3 terms:
256
+ This `b` can be computed exactly using integer arithmetic.
257
+ To avoid the costly integer division by `k!`, we collect
258
+ more terms and do only one division, for example with 3 terms:
264
259
265
260
.. MATH::
266
261
267
262
\frac{k^n}{k!} + \frac{(k+1)^n}{(k+1)!} + \frac{(k+2)^n}{(k+2)!}
268
263
= \frac{k^n (k+1)(k+2) + (k+1)^n (k+2) + (k+2)^n}{(k+2)!}
269
264
270
- using this all above error terms.
265
+ In the implementation, we collect `\sqrt{n}/2` terms.
266
+
267
+ To actually compute `B_n` from `b`,
268
+ we let `p = \lfloor \log_2(b) \rfloor + 1` such that `b < 2^p` and
269
+ we compute with `p` bits of precision.
270
+ This implies that `b` (and `q < b`) can be represented exactly.
271
+
272
+ We compute `\frac{e^{-1}}{q} b`, rounding up, and we must have an
273
+ absolute error of at most `1/4` (given that `E_5 < 3/4`).
274
+ This means that we need a relative error of at most
275
+
276
+ .. MATH::
277
+
278
+ \frac{e q}{4 b} > \frac{(e q)/4}{2^p} > \frac{7}{2^p}
279
+
280
+ (assuming `n \geq 5`).
281
+ With a precision of `p` bits and rounding up, every rounding
282
+ has a relative error of at most `2^{1-p} = 2/2^p`.
283
+ Since we do 3 roundings (`b` and `q` do not require rounding),
284
+ we get a relative error of at most `6/2^p`
285
+ (plus some epsilon for errors on the errors).
286
+ All this implies that the precision of `p` bits is sufficient.
271
287
272
288
EXAMPLES::
273
289
@@ -276,7 +292,9 @@ def bell_number(n, algorithm='dobinski', **options):
276
292
sage: bell_number(2)
277
293
2
278
294
sage: bell_number(-10)
279
- 1
295
+ Traceback (most recent call last):
296
+ ...
297
+ ArithmeticError: Bell numbers not defined for negative indices
280
298
sage: bell_number(1)
281
299
1
282
300
sage: bell_number(1/3)
@@ -287,8 +305,7 @@ def bell_number(n, algorithm='dobinski', **options):
287
305
When using the mpmath algorithm, we are required have mpmath's precision
288
306
set to at least `\log_2(B_n)` bits. If upon computing the Bell number the
289
307
first time, we deem the precision too low, we use our guess to
290
- (temporarily) raise mpmath's precision and the Bell number is recomputed.
291
- The result from GAP's bell number was checked agaist OEIS. ::
308
+ (temporarily) raise mpmath's precision and the Bell number is recomputed. ::
292
309
293
310
sage: k = bell_number(30, 'mpmath'); k
294
311
846749014511809332450147
@@ -315,7 +332,7 @@ def bell_number(n, algorithm='dobinski', **options):
315
332
316
333
TESTS::
317
334
318
- sage: all([bell_number(n) == bell_number(n,'gap') for n in range(200, 220 )])
335
+ sage: all([bell_number(n) == bell_number(n,'gap') for n in range(200)])
319
336
True
320
337
sage: all([bell_number(n) == bell_number(n,'mpmath', prec=500) for n in range(200, 220)])
321
338
True
@@ -324,12 +341,18 @@ def bell_number(n, algorithm='dobinski', **options):
324
341
325
342
- Robert Gerbicz
326
343
344
+ - Jeroen Demeyer: improved implementation of Dobinski formula with
345
+ more accurate error estimates (:trac:`17157`)
346
+
327
347
REFERENCES:
328
348
329
349
- :wikipedia:`Bell_number`
330
350
- http://fredrik-j.blogspot.com/2009/03/computing-generalized-bell-numbers.html
331
351
- http://mathworld.wolfram.com/DobinskisFormula.html
332
352
"""
353
+ n = ZZ (n )
354
+ if n < 0 :
355
+ raise ArithmeticError ('Bell numbers not defined for negative indices' )
333
356
if algorithm == 'mpmath' :
334
357
from sage .libs .mpmath .all import bell , mp , mag
335
358
old_prec = mp .dps
@@ -346,24 +369,37 @@ def bell_number(n, algorithm='dobinski', **options):
346
369
mp .dps = old_prec
347
370
return ret
348
371
return ZZ (int (ret_mp ))
349
- if n < 200 or algorithm == 'gap' :
350
- return ZZ (gap .eval ("Bell(%s)" % ZZ (n )))
351
- from sage .functions .log import log
352
- from sage .misc .functional import ceil , N , isqrt , exp as exp2
353
- b , fact , k , n2 , si = Integer (0 ), Integer (1 ), Integer (1 ), \
354
- Integer (n )** 2 , isqrt (Integer (n )) // 2
355
- while True :
356
- mult , v = n2 , Integer (0 )
357
- for i in range (si - 1 , - 1 , - 1 ):
358
- v += mult * (k + i )** n
359
- mult *= k + i
360
- fact *= mult // n2
361
- v //= fact
362
- b += v
363
- k += si
364
- if v == 0 :
365
- break
366
- return ZZ (ceil (N ((b - n ) / n2 * exp2 (Integer (- 1 )) - 1 / 4 , log (b , 2 ) + 3 )))
372
+
373
+ elif algorithm == 'gap' :
374
+ from sage .libs .gap .libgap import libgap
375
+ return libgap .eval ("Bell(%s)" % n ).sage ()
376
+
377
+ elif algorithm == 'dobinski' :
378
+ # Hardcode small cases. We only proved the algorithm below
379
+ # for n >= 5, but it turns out that n = 4 also works.
380
+ if n < 4 :
381
+ return Integer ( (1 , 1 , 2 , 5 )[n ] )
382
+ b = ZZ .zero ()
383
+ fact = k = ZZ .one ()
384
+ q = 2 * n + 1
385
+ si = Integer (n ).sqrtrem ()[0 ] // 2
386
+ while True :
387
+ partfact = ZZ .one ()
388
+ v = ZZ .zero ()
389
+ for i in range (si - 1 , - 1 , - 1 ):
390
+ v += partfact * (k + i )** n
391
+ partfact *= k + i
392
+ fact *= partfact
393
+ v = (q * v ) // fact
394
+ if not v :
395
+ break
396
+ b += v
397
+ k += si
398
+ from sage .rings .all import RealField
399
+ R = RealField (b .exact_log (2 ) + 1 , rnd = 'RNDU' )
400
+ return ( (R (- 1 ).exp () / q ) * b ).ceil ()
401
+
402
+ raise ValueError ("unknown algorithm %r" % algorithm )
367
403
368
404
def catalan_number (n ):
369
405
r"""
0 commit comments