File size: 5,059 Bytes
a1dd5ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""SELF-RECOGNIZED action contrast — pseudo-relevance feedback in the
video-native feature space. No class names, no verb maps, no dataset
priors in code (user rule: priors must be recognized from the corpus,
not typed — a self-driving corpus must work with this exact file).

Mechanism (Rocchio, 1971 — the oldest trick in retrieval, applied
cross-modally): the TEXT channels' top-K for the query are weak
positives; the swap-query's top-K are weak negatives; the action
contrast IS the difference of their mean V-JEPA vectors. V-JEPA
features are self-supervised and domain-general — the same anchors
form for "closing the drawer"/"opening the drawer" on bridge and for
"merging left"/"merging right" on driving footage. The corpus itself
defines what the direction looks like here.

Also here: per-query CHANNEL INFORMATIVENESS — a channel that ranks
episodes identically for the query and its swap carries no direction
information for THIS query (measured, not declared)."""
from __future__ import annotations

import numpy as np

_VJ = {}


def _vjepa_matrix(store, keys):
    """Episode-aligned V-JEPA vectors (normalized), cached per store
    version. NaN rows for episodes without a vector."""
    from .embeddings import _vec_table
    ver = store.table("vjepa_vectors").state().version
    ck = (str(store.dir), ver, len(keys))
    if ck in _VJ:
        return _VJ[ck]
    tbl, vecs = _vec_table(store, "vjepa_vectors")
    idx = {}
    for r, (s, a) in enumerate(zip(tbl.column("stream").to_pylist(),
                                   (int(v) for v in
                                    tbl.column("ts").to_pylist()))):
        idx[(str(s), a)] = r
    V = np.asarray(vecs)
    V = V / (np.linalg.norm(V, axis=1, keepdims=True) + 1e-8)
    M = np.full((len(keys), V.shape[1]), np.nan, np.float32)
    for i, (s, a, b) in enumerate(keys):
        r = idx.get((s, a))
        if r is not None:
            M[i] = V[r]
    if len(_VJ) > 4:
        _VJ.clear()
    _VJ[ck] = M
    return M


def prf_contrast(store, keys, seed_scores, swap_seed_scores=None,
                 k=16):
    """Per-episode contrast scores from corpus-derived anchors.

    seed_scores: text-channel scores for the query (weak relevance);
    swap_seed_scores: same for the swapped query, or None (falls back
    to the corpus mean as the neutral anchor). Returns scores aligned
    to keys (NaN where no video-native vector exists)."""
    M = _vjepa_matrix(store, keys)
    have = np.isfinite(M[:, 0])

    def anchor(sc):
        s = np.where(np.isfinite(sc) & have, sc, -np.inf)
        top = np.argsort(-s)[:k]
        top = top[np.isfinite(s[top])]
        if len(top) == 0:
            return None
        a = M[top].mean(0)
        return a / (np.linalg.norm(a) + 1e-8)

    a_pos = anchor(np.asarray(seed_scores, float))
    if a_pos is None:
        return np.full(len(keys), np.nan)
    if swap_seed_scores is not None:
        a_neg = anchor(np.asarray(swap_seed_scores, float))
    else:
        a_neg = None
    if a_neg is None:
        a_neg = np.nanmean(M[have], 0)
        a_neg = a_neg / (np.linalg.norm(a_neg) + 1e-8)
    d = a_pos - a_neg
    n = np.linalg.norm(d)
    if n < 1e-6:
        return np.full(len(keys), np.nan)
    out = M @ (d / n)
    out[~have] = np.nan
    return out


def informativeness(scores_text, scores_swap):
    """1 - |rank correlation| between the channel's view of the query
    and of its swap: ~0 means the channel cannot tell the directions
    apart FOR THIS QUERY on THIS corpus. Measured in microseconds,
    needs no truth."""
    a = np.asarray(scores_text, float)
    b = np.asarray(scores_swap, float)
    fin = np.isfinite(a) & np.isfinite(b)
    if fin.sum() < 8:
        return 0.0
    ra = np.argsort(np.argsort(a[fin]))
    rb = np.argsort(np.argsort(b[fin]))
    r = np.corrcoef(ra, rb)[0, 1]
    if not np.isfinite(r):
        return 0.0
    return float(1.0 - abs(r))


def anchor_support(store, keys, seed_scores, k=16, trials=64):
    """Self-recognized no-match signal: how much more coherent is the
    pseudo-positive set than random corpus draws, in video-native
    space? z << 1 means the text channels found no distinctive
    neighborhood — the queried thing plausibly does not happen here."""
    rng = np.random.default_rng(0)
    M = _vjepa_matrix(store, keys)
    have = np.where(np.isfinite(M[:, 0]))[0]
    s = np.where(np.isfinite(np.asarray(seed_scores, float)),
                 seed_scores, -np.inf)
    top = np.argsort(-s)[:k]
    top = top[np.isfinite(np.asarray(s)[top])]
    top = [t for t in top if np.isfinite(M[t, 0])]
    if len(top) < 4 or len(have) < 4 * k:
        return None
    def coh(rows):
        X = M[rows]
        g = X @ X.T
        n = len(rows)
        return float((g.sum() - n) / max(1, n * n - n))
    obs = coh(np.asarray(top))
    null = np.array([coh(rng.choice(have, size=len(top),
                                    replace=False))
                     for _ in range(trials)])
    return float((obs - null.mean()) / (null.std() + 1e-9))