Skip to content

Commit dbea112

Browse files
committed
Improve BY adjustment performance by approximating harmonic numbers
The Benjamini-Yekutieli uses the harmonic number in its step function. The previous implementation through summation of the individual 1/x terms was very inefficient for large x. This has been replaced by an approximation of the harmonic number with constant run time. In comparison with the previous implementation, - run time is equivalent for small n - run time is reduced by several orders of magnitude for large n - the approximated values are within one order of magnitude to floating point precision compared to the exact numbers, similarly to the precision obtained through summation.
1 parent 7e391b6 commit dbea112

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/pval-adjustment.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function benjamini_yekutieli(pValues::PValues, n::Integer)
8787
return min(sortedPValues[originalOrder], 1)
8888
end
8989

90-
benjamini_yekutieli_step(p::AbstractFloat, i::Int, k::Int, n::Int) = p * sum(1./(1:n))*n/(k-i)
90+
benjamini_yekutieli_step(p::AbstractFloat, i::Int, k::Int, n::Int) = p * harmonic_number(n) * n/(k-i)
9191

9292

9393
# Benjamini-Liu
@@ -261,3 +261,6 @@ function check_number_tests(k::Integer, n::Integer)
261261
throw(ArgumentError(msg))
262262
end
263263
end
264+
265+
266+
harmonic_number(n::Integer) = digamma(n+1) + γ

test/test-utils.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,24 @@ using Base.Test
103103
end
104104

105105

106+
@testset "harmonic_number" begin
107+
108+
# Exact computation as reference
109+
harm_n_exact(n::Integer) = sum([Rational(1, i) for i in 1:BigInt(n)])
110+
111+
n = [1:100; 200:200:1000; 10000]
112+
113+
max_d = 0.0
114+
for i in n
115+
hn1 = MultipleTesting.harmonic_number(i)
116+
hn2 = harm_n_exact(i)
117+
max_d = max(abs(hn1 - hn2), max_d)
118+
end
119+
# approximation error in the range of floating point inaccuracy
120+
@test max_d < (10*eps())
121+
122+
end
123+
106124
end
107125

108126
end

0 commit comments

Comments
 (0)