File size: 3,297 Bytes
ebeed67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""The candidate's per-class floors, by the D739 rule, with their reasons.

The rule itself is the harness's (``_vendor/camstack_eval/floors.py``): the
lowest grid floor at which the candidate raises no more false positives on the
holdout than the baseline does at its shipped floor; a class with fewer than
``minSupport`` holdout positives inherits the baseline's floor; the result is
clamped to ±``clamp`` of it. This module turns the harness's per-class
proposals into the ``floors`` block of result.json, with one human note per
class that did not get a fitted floor — and inherits every floor when there
was no holdout to fit on.
"""
from __future__ import annotations

from typing import Optional, Sequence

from ._vendor.camstack_eval.floors import FloorPolicy, ProposedFloor, ScoredDetection, propose_floor
from .spec import FLOOR_CLASSES


def propose(
    baseline: Sequence[ScoredDetection],
    baseline_floor: float,
    candidate: Sequence[ScoredDetection],
    positives: int,
    policy: FloorPolicy,
) -> ProposedFloor:
    return propose_floor(baseline, baseline_floor, candidate, positives, policy)


def note_for(cls: str, proposal: dict, positives: int, baseline_floor: float, policy: FloorPolicy) -> Optional[str]:
    reason = proposal["reason"]
    if reason == "low-support":
        return f"{cls}: {positives} holdout positives < {policy.min_support}, inherits {baseline_floor}"
    if reason == "clamped":
        fitted = proposal.get("fitted")
        fit = "no grid floor met the false-positive budget" if fitted is None else f"fitted {fitted}"
        return f"{cls}: {fit}, clamped to {proposal['value']} (±{policy.clamp} of {baseline_floor})"
    return None


def floors_from_report(
    report: Optional[dict], baseline_floors: dict[str, float], policy: FloorPolicy
) -> tuple[dict[str, float], list[str]]:
    """(floors, notes) for one candidate report; no report ⇒ the baseline's floors."""
    if report is None:
        return {c: baseline_floors[c] for c in FLOOR_CLASSES}, [
            "no complete holdout frame: every floor inherits the baseline"
        ]
    floors: dict[str, float] = {}
    notes: list[str] = []
    for cls in FLOOR_CLASSES:
        entry = report["classes"].get(cls)
        if entry is None:
            floors[cls] = baseline_floors[cls]
            notes.append(f"{cls}: not evaluated, inherits {baseline_floors[cls]}")
            continue
        proposal = entry["proposedFloor"]
        floors[cls] = float(proposal["value"])
        note = note_for(cls, proposal, int(entry["positives"]), baseline_floors[cls], policy)
        if note is not None:
            notes.append(note)
    return floors, notes


def floors_block(
    candidate: Optional[dict],
    candidate_int8: Optional[dict],
    baseline_floors: dict[str, float],
    policy: FloorPolicy,
    int8_present: bool,
) -> dict:
    base, notes = floors_from_report(candidate, baseline_floors, policy)
    int8 = None
    if int8_present:
        int8, int8_notes = floors_from_report(candidate_int8, baseline_floors, policy)
        notes = notes + [f"int8 {n}" for n in int8_notes]
    return {
        "baseline": {c: baseline_floors[c] for c in FLOOR_CLASSES},
        "candidate": base,
        "candidateInt8": int8,
        "notes": notes,
    }