"""WoT members threshold formula for binary votes. Core formula: Result = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T - C) Where: C = constant_base B = base_exponent W = wot_size (corpus of eligible voters) T = total_votes (for + against) M = majority_ratio (majority_pct / 100) G = gradient_exponent Inertia behaviour: - Low participation (T << W) -> near-unanimity required - High participation (T -> W) -> simple majority M suffices Reference test case: wot_size=7224, votes_for=97, votes_against=23 (total=120) params M50 B.1 G.2 => threshold=94, adopted (97 >= 94) """ from __future__ import annotations import math def wot_threshold( wot_size: int, total_votes: int, majority_pct: int = 50, base_exponent: float = 0.1, gradient_exponent: float = 0.2, constant_base: float = 0.0, ) -> int: """Compute the minimum number of *for* votes required for adoption. Parameters ---------- wot_size: Size of the eligible voter corpus (WoT members). total_votes: Number of votes cast (for + against). majority_pct: Majority percentage (0-100). 50 = simple majority at full participation. base_exponent: B in the formula. ``B^W`` contributes a vanishingly small offset when W is large (0 < B < 1). gradient_exponent: G controls how fast the required super-majority decays toward M as participation increases. constant_base: C, a fixed additive floor on the threshold. Returns ------- int The ceiling of the computed threshold. A vote passes when ``votes_for >= wot_threshold(...)``. """ if wot_size <= 0: raise ValueError("wot_size doit etre strictement positif") if total_votes < 0: raise ValueError("total_votes ne peut pas etre negatif") if not (0 <= majority_pct <= 100): raise ValueError("majority_pct doit etre entre 0 et 100") C = constant_base B = base_exponent W = wot_size T = total_votes M = majority_pct / 100.0 G = gradient_exponent # Guard: if no votes, threshold is at least ceil(C + B^W) if T == 0: return math.ceil(C + B ** W) # Core formula participation_ratio = T / W inertia_factor = 1.0 - participation_ratio ** G required_ratio = M + (1.0 - M) * inertia_factor result = C + B ** W + required_ratio * max(0.0, T - C) return math.ceil(result)