Skip to content

Commit e447e3f

Browse files
Jammy2211claude
authored andcommitted
refactor: split fit tests into granular focused tests
Split each monolithic test function into individual focused tests, one per property or behaviour being verified. Tests now fail with precise names that identify exactly which quantity is wrong (e.g. chi_squared, residual_map, log_evidence) rather than a single large function covering a dozen assertions. Changes per file: - test_fit_imaging.py: 3 tests → 21 tests; helper builders extracted to avoid repetition; dirty-image block was left as fixture-based tests - test_fit_interferometer.py: 4 tests → 27 tests; dirty quantities split into one test per map type - test_fit_dataset.py: 3 tests → 6 tests; figure_of_merit split by inversion regularization branch; chi_squared covariance tests separated - test_fit_util.py: 12 tests → 30 tests; each util function now has one test per scenario; parametrize not needed as inputs differ meaningfully Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0eefe0c commit e447e3f

4 files changed

Lines changed: 528 additions & 223 deletions

File tree

test_autoarray/fit/test_fit_dataset.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import autoarray as aa
44

55

6-
def test__figure_of_merit__with_inversion(masked_imaging_7x7, model_image_7x7):
6+
def test__figure_of_merit__with_inversion_and_regularization__equals_log_evidence(
7+
masked_imaging_7x7, model_image_7x7
8+
):
79
inversion = aa.m.MockInversion(
810
linear_obj_list=[aa.m.MockMapper(regularization=aa.m.MockRegularization())],
911
data_vector=1,
@@ -21,6 +23,10 @@ def test__figure_of_merit__with_inversion(masked_imaging_7x7, model_image_7x7):
2123

2224
assert fit.figure_of_merit == fit.log_evidence
2325

26+
27+
def test__figure_of_merit__with_inversion_and_no_regularization__equals_log_likelihood(
28+
masked_imaging_7x7, model_image_7x7
29+
):
2430
inversion = aa.m.MockInversion(
2531
linear_obj_list=[aa.m.MockLinearObj(regularization=None)], data_vector=1
2632
)
@@ -35,8 +41,8 @@ def test__figure_of_merit__with_inversion(masked_imaging_7x7, model_image_7x7):
3541
assert fit.figure_of_merit == fit.log_likelihood
3642

3743

38-
def test__figure_of_merit__with_noise_covariance_matrix_in_dataset(
39-
masked_imaging_covariance_7x7, model_image_7x7, masked_imaging_7x7
44+
def test__chi_squared__with_noise_covariance_matrix__uses_covariance_weighted_formula(
45+
masked_imaging_covariance_7x7, model_image_7x7
4046
):
4147
fit = aa.m.MockFitImaging(
4248
dataset=masked_imaging_covariance_7x7,
@@ -51,21 +57,49 @@ def test__figure_of_merit__with_noise_covariance_matrix_in_dataset(
5157

5258
assert fit.chi_squared == chi_squared
5359

60+
61+
def test__figure_of_merit__with_noise_covariance_matrix__equals_negative_half_chi_squared_plus_noise_normalization(
62+
masked_imaging_covariance_7x7, model_image_7x7
63+
):
64+
fit = aa.m.MockFitImaging(
65+
dataset=masked_imaging_covariance_7x7,
66+
use_mask_in_fit=False,
67+
model_data=model_image_7x7,
68+
)
69+
5470
assert fit.figure_of_merit == pytest.approx(
5571
-0.5 * (fit.chi_squared + fit.noise_normalization), 1.0e-4
5672
)
5773

58-
fit = aa.m.MockFitImaging(
59-
dataset=masked_imaging_7x7,
74+
75+
def test__chi_squared__without_noise_covariance_matrix__differs_from_covariance_weighted_result(
76+
masked_imaging_covariance_7x7, masked_imaging_7x7, model_image_7x7
77+
):
78+
fit_with_covariance = aa.m.MockFitImaging(
79+
dataset=masked_imaging_covariance_7x7,
6080
use_mask_in_fit=False,
6181
model_data=model_image_7x7,
6282
)
6383

64-
assert fit.chi_squared != pytest.approx(chi_squared, 1.0e-4)
84+
chi_squared_covariance = aa.util.fit.chi_squared_with_noise_covariance_from(
85+
residual_map=fit_with_covariance.residual_map,
86+
noise_covariance_matrix_inv=masked_imaging_covariance_7x7.noise_covariance_matrix_inv,
87+
)
6588

89+
fit_without_covariance = aa.m.MockFitImaging(
90+
dataset=masked_imaging_7x7,
91+
use_mask_in_fit=False,
92+
model_data=model_image_7x7,
93+
)
94+
95+
assert fit_without_covariance.chi_squared != pytest.approx(
96+
chi_squared_covariance, 1.0e-4
97+
)
6698

67-
def test__grid_offset_via_data_model(imaging_7x7, mask_2d_7x7, model_image_7x7):
6899

100+
def test__grids__with_dataset_model_grid_offset__lp_and_pixelization_grids_offset_correctly(
101+
imaging_7x7, mask_2d_7x7, model_image_7x7
102+
):
69103
masked_imaging_7x7 = imaging_7x7.apply_mask(mask=mask_2d_7x7)
70104

71105
fit = aa.m.MockFitImaging(
@@ -76,6 +110,5 @@ def test__grid_offset_via_data_model(imaging_7x7, mask_2d_7x7, model_image_7x7):
76110
)
77111

78112
assert fit.dataset_model.grid_offset == (1.0, 2.0)
79-
80113
assert fit.grids.lp[0] == pytest.approx((0.0, -3.0), 1.0e-4)
81114
assert fit.grids.pixelization[0] == pytest.approx((0.0, -3.0), 1.0e-4)

test_autoarray/fit/test_fit_imaging.py

Lines changed: 148 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,205 @@
33
import autoarray as aa
44

55

6-
def test__data_and_model_are_identical__no_masking__check_values_are_correct():
7-
mask = aa.Mask2D(mask=[[False, False], [False, False]], pixel_scales=(1.0, 1.0))
6+
# ---------------------------------------------------------------------------
7+
# Helper: build the "identical model, no masking" fit used by multiple tests
8+
# ---------------------------------------------------------------------------
89

10+
def _make_identical_fit_no_mask():
11+
mask = aa.Mask2D(mask=[[False, False], [False, False]], pixel_scales=(1.0, 1.0))
912
data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
1013
noise_map = aa.Array2D(values=[2.0, 2.0, 2.0, 2.0], mask=mask)
11-
1214
dataset = aa.Imaging(data=data, noise_map=noise_map)
13-
1415
dataset = dataset.apply_mask(mask=mask)
15-
1616
model_data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
17+
fit = aa.m.MockFitImaging(
18+
dataset=dataset, use_mask_in_fit=False, model_data=model_data
19+
)
20+
return fit, noise_map
1721

22+
23+
def _make_different_fit_with_mask():
24+
mask = aa.Mask2D(mask=[[False, False], [True, False]], pixel_scales=(1.0, 1.0))
25+
data = aa.Array2D(values=[1.0, 2.0, 4.0], mask=mask)
26+
noise_map = aa.Array2D(values=[2.0, 2.0, 2.0], mask=mask)
27+
dataset = aa.Imaging(data=data, noise_map=noise_map)
28+
model_data = aa.Array2D(values=[1.0, 2.0, 3.0], mask=mask)
1829
fit = aa.m.MockFitImaging(
1930
dataset=dataset, use_mask_in_fit=False, model_data=model_data
2031
)
32+
return fit, noise_map
33+
34+
35+
def _make_identical_fit_with_inversion():
36+
mask = aa.Mask2D(mask=[[False, False], [False, False]], pixel_scales=(1.0, 1.0))
37+
data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
38+
noise_map = aa.Array2D(values=[2.0, 2.0, 2.0, 2.0], mask=mask)
39+
dataset = aa.Imaging(data=data, noise_map=noise_map)
40+
dataset = dataset.apply_mask(mask=mask)
41+
model_data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
42+
inversion = aa.m.MockInversion(
43+
linear_obj_list=[aa.m.MockMapper()],
44+
data_vector=1,
45+
regularization_term=2.0,
46+
log_det_curvature_reg_matrix_term=3.0,
47+
log_det_regularization_matrix_term=4.0,
48+
)
49+
fit = aa.m.MockFitImaging(
50+
dataset=dataset,
51+
use_mask_in_fit=False,
52+
model_data=model_data,
53+
inversion=inversion,
54+
)
55+
return fit, noise_map
56+
57+
58+
# ---------------------------------------------------------------------------
59+
# Tests: identical data and model, no masking
60+
# ---------------------------------------------------------------------------
61+
62+
63+
def test__mask__no_masking__returns_2x2_all_false_mask():
64+
fit, _ = _make_identical_fit_no_mask()
2165

2266
assert (fit.mask == np.array([[False, False], [False, False]])).all()
67+
68+
69+
def test__data__no_masking__returns_correct_data_values():
70+
fit, _ = _make_identical_fit_no_mask()
71+
2372
assert (fit.data == np.array([1.0, 2.0, 3.0, 4.0])).all()
73+
74+
75+
def test__noise_map__no_masking__returns_correct_noise_map_values():
76+
fit, _ = _make_identical_fit_no_mask()
77+
2478
assert (fit.noise_map == np.array([2.0, 2.0, 2.0, 2.0])).all()
79+
80+
81+
def test__signal_to_noise_map__no_masking__returns_correct_signal_to_noise_values():
82+
fit, _ = _make_identical_fit_no_mask()
83+
2584
assert (fit.signal_to_noise_map == np.array([0.5, 1.0, 1.5, 2.0])).all()
26-
assert (fit.model_data == np.array([1.0, 2.0, 3.0, 4.0])).all()
85+
86+
87+
def test__residual_map__identical_data_and_model__all_zero_residuals():
88+
fit, _ = _make_identical_fit_no_mask()
89+
2790
assert (fit.residual_map == np.array([0.0, 0.0, 0.0, 0.0])).all()
91+
92+
93+
def test__normalized_residual_map__identical_data_and_model__all_zero_normalized_residuals():
94+
fit, _ = _make_identical_fit_no_mask()
95+
2896
assert (fit.normalized_residual_map == np.array([0.0, 0.0, 0.0, 0.0])).all()
97+
98+
99+
def test__chi_squared_map__identical_data_and_model__all_zero_chi_squared_map():
100+
fit, _ = _make_identical_fit_no_mask()
101+
29102
assert (fit.chi_squared_map == np.array([0.0, 0.0, 0.0, 0.0])).all()
30103

104+
105+
def test__chi_squared__identical_data_and_model__is_zero():
106+
fit, _ = _make_identical_fit_no_mask()
107+
31108
assert fit.chi_squared == 0.0
109+
110+
111+
def test__reduced_chi_squared__identical_data_and_model__is_zero():
112+
fit, _ = _make_identical_fit_no_mask()
113+
32114
assert fit.reduced_chi_squared == 0.0
115+
116+
117+
def test__noise_normalization__uniform_noise_map__correct_log_sum_formula():
118+
fit, noise_map = _make_identical_fit_no_mask()
119+
33120
assert fit.noise_normalization == np.sum(np.log(2 * np.pi * noise_map.array**2.0))
34-
assert fit.log_likelihood == -0.5 * (fit.chi_squared + fit.noise_normalization)
35121

36122

37-
def test__data_and_model_are_different__include_masking__check_values_are_correct():
38-
mask = aa.Mask2D(mask=[[False, False], [True, False]], pixel_scales=(1.0, 1.0))
123+
def test__log_likelihood__identical_data_and_model__negative_half_noise_normalization():
124+
fit, _ = _make_identical_fit_no_mask()
39125

40-
data = aa.Array2D(values=[1.0, 2.0, 4.0], mask=mask)
41-
noise_map = aa.Array2D(values=[2.0, 2.0, 2.0], mask=mask)
126+
assert fit.log_likelihood == -0.5 * (fit.chi_squared + fit.noise_normalization)
42127

43-
dataset = aa.Imaging(data=data, noise_map=noise_map)
44128

45-
model_data = aa.Array2D(values=[1.0, 2.0, 3.0], mask=mask)
129+
# ---------------------------------------------------------------------------
130+
# Tests: different data and model with partial mask
131+
# ---------------------------------------------------------------------------
46132

47-
fit = aa.m.MockFitImaging(
48-
dataset=dataset, use_mask_in_fit=False, model_data=model_data
49-
)
50133

51-
assert (fit.mask == np.array([[False, False], [True, False]])).all()
52-
assert (fit.data.slim == np.array([1.0, 2.0, 4.0])).all()
53-
assert (fit.noise_map.slim == np.array([2.0, 2.0, 2.0])).all()
54-
assert (fit.signal_to_noise_map.slim == np.array([0.5, 1.0, 2.0])).all()
55-
assert (fit.model_data.slim == np.array([1.0, 2.0, 3.0])).all()
134+
def test__residual_map__different_data_and_model_with_partial_mask__correct_slim_residuals():
135+
fit, _ = _make_different_fit_with_mask()
136+
56137
assert (fit.residual_map.slim == np.array([0.0, 0.0, 1.0])).all()
138+
139+
140+
def test__normalized_residual_map__different_data_and_model_with_partial_mask__correct_slim_values():
141+
fit, _ = _make_different_fit_with_mask()
142+
57143
assert (fit.normalized_residual_map.slim == np.array([0.0, 0.0, 0.5])).all()
144+
145+
146+
def test__chi_squared_map__different_data_and_model_with_partial_mask__correct_slim_chi_squared():
147+
fit, _ = _make_different_fit_with_mask()
148+
58149
assert (fit.chi_squared_map.slim == np.array([0.0, 0.0, 0.25])).all()
59150

151+
152+
def test__chi_squared__different_model_with_masked_data__correct_value():
153+
fit, _ = _make_different_fit_with_mask()
154+
60155
assert fit.chi_squared == 0.25
156+
157+
158+
def test__reduced_chi_squared__different_model_with_masked_data__divided_by_unmasked_pixel_count():
159+
fit, _ = _make_different_fit_with_mask()
160+
61161
assert fit.reduced_chi_squared == 0.25 / 3.0
162+
163+
164+
def test__log_likelihood__different_model_with_masked_data__correct_value():
165+
fit, noise_map = _make_different_fit_with_mask()
166+
62167
assert fit.noise_normalization == np.sum(np.log(2 * np.pi * noise_map.array**2.0))
63168
assert fit.log_likelihood == -0.5 * (fit.chi_squared + fit.noise_normalization)
64169

65170

66-
def test__data_and_model_are_identical__inversion_included__changes_certain_properties():
67-
mask = aa.Mask2D(mask=[[False, False], [False, False]], pixel_scales=(1.0, 1.0))
171+
# ---------------------------------------------------------------------------
172+
# Tests: identical data and model with inversion
173+
# ---------------------------------------------------------------------------
68174

69-
data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
70-
noise_map = aa.Array2D(values=[2.0, 2.0, 2.0, 2.0], mask=mask)
71175

72-
dataset = aa.Imaging(data=data, noise_map=noise_map)
176+
def test__chi_squared__identical_data_and_model_with_inversion__is_zero():
177+
fit, _ = _make_identical_fit_with_inversion()
73178

74-
dataset = dataset.apply_mask(mask=mask)
179+
assert fit.chi_squared == 0.0
75180

76-
model_data = aa.Array2D(values=[1.0, 2.0, 3.0, 4.0], mask=mask)
77181

78-
inversion = aa.m.MockInversion(
79-
linear_obj_list=[aa.m.MockMapper()],
80-
data_vector=1,
81-
regularization_term=2.0,
82-
log_det_curvature_reg_matrix_term=3.0,
83-
log_det_regularization_matrix_term=4.0,
84-
)
85-
86-
fit = aa.m.MockFitImaging(
87-
dataset=dataset,
88-
use_mask_in_fit=False,
89-
model_data=model_data,
90-
inversion=inversion,
91-
)
182+
def test__reduced_chi_squared__identical_data_and_model_with_inversion__is_zero():
183+
fit, _ = _make_identical_fit_with_inversion()
92184

93-
assert fit.chi_squared == 0.0
94185
assert fit.reduced_chi_squared == 0.0
95-
assert fit.noise_normalization == np.sum(np.log(2 * np.pi * noise_map.array**2.0))
96-
assert fit.log_likelihood == -0.5 * (fit.chi_squared + fit.noise_normalization)
186+
187+
188+
def test__log_likelihood_with_regularization__with_inversion__adds_regularization_term():
189+
fit, noise_map = _make_identical_fit_with_inversion()
97190

98191
assert fit.log_likelihood_with_regularization == -0.5 * (
99192
fit.chi_squared + 2.0 + fit.noise_normalization
100193
)
194+
195+
196+
def test__log_evidence__with_inversion__uses_chi_squared_reg_and_determinant_terms():
197+
fit, noise_map = _make_identical_fit_with_inversion()
198+
101199
assert fit.log_evidence == -0.5 * (
102200
fit.chi_squared + 2.0 + 3.0 - 4.0 + fit.noise_normalization
103201
)
202+
203+
204+
def test__figure_of_merit__with_inversion__equals_log_evidence():
205+
fit, _ = _make_identical_fit_with_inversion()
206+
104207
assert fit.figure_of_merit == fit.log_evidence

0 commit comments

Comments
 (0)