File size: 2,860 Bytes
0ce9643
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import type { ActivationData, AnomalyData, CircuitData } from '../types/scan';
import type { CompareData, LayerDiff } from '../types/compare';
import type { ScanMode } from '../types/model';

export interface ScanDataPair {
  activationData: ActivationData | null;
  circuitData: CircuitData | null;
  anomalyData: AnomalyData | null;
}

/**
 * Compute layer-wise diffs between two scan datasets.
 * Works for both multi-prompt (same model) and cross-model comparisons.
 */
export function computeLayerDiffs(
  mode: ScanMode,
  labelA: string,
  labelB: string,
  tokensA: string[],
  tokensB: string[],
  dataA: ScanDataPair,
  dataB: ScanDataPair,
): CompareData | null {
  if (mode === 'fMRI' && dataA.activationData && dataB.activationData) {
    const a = dataA.activationData;
    const b = dataB.activationData;
    const diffs: LayerDiff[] = [];
    for (let i = 0; i < Math.min(a.layers.length, b.layers.length); i++) {
      const aActs = a.layers[i].activations;
      const bActs = b.layers[i].activations;
      const avgA = aActs.reduce((s, v) => s + v, 0) / Math.max(aActs.length, 1);
      const avgB = bActs.reduce((s, v) => s + v, 0) / Math.max(bActs.length, 1);
      diffs.push({ layer_id: a.layers[i].layer_id, delta: avgB - avgA });
    }
    const maxAbs = Math.max(...diffs.map((d) => Math.abs(d.delta)), 0.001);
    return { promptA: labelA, promptB: labelB, tokens_a: tokensA, tokens_b: tokensB, layerDiffs: diffs, maxAbsDelta: maxAbs };
  }

  if (mode === 'DTI' && dataA.circuitData && dataB.circuitData) {
    const a = dataA.circuitData;
    const b = dataB.circuitData;
    const aMap = new Map(a.components.map((c) => [c.layer_id, c.importance]));
    const diffs: LayerDiff[] = b.components.map((c) => ({
      layer_id: c.layer_id,
      delta: c.importance - (aMap.get(c.layer_id) ?? 0),
    }));
    const maxAbs = Math.max(...diffs.map((d) => Math.abs(d.delta)), 0.001);
    return { promptA: labelA, promptB: labelB, tokens_a: tokensA, tokens_b: tokensB, layerDiffs: diffs, maxAbsDelta: maxAbs };
  }

  if (mode === 'FLAIR' && dataA.anomalyData && dataB.anomalyData) {
    const a = dataA.anomalyData;
    const b = dataB.anomalyData;
    const diffs: LayerDiff[] = [];
    for (let i = 0; i < Math.min(a.layers.length, b.layers.length); i++) {
      const aScores = a.layers[i].anomaly_scores;
      const bScores = b.layers[i].anomaly_scores;
      const avgA = aScores.reduce((s, v) => s + v, 0) / Math.max(aScores.length, 1);
      const avgB = bScores.reduce((s, v) => s + v, 0) / Math.max(bScores.length, 1);
      diffs.push({ layer_id: a.layers[i].layer_id, delta: avgB - avgA });
    }
    const maxAbs = Math.max(...diffs.map((d) => Math.abs(d.delta)), 0.001);
    return { promptA: labelA, promptB: labelB, tokens_a: tokensA, tokens_b: tokensB, layerDiffs: diffs, maxAbsDelta: maxAbs };
  }

  return null;
}