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