static int get_approximated_bits (mps_approximation * appr) { rdpe_t module; mpc_rmod (module, appr->mvalue); return (rdpe_log (module) - rdpe_log (appr->drad)) / LOG2 - 1; }
static rdpe_t * evaluate_root_conditioning (mps_context * ctx, mps_polynomial * p, mps_approximation ** appr, int n) { int i; rdpe_t * root_conditioning = rdpe_valloc (n); for (i = 0; i < n; i++) { mpc_t value; rdpe_t error, module; mpc_init2 (value, appr[i]->wp); mps_polynomial_meval (ctx, p, appr[i]->mvalue, value, error); mpc_rmod (module, value); /* Get the relative error of this evaluation */ if (!rdpe_eq_zero (module)) rdpe_div_eq (error, module); else rdpe_set_d (error, DBL_EPSILON * p->degree); /* log2(error) + wp - log(n) is a good estimate of log(k) */ rdpe_set_d (root_conditioning[i], rdpe_log (error) / LOG2 + appr[i]->wp - log2 (n)); rdpe_exp_eq (root_conditioning[i]); rdpe_div_eq (root_conditioning[i], appr[i]->drad); mpc_clear (value); } return root_conditioning; }
/** * @brief Improve all the approximations up to prec_out digits. * * For each approximation compute the value of sigma such that, given some * approximations \f$x_j\f$ of the roots, \f$r_j\f$ the values of the * inclusion radii and \f$d_i\f$ the number of correct digits: * \f[ * e_j < e_0 * \sigma^{2^j} \qquad \sigma=\frac{k}{k-1}=\frac{1}{1-t} \qquad k=\frac{1}{t} * \f] * and * \f[ * t = \min_j |z_i-z_j|-r_j * \f] * Then compute the number of digits needed for the j-th * iteration i.e., if \f$cond\f$ is the conditioning of the root: * \f[ * d_j = \log(\frac{e_j}{|x|}) + cond * \f] * where * \f[ * \log(\frac{e_j}{|x|}) = (f+g){2j} \qquad * cond = \log(\frac{rad}{\epsilon}) * \f] * and * \f[ * cond \approx \lVert p \rVert (1+ \frac{|x_i|}{a_n \prod_{j \neq i} |x_i-x_j|} * \f] * and * \f[ * cond \approx \frac{r_i}{\epsilon |x_i|} * \f] * for user-defined polynomials. * * <code>s->mpwp</code> denotes the number of bits of the current working * precision. * * @param ctx The mps_context associated with the computation. */ MPS_PRIVATE void mps_improve (mps_context * ctx) { int i; long int current_precision = 0L; int approximated_roots = 0; mps_polynomial * p = ctx->active_poly; rdpe_t * root_conditioning = NULL; ctx->operation = MPS_OPERATION_REFINEMENT; /* We need to be able to evaluate the Newton correction in a point * in order to perform the refinement. This is not necessary true * for custom polynomial types, so add a check in here */ if (p->mnewton == NULL && p->density != MPS_DENSITY_USER) return; /* Set lastphase to mp */ ctx->lastphase = mp_phase; /* Determine the conditioning of the roots */ root_conditioning = evaluate_root_conditioning (ctx, p, ctx->root, ctx->n); /* We adopt the strategy of various iterations refinements on * the approximations by setting the precision of the input * polynomial in an increasing sequence. */ /* We start by determining the minimum precision at which we can * extract some information. */ current_precision = LONG_MAX; for (i = 0; i < ctx->n; i++) { if (ctx->root[i]->wp < current_precision) current_precision = ctx->root[i]->wp; if (MPS_ROOT_STATUS_IS_APPROXIMATED (ctx->root[i]->status) || ctx->root[i]->inclusion == MPS_ROOT_INCLUSION_OUT) approximated_roots++; } /* Start by iterating on the roots that are not approximated, and * continue until we get all of them. */ while (approximated_roots < ctx->n) { mps_polynomial_raise_data (ctx, p, current_precision); MPS_DEBUG (ctx, "Step of improvement"); for (i = 0; i < ctx->n; i++) if (ctx->root[i]->status == MPS_ROOT_STATUS_ISOLATED && ctx->root[i]->inclusion != MPS_ROOT_INCLUSION_OUT) { /* Evaluate the necessary precision to iterate on this root. * If the the current polynomial precision is enough, iterate on it. * Otherwise, let it for the next round. */ long int necessary_precision = get_approximated_bits (ctx->root[i]) + log2 (ctx->n) + rdpe_log (root_conditioning[i]) / LOG2; if (necessary_precision < current_precision) { __improve_root_data * data = mps_new (__improve_root_data); data->ctx = ctx; data->p = p; data->root = ctx->root[i]; data->precision = current_precision; mps_thread_pool_assign (ctx, NULL, improve_root_wrapper, data); } } mps_thread_pool_wait (ctx, ctx->pool); for (i = 0; i < ctx->n; i++) if (!MPS_ROOT_STATUS_IS_APPROXIMATED (ctx->root[i]->status) && get_approximated_bits (ctx->root[i]) >= ctx->output_config->prec) { ctx->root[i]->status = MPS_ROOT_STATUS_APPROXIMATED; approximated_roots++; if (ctx->debug_level & MPS_DEBUG_IMPROVEMENT) MPS_DEBUG (ctx, "Approximated roots = %d", approximated_roots); } /* Increase precision to reach the desired number of approximated roots */ current_precision = 2 * current_precision; /* Check if we have gone too far with the precision, and we have gone over * the maximum precision allowed for this polynomial. */ if (current_precision > p->prec && p->prec != 0) { ctx->over_max = true; goto cleanup; } /* Increase data prec max that will be useful to the end user to know * the precision needed to hold these approximations. */ ctx->data_prec_max.value = current_precision; if (ctx->debug_level & MPS_DEBUG_IMPROVEMENT) MPS_DEBUG (ctx, "Increasing precision to %ld", current_precision); } cleanup: free (root_conditioning); }
/** * @brief Check consistency of data and makes some basic adjustments. * * This routine check, for example, if there are zero roots in the polynomial * (i.e. no costant term) and deflates the polynomial if necessary (shifting * the coefficients). * * It sets the value of the parameter <code>which_case</code> to <code>'f'</code> * if a floating point phase is enough, or to <code>'d'</code> if * a <code>dpe</code> phase is needed. * * @param s The <code>mps_context</code> associated with the current computation. * @param which_case the address of the variable which_case; */ MPS_PRIVATE void mps_check_data (mps_context * s, char *which_case) { rdpe_t min_coeff, max_coeff, tmp; mps_monomial_poly *p = NULL; int i; /* case of user-defined polynomial */ if (! MPS_IS_MONOMIAL_POLY (s->active_poly)) { if (s->output_config->multiplicity) mps_error (s, "Multiplicity detection not yet implemented for user polynomial"); if (s->output_config->root_properties) mps_error (s, "Real/imaginary detection not yet implemented for user polynomial"); *which_case = 'd'; return; } else p = MPS_MONOMIAL_POLY (s->active_poly); /* Check consistency of input */ if (rdpe_eq (p->dap[s->n], rdpe_zero)) { mps_warn (s, "The leading coefficient is zero"); do (s->n)--; while (rdpe_eq (p->dap[s->n], rdpe_zero)); MPS_POLYNOMIAL (p)->degree = s->n; } /* Compute min_coeff */ if (rdpe_lt (p->dap[0], p->dap[s->n])) rdpe_set (min_coeff, p->dap[0]); else rdpe_set (min_coeff, p->dap[s->n]); /* Compute max_coeff and its logarithm */ rdpe_set (max_coeff, p->dap[0]); for (i = 1; i <= s->n; i++) if (rdpe_lt (max_coeff, p->dap[i])) rdpe_set (max_coeff, p->dap[i]); s->lmax_coeff = rdpe_log (max_coeff); /* Multiplicity and sep */ if (s->output_config->multiplicity) { if (MPS_STRUCTURE_IS_INTEGER (s->active_poly->structure)) { mps_compute_sep (s); } else if (MPS_STRUCTURE_IS_RATIONAL (s->active_poly->structure)) { mps_warn (s, "The multiplicity option has not been yet implemented"); s->sep = 0.0; } else { mps_warn (s, "The input polynomial has neither integer nor rational"); mps_warn (s, " coefficients: unable to compute multiplicities"); s->sep = 0.0; } } /* Real/Imaginary detection */ if (s->output_config->root_properties || s->output_config->search_set == MPS_SEARCH_SET_REAL || s->output_config->search_set == MPS_SEARCH_SET_IMAG) { if (MPS_STRUCTURE_IS_INTEGER (s->active_poly->structure)) { mps_compute_sep (s); } else if (MPS_STRUCTURE_IS_RATIONAL (s->active_poly->structure)) { mps_error (s, "The real/imaginary option has not been yet implemented for rational input"); return; } else { mps_error (s, "The input polynomial has neither integer nor rational " "coefficients: unable to perform real/imaginary options"); return; } } /* Select cases (dpe or floating point) * First normalize the polynomial (only the float version) */ rdpe_div (tmp, max_coeff, min_coeff); rdpe_mul_eq_d (tmp, (double)(s->n + 1)); rdpe_mul_eq (tmp, rdpe_mind); rdpe_div_eq (tmp, rdpe_maxd); if (rdpe_lt (tmp, rdpe_one)) { mpc_t m_min_coeff; cdpe_t c_min_coeff; /* if (n+1)*max_coeff/min_coeff < dhuge/dtiny - float case */ *which_case = 'f'; rdpe_mul_eq (min_coeff, max_coeff); rdpe_mul (tmp, rdpe_mind, rdpe_maxd); rdpe_div (min_coeff, tmp, min_coeff); rdpe_sqrt_eq (min_coeff); rdpe_set (cdpe_Re (c_min_coeff), min_coeff); rdpe_set (cdpe_Im (c_min_coeff), rdpe_zero); mpc_init2 (m_min_coeff, mpc_get_prec (p->mfpc[0])); mpc_set_cdpe (m_min_coeff, c_min_coeff); /* min_coeff = sqrt(dhuge*dtiny/(min_coeff*max_coeff)) * NOTE: This is enabled for floating point polynomials only * for the moment, but it may work nicely also for other representations. */ { for (i = 0; i <= s->n; i++) { /* Multiply the MP leading coefficient */ mpc_mul_eq (p->mfpc[i], m_min_coeff); rdpe_mul (tmp, p->dap[i], min_coeff); rdpe_set (p->dap[i], tmp); p->fap[i] = rdpe_get_d (tmp); mpc_get_cdpe (p->dpc[i], p->mfpc[i]); cdpe_get_x (p->fpc[i], p->dpc[i]); } } mpc_clear (m_min_coeff); } else *which_case = 'd'; }