Improve phenotype scaling and safeguarded line search
This commit is contained in:
@@ -165,6 +165,49 @@ void test_ai_reml_fit_improves_likelihood() {
|
||||
"reported sigma_g2 is inconsistent");
|
||||
}
|
||||
|
||||
void test_internal_phenotype_scaling_restores_original_units() {
|
||||
Fixture fixture;
|
||||
constexpr double scale = 1.0e6;
|
||||
std::vector<double> scaled_y = fixture.y;
|
||||
for (double& value : scaled_y) {
|
||||
value *= scale;
|
||||
}
|
||||
spectra::reml::RemlOptions options;
|
||||
options.max_iterations = 150;
|
||||
const auto original = spectra::reml::fit_ai_reml_spectral(
|
||||
fixture.y, fixture.x, fixture.lambda, options);
|
||||
const auto scaled = spectra::reml::fit_ai_reml_spectral(
|
||||
scaled_y, fixture.x, fixture.lambda, options);
|
||||
require(original.has_estimates() && scaled.has_estimates(),
|
||||
"scale-invariance fixture returned no estimates");
|
||||
require(original.status == scaled.status,
|
||||
"phenotype scaling changed the fit status");
|
||||
require_near(scaled.sigma_e2, original.sigma_e2 * scale * scale, 2e-10,
|
||||
"sigma_e2 was not restored to phenotype units");
|
||||
require_near(scaled.sigma_g2, original.sigma_g2 * scale * scale, 2e-10,
|
||||
"sigma_g2 was not restored to phenotype units");
|
||||
require_near(scaled.h2, original.h2, 2e-11,
|
||||
"phenotype scaling changed h2");
|
||||
for (std::size_t i = 0; i < original.beta.size(); ++i) {
|
||||
require_near(scaled.beta[i], original.beta[i] * scale, 2e-10,
|
||||
"beta was not restored to phenotype units");
|
||||
}
|
||||
for (std::size_t i = 0;
|
||||
i < original.beta_covariance_packed_lower.size(); ++i) {
|
||||
require_near(scaled.beta_covariance_packed_lower[i],
|
||||
original.beta_covariance_packed_lower[i] * scale * scale,
|
||||
3e-10,
|
||||
"beta covariance was not restored to phenotype units");
|
||||
}
|
||||
const double expected_log_likelihood_shift =
|
||||
-static_cast<double>(fixture.y.size() - fixture.x.cols()) *
|
||||
std::log(scale);
|
||||
require_near(scaled.log_likelihood,
|
||||
original.log_likelihood + expected_log_likelihood_shift,
|
||||
2e-11,
|
||||
"REML likelihood was not restored to phenotype units");
|
||||
}
|
||||
|
||||
void test_residual_only_kkt_boundary() {
|
||||
constexpr std::size_t n = 14;
|
||||
spectra::reml::ColMajorMatrix x(n, 1);
|
||||
@@ -216,6 +259,7 @@ int main() {
|
||||
test_score_matches_finite_difference();
|
||||
test_signed_parameterization_and_row_permutation();
|
||||
test_ai_reml_fit_improves_likelihood();
|
||||
test_internal_phenotype_scaling_restores_original_units();
|
||||
test_residual_only_kkt_boundary();
|
||||
std::cout << "test_reml_synthetic: PASS\n";
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -90,6 +90,8 @@ class SpectraRemlCliTests(unittest.TestCase):
|
||||
"--extra-indices",
|
||||
"--n-phenotype-rows",
|
||||
"--n-extra-covariate-rows",
|
||||
"--line-search-expansion",
|
||||
"--zoom-safeguard",
|
||||
):
|
||||
self.assertEqual(command.count(option), 1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user