import argparse import json import re import statistics from math import comb import jev from harness import run from rerank import rerank from retrieve import retrieve def page_rank(chunks, gold, section=None): for i, chunk in enumerate(chunks): if chunk["url"] in gold and section in (None, chunk["section"]): return i + 1 return None def mcnemar_exact(b, c): n = b + c if n == 0: return 1.0 tail = sum(comb(n, k) for k in range(min(b, c) + 1)) / 2 ** n return min(1.0, 2 * tail) def retrieval_metrics(ranks): hits = [r is not None and r <= 5 for r in ranks] top1 = sum(r == 1 for r in ranks) / len(ranks) mrr = statistics.mean(1 / r if r else 0 for r in ranks) return hits, {"recall@1": top1, "recall@5": sum(hits) / len(hits), "mrr@20": mrr, "n": len(hits)} def mcnemar(a_ranks, b_ranks, k): a_hits = [r is not None and r <= k for r in a_ranks] b_hits = [r is not None and r <= k for r in b_ranks] b = sum(x and not y for x, y in zip(a_hits, b_hits)) c = sum(y and not x for x, y in zip(a_hits, b_hits)) return {"only_first": b, "only_second": c, "p_exact": mcnemar_exact(b, c)} def cited_urls(answer, chunks): ids = {int(i) for i in re.findall(r"\[c(\d+)\]", answer)} return {chunks[i - 1]["url"] for i in ids if 0 < i <= len(chunks)} def p50(values): return statistics.median(values) if values else None NUM = re.compile(r"(?