GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GH-81620: Add random.binomialvariate() by rhettinger · Pull Request #94719 · python/cpython

Conversation

@rhettinger

@rhettinger rhettinger commented Jul 9, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor
  • Issue: Add random.binomialvariate() #81620

Here are some comparisons between actual and expected histograms of the random variable across various input parameters chosen to cover all the code paths:

raymond@raymonds-mbp cpython % ./python.exe show_dist2.py
n=0	p=0.5	times=131072
[131072] actual
[131072] expected

n=1	p=0.5	times=131072
[65449, 65623] actual
[65536, 65536] expected

n=1	p=0.1	times=131072
[118042, 13030] actual
[117965, 13107] expected

n=1	p=0.9	times=131072
[13093, 117979] actual
[13107, 117965] expected

n=1	p=0.0	times=131072
[131072, 0] actual
[131072, 0] expected

n=1	p=1.0	times=131072
[0, 131072] actual
[0, 131072] expected

n=2	p=0.5	times=131072
[32623, 65655, 32794] actual
[32768, 65536, 32768] expected

n=3	p=0.5	times=131072
[16265, 49238, 49219, 16350] actual
[16384, 49152, 49152, 16384] expected

n=3	p=0.5	times=131072
[16401, 49226, 48791, 16654] actual
[16384, 49152, 49152, 16384] expected

n=4	p=0.5	times=131072
[8182, 32534, 49367, 32803, 8186] actual
[8192, 32768, 49152, 32768, 8192] expected

n=2	p=0.25	times=131072
[73709, 49328, 8035] actual
[73728, 49152, 8192] expected

n=3	p=0.25	times=131072
[55206, 55418, 18407, 2041] actual
[55296, 55296, 18432, 2048] expected

n=3	p=0.25	times=131072
[55739, 54719, 18568, 2046] actual
[55296, 55296, 18432, 2048] expected

n=4	p=0.25	times=131072
[41531, 55530, 27212, 6296, 503] actual
[41472, 55296, 27648, 6144, 512] expected

n=2	p=0.75	times=131072
[8104, 49441, 73527] actual
[8192, 49152, 73728] expected

n=3	p=0.75	times=131072
[2137, 18494, 55245, 55196] actual
[2048, 18432, 55296, 55296] expected

n=3	p=0.75	times=131072
[2125, 18426, 55237, 55284] actual
[2048, 18432, 55296, 55296] expected

n=4	p=0.75	times=131072
[501, 6189, 27652, 55351, 41379] actual
[512, 6144, 27648, 55296, 41472] expected

n=21	p=0.5	times=8388608
[3, 83, 861, 5459, 23954, 81369, 216626, 464857, 814107, 1175105, 1410003, 1412399, 1175408, 813977, 465240, 217611, 81517, 23835, 5267, 849, 75, 3] actual
[4, 84, 840, 5320, 23940, 81396, 217056, 465120, 813960, 1175720, 1410864, 1410864, 1175720, 813960, 465120, 217056, 81396, 23940, 5320, 840, 84, 4] expected

n=23	p=0.44	times=33554432
[50, 996, 8357, 46376, 182566, 546412, 1288350, 2457192, 3860402, 5054928, 5561908, 5163281, 4055424, 2698094, 1514653, 714189, 280545, 91110, 23760, 4920, 827, 85, 7, 0] actual
[54, 980, 8467, 46568, 182945, 546223, 1287525, 2456809, 3860700, 5055678, 5561246, 5164014, 4057440, 2697528, 1513919, 713705, 280384, 90712, 23758, 4912, 772, 87, 6, 0] expected

n=23	p=0.56	times=33554432
[1, 12, 81, 804, 4820, 23672, 90753, 279718, 713524, 1514626, 2698389, 4061304, 5162182, 5560620, 5056002, 3861575, 2455442, 1287630, 544792, 182352, 46622, 8448, 1002, 61] actual
[0, 6, 87, 772, 4912, 23758, 90712, 280384, 713705, 1513919, 2697528, 4057440, 5164014, 5561246, 5055678, 3860700, 2456809, 1287525, 546223, 182945, 46568, 8467, 980, 54] expected

