1 /*
2  * This file is part of MPSolve 3.2.1
3  *
4  * Copyright (C) 2001-2020, Dipartimento di Matematica "L. Tonelli", Pisa.
5  * License: http://www.gnu.org/licenses/gpl.html GPL version 3 or higher
6  *
7  * Authors:
8  *   Dario Andrea Bini <bini@dm.unipi.it>
9  *   Giuseppe Fiorentino <fiorent@dm.unipi.it>
10  *   Leonardo Robol <leonardo.robol@unipi.it>
11  */
12 
13 #define _GNU_SOURCE
14 
15 #include <mps/mps.h>
16 #include <string.h>
17 
18 static mps_context ** context_factory = NULL;
19 static int context_factory_size = 0;
20 static pthread_mutex_t context_factory_mutex = PTHREAD_MUTEX_INITIALIZER;
21 
22 #define MPS_CONTEXT_FACTORY_MAXIMUM_SIZE 0
23 
24 long int
mps_context_get_minimum_precision(mps_context * s)25 mps_context_get_minimum_precision (mps_context * s)
26 {
27   return s->minimum_gmp_precision;
28 }
29 
30 long int
mps_context_get_data_prec_max(mps_context * s)31 mps_context_get_data_prec_max (mps_context * s)
32 {
33   long int ret;
34 
35   MPS_LOCK (s->data_prec_max);
36   ret = s->data_prec_max.value;
37   MPS_UNLOCK (s->data_prec_max);
38   return ret;
39 }
40 
41 int
mps_context_get_degree(mps_context * s)42 mps_context_get_degree (mps_context * s)
43 {
44   return s->n;
45 }
46 
47 /**
48  * @brief Select algorithm to use for computation.
49  *
50  * Valid values for this field are
51  * - MPS_ALGORITHM_STANDARD_MPSOLVE for the standard MPSolve algorithm;
52  * - MPS_ALGORITHM_SECULAR_GA for the algorithm based on coefficient regeneration
53  *   applied to secular equations;
54  */
55 void
mps_context_select_algorithm(mps_context * s,mps_algorithm algorithm)56 mps_context_select_algorithm (mps_context * s, mps_algorithm algorithm)
57 {
58   /* First set algorithm in the mps_context */
59   s->algorithm = algorithm;
60 
61   switch (algorithm)
62     {
63     case MPS_ALGORITHM_STANDARD_MPSOLVE:
64       s->mpsolve_ptr = MPS_MPSOLVE_PTR (mps_standard_mpsolve);
65       break;
66 
67     case MPS_ALGORITHM_SECULAR_GA:
68       s->mpsolve_ptr = MPS_MPSOLVE_PTR (mps_secular_ga_mpsolve);
69       break;
70     }
71 }
72 
73 /**
74  * @brief Select the starting strategy used to dispose the initial approximations.
75  */
76 void
mps_context_select_starting_strategy(mps_context * s,mps_starting_strategy strategy)77 mps_context_select_starting_strategy (mps_context * s, mps_starting_strategy strategy)
78 {
79   s->starting_strategy = strategy;
80 }
81 
82 static void
mps_context_init(mps_context * s)83 mps_context_init (mps_context * s)
84 {
85   mpf_t test;
86 
87   /* Set default streams */
88   s->instr = stdin;
89   s->outstr = stdout;
90   s->logstr = stdout;
91 
92   /* Allocate space for the configurations */
93   s->input_config = (mps_input_configuration*)mps_malloc (sizeof(mps_input_configuration));
94   s->output_config = (mps_output_configuration*)mps_malloc (sizeof(mps_output_configuration));
95 
96   mps_set_default_values (s);
97 
98   /* Find minimum GMP supported precision */
99   mpf_init2 (test, 1);
100   s->minimum_gmp_precision = mpf_get_prec (test);
101   mpf_clear (test);
102 
103   /* Set standard precision */
104   s->output_config->prec = (int)(0.9 * DBL_DIG * LOG2_10);
105   MPS_DEBUG (s, "Setting prec_out to %ld digits", s->output_config->prec);
106 
107   mps_mp_set_prec (s, DBL_DIG * LOG2_10 + 1);
108 
109   s->initialized = false;
110   s->exit_required = false;
111 }
112 
113 /**
114  * @brief Allocate a new mps_context struct with default
115  * options.
116  */
117 mps_context *
mps_context_new()118 mps_context_new ()
119 {
120   mps_context * ctx = NULL;
121 
122   /* Try to get a low cost context from the factory */
123   pthread_mutex_lock (&context_factory_mutex);
124   if (context_factory_size > 0)
125     {
126       /* Pop out a context */
127       ctx = context_factory[--context_factory_size];
128 
129       if (context_factory_size)
130         context_factory = mps_realloc (context_factory,
131                                        sizeof(mps_context*) * context_factory_size);
132       else
133         {
134           free (context_factory);
135           context_factory = NULL;
136         }
137     }
138   pthread_mutex_unlock (&context_factory_mutex);
139 
140   /* Allocate the new mps_context and load default options */
141   if (!ctx)
142     {
143       ctx = (mps_context*)mps_malloc (sizeof(mps_context));
144       mps_context_init (ctx);
145     }
146 
147   return ctx;
148 }
149 
150 
151 /**
152  * @brief Free a not more useful mps_context.
153  *
154  * @param s the mps_context struct pointer to free.
155  */
156 void
mps_context_free(mps_context * s)157 mps_context_free (mps_context * s)
158 {
159   /* Close input and output streams if they're not stdin, stdout and
160    * stderr. For the case in which this context will re-used, set them
161    * to their default values. */
162   if (s->instr != stdin && s->instr != NULL)
163     fclose (s->instr);
164   if (s->logstr != stderr && s->logstr != stdout && s->logstr != NULL)
165     fclose (s->logstr);
166 
167   s->instr = stdin;
168   s->logstr = stderr;
169 
170   /* There's no need to resize bmpc since they will be allocated on demand.
171    * We free them here to correct bad assumptions on the size of this
172    * vector. */
173   free (s->bmpc);
174   s->bmpc = NULL;
175 
176   pthread_mutex_lock (&context_factory_mutex);
177 
178   if (context_factory_size < MPS_CONTEXT_FACTORY_MAXIMUM_SIZE)
179     {
180       context_factory = mps_realloc (context_factory,
181                                      sizeof(mps_context*) * (context_factory_size + 1));
182       context_factory[context_factory_size++] = s;
183       pthread_mutex_unlock (&context_factory_mutex);
184       return;
185     }
186   pthread_mutex_unlock (&context_factory_mutex);
187 
188   if (s->initialized)
189     mps_free_data (s);
190 
191   mps_thread_pool_free (s, s->pool);
192 
193   free (s->input_config);
194   free (s->output_config);
195 
196   s->active_poly = NULL;
197 
198   if (s->secular_equation)
199     mps_secular_equation_free (s, MPS_POLYNOMIAL (s->secular_equation));
200 
201   free (s);
202 }
203 
204 void
mps_context_abort(mps_context * s)205 mps_context_abort (mps_context * s)
206 {
207   s->exit_required = true;
208 }
209 
210 static void
mps_context_shrink(mps_context * s,int n)211 mps_context_shrink (mps_context * s, int n)
212 {
213   int i;
214 
215   for (i = n; i < s->n - s->zero_roots; i++)
216     {
217       mps_approximation_free (s, s->root[i]);
218     }
219 
220   s->root = mps_realloc (s->root, sizeof(mps_approximation*) * n);
221 
222   s->order = mps_realloc (s->order, sizeof(int) * n);
223 
224   s->fppc1 = mps_realloc (s->fppc1, sizeof(cplx_t) * (n + 1));
225 
226   for (i = n + 1; i <= s->n - s->zero_roots; i++)
227     mpc_clear (s->mfpc1[i]);
228 
229   s->mfpc1 = mps_realloc (s->mfpc1, sizeof(mpc_t) * (n + 1));
230 
231   for (i = n + 1; i <= s->n- s->zero_roots; i++)
232     mpc_clear (s->mfppc1[i]);
233 
234   s->mfppc1 = mps_realloc (s->mfppc1, sizeof(mpc_t) * (n + 1));
235 
236   /* temporary vectors */
237   s->spar1 = mps_realloc (s->spar1, sizeof(mps_boolean) * (n + 2));
238   s->again_old = mps_realloc (s->again_old, sizeof(mps_boolean) * (n));
239 
240   s->fap1 = mps_realloc (s->fap1, sizeof(double) * (n + 1));
241   s->fap2 = mps_realloc (s->fap2, sizeof(double) * (n + 1));
242 
243   s->dap1 = mps_realloc (s->dap1, sizeof(rdpe_t) * (n + 1));
244   s->dpc1 = mps_realloc (s->dpc1, sizeof(cdpe_t) * (n + 1));
245   s->dpc2 = mps_realloc (s->dpc2, sizeof(cdpe_t) * (n + 1));
246 
247   /* Setting some default here, that were not settable because we didn't know
248    * the degree of the polynomial */
249   for (i = 0; i < n; i++)
250     s->root[i]->wp = DBL_DIG * LOG2_10;
251 }
252 
253 static void
mps_context_expand(mps_context * s,int n)254 mps_context_expand (mps_context * s, int n)
255 {
256   int i;
257   long int previous_prec = mpc_get_prec (s->mfpc1[0]);
258 
259   s->root = mps_realloc (s->root, sizeof(mps_approximation*) * n);
260   for (i = s->n - s->zero_roots; i < n; i++)
261     {
262       s->root[i] = mps_approximation_new (s);
263     }
264 
265   s->order = mps_realloc (s->order, sizeof(int) * n);
266 
267   s->fppc1 = mps_realloc (s->fppc1, sizeof(cplx_t) * (n + 1));
268   s->mfpc1 = mps_realloc (s->mfpc1, sizeof(mpc_t) * (n + 1));
269 
270   for (i = s->n + 1 - s->zero_roots; i < n + 1; i++)
271     mpc_init2 (s->mfpc1[i], previous_prec);
272 
273   s->mfppc1 = mps_realloc (s->mfppc1, sizeof(mpc_t) * (n + 1));
274   for (i = s->n + 1- s->zero_roots; i <= n; i++)
275     mpc_init2 (s->mfppc1[i], previous_prec);
276 
277   /* temporary vectors */
278   s->spar1 = mps_realloc (s->spar1, sizeof(mps_boolean) * (n + 2));
279   s->again_old = mps_realloc (s->again_old, sizeof(mps_boolean) * (n));
280 
281   s->fap1 = mps_realloc (s->fap1, sizeof(double) * (n + 1));
282   s->fap2 = mps_realloc (s->fap2, sizeof(double) * (n + 1));
283 
284   s->dap1 = mps_realloc (s->dap1, sizeof(rdpe_t) * (n + 1));
285   s->dpc1 = mps_realloc (s->dpc1, sizeof(cdpe_t) * (n + 1));
286   s->dpc2 = mps_realloc (s->dpc2, sizeof(cdpe_t) * (n + 1));
287 
288   /* Setting some default here, that were not settable because we didn't know
289    * the degree of the polynomial */
290   for (i = 0; i < n; i++)
291     s->root[i]->wp = DBL_DIG * LOG2_10;
292 }
293 
294 void
mps_context_resize(mps_context * s,int n)295 mps_context_resize (mps_context * s, int n)
296 {
297   /* We're excluding the case n == s->n that, clearly, doesn't
298    * need any operation at all. */
299   if (n > s->n)
300     mps_context_expand (s, n);
301   if (n < s->n)
302     mps_context_shrink (s, n);
303 }
304 
305 void
mps_context_set_degree(mps_context * s,int n)306 mps_context_set_degree (mps_context * s, int n)
307 {
308   if (s->initialized)
309     {
310       if (s->secular_equation != NULL)
311 	{
312 	  mps_secular_equation_free (s, MPS_POLYNOMIAL (s->secular_equation));
313 	  s->secular_equation = NULL;
314 	}
315 
316       mps_context_resize (s, n);
317     }
318 
319   s->deg = s->n = n;
320 
321   /* Check if the numer of thread is greater of the number of roots,
322      and in that case decrease it */
323   if (s->n_threads > s->deg)
324     {
325       MPS_DEBUG_WITH_INFO (s, "Adjusting concurrency limit to %d", s->deg);
326       mps_thread_pool_set_concurrency_limit (s, s->pool, s->deg);
327     }
328 
329   /* If a secular equation is present in the old context we should free it
330    * now so it will be reallocated on the first call to the algorithm. */
331   if (s->secular_equation && MPS_POLYNOMIAL (s->secular_equation)->degree < n)
332     mps_secular_equation_free (s, MPS_POLYNOMIAL (s->secular_equation));
333   s->secular_equation = NULL;
334 
335 }
336 
337 /**
338  * @brief Set the monomial poly p as the input polynomial for
339  * the current equation.
340  *
341  * @param s The mps_context to set the monomial_poly into.
342  * @param p The mps_monomial_poly to solve.
343  */
344 void
mps_context_set_input_poly(mps_context * s,mps_polynomial * p)345 mps_context_set_input_poly (mps_context * s, mps_polynomial * p)
346 {
347   MPS_DEBUG_THIS_CALL (s);
348 
349   MPS_DEBUG (s, "Setting input poly");
350 
351   if (p->degree < 0)
352     {
353       mps_error (s, "Polynomial degree should be positive");
354       return;
355     }
356 
357   int i;
358   s->active_poly = p;
359 
360   if (!p->thread_safe)
361     mps_thread_pool_set_concurrency_limit (s, s->pool, 1);
362 
363   /* Set the density or sparsity of the polynomial, if it's not
364    * a user polynomial */
365   if (MPS_IS_MONOMIAL_POLY (p))
366     {
367       int original_degree = p->degree;
368       mps_monomial_poly *mp = MPS_MONOMIAL_POLY (p);
369 
370       /* Deflate the polynomial if necessary */
371       mps_monomial_poly_deflate (s, p);
372       s->zero_roots = original_degree - p->degree;
373 
374       MPS_DEBUG_WITH_INFO (s, "Degree = %d", p->degree);
375 
376       /* Check if the input polynomial is sparse or not. We can simply check if
377        * the again vector is all of true values */
378       p->density = MPS_DENSITY_DENSE;
379       for (i = 0; i <= MPS_POLYNOMIAL (mp)->degree; ++i)
380         {
381           if (!mp->spar[i])
382             {
383               p->density = MPS_DENSITY_SPARSE;
384               break;
385             }
386         }
387     }
388 
389   mps_context_set_degree (s, p->degree);
390 }
391 
392 /**
393  * @brief Set active polynomial as a real floating point coefficient
394  * polynomial of degree <code>n</code> with coefficient exactly
395  * determined by components of vector coeff.
396  *
397  * Precisely, if \f${\mathrm coeff}\f$ is a vector of \f$n+1\f$ components,
398  * \f[
399  *   p(x) = \sum_{i = 0}^{n} {\mathrm coeff}_i  x^i
400  * \f]
401  */
402 int
mps_context_set_poly_d(mps_context * s,cplx_t * coeff,long unsigned int n)403 mps_context_set_poly_d (mps_context * s, cplx_t * coeff, long unsigned int n)
404 {
405   int i;
406 
407   /* Allocate space for a polynomial of degree n */
408   mps_monomial_poly * p = mps_monomial_poly_new (s, n);
409 
410   /* Fill polynomial coefficients */
411   for (i = 0; i <= n; i++)
412     {
413       mps_monomial_poly_set_coefficient_d (s, p, i, cplx_Re (coeff[i]),
414                                            cplx_Im (coeff[i]));
415     }
416 
417   mps_context_set_input_poly (s, MPS_POLYNOMIAL (p));
418 
419   return 0;
420 }
421 
422 /**
423  * @brief Set active polynomial as a integer coefficient
424  * polynomial of degree <code>n</code> with coefficient exactly
425  * determined by components of vector coeff.
426  *
427  * Precisely, if \f${\mathrm coeff}\f$ is a vector of \f$n+1\f$ components,
428  * \f[
429  *   p(x) = \sum_{i = 0}^{n} {\mathrm coeff}_i  x^i
430  * \f]
431  */
432 int
mps_context_set_poly_i(mps_context * s,int * coeff,long unsigned int n)433 mps_context_set_poly_i (mps_context * s, int *coeff, long unsigned int n)
434 {
435   int i;
436 
437   /* Allocate data in mps_context to hold the polynomial of degree n */
438   mps_monomial_poly * p = mps_monomial_poly_new (s, n);
439 
440   /* Fill polynomial */
441   for (i = 0; i <= n; i++)
442     {
443       mpq_set_si (p->initial_mqp_r[i], coeff[i], 1U);
444     }
445 
446   mps_context_set_input_poly (s, MPS_POLYNOMIAL (p));
447 
448   return 0;
449 }
450 
451 /**
452  * @brief Set <code>roots[i]</code> to the i-th root of the polynomial
453  * and (if it is not <code>NULL</code>) <code>radius[i]</code>
454  * to the i-th inclusion radius.
455  *
456  * @param s The current mps_context.
457  * @param roots A pointer to an array of cplx_t variables. if *roots == NULL,
458  * MPSolve will take care of allocating these for you. You are in charge to free
459  * them when you don't need them anymore.
460  *
461  * @param radius A pointer to an array of double where MPSolve should store the
462  * inclusion radii. If *radius == NULL MPSolve will allocate those radii for you.
463  * If radius == NULL no radii will be returned.
464  */
465 int
mps_context_get_roots_d(mps_context * s,cplx_t ** roots,double ** radius)466 mps_context_get_roots_d (mps_context * s, cplx_t ** roots, double **radius)
467 {
468   int i;
469 
470   if (*roots == NULL)
471     *roots = cplx_valloc (s->n);
472 
473   if (radius && !*radius)
474     *radius = double_valloc (s->n);
475 
476   for (i = 0; i < s->n; i++)
477     {
478       if (radius && *radius != NULL)
479         {
480           if (s->lastphase == float_phase || s->lastphase == dpe_phase)
481             {
482               (*radius)[i] = s->root[i]->frad;
483             }
484           else
485             {
486               (*radius)[i] = rdpe_get_d (s->root[i]->drad);
487             }
488         }
489 
490       if (s->lastphase == mp_phase)
491         {
492           mpc_get_cplx ((*roots)[i], s->root[i]->mvalue);
493         }
494       else if (s->lastphase == float_phase)
495         {
496           cplx_set ((*roots)[i], s->root[i]->fvalue);
497         }
498       else if (s->lastphase == dpe_phase)
499         {
500           cdpe_get_x ((*roots)[i], s->root[i]->dvalue);
501         }
502     }
503   return 0;
504 }
505 
506 /**
507  * @brief Get the roots computed as multiprecision complex numbers.
508  *
509  * @param roots A pointer to an array of mpc_t variables. if *roots == NULL,
510  * MPSolve will take care of allocate and init those for you. You are in charge to free
511  * and clear them when you don't need them anymore.
512  *
513  * @param radius A pointer to an array of rdpe_t where MPSolve should store the
514  * inclusion radii. If *radius == NULL MPSolve will allocate those radii for you.
515  * If radius == NULL no radii will be returned.
516  */
517 int
mps_context_get_roots_m(mps_context * s,mpc_t ** roots,rdpe_t ** radius)518 mps_context_get_roots_m (mps_context * s, mpc_t ** roots, rdpe_t ** radius)
519 {
520   int i;
521 
522   if (!*roots)
523     {
524       *roots = mpc_valloc (s->n);
525       mpc_vinit2 (*roots, s->n, 0);
526     }
527 
528   if (radius && !*radius)
529     {
530       *radius = rdpe_valloc (s->n);
531     }
532 
533   {
534     mpc_t * local_roots = *roots;
535     rdpe_t * local_radius = radius ? *radius : NULL;
536 
537     for (i = 0; i < s->n; i++)
538       {
539         mpc_set_prec (local_roots[i], mpc_get_prec (s->root[i]->mvalue));
540         mpc_set (local_roots[i], s->root[i]->mvalue);
541 
542         if (radius)
543           rdpe_set (local_radius[i], s->root[i]->drad);
544       }
545   }
546 
547   return 0;
548 }
549 
550 /**
551  * @brief Retrieve a pointer to the current approximations in the context.
552  *
553  * @param ctx The current mps_context.
554  * @return A vector of n mps_approximation pointer,
555  * where n is the degree of the current polynomial
556  * that can be retrieve with mps_context_get_degree().
557  *
558  * Note that the value returned is a copy of the original approximations, so
559  * it should be freed when not needed anymore.
560  *
561  * Also note that mps_approximation_free() need the context where the approximations
562  * were created to proceed, so you should free those approximaitions _before_
563  * freeing the context.
564  */
565 mps_approximation **
mps_context_get_approximations(mps_context * ctx)566 mps_context_get_approximations (mps_context * ctx)
567 {
568   mps_approximation ** approximations = NULL;
569   int i;
570 
571   if (!ctx->root)
572     {
573       /* This means that an error occurred in the previous computation and the
574        * polynomial has not been solved (or mps_mpsolve has not been called at all). */
575       return NULL;
576     }
577   else
578     approximations = mps_newv (mps_approximation *, ctx->n + ctx->zero_roots);
579 
580   for (i = 0; i < ctx->n; i++)
581     {
582       approximations[i] = mps_approximation_copy (ctx, ctx->root[i]);
583 
584       /* Copy relevant data from the multiprecision values */
585       mpc_get_cdpe (approximations[i]->dvalue, approximations[i]->mvalue);
586       mpc_get_cplx (approximations[i]->fvalue, approximations[i]->mvalue);
587       approximations[i]->frad = rdpe_get_d (approximations[i]->drad);
588     }
589 
590   for (i = ctx->n; i < ctx->n + ctx->zero_roots; i++)
591     {
592       approximations[i] = mps_approximation_new (ctx);
593       approximations[i]->status = MPS_ROOT_STATUS_APPROXIMATED;
594 
595       mpc_set_ui (approximations[i]->mvalue, 0U, 0U);
596       cdpe_set (approximations[i]->dvalue, cdpe_zero);
597       cplx_set (approximations[i]->fvalue, cplx_zero);
598 
599       rdpe_set (approximations[i]->drad, rdpe_zero);
600       approximations[i]->frad = 0.0;
601     }
602 
603   return approximations;
604 }
605 
606 
607 /**
608  * @brief Set the output precision for the roots.
609  *
610  * This has different meaning based on the output goal.
611  * If the goal is <code>MPS_OUTPUT_GOAL_ISOLATE</code>, this
612  * is the maximum precision used to try to isolate the roots,
613  * but roots won't be approximated at this precision if they
614  * are isolated with less precision.
615  *
616  * If the goal is <code>MPS_OUTPUT_GOAL_APPROXIMATE</code>,
617  * this is the minimum precision required for the roots in
618  * output.
619  *
620  * @param s The <code>mps_context</code> of the computation.
621  * @param prec The desired output precision.
622  */
623 void
mps_context_set_output_prec(mps_context * s,long int prec)624 mps_context_set_output_prec (mps_context * s, long int prec)
625 {
626   s->output_config->prec = prec;
627   rdpe_set_2dl (s->eps_out, 1.0, -prec);
628 }
629 
630 /**
631  * @brief Set the bits of precision of the input coefficients.
632  *
633  * This has meaning only for fp coefficients, and the special
634  * value 0 means infinite precision.
635  *
636  * @param s The mps_context of the current computation.
637  * @param prec The precisision to be set.
638  */
639 void
mps_context_set_input_prec(mps_context * s,long int prec)640 mps_context_set_input_prec (mps_context * s, long int prec)
641 {
642   if (!s->active_poly)
643     return;
644   else
645     mps_polynomial_set_input_prec (s, s->active_poly, prec);
646 }
647 
648 /**
649  * @brief Set the desired output format that will be used when
650  * calling mps_output().
651  *
652  * @param s The <code>mps_context</code> of the current computation.
653  * @param format The format chosen for the output.
654  */
655 void
mps_context_set_output_format(mps_context * s,mps_output_format format)656 mps_context_set_output_format (mps_context * s, mps_output_format format)
657 {
658   s->output_config->format = format;
659 
660   /* Special handling of GNUPLOT format */
661   if (format == MPS_OUTPUT_FORMAT_GNUPLOT_FULL)
662     {
663       s->gnuplot_format = "xyerrorbars";
664     }
665 }
666 
667 /**
668  * @brief Set the output goal for the computation.
669  *
670  * @param s The <code>mps_context</code> of the computation.
671  * @param goal The goal that will be reached before stopping.
672  */
673 void
mps_context_set_output_goal(mps_context * s,mps_output_goal goal)674 mps_context_set_output_goal (mps_context * s, mps_output_goal goal)
675 {
676   s->output_config->goal = goal;
677 }
678 
679 /**
680  * @brief Set the value of the jacobi iterations switch in the MPSolve context.
681  *
682  * If jacobi_iterations is true then the Ehrlich-Aberth iterations will be carried
683  * out in a Jacobi fashion, otherwise Gauss-Seidel style will be employed.
684  *
685  * @param s The mps_context where the value will be set
686  * @param jacobi_iterations The desired value for the jacobi_iterations switch.
687  */
688 void
mps_context_set_jacobi_iterations(mps_context * s,mps_boolean jacobi_iterations)689 mps_context_set_jacobi_iterations (mps_context * s, mps_boolean jacobi_iterations)
690 {
691   s->jacobi_iterations = jacobi_iterations;
692 }
693 
694 
695 /**
696  * @brief Set the debug level in MPSolve.
697  *
698  * @param s The <code>mps_context</code> of the current computation.
699  * @param level The debug_level to set.
700  */
701 void
mps_context_set_debug_level(mps_context * s,mps_debug_level level)702 mps_context_set_debug_level (mps_context * s, mps_debug_level level)
703 {
704   s->debug_level = level;
705   if (level)
706     {
707       s->DOLOG = true;
708       if (!s->logstr)
709         s->logstr = stderr;
710     }
711 }
712 
713 /**
714  * @brief Add another debug domain to the ones displayed. This will
715  * enable debug if disabled and show message from the given region.
716  *
717  * @param s The <code>mps_context</code> of the current computation.
718  * @param level The domain to add to the already set debug_level.
719  */
720 void
mps_context_add_debug_domain(mps_context * s,mps_debug_level level)721 mps_context_add_debug_domain (mps_context * s, mps_debug_level level)
722 {
723   mps_context_set_debug_level (s, s->debug_level | level);
724 }
725 
726 /**
727  * @brief Get a pointer to the input config stored in the
728  * given mps_context.
729  *
730  * @param s The <code>mps_context</code> of the current computation.
731  */
732 mps_input_configuration *
mps_context_get_input_config(mps_context * s)733 mps_context_get_input_config (mps_context * s)
734 {
735   return s->input_config;
736 }
737 
738 /**
739  * @brief Get a pointer to the output config stored in the
740  * given mps_context.
741  *
742  * @param s The <code>mps_context</code> of the current computation.
743  */
744 mps_output_configuration *
mps_context_get_output_config(mps_context * s)745 mps_context_get_output_config (mps_context * s)
746 {
747   return s->output_config;
748 }
749 
750 
751 /**
752  * @brief Set logstr as the default output for logging.
753  *
754  * @param s The <code>mps_context</code> of the current computation.
755  * @param logstr The desired stream to be used for logging.
756  */
757 void
mps_context_set_log_stream(mps_context * s,FILE * logstr)758 mps_context_set_log_stream (mps_context * s, FILE * logstr)
759 {
760   s->logstr = logstr;
761 }
762 
763 /**
764  * @brief Set the phase from which the computation should start.
765  *
766  * @param s The <code>mps_context</code> of the current computation.
767  * @param phase The phase which should be chosen at the start of the
768  * computation.
769  */
770 void
mps_context_set_starting_phase(mps_context * s,mps_phase phase)771 mps_context_set_starting_phase (mps_context * s, mps_phase phase)
772 {
773   s->input_config->starting_phase = phase;
774 }
775 
776 /**
777  * @brief Get the number of zero roots in the output. Must be called
778  * after mps_mpsolve() has complete.
779  *
780  * @param s The <code>mps_context</code> of the current computation.
781  */
782 int
mps_context_get_zero_roots(mps_context * s)783 mps_context_get_zero_roots (mps_context * s)
784 {
785   return s->zero_roots;
786 }
787 
788 /**
789  * @brief Return true of the computation has passed the maximum
790  * admitted precision, and so was unable to reach desired output
791  * precision without any further information on the input
792  * coefficients.
793  *
794  * @param s The <code>mps_context</code> of the current computation.
795  */
796 mps_boolean
mps_context_get_over_max(mps_context * s)797 mps_context_get_over_max (mps_context * s)
798 {
799   return s->over_max;
800 }
801 
802 /**
803  * @brief Return true if mpsolve has encountered an error
804  * in the computation.
805  *
806  * @param s The <code>mps_context</code> of the current computation.
807  */
mps_context_has_errors(mps_context * s)808 mps_boolean mps_context_has_errors (mps_context * s)
809 {
810   return s->error_state;
811 }
812 
813 /**
814  * @brief Return a copy of the string describing the error msg, or
815  * NULL if no error has been encountered.
816  *
817  * This char array should be freed by the user.
818  *
819  * @param s The <code>mps_context</code> of the current computation.
820  */
mps_context_error_msg(mps_context * s)821 char * mps_context_error_msg (mps_context * s)
822 {
823   if (s->last_error)
824     return strdup (s->last_error);
825   else
826     return NULL;
827 }
828 
829 /**
830  * @brief Retrieve a pointer to the active polynomial being solved.
831  *
832  * @return A pointer to the requested active polynomial.
833  */
834 mps_polynomial*
mps_context_get_active_poly(mps_context * ctx)835 mps_context_get_active_poly (mps_context * ctx)
836 {
837   return ctx->active_poly;
838 }
839 
840 /**
841  * @brief Retrieve the status of the root in position i.
842  *
843  * This method can be used to obtain more insight on the status of
844  * the approximations previously obtained by a call to mps_context_get_roots_m()
845  * or mps_context_get_roots_d().
846  *
847  * @return A copy to the mps_root_status of the approximation.
848  */
849 mps_root_status
mps_context_get_root_status(mps_context * ctx,int i)850 mps_context_get_root_status (mps_context * ctx, int i)
851 {
852   return ctx->root[i]->status;
853 }
854 
855 /**
856  * @brief Set the internal flag "avoid_multiprecision" to the specified value.
857  *
858  * If avoid_multiprecision is true MPSolve will not enter a multiprecision stage
859  * thus making impossible the computation of more digits than the one that are
860  * representable in standard floating point.
861  *
862  * This may be a useful flag to approximate roots of very ill-conditioned polynomials
863  * of high degree when no strict isolation is required. In this case it's possible to
864  * obtain very good approximations that are not Newton-isolated but are still satisfactory.
865  */
866 void
mps_context_set_avoid_multiprecision(mps_context * s,mps_boolean avoid_multiprecision)867 mps_context_set_avoid_multiprecision (mps_context * s, mps_boolean avoid_multiprecision)
868 {
869   s->avoid_multiprecision = avoid_multiprecision;
870 }
871 
872 /**
873  * @brief Enable the "crude" only approximation mode of MPSolve.
874  *
875  * If this mode is activated MPSolve will only perform a basic Aberth iteration
876  * in floating point and then exit. Note that the output result will still be
877  * guaranteed but in general it will not be possible to reach arbitrary precision
878  * and the results may be quite far from the roots for bad conditioned polynomials.
879  */
880 void
mps_context_set_crude_approximation_mode(mps_context * s,mps_boolean crude_approximation_mode)881 mps_context_set_crude_approximation_mode (mps_context * s, mps_boolean crude_approximation_mode)
882 {
883   s->crude_approximation_mode = crude_approximation_mode;
884 }
885 
886 /**
887  * @brief Select the regeneration driver implementation to use.
888  *
889  * The user of the library can change the default regeneration driver by providing
890  * a custom implementation of mps_regeneration_driver and calling this function.
891  *
892  * The custom implementation is obtained by hooking the function pointers defined
893  * in mps_regeneration_driver to custom routines that update a secular equation
894  * given new nodes.
895  *
896  * As usual, three routines for every data type supported by MPSolve must be provided.
897  *
898  * @param s The context where the change will have effect.
899  * @param rd The custom regeneration driver. Optionally this field may be NULL to restore
900  * the default implementation.
901  */
902 void
mps_context_set_regeneration_driver(mps_context * s,mps_regeneration_driver * rd)903 mps_context_set_regeneration_driver (mps_context * s, mps_regeneration_driver * rd)
904 {
905   s->regeneration_driver = rd;
906 }
907