// construct an approximating Gaussian model // Note the difference to previous versions, the convergence is assessed only // by checking the changes in mode, not the actual function values. This is // slightly faster and sufficient as the approximation doesn't need to be accurate. // Using function values would be safer though, as we could use line search etc // in case of potential divergence etc... ugg_ssm ung_ssm::approximate(arma::vec& mode_estimate, const unsigned int max_iter, const double conv_tol) { //Construct y and H for the Gaussian model arma::vec approx_y(n, arma::fill::zeros); arma::vec approx_H(n, arma::fill::zeros); // RNG of approximate model is only used in basic IS sampling // set seed for new RNG stream based on the original model std::uniform_int_distribution<> unif(0, std::numeric_limits<int>::max()); const unsigned int new_seed = unif(engine); ugg_ssm approx_model(approx_y, Z, approx_H, T, R, a1, P1, xreg, beta, D, C, new_seed); unsigned int i = 0; double diff = conv_tol + 1; while(i < max_iter && diff > conv_tol) { i++; //Construct y and H for the Gaussian model laplace_iter(mode_estimate, approx_model.y, approx_model.H); approx_model.compute_HH(); // compute new guess of mode arma::vec mode_estimate_new(n); if (distribution == 0) { mode_estimate_new = arma::vectorise(approx_model.fast_smoother().head_cols(n)); } else { arma::mat alpha = approx_model.fast_smoother().head_cols(n); for (unsigned int t = 0; t < n; t++) { mode_estimate_new(t) = arma::as_scalar(Z.col(Ztv * t).t() * alpha.col(t)); } } diff = arma::mean(arma::square(mode_estimate_new - mode_estimate)); mode_estimate = mode_estimate_new; } return approx_model; }
size_t Approximator::test_function(const std::string& name, const Function& fun) { POMAGMA_INFO("Testing " << name << " approximation"); size_t ob_fail_count = 0; size_t upper_fail_count = 0; size_t upper_extra_count = 0; size_t upper_missing_count = 0; size_t lower_fail_count = 0; size_t lower_extra_count = 0; size_t lower_missing_count = 0; const size_t item_dim = m_item_dim; #pragma omp parallel { DenseSet temp_set(item_dim); #pragma omp for schedule(dynamic, 1) for (Ob x = 1; x <= item_dim; ++x) { Approximation approx_x(x, m_less); approx_x.ob = 0; for (auto iter = fun.iter_lhs(x); iter.ok(); iter.next()) { Ob y = *iter; Approximation approx_y(y, m_less); approx_y.ob = 0; Ob xy = fun.find(x, y); Approximation expected(xy, m_less); Approximation actual = find(fun, approx_x, approx_y); if (actual.ob != expected.ob) { #pragma omp atomic ob_fail_count += 1; } if (actual.upper != expected.upper) { #pragma omp atomic upper_fail_count += 1; temp_set.set_diff(actual.upper, expected.upper); if (size_t count = temp_set.count_items()) { #pragma omp atomic upper_extra_count += count; } temp_set.set_diff(expected.upper, actual.upper); if (size_t count = temp_set.count_items()) { #pragma omp atomic upper_missing_count += count; } } if (actual.lower != expected.lower) { #pragma omp atomic lower_fail_count += 1; temp_set.set_diff(actual.lower, expected.lower); if (size_t count = temp_set.count_items()) { #pragma omp atomic lower_extra_count += count; } temp_set.set_diff(expected.lower, actual.lower); if (size_t count = temp_set.count_items()) { #pragma omp atomic lower_missing_count += count; } } } } } if (ob_fail_count) { POMAGMA_WARN(name << " ob failed " << ob_fail_count << " cases"); } if (upper_missing_count or upper_extra_count) { POMAGMA_WARN(name << " upper has " << upper_missing_count << " missing and " << upper_extra_count << " extra obs in " << upper_fail_count << " cases"); } if (lower_missing_count or lower_extra_count) { POMAGMA_WARN(name << " lower has " << lower_missing_count << " missing and " << lower_extra_count << " extra obs in " << lower_fail_count << " cases"); } return ob_fail_count + upper_fail_count + lower_fail_count; }