In [64]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import math
import heapq

In [65]:
MAX_ITER = 64

eps = 1.19209e-07


cp_n = 0
cnx = []
nx = {}

#range_array = []

def get_possibilities(n, p):
    global cp_n, cnx, nx
    if cp_n != n:
        cp_n = n
        cnx = np.zeros(n+1)
        cnx[0] = 1.0
        for i in range(1, n+1):
            cnx[i] = cnx[i-1] * (n - i + 1) / i
        nx = {}
    if p not in nx:
        ps = np.zeros(n+1)
        for i in range(n+1):
            ps[i] = cnx[i] * (p**i) * ((1-p)**(n-i))
        nx[p] = ps
    return nx[p]
    
def compute_possibility(n, p, x):
    nx = get_possibilities(n, p)
    return nx[x]

def compute_confidence(n, L, t, p):
    nx = get_possibilities(n, p)
    s = np.sum(nx[(L <= p) & ((L + t) >= p)])
    return s
        
def bs_next_helper(n, c, t, L, m, p):  
    nx = get_possibilities(n, p)
    nx = nx[:m+1]
    Lm = L[:m+1]
    s = np.sum(nx[(Lm <= p) & ((Lm + t) >= p)])
    #s = np.sum(nx[(L <= p) & ((L + t) >= p)])
    if s >= c:
        return True
    return False

#print(bs_next_helper(10, 0.9, 1.0, [0.0,0.0], 0, 0.0001))

def bs_next(n, c, t, L, i, hq):
    if len(hq) == 0:
        return 1.0
    
    beg = heapq.heappop(hq)
    while len(hq) > 0:
        end = heapq.heappop(hq)
        #print(end, bs_next_helper(n, c, t, L, i, end))
        if bs_next_helper(n, c, t, L, i, end):
            beg = end
            continue
        
        if bs_next_helper(n, c, t, L, i, end - eps):
            beg = end - eps
        else:
            for _ in range(MAX_ITER):
                mid = (beg + end) / 2.0
                if mid == beg:
                    break
                #print("mid:", mid, L[0], t, c, bs_next_helper(n, c, t, L, i+1, mid))
                if bs_next_helper(n, c, t, L, i, mid):
                    beg = mid
                else:
                    end = mid
        
        heapq.heappush(hq, beg)
        heapq.heappush(hq, min(1.0, beg+t+eps))
        L[i+1] = beg
        if not bs_next_helper(n, c, t, L, i+1, end):
            heapq.heappush(hq, end)
        return beg
    
    return 1.0
        

def bci_helper(n, c, t, L):
    #L -= 3.0
    L[0] = 0.0
    
    # wrong
    #hq = [0.0, 1.0]
    
    hq = [i / n for i in range(n+1)]
    
    heapq.heappush(hq, t)
    for i in range(n):
        L[i+1] = bs_next(n, c, t, L, i, hq)
        #print(hq)
    
    #tmp = test_bci(n, L, t, 0.01)
    #if tmp >= c:
    #    return True
    #return False
    
    while len(hq) > 0:
        p = heapq.heappop(hq)
        if compute_confidence(n, L, t, p) < c:
            return False
        if p == 1.0:
            break
    return True

def compute_binomail_confidence_interval(n, c):
    #global range_array
    #range_array = np.array(range(n))
    L = np.zeros(n+1)
    beg = 0.0
    end = 1.0
    for i in range(MAX_ITER):
        mid = (beg + end) / 2.0
        if mid == beg:
            break
        ok = bci_helper(n, c, mid, L)
        print(i, mid, ok)
        if ok:
            end = mid
        else:
            beg = mid
    bci_helper(n, c, end, L)
    return L, L + end, end

            

def test_bci(n, L, t, step):
    ret = compute_confidence(n, L, t, 1.0)
    ind = 1.0
    p = 0
    while p <= 1.0:
        tmp = compute_confidence(n, L, t, p)
        if tmp < ret:
            ret = tmp
            ind = p
        p += step
    return ret, ind

def compute_and_test(n, c, step):
    L, R, t = compute_binomail_confidence_interval(n, c)
    ret, ret_p = test_bci(n, L, t, step)
    print("result:", c, ret, ret_p)
    return L, R, t

# compute_binomail_confidence_interval(10, 0.9)  
# %time L, R, t = compute_and_test(200, 0.99, 0.01)

In [66]:
n = 20
c = 0.7
steps = 100
L, R, t = compute_and_test(n, c, (1.0 / steps))
print("interval:", t)
x = [i * (1.0 / steps) for i in range(steps+1)]
y = [compute_confidence(n, L, t, i) for i in x]
#print(x, y)

plt.plot(x,y)
#for i,j in zip(x, y):
#    print(i,j)


0 0.5 True
1 0.25 True
2 0.125 False
3 0.1875 False
4 0.21875 True
5 0.203125 False
6 0.2109375 False
7 0.21484375 True
8 0.212890625 True
9 0.2119140625 False
10 0.21240234375 True
11 0.212158203125 False
12 0.2122802734375 False
13 0.21234130859375 True
14 0.212310791015625 False
15 0.2123260498046875 False
16 0.21233367919921875 True
17 0.21232986450195312 True
18 0.2123279571533203 False
19 0.21232891082763672 True
20 0.21232843399047852 True
21 0.21232819557189941 True
22 0.21232807636260986 False
23 0.21232813596725464 False
24 0.21232816576957703 False
25 0.21232818067073822 False
26 0.21232818812131882 False
27 0.21232819184660912 False
28 0.21232819370925426 False
29 0.21232819464057684 True
30 0.21232819417491555 False
31 0.2123281944077462 False
32 0.21232819452416152 False
33 0.21232819458236918 True
34 0.21232819455326535 False
35 0.21232819456781726 True
36 0.2123281945605413 False
37 0.21232819456417928 False
38 0.21232819456599827 False
39 0.21232819456690777 True
40 0.21232819456645302 False
41 0.2123281945666804 False
42 0.21232819456679408 False
43 0.21232819456685093 False
44 0.21232819456687935 True
45 0.21232819456686514 True
46 0.21232819456685803 False
47 0.21232819456686158 True
48 0.2123281945668598 True
49 0.21232819456685892 True
50 0.21232819456685847 True
51 0.21232819456685825 True
52 0.21232819456685814 False
53 0.2123281945668582 True
54 0.21232819456685817 False
55 0.2123281945668582 True
56 0.2123281945668582 True
57 0.2123281945668582 True
58 0.2123281945668582 True
59 0.2123281945668582 True
60 0.2123281945668582 True
61 0.2123281945668582 True
62 0.2123281945668582 True
63 0.2123281945668582 True
result: 0.7 0.7151181128760234 0.18000000000000002
interval: 0.2123281945668582
Out[66]:
[<matplotlib.lines.Line2D at 0x189456edb00>]

In [67]:
print("n:", n, ", confidence:", c, ", interval:", t)
for i, l in enumerate(L):
    print(i, [l,  min(1.0, l + t)], i / n)
#compute_confidence(n, L, t, 0.713201540802663)


n: 20 , confidence: 0.7 , interval: 0.2123281945668582
0 [0.0, 0.2123281945668582] 0.0
1 [0.017675667042795048, 0.23000386160965325] 0.05
2 [0.05474410483285246, 0.26707229939971067] 0.1
3 [0.09594299769071496, 0.30827119225757316] 0.15
4 [0.1391332389191057, 0.3514614334859639] 0.2
5 [0.18362101456330895, 0.3959492091301672] 0.25
6 [0.22759121141747968, 0.4399194059843379] 0.3
7 [0.26707229939971067, 0.47940049396656886] 0.35
8 [0.30827119225757316, 0.5205993868244314] 0.4
9 [0.3514614334859639, 0.5637896280528221] 0.45
10 [0.3959492091301672, 0.6082774036970253] 0.5
11 [0.4399194059843379, 0.6522476005511961] 0.55
12 [0.47940049396656886, 0.6917286885334271] 0.6
13 [0.5205993868244314, 0.7329275813912897] 0.65
14 [0.5637896280528221, 0.7761178226196803] 0.7
15 [0.6082774036970253, 0.8206055982638836] 0.75
16 [0.6522476005511961, 0.8645757951180544] 0.8
17 [0.6917286885334271, 0.9040568831002853] 0.85
18 [0.7329275813912897, 0.9452557759581479] 0.9
19 [0.7761178226196803, 0.9884460171865386] 0.95
20 [0.8206055982638836, 1.0] 1.0