File size: 1,410 Bytes
77dfe62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""The operating point, shared by the runtime, the export check and the scorecard so they never disagree.

A pair is hostile exactly when its hostility probability reaches tau. Then the act is the most likely hostile class
(or a demand, at high intensity, when demand is the top class). Otherwise it is the most likely non-hostile class, and
a demand is held below high intensity. So the tags the meters receive are hostile exactly when the scorecard says so.
"""
from __future__ import annotations

from contracts.schemas.line_tags import ACTS, HOSTILE_ACTS


def decide(pa, p_host: float, tau: float, intensity: str) -> tuple[str, str]:
    """pa: probabilities over ACTS; intensity: the intensity head's top class. Returns (act, intensity)."""
    order = sorted(range(len(ACTS)), key=lambda i: -float(pa[i]))
    if p_host >= tau:
        if ACTS[order[0]] == "demand":
            return "demand", "high"
        act = next(ACTS[i] for i in order if ACTS[i] in HOSTILE_ACTS)
        return act, intensity
    act = next(ACTS[i] for i in order if ACTS[i] not in HOSTILE_ACTS)
    if act == "demand" and intensity == "high":
        intensity = "medium"
    return act, "low" if act == "none" else intensity


def summed_hostility(pa) -> float:
    """For models without a hostility head: the probability mass on the hostile classes."""
    return float(sum(float(pa[ACTS.index(a)]) for a in HOSTILE_ACTS))