1import numpy as np
3from challenge_tools.metrics import spectrogram, spectrogram_l2, waveform_l2
4from challenge_tools.reference import OrderInfo, collect_order, maximal_elements, select_reference
7def test_waveform_l2():
8 r = np.array([1.0, 2.0, 2.0])
9 assert waveform_l2(r, r) == 0.0
10 assert abs(waveform_l2(r * 1.1, r) - 0.1) < 1e-12
13def test_spectrogram_shape():
14 x = np.zeros(96000)
15 s = spectrogram(x, 2048, 512)
16 assert s.shape == ((96000 - 2048) // 512 + 1, 1025)
19def test_spectrogram_phase_insensitive():
20 t = np.arange(96000) / 48000
21 a = np.sin(2 * np.pi * 440 * t)
22 b = np.sin(2 * np.pi * 440 * t + 1.0)
23 assert waveform_l2(a, b) > 0.5
24 assert spectrogram_l2(a, b, 2048, 512) < 1e-2
27def test_reference_selection_prefers_order_preserving_candidate():
28 subs = [
29 {"submission_id": "x", "solutions": [
30 {"solution_id": "a", "more_accurate_than": []},
31 {"solution_id": "b", "more_accurate_than": ["a"]},
32 ]},
33 {"submission_id": "y", "solutions": [
34 {"solution_id": "c", "more_accurate_than": []},
35 {"solution_id": "d", "more_accurate_than": ["c"]},
36 ]},
37 ]
38 info = collect_order(subs)
39 assert set(maximal_elements(info)) == {"x/b", "y/d"}
40 # Truth: x/b is exact; y/d is wrong. Errors to x/b respect y's chain, errors to y/d do not respect x's chain.
41 keys = ["x/a", "x/b", "y/c", "y/d"]
42 truth = {"x/a": 1.0, "x/b": 0.0, "y/c": 3.0, "y/d": 2.5}
43 err = {a: {b: abs(truth[a] - truth[b]) for b in keys} for a in keys}
44 # under y/d: err(x/b)=2.5 > err(x/a)=1.5, so x's pair is violated
45 rep = select_reference(info, err)
46 assert rep["reference"] == "x/b"
47 assert rep["candidates"][0]["score"] == 1.0
50def test_reference_selection_medoid_fallback():
51 info = OrderInfo(pairs=[], submission_of={"p/a": "p", "q/b": "q", "r/c": "r"})
52 keys = list(info.submission_of)
53 pos = {"p/a": 0.0, "q/b": 1.0, "r/c": 5.0}
54 err = {a: {b: abs(pos[a] - pos[b]) for b in keys} for a in keys}
55 rep = select_reference(info, err)
56 assert rep["reference"] == "q/b"
59def test_reference_selection_tie_broken_by_convergence_gap():
60 subs = [
61 {"submission_id": "x", "solutions": [
62 {"solution_id": "a", "more_accurate_than": []},
63 {"solution_id": "b", "more_accurate_than": ["a"]},
64 ]},
65 {"submission_id": "y", "solutions": [
66 {"solution_id": "c", "more_accurate_than": []},
67 {"solution_id": "d", "more_accurate_than": ["c"]},
68 ]},
69 ]
70 info = collect_order(subs)
71 keys = ["x/a", "x/b", "y/c", "y/d"]
72 # both chains monotone toward 0; x/b is much closer to its sibling than y/d is to its own
73 truth = {"x/a": 0.03, "x/b": 0.0001, "y/c": 1.0, "y/d": 0.01}
74 err = {a: {b: abs(truth[a] - truth[b]) for b in keys} for a in keys}
75 rep = select_reference(info, err)
76 assert [c["score"] for c in rep["candidates"]] == [1.0, 1.0]
77 assert rep["reference"] == "x/b"