File size: 3,124 Bytes
c881b77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Claim 5 (faithful, scaled): Raisa et al. synthetic benchmark mechanism.

Uses the OFFICIAL GICDM repo (github.com/nicolassalvy/GICDM) Clipped Density /
Clipped Coverage with the standard vs GICDM DataProcessor. We run representative
Raisa scenarios on modest synthetic data (scaled down N,d) and tally whether each
metric behaves correctly with/without GICDM. We report the *direction* of change
and note the paper's full pass counts (Clipped Density Purpose 8/14 -> 10/14,
Bounds 8/13 -> 11/13; Clipped Coverage 8/14->10/14, 9/13->11/13).
"""
import numpy as np
import sys, os
sys.path.insert(0, "/Users/equan_p/Developer/playground/ICML-2/official/GICDM")
from metrics.hubness_processor.standard import DataProcessorStandard
from metrics.hubness_processor.gicdm import GICDM
from metrics.metrics.clipped_density_coverage import ClippedDensityCoverage


def make_processor(Xr, use_gicdm, K=5):
    if use_gicdm:
        return GICDM(Xr, K=K, n_jobs=4, scale_factor=10)
    return DataProcessorStandard(Xr, K=K, n_jobs=4)


def cd_cc(Xr, Xg, use_gicdm, K=5):
    dp = make_processor(Xr, use_gicdm, K)
    cdc = ClippedDensityCoverage(dp)
    cd = cdc.clipped_density(Xg)
    cc = cdc.clipped_coverage(Xg)
    return float(cd), float(cc)


def sphere(d, n, r, rng):
    v = rng.normal(size=(n, d)); v /= np.linalg.norm(v, axis=1, keepdims=True)
    return v * r


def main():
    rng = np.random.default_rng(0)
    d, n = 100, 1500
    rows = []
    scenarios = {}

    # 1. GAUSSIAN MEAN DIFFERENCE: shift=0 -> identical -> CD,CC should be ~1
    Xr = rng.normal(0, 1, size=(n, d)); Xg0 = rng.normal(0, 1, size=(n, d))
    scenarios['gauss_mean_equal'] = (Xr.copy(), Xg0.copy())

    # 2. GAUSSIAN STD DEVIATION DIFFERENCE: scale mismatch
    Xg_std = rng.normal(0, 1.5, size=(n, d))
    scenarios['gauss_std_1p5'] = (Xr.copy(), Xg_std.copy())

    # 3. HYPERSPHERE SURFACE equal radius (should be ~1)
    sr = sphere(d, n, 1.0, rng); sg = sphere(d, n, 1.0, rng)
    scenarios['hypersphere_equal'] = (sr, sg)

    # 4. MODE COLLAPSE: gen collapses to one of 5 modes
    centers = rng.normal(0, 5, size=(5, d))
    Xr_m = centers[rng.integers(0, 5, n)] + rng.normal(0, 0.3, (n, d))
    Xg_mc = centers[0] + rng.normal(0, 0.3, (n, d))
    scenarios['mode_collapse'] = (Xr_m.copy(), Xg_mc.copy())
    Xg_mf = centers[rng.integers(0, 5, n)] + rng.normal(0, 0.3, (n, d))
    scenarios['mode_full'] = (Xr_m.copy(), Xg_mf.copy())

    # 5. SPHERE vs TORUS-like (sphere vs scaled sphere offset)
    st = sphere(d, n, 1.0, rng) + 3.0  # offset sphere -> out of manifold
    scenarios['sphere_offset'] = (sr.copy(), st.copy())

    results = {}
    for name, (Xr_, Xg_) in scenarios.items():
        cd0, cc0 = cd_cc(Xr_, Xg_, False)
        cdg, ccg = cd_cc(Xr_, Xg_, True)
        results[name] = dict(cd_raw=cd0, cc_raw=cc0, cd_gicdm=cdg, cc_gicdm=ccg)
        print(f"{name:18s} CD raw={cd0:.3f} GICDM={cdg:.3f} | CC raw={cc0:.3f} GICDM={ccg:.3f}")

    import json
    json.dump(results, open("/Users/equan_p/Developer/playground/ICML-2/repro_gicdm/results/claim5_official.json", "w"))


if __name__ == "__main__":
    main()