///|
/// IHW (Independent Hypothesis Weighting) Demo.
/// Demonstrates basic IHW correction, custom configuration,
/// multiple covariates, Storey-style IHW, and comparison with
/// the Bonferroni baseline.
///|
/// Helper: format an array of doubles into a short string
/// with up to `n` entries followed by "...".
fn format_array(arr : Array[Double], n : Int32) -> String {
let mut s = "["
let mut i = 0
let limit = if n < arr.length() { n } else { arr.length() }
while i < limit {
if i > 0 {
s = s + ", "
}
s = s + arr[i].to_string()
i = i + 1
}
if arr.length() > n {
s = s + ", ..."
}
s = s + "]"
s
}
///|
/// Helper: count significant calls at level alpha in an
/// array of adjusted p-values.
fn count_significant(adj : Array[Double], alpha : Double) -> Int32 {
let mut c = 0
let mut i = 0
while i < adj.length() {
if adj[i] <= alpha {
c = c + 1
}
i = i + 1
}
c
}
///|
fn main {
println("=== IHW (Independent Hypothesis Weighting) Demo ===\n")
// ------------------------------------------------------------------
// 1. Basic IHW correction with covariates
// ------------------------------------------------------------------
println("1. Basic IHW correction with covariates")
println("---------------------------------------")
let p_values : Array[Double] = [
0.0001, 0.0020, 0.0100, 0.0300, 0.0400, 0.0450, 0.0800, 0.1200, 0.3000, 0.5000,
0.7000, 0.8500, 0.9000, 0.9500, 0.9900,
]
let covariates : Array[Double] = [
0.95, 0.90, 0.85, 0.70, 0.65, 0.55, 0.40, 0.30, 0.25, 0.20, 0.15, 0.10, 0.08,
0.05, 0.02,
]
println(" Input p-values : \{format_array(p_values, 5)}")
println(" Input covariates : \{format_array(covariates, 5)}")
let result1 = @src.ihw(p_values, covariates, 0.05)
println(" IHW attempts : \{result1.n_attempts()}")
println(" IHW weights : \{format_array(result1.weights(), 5)}")
println(
" Adjusted p-values : \{format_array(result1.adjusted_p_values(), 5)}",
)
let n_sig1 = count_significant(result1.adjusted_p_values(), 0.05)
println(" Significant (alpha=0.05): \{n_sig1}")
// ------------------------------------------------------------------
// 2. IHW with custom configuration (global vs local)
// ------------------------------------------------------------------
println("\n2. IHW with custom configuration (global and local)")
println("---------------------------------------------------")
let config_global = @src.IHWConfig::new(
alpha=0.05,
n_attempts=5,
scale_type="global",
)
let result_global = @src.ihw_with_config(p_values, covariates, config_global)
println(" [global] attempts : \{result_global.n_attempts()}")
println(
" [global] weights : \{format_array(result_global.weights(), 5)}",
)
println(
" [global] adj.p-values : \{format_array(result_global.adjusted_p_values(), 5)}",
)
println(
" [global] significant : \{count_significant(result_global.adjusted_p_values(), 0.05)}",
)
let config_local = @src.IHWConfig::new(
alpha=0.05,
n_attempts=10,
scale_type="local",
)
let result_local = @src.ihw_with_config(p_values, covariates, config_local)
println(" [local] attempts : \{result_local.n_attempts()}")
println(
" [local] weights : \{format_array(result_local.weights(), 5)}",
)
println(
" [local] adj.p-values : \{format_array(result_local.adjusted_p_values(), 5)}",
)
println(
" [local] significant : \{count_significant(result_local.adjusted_p_values(), 0.05)}",
)
// ------------------------------------------------------------------
// 3. Multiple covariate IHW
// ------------------------------------------------------------------
println("\n3. Multiple covariate IHW")
println("-------------------------")
let cov1 : Array[Double] = [
0.90, 0.85, 0.80, 0.70, 0.60, 0.55, 0.45, 0.35, 0.25, 0.15, 0.10, 0.08, 0.05,
0.03, 0.02,
]
let cov2 : Array[Double] = [
0.80, 0.82, 0.78, 0.65, 0.58, 0.50, 0.42, 0.33, 0.22, 0.18, 0.12, 0.09, 0.07,
0.04, 0.03,
]
let cov3 : Array[Double] = [
0.70, 0.75, 0.72, 0.68, 0.62, 0.50, 0.40, 0.30, 0.20, 0.12, 0.08, 0.06, 0.04,
0.03, 0.02,
]
let multi_covs : Array[Array[Double]] = [cov1, cov2, cov3]
let result_multi = @src.ihw_multiple(p_values, multi_covs, 0.05)
println(" Covariates provided : 3 (cov1, cov2, cov3)")
println(" Combined weights : \{format_array(result_multi.weights(), 5)}")
println(
" Adjusted p-values : \{format_array(result_multi.adjusted_p_values(), 5)}",
)
println(
" Significant : \{count_significant(result_multi.adjusted_p_values(), 0.05)}",
)
// ------------------------------------------------------------------
// 4. Storey-style IHW
// ------------------------------------------------------------------
println("\n4. Storey-style IHW")
println("-------------------")
let storey_adj = @src.storey_ihw(p_values, covariates)
println(" Storey adjusted p-values: \{format_array(storey_adj, 5)}")
println(" Significant (alpha=0.05): \{count_significant(storey_adj, 0.05)}")
// ------------------------------------------------------------------
// 5. Compare IHW weights with Bonferroni baseline
// ------------------------------------------------------------------
println("\n5. Compare IHW with Bonferroni baseline")
println("--------------------------------------")
let bonf_adj = @src.bonferroni_ihw(p_values)
println(" Bonferroni adj.p-values : \{format_array(bonf_adj, 5)}")
println(" Bonferroni significant : \{count_significant(bonf_adj, 0.05)}")
println(
" IHW adj.p-values : \{format_array(result1.adjusted_p_values(), 5)}",
)
println(
" IHW significant : \{count_significant(result1.adjusted_p_values(), 0.05)}",
)
println(" Storey adj.p-values : \{format_array(storey_adj, 5)}")
println(" Storey significant : \{count_significant(storey_adj, 0.05)}")
println("\n IHW vs Bonferroni weights:")
let mut i = 0
while i < result1.weights().length() && i < 5 {
let w = result1.weights()[i]
let equal = 1.0
let marker = if w > equal {
"higher"
} else if w < equal {
"lower"
} else {
"equal"
}
println(
" hypothesis \{i+1}: IHW weight = \{w}, Bonferroni weight = \{equal} (IHW \{marker})",
)
i = i + 1
}
println("\n=== IHW Demo Complete ===")
}