Skip to content

Commit 101304f

Browse files
authored
Merge pull request #230 from Jammy2211/feature/refactor-fit-tests
refactor: split fit tests into granular focused tests
2 parents e21a282 + e447e3f commit 101304f

File tree

4 files changed

+528
-223
lines changed

4 files changed

+528
-223
lines changed

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)