def __call__(self, n, t, y_t): if self.min_stop_check(t): return False y = y_t not_y = t - y # The amount for winner under alternative p1N = int(n * self.p) # The amount for winner under null p0N = int(n * self.p_0) # The amount for winner is greater than alternative if y >= p1N: return True # The amount for loser is greater than votes in null hypothesis for loser elif not_y >= n - p0N: return False # log(top) log_prob_p1 = hypergeom_pmf(y, n, p1N, t, log=True) # log(bot) log_prob_p0 = hypergeom_pmf(y, n, p0N, t, log=True) inf_p0 = isinf(log_prob_p0) inf_p1 = isinf(log_prob_p1) # Both return null, means the chance is in between if inf_p0 and inf_p1: # if y > p0N: return True return False # Chance for null is zero elif inf_p0: return True # Chance for alternative is zero elif inf_p1: return False # total log(top) - log(bottom) ratio = log_prob_p1 - log_prob_p0 # print(n, t, y_t, log_prob_p0, log_prob_p1, ratio, self.critical_value) return ratio >= self.critical_value
def single_node_update(rejection_fn, n, t, y_t, p_t, step, p, replacement, *args, **kwargs): rejection_dict = defaultdict(float) q = OrderedDict() # Take the floor for winner's share w = floor(n * p) t_next = t + step n_remain = n - t w_remain = w - y_t # All possible generated sa for next batch for i in range(step + 1): y_t_next = y_t + i if not replacement: # If no replacement sample from hypergeometric distribution p_next = hypergeom_pmf(i, n_remain, w_remain, step) else: # Else use binomial compute probability p_next = binom_pmf(i, step, p) # Is this state rejected? reject = rejection_fn(n, t_next, y_t_next, *args, **kwargs) # Compose the node node = (t_next, y_t_next, p_next * p_t) if isnull(node[2]): node = (t_next, y_t_next, 0) # Don't add to queue or dict if there is no chance for it if node[2] == 0: continue # if null is rejected, put it in the risk dict if reject: rejection_dict[node[:2]] += node[2] else: q.append(node[:2], node[2]) return rejection_dict, q
def audit_process_simulation_serial(rejection_fn, election: Election, progression=False, *args, **kwargs): m = election.m n = election.n step = election.step replacement = election.replacement p = election.p if m == -1: m = n + 1 w = floor(n * p) progression_bar = null_bar if progression: progression_bar = SimpleProgressionBar(m) rejection_dict = defaultdict(float) # first element: t, # second element: y_t, (observe every step time) # third element: probability going to this state source = (0, 0, 1) q = OrderedDict() q.append(source[:2], source[2]) # While q is not empty while len(q): # get next node to explore key, value = q.peek() # Update progression progression_bar(key[0]) # If sampled to the max number already, break (max number exclusive) if isinstance(m, int) and key[0] >= m: break if replacement and key[0] > n: break # Remove the value q.popitem(last=False) t, y_t, p_t = *key, value console_logger.debug(" poped: {}".format((t, y_t, p_t))) n_remain = n - t w_remain = w - y_t t_next = t + step reject = False # All possible generated sa for next batch for i in range(0, step + 1): y_t_next = y_t + i if not replacement: n_remain_next = n - t_next w_remain_next = w - y_t_next l_remain_next = n_remain_next - w_remain_next if n_remain_next < 0 or w_remain_next < 0 or l_remain_next < 0: continue if y_t_next < 0: break if not replacement: # If no replacement sample from hypergeometric distribution p_next = hypergeom_pmf(i, n_remain, w_remain, step) else: # Else use binomial compute probability p_next = binom_pmf(i, step, p) # Update reject if it's False, don't need to compute reject if it's True already (as is tested sequentially) if not reject: # Remainder: Don't use is to compare True False reject = rejection_fn(n, t_next, y_t_next, *args, **kwargs) # Compose the node node = (t_next, y_t_next, p_next * p_t) if isnull(p_next * p_t): node = (t_next, y_t_next, 0) # if null is rejected, put it in the risk dict if reject: rejection_dict[node[:2]] += node[2] else: q.append(node[:2], node[2]) # The information in this is enough to determine the result return rejection_dict
from utility.program_utility import CachedMethod, string_to_num