The above output was created using this test function:

from random import binomialvariate
from collections import Counter
from math import comb

def compare(n=1, p=0.5, times=2**17):
    c = Counter(binomialvariate(n, p) for i in range(times))
    assert c.total() == times
    expected = []
    actual = []
    for r in range(n + 1):
        exp = round(times * comb(n, r) * p ** r * (1 - p) ** (n - r))
        act = c.pop(r, 0)
        expected.append(exp)
        actual.append(act)
    assert not c
    print(f'{n=}\t{p=}\t{times=}')
    print(actual, 'actual')
    print(expected, 'expected')
    print()

This code is useful for instrumenting how many calls to random() are made:

from random import _inst, binomialvariate as B
from unittest.mock import patch

def run(n=1, p=0.5):
    with patch.object(_inst, 'random', side_effect=_inst.random) as mo:
        b = B(n, p)
        print(f"B({n}, {p})={b}   {mo.call_count=}")

This demonstrates that how few loops are needed:

# Fast path
B(1, 0.5)=1   mo.call_count=1

# BG for n*p < 10
B(10, 0.5)=6   mo.call_count=6
B(10, 0.25)=2   mo.call_count=3
B(10, 0.01)=0   mo.call_count=1
B(10, 0.75)=8   mo.call_count=3
B(10, 0.99)=10   mo.call_count=1

# BTRS for n*p >= 10
B(100000, 0.5)=49853   mo.call_count=4
B(100000, 0.001)=102   mo.call_count=2
B(100000, 0.999)=99909   mo.call_count=2

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
rhettinger added 9 commits July 8, 2022 23:16
@rhettinger
First draft. Need to check against expected dists, including extreme …
3477a9f
…values.
@rhettinger
Get distribution correct for BG
38ba9e6
@rhettinger
Fix log() call missing from original paper
1e4e7ab
@rhettinger
Loop invariant code motion
b224ef2
@rhettinger
Add section comments to link back to original text
f806df3
@rhettinger
Add comment to help relate to the paper
d6a3ddf
@rhettinger
More elaborate comments
c9d3ca8
@rhettinger
Add documentation
8e24e22
@rhettinger
Add blurb
2b2e589
@rhettinger rhettinger added type-feature A feature request or enhancement stdlib Standard Library Python modules in the Lib/ directory labels Jul 9, 2022
@rhettinger
rhettinger requested review from mdickinson and tim-one July 9, 2022 20:26
@rhettinger rhettinger self-assigned this Jul 9, 2022
@bedevere-bot bedevere-bot added the awaiting core review label Jul 9, 2022
rhettinger added 10 commits July 9, 2022 16:22
@rhettinger
Add unittests
198904b
@rhettinger
Add tests for large n
9f65a39
@rhettinger
Switch short name from "bv" to "B"
8286532
@rhettinger
Only perform step 3.0 setup when needed and only once.
40ec6a1
@rhettinger
Add binomialvariate to the in-module test code
6dfcd0c
@rhettinger
Fix function name in docs. Add a reference link.
9ada9c0
@rhettinger
Neated-up comments
05653a8
@rhettinger
Tighten-up comments and improve a variable name
1b12462
@rhettinger
Inline _logfact() for 7% speed and keeping all code in one place.
f51add2
@rhettinger
Update simulation example
1e16bbb
@rhettinger
rhettinger merged commit ed06ec1 into python:main Jul 13, 2022
@bedevere-bot bedevere-bot removed the awaiting core review label Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@mdickinson mdickinson Awaiting requested review from mdickinson
@tim-one tim-one Awaiting requested review from tim-one

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@rhettinger rhettinger

Labels

stdlib Standard Library Python modules in the Lib/ directory type-feature A feature request or enhancement

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@rhettinger @bedevere-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.