/** * @brief Update the MP version of the roots to the latest and greatest approximations. * * @param s A pointer to the current mps_context. */ MPS_PRIVATE void mps_copy_roots (mps_context * s) { int i; MPS_DEBUG_THIS_CALL (s); switch (s->lastphase) { case no_phase: mps_error (s, "Nothing to copy"); break; case float_phase: if (s->DOSORT) mps_fsort (s); for (i = 0; i < s->n; i++) { mpc_set_prec (s->root[i]->mvalue, DBL_MANT_DIG); mpc_set_cplx (s->root[i]->mvalue, s->root[i]->fvalue); rdpe_set_d (s->root[i]->drad, s->root[i]->frad); } break; case dpe_phase: if (s->DOSORT) mps_dsort (s); for (i = 0; i < s->n; i++) { mpc_set_prec (s->root[i]->mvalue, DBL_MANT_DIG); mpc_set_cdpe (s->root[i]->mvalue, s->root[i]->dvalue); } break; case mp_phase: if (s->DOSORT) mps_msort (s); break; } }
void mps_maberth_s_wl (mps_context * s, int j, mps_cluster * cluster, mpc_t abcorr, pthread_mutex_t * aberth_mutexes) { int k; mps_root * root; cdpe_t z, temp; mpc_t diff, mroot; mpc_init2 (mroot, s->mpwp); mpc_init2 (diff, s->mpwp); pthread_mutex_lock (&aberth_mutexes[j]); mpc_set (mroot, s->root[j]->mvalue); pthread_mutex_unlock (&aberth_mutexes[j]); cdpe_set (temp, cdpe_zero); for (root = cluster->first; root != NULL; root = root->next) { k = root->k; if (k == j) continue; pthread_mutex_lock (&aberth_mutexes[k]); mpc_sub (diff, mroot, s->root[k]->mvalue); pthread_mutex_unlock (&aberth_mutexes[k]); mpc_get_cdpe (z, diff); if (cdpe_eq_zero(z)) continue; cdpe_inv_eq (z); cdpe_add_eq (temp, z); } mpc_set_cdpe (abcorr, temp); mpc_clear (mroot); mpc_clear (diff); }
/** * @brief Compute Aberth correction for j-th root, without * selective correction. */ void mps_maberth (mps_context * s, mps_approximation * root, mpc_t abcorr) { int i; cdpe_t z, temp; mpc_t diff; mpc_init2 (diff, s->mpwp); cdpe_set (temp, cdpe_zero); for (i = 0; i < s->n; i++) { if (s->root[i] == root) continue; mpc_sub (diff, root->mvalue, s->root[i]->mvalue); mpc_get_cdpe (z, diff); cdpe_inv_eq (z); cdpe_add_eq (temp, z); } mpc_set_cdpe (abcorr, temp); mpc_clear (diff); }
/** * @brief Compute Aberth correction for the j-th root, * but only with other roots of the <code>jc</code>-th * cluster. */ void mps_maberth_s (mps_context * s, mps_approximation * ab_root, mps_cluster * cluster, mpc_t abcorr) { mps_root * root; cdpe_t z, temp; mpc_t diff; mpc_init2 (diff, s->mpwp); cdpe_set (temp, cdpe_zero); for (root = cluster->first; root != NULL; root = root->next) { mps_approximation * appr = s->root[root->k]; if (appr == ab_root) continue; mpc_sub (diff, ab_root->mvalue, appr->mvalue); mpc_get_cdpe (z, diff); cdpe_inv_eq (z); cdpe_add_eq (temp, z); } mpc_set_cdpe (abcorr, temp); mpc_clear (diff); }
/** * @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'; }
/** * @brief Main routine of the program that implements the algorithm * in the standard polynomial version. * * The program is divided into many parts * - Check the correctness of data, scale coefficients if * needed, and select cases: the variable <code>which_case</code> is * <code>'f'</code> or <code>'d'</code> according to float or dpe case. * - Call msolve or dsolve according to the value of which_case. * - Allocate MP variables mfpc, mroot, drad (if needed). * - Start MPsolve loop * - prepare data according to the current precision * and to the data_type (density/sparsity/user) * - Call msolve with the current precision * - check for termination */ MPS_PRIVATE void mps_standard_mpsolve (mps_context * s) { int i, nzc; char which_case; mps_boolean d_after_f, computed; #ifndef DISABLE_DEBUG clock_t *my_timer = mps_start_timer (); #endif mps_allocate_data (s); if (s->DOLOG) s->debug_level |= MPS_DEBUG_TRACE; /* == 1 == Setup variables, i.e. copy coefficients into dpr, dpc and similar. */ mps_setup (s); s->lastphase = no_phase; computed = false; s->over_max = false; /* == 2 == Resume from pre-computed roots */ if (s->resume) { mps_error (s, "Resume not supported yet"); #ifndef DISABLE_DEBUG mps_stop_timer (my_timer); #endif return; } /* == 3 == Check data and get starting phase */ if (s->skip_float) which_case = 'd'; else which_case = 'f'; /* This variable is true if we need a dpe phase after the * float phase */ d_after_f = false; /* Check if a dpe phase is needed and deflate polynomial */ mps_check_data (s, &which_case); /* Check for errors in check data */ if (mps_context_has_errors (s)) { #ifndef DISABLE_DEBUG mps_stop_timer (my_timer); #endif return; } rdpe_set_2dl (s->eps_out, 1.0, -s->output_config->prec); if (s->DOLOG) fprintf (s->logstr, "Which_case = %c, skip_float= %d\n", which_case, s->skip_float); /* == 4 == Float phase */ if (which_case == 'f') { if (s->DOLOG) fprintf (s->logstr, "Float phase ...\n"); mps_fsolve (s, &d_after_f); s->lastphase = float_phase; if (s->DOLOG) mps_dump (s); computed = mps_check_stop (s); if (computed && s->output_config->goal != MPS_OUTPUT_GOAL_APPROXIMATE) goto exit_sub; /* stop for COUNT and ISOLATE goals */ } /* == 5 == DPE phase */ if (which_case == 'd' || d_after_f) { /* DPE phase */ if (s->DOLOG) fprintf (s->logstr, "DPE phase ...\n"); /* If we are arriving from a float phase copy the floating points * roots approximations in the DPE root approximations. */ if (d_after_f) for (i = 0; i < s->n; i++) { rdpe_set_d (s->root[i]->drad, s->root[i]->frad); cdpe_set_x (s->root[i]->dvalue, s->root[i]->fvalue); } s->lastphase = dpe_phase; mps_dsolve (s, d_after_f); if (s->DOLOG) mps_dump (s); computed = mps_check_stop (s); if (computed && s->output_config->goal != MPS_OUTPUT_GOAL_APPROXIMATE) goto exit_sub; } /* == 6 == Allocate MP variables mfpc, mroot, drad, mfppc, mfppc1 * (the real input case is not implemented yet ) */ MPS_DEBUG (s, "Starting MP phase"); s->lastphase = mp_phase; /* ==== 6.1 initialize mp variables */ mps_mp_set_prec (s, 2 * DBL_MANT_DIG); /* Prepare data according to the current working precision */ mps_prepare_data (s, s->mpwp); /* ==== 6.2 set initial values for mp variables */ for (i = 0; i < s->n; i++) { if (which_case == 'd' || d_after_f) mpc_set_cdpe (s->root[i]->mvalue, s->root[i]->dvalue); else { mpc_set_cplx (s->root[i]->mvalue, s->root[i]->fvalue); rdpe_set_d (s->root[i]->drad, s->root[i]->frad); } } if (computed && s->output_config->goal == MPS_OUTPUT_GOAL_APPROXIMATE) { MPS_DEBUG (s, "Exiting since the approximation are computed and the goal is MPS_OUTPUT_GOAL_APPROXIMATE"); goto exit_sub; } MPS_DEBUG (s, "s->mpwp = %ld, s->mpwp_max = %ld", s->mpwp, s->mpwp_max); MPS_DEBUG (s, "s->input_config->prec = %ld", s->active_poly->prec); /* == 7 == Start MPSolve loop */ s->mpwp = mps_context_get_minimum_precision (s); /* Poor man GMP - machine precision detection. We need that min_prec is contained * in the interval [ DBL_MANT_DIG , 2 * DBL_MANT_DIG ]. This is probably true on most * architectures with the instruction above, but we want to be sure. */ while (s->mpwp < DBL_MANT_DIG) s->mpwp <<= 1; while (s->mpwp > 2 * DBL_MANT_DIG) s->mpwp >>= 1; while (!computed && s->mpwp < s->mpwp_max) { s->mpwp *= 2; if (s->mpwp > s->mpwp_max) { s->mpwp = s->mpwp_max; s->over_max = true; } if (s->DOLOG) fprintf (s->logstr, "MAIN: mp_loop: mpwp=%ld\n", s->mpwp); /* == 7.1 == prepare data according to the current precision */ mps_mp_set_prec (s, s->mpwp); mps_prepare_data (s, s->mpwp); /* == 7.2 == Call msolve with the current precision */ if (s->DOLOG) fprintf (s->logstr, "MAIN: now call msolve nclust=%ld\n", s->clusterization->n); mps_msolve (s); s->lastphase = mp_phase; /* if (s->DOLOG) dump(logstr); */ if (s->DOLOG) { /* count isolated zeros */ nzc = 0; for (i = 0; i < s->n; i++) { if (s->root[i]->status == MPS_ROOT_STATUS_ISOLATED || s->root[i]->status == MPS_ROOT_STATUS_APPROXIMATED) nzc++; } fprintf (s->logstr, "MAIN: isolated %d roots\n", nzc); fprintf (s->logstr, "MAIN: after msolve check stop\n"); } /* == 7.3 == Check the stop condition */ computed = mps_check_stop (s); mps_mmodify (s, true); /* == 7.4 == reset the status vector */ for (i = 0; i < s->n; i++) if (s->root[i]->status == MPS_ROOT_STATUS_NEW_CLUSTERED) s->root[i]->status = MPS_ROOT_STATUS_CLUSTERED; } /* == 8 == Check for termination */ if (!computed) { if (s->over_max) { s->over_max = true; /* mps_error (s, "Reached the maximum working precision"); */ MPS_DEBUG (s, "Reached the maximum working precision"); goto exit_sub; } else { /* mps_warn (s, "Reached the input precision"); */ MPS_DEBUG (s, "Reached the input precision"); goto exit_sub; } } exit_sub: /* == 9 == Check inclusion disks */ if (computed && s->clusterization->n < s->n) if (!mps_inclusion (s)) { mps_error (s, "Unable to compute inclusion disks"); return; } /* == 10 == Refine roots */ if (computed && !s->over_max && s->output_config->goal == MPS_OUTPUT_GOAL_APPROXIMATE) { s->lastphase = mp_phase; mps_improve (s); } /* == 11 == Check inclusions */ /* This step is disabled since it cause problems with the lar* kind of polynomials. * To be re-enabled a careful check of the necessary precision to avoid NULL DERIVATIVE * warnings should be implemented. * if (s->active_poly->prec > 0) * mps_validate_inclusions (s); */ /* == 12 == Restore to highest used precision */ if (s->lastphase == mp_phase) mps_restore_data (s); #ifndef DISABLE_DEBUG { unsigned long time = mps_stop_timer (my_timer); MPS_DEBUG (s, "Total time using MPSolve: %lu ms", time); } #endif /* Finally copy the roots ready for output */ mps_copy_roots (s); }