void* mps_caller (mps_context * s) { if (!mps_context_has_errors (s)) s->mpsolve_ptr (s); /* Call user defined callback if available */ if (s->callback == NULL) return NULL; else return (*s->callback) (s, s->user_data); }
/** * @brief Call the real polynomial (or secular equation, or whatever) solver * and do the computation. * * The algorithm used must be selected before this call with <code>mps_select_algorithm</code> * and the data (the coefficients, or whatever the algorithm may require) should be provided * after that. * * Roots can then be obtained with the functions <code>mps_context_get_roots_*</code> * */ void mps_mpsolve (mps_context * s) { #ifdef MPS_CATCH_FPE feenableexcept (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW); #endif if (mps_context_has_errors (s)) return; (*s->mpsolve_ptr) (s); }
void* cleanup_context (mps_context * ctx, void * user_data) { /* Check for errors */ if (mps_context_has_errors (ctx)) { mps_print_errors (ctx); return NULL; } /* Output the roots */ mps_output (ctx); #ifdef HAVE_GRAPHICAL_DEBUGGER if (logger_closed) gtk_main_quit (); else if (logger) { /* In the other case copy the approximation in the right place * so the logger can display them again. */ int i = 0; mps_approximation ** approximations = malloc (sizeof (mps_approximation*) * ctx->n); for (i = 0; i < ctx->n; i++) approximations[i] = mps_approximation_copy (ctx, ctx->root[i]); mps_iteration_logger_set_roots (logger, approximations, ctx->n); } #endif /* Free used data */ if (poly) mps_polynomial_free (ctx, poly); mps_context_free (ctx); s = NULL; return NULL; }
int main (int argc, char **argv) { #if HAVE_GRAPHICAL_DEBUGGER mps_boolean graphic_debug = false; #endif /* Create a new status */ s = mps_context_new (); /* Associate the SIGUSR1 signal to the mps_dump () function */ #ifndef __WINDOWS signal (SIGUSR1, status); #endif /* Leave this value to -1 if not precision has been enforced * by the user. Otherwise, override the polynomial input * precision. */ long int input_precision = -1; char * inline_poly = NULL; FILE *infile; /* Parse options */ mps_opt *opt; mps_phase phase = no_phase; /* This will be true if the user has explicitely selected the algorithm, otherwise we will be using our own heuristic. */ mps_boolean explicit_algorithm_selection = false; opt = NULL; while ((mps_getopts (&opt, &argc, &argv, MPSOLVE_GETOPT_STRING))) { switch (opt->optchar) { case 'l': { FILE* logstr = fopen (opt->optvalue, "w"); if (!logstr) mps_error (s, "Cannot open selected log file."); mps_context_set_log_stream (s, logstr); } break; case 'v': #ifdef HAVE_CONFIG_H printf (PACKAGE_STRING "\n"); #else printf ("MPSolve 3.1.5\n"); #endif mps_context_free (s); exit (EXIT_SUCCESS); case 'r': mps_context_select_starting_strategy (s, MPS_STARTING_STRATEGY_RECURSIVE); break; case 'O': /* Select the desired output format */ if (!opt->optvalue) { mps_error (s, "An argument is needed for option 'O'"); break; } switch (*opt->optvalue) { case 'f': mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_FULL); break; case 'b': mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_BARE); break; case 'g': mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_GNUPLOT); if (*(opt->optvalue + 1) == 'f') { mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_GNUPLOT_FULL); s->gnuplot_format = "xyerrorbars"; } else if (*(opt->optvalue + 1) == 'p') { mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_GNUPLOT_FULL); s->gnuplot_format = "points"; } break; case 'v': mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_VERBOSE); break; case 'c': mps_context_set_output_format (s, MPS_OUTPUT_FORMAT_COMPACT); break; default: mps_error (s, "The selected output format is not supported"); break; } break; /* select search set */ case 'S': switch (*opt->optvalue) { case 'a': s->output_config->search_set = MPS_SEARCH_SET_COMPLEX_PLANE; break; case 'r': s->output_config->search_set = MPS_SEARCH_SET_POSITIVE_REAL_PART; break; case 'l': s->output_config->search_set = MPS_SEARCH_SET_NEGATIVE_REAL_PART; break; case 'u': s->output_config->search_set = MPS_SEARCH_SET_POSITIVE_IMAG_PART; break; case 'd': s->output_config->search_set = MPS_SEARCH_SET_NEGATIVE_IMAG_PART; break; case 'i': s->output_config->search_set = MPS_SEARCH_SET_UNITARY_DISC; break; case 'o': s->output_config->search_set = MPS_SEARCH_SET_UNITARY_DISC_COMPL; break; case 'R': s->output_config->search_set = MPS_SEARCH_SET_REAL; break; case 'I': s->output_config->search_set = MPS_SEARCH_SET_IMAG; break; case 'U': s->output_config->search_set = MPS_SEARCH_SET_CUSTOM; break; default: mps_error (s, "Bad search set switch: ", opt->optvalue, ", use a|r|l|u|d|i|o|R|I|U"); } if (strlen (opt->optvalue) != 1) mps_error (s, "Bad set: ", opt->optvalue); break; /* select multiplicity */ case 'M': switch (*opt->optvalue) { case '+': s->output_config->multiplicity = true; break; case '-': s->output_config->multiplicity = false; break; default: mps_error (s, "Bad multiplicity switch: ", opt->optvalue, ", use +|-"); } if (strlen (opt->optvalue) != 3) mps_error (s, "Bad multiplicity option: ", opt->optvalue); break; /* detection */ case 'D': switch (*opt->optvalue) { case 'n': s->output_config->root_properties = MPS_OUTPUT_PROPERTY_NONE; break; case 'r': s->output_config->root_properties = MPS_OUTPUT_PROPERTY_REAL; break; case 'i': s->output_config->root_properties = MPS_OUTPUT_PROPERTY_IMAGINARY; break; case 'b': s->output_config->root_properties = MPS_OUTPUT_PROPERTY_REAL | MPS_OUTPUT_PROPERTY_IMAGINARY; break; default: mps_error (s, "Bad detection switch: ", opt->optvalue, ", use n|r|i|b"); } if (strlen (opt->optvalue) != 1) mps_error (s, "Bad detection option: ", opt->optvalue); break; /* I/O streams */ case 'R': s->rtstr = fopen (opt->optvalue, "r"); if (s->rtstr == NULL) mps_error (s, "Cannot open roots file: ", opt->optvalue); s->resume = true; break; /* Additional checks */ case 'C': switch (*opt->optvalue) { case 'R': s->chkrad = true; break; case 'r': s->chkrad = false; break; default: mps_error (s, "Bad check switch: ", opt->optvalue, ", use R|r"); } if (strlen (opt->optvalue) != 1) mps_error (s, "Bad check option: ", opt->optvalue); break; case 'a': explicit_algorithm_selection = true; switch (*opt->optvalue) { case 'u': mps_context_select_algorithm (s, MPS_ALGORITHM_STANDARD_MPSOLVE); break; case 's': mps_context_select_algorithm (s, MPS_ALGORITHM_SECULAR_GA); break; default: mps_error (s, "The selected algorithm is not supported"); break; } break; case 'b': mps_context_set_jacobi_iterations (s, true); break; case 'c': mps_context_set_crude_approximation_mode (s, true); break; case 'o': mps_context_set_output_prec (s, (atoi (opt->optvalue)) * LOG2_10 + 1); break; case 'i': input_precision = atoi (opt->optvalue) * LOG2_10; break; case 'G': switch (*opt->optvalue) { case 'a': mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_APPROXIMATE); break; case 'i': mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_ISOLATE); break; case 'c': mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_COUNT); break; default: mps_error (s, "The selected goal does not exists"); break; } break; case 'p': inline_poly = strdup (opt->optvalue); break; #ifndef DISABLE_DEBUG case 'd': mps_context_add_debug_domain (s, MPS_DEBUG_INFO); if (!opt->optvalue) break; /* If debugging was enabled, parse debug_level */ while (*opt->optvalue) { char output[255]; switch (*opt->optvalue++) { case 't': mps_context_add_debug_domain (s, MPS_DEBUG_TRACE); break; case 'a': mps_context_add_debug_domain (s, MPS_DEBUG_APPROXIMATIONS); break; case 'c': mps_context_add_debug_domain (s, MPS_DEBUG_CLUSTER); break; case 'i': mps_context_add_debug_domain (s, MPS_DEBUG_IMPROVEMENT); break; case 'w': mps_context_add_debug_domain (s, MPS_DEBUG_TIMINGS); break; case 'o': mps_context_add_debug_domain (s, MPS_DEBUG_IO); break; case 'm': mps_context_add_debug_domain (s, MPS_DEBUG_MEMORY); break; case 'f': mps_context_add_debug_domain (s, MPS_DEBUG_FUNCTION_CALLS); break; case 'p': mps_context_add_debug_domain (s, MPS_DEBUG_PACKETS); break; case 'r': mps_context_add_debug_domain (s, MPS_DEBUG_REGENERATION); break; default: sprintf (output, "Unrecognized debug option: %c", *(opt->optvalue - 1)); mps_error (s, output); break; } } break; #endif #if HAVE_GRAPHICAL_DEBUGGER case 'x': graphic_debug = true; break; #endif case 's': if (opt->optvalue == NULL) { mps_error (s, "You need to specify a valid file with -s"); break; } else { s->rtstr = fopen (opt->optvalue, "r"); if (! s->rtstr) { mps_error (s, "Cannot open the given file: %s", opt->optvalue); break; } else { mps_context_select_starting_strategy (s, MPS_STARTING_STRATEGY_FILE); } } break; case 't': switch (opt->optvalue[0]) { case 'f': phase = float_phase; break; case 'd': phase = dpe_phase; break; default: usage (s, argv[0]); } break; case 'j': mps_thread_pool_set_concurrency_limit (s, NULL, atoi (opt->optvalue)); s->n_threads = atoi (opt->optvalue); break; default: usage (s, argv[0]); break; } } #if HAVE_GRAPHICAL_DEBUGGER if (graphic_debug) { /* Init GTK only if graphic debug is requested. In all other case is unnecessary * and will waste computational time that is likely to bias benchmarks. */ gtk_init (&argc, &argv); logger = mps_iteration_logger_new (); mps_iteration_logger_set_mps_context (logger, s); g_signal_connect (GTK_WIDGET (logger), "delete_event", G_CALLBACK (on_iteration_logger_destroy), NULL); gtk_widget_show_all (GTK_WIDGET (logger)); } #endif if (mps_context_has_errors (s)) { mps_print_errors (s); return EXIT_FAILURE; } if (argc > 2) usage (s, argv[0]); /* If no file is provided use standard input */ if (inline_poly) { // poly = mps_parse_inline_poly_from_string (s, inline_poly); mps_abstract_input_stream * stream = (mps_abstract_input_stream *) mps_memory_file_stream_new (inline_poly); poly = mps_monomial_yacc_parser (s, stream); if (mps_context_has_errors (s)) { mps_print_errors (s); return EXIT_FAILURE; } free (inline_poly); } else { if (argc == 1) infile = stdin; else infile = fopen (argv[1], "r"); if (!infile) { mps_error (s, "Cannot open input file for read, aborting."); mps_print_errors (s); return EXIT_FAILURE; } /* Parse the input stream and if a polynomial is given as output, * allocate also a secular equation to be used in regeneration */ poly = mps_parse_stream (s, infile); } if (!poly) { mps_error (s, "Error while parsing the polynomial, aborting."); mps_print_errors (s); return EXIT_FAILURE; } else mps_context_set_input_poly (s, poly); /* Override input precision if needed */ if (input_precision >= 0) mps_polynomial_set_input_prec (s, poly, input_precision); /* Perform some heuristic for the algorithm selection, but only if the user * hasn't explicitely selected one. */ if (! explicit_algorithm_selection) { mps_context_select_algorithm (s, (MPS_IS_MONOMIAL_POLY (poly) && MPS_DENSITY_IS_SPARSE (poly->density)) ? MPS_ALGORITHM_STANDARD_MPSOLVE : MPS_ALGORITHM_SECULAR_GA ); } /* Close the file if it's not stdin */ if (argc == 2 && ! inline_poly) fclose (infile); /* Select the starting phase according to user input */ mps_context_set_starting_phase (s, phase); /* Solve the polynomial */ #if HAVE_GRAPHICAL_DEBUGGER if (graphic_debug) { mps_mpsolve_async (s, cleanup_context, NULL); gtk_main (); } else { #endif mps_mpsolve (s); cleanup_context (s, NULL); #if HAVE_GRAPHICAL_DEBUGGER } #endif }
/** * @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); }