Skip to content

Commit 54d2d37

Browse files
committed
Update of inclusion probabilities calculation
1 parent 1197604 commit 54d2d37

File tree

1 file changed

+44
-10
lines changed

1 file changed

+44
-10
lines changed

src/IncluProbs.jl

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,51 @@
11
# Inclusion probabilities
22
# Transform weights into first order inclusion probabilities
3-
# 1: p(w)=x*w+y
3+
# 1: p(w)=w*x+y
44
# 2: Sum constraint: sum(probs)=n => sum(p.(ws))=n
55
# 3: Minimum probability constraint: p(w_min)=w_min
6-
function inclusion_prob(sampler::Sampler, n::Int)
6+
#
7+
# Algebra: y = w_min*(1 - x)
8+
# x = (n - N*w_min) / (sum(ws) - N*w_min) == (n - N*w_min) / (N*(μ - w_min))
9+
function inclusion_prob(sampler::Sampler, n::Integer; highprec::Bool=false)
710
@views ws = sampler.weights
811
N = length(ws)
9-
min_prob = minimum(ws)
10-
A = [ sum(ws) N;
11-
minimum(ws) 1.0]
12-
b = [n, min_prob]
13-
x, y = A \ b
14-
ps = x*ws.+y
15-
return ps
16-
end
12+
@assert N > 0 "empty weights"
13+
14+
if !highprec
15+
wmin = minimum(ws)
16+
μ = mean(ws)
17+
den = N*- wmin)
18+
num = n - N*wmin
19+
20+
# If nearly singular, switch to high precision automatically
21+
if den == 0 || abs(den) 1e-12 * max(1.0, abs(N*μ))
22+
return inclusion_prob(sampler, n; highprec=true)
23+
end
1724

25+
x = num / den
26+
y = muladd(-wmin, x, wmin) # y = wmin*(1 - x)
27+
ps = @. muladd(x, ws, y) # p = x*ws + y
28+
29+
return ps
30+
else
31+
# Compute coefficients in high precision, then cast back
32+
ps = let
33+
setprecision(256) do
34+
W = big.(ws)
35+
NB = big(N)
36+
nB = big(n)
37+
wmin = minimum(W)
38+
μ = mean(W)
39+
den = NB*- wmin)
40+
num = nB - NB*wmin
41+
@assert den != 0 "Constraints are singular: mean(ws) == w_min"
42+
43+
x = num / den
44+
y = wmin*(1 - x)
45+
T = eltype(ws)
46+
T.( @. x*W + y )
47+
end
48+
end
49+
return ps
50+
end
51+
end

0 commit comments

Comments
 (0)