Statistiques
| Révision :

root / pobysoC-4.0 / src / pobyso.c @ 29

Historique | Voir | Annoter | Télécharger (18,79 ko)

1
/** @file pobyso.c
2
 * Name & purpose
3
 *
4
 * @author S.T.
5
 * @date 2011-10-12
6
 *
7
 *
8
 */
9
/******************************************************************************/
10
/* Headers, applying the "particular to general" convention.*/
11

    
12
#include "pobyso.h"
13

    
14
/* includes of local headers */
15

    
16
/* includes of project headers */
17

    
18
/* includes of system headers */
19

    
20
/* Other declarations */
21

    
22
/* Internal prototypes */
23
void
24
pobyso_error_message(char *functionName, char *messageName, char* message);
25
/* Types, constants and macros definitions */
26

    
27
/* Global variables */
28

    
29
/* Functions */
30
void
31
pobyso_autoprint(sollya_obj_t solObj, ...)
32
{
33
  va_list va;
34
  va_start(va, solObj);
35
  sollya_lib_v_autoprint(solObj, va);
36
  va_end(va);
37
} /* End pobyso_autoprint. */
38

    
39
sollya_obj_t
40
pobyso_parse_string(const char* expression)
41
{
42
  if (expression == NULL)
43
  {
44
    pobyso_error_message("pobyso_parse_string",
45
                        "NULL_POINTER_ARGUMENT",
46
                        "The expression is a NULL pointer");
47
    return(NULL);
48
  }
49
  return(sollya_lib_parse_string(expression));
50
} /* pobyso_parse_string */
51

    
52
void
53
pobyso_set_verbosity_off(sollya_obj_t* currentVerbosityLevel)
54
{
55
  sollya_obj_t verbosityLevelZero;
56
  if (currentVerbosityLevel != NULL)
57
  {
58
     *currentVerbosityLevel = sollya_lib_get_verbosity();
59
  }
60
  verbosityLevelZero = sollya_lib_constant_from_int(0);
61
  sollya_lib_set_verbosity(verbosityLevelZero);
62
  sollya_lib_clear_obj(verbosityLevelZero);
63
} /* End of pobyso_set_verbosity_off. */
64

    
65
void
66
pobyso_set_verbosity_to(sollya_obj_t newVerbosityLevel)
67
{
68
  if (newVerbosityLevel == NULL)
69
  {
70
    pobyso_error_message("pobyso_set_verbosity_to",
71
                        "NULL_POINTER_ARGUMENT",
72
                        "The new verbosity level is a NULL pointer");
73
    return;
74
  }
75
  sollya_lib_set_verbosity(newVerbosityLevel);
76
} /* End of pobyso_set_verbosity_to. */
77

    
78
/* Attic from the sollya_lib < 4. */
79
#if 0
80
chain*
81
pobyso_create_canonical_monomials_base(const unsigned int degree)
82
{
83
  int i    = 0;
84
  chain *monomials  = NULL;
85
  node  *monomial   = NULL;
86

87
  for(i = degree ; i >= 0  ; i--)
88
  {
89
     monomial   = makePow(makeVariable(), makeConstantDouble((double)i));
90
     monomials  = addElement(monomials, monomial);
91
     fprintf(stderr, "pobyso_create_canonical_monomials_base: %u\n", i);
92
  }
93
  if (monomials == NULL)
94
  {
95
    pobyso_error_message("pobyso_create_canonical_monomial_base",
96
                        "CHAIN_CREATION_ERROR",
97
                        "Could not create the monomials chain");
98
    return(NULL);
99
  }
100
  return(monomials);
101
} /* End pobyso_create_canonical_monomials_base. */
102

103
chain*
104
pobyso_create_chain_from_int_array(int* intArray,
105
                                    const unsigned int arrayLength)
106
{
107
  int i = 0;
108
  chain *newChain = NULL;
109
  int *currentInt;
110

111
  if (arrayLength == 0) return(NULL);
112
  if (intArray == NULL)
113
  {
114
    pobyso_error_message("pobyso_create_chain_from_int_array",
115
                        "NULL_POINTER_ARGUMENT",
116
                        "The array is a NULL pointer");
117
    return(NULL);
118
  }
119
  for (i = arrayLength - 1 ; i >= 0 ; i--)
120
  {
121
    currentInt = malloc(sizeof(int));
122
    if (currentInt == NULL)
123
    {
124
      pobyso_error_message("pobyso_create_chain_from_int_array",
125
                          "MEMORY_ALLOCATION_ERROR",
126
                          "Could not allocate one of the integers");
127
      freeChain(newChain, free);
128
      return(NULL);
129
    }
130
    *currentInt = intArray[i];
131
    newChain = addElement(newChain, currentInt);
132
  }
133
  return(newChain);
134
} // End pobyso_create_chain_from_int_array. */
135

136
chain*
137
pobyso_create_chain_from_unsigned_int_array(unsigned int* intArray,
138
                                        const unsigned int arrayLength)
139
{
140
  int i = 0;
141
  chain *newChain = NULL;
142
  unsigned int *currentInt;
143

144
  /* Argument checking. */
145
  if (arrayLength == 0) return(NULL);
146
  if (intArray == NULL)
147
  {
148
    pobyso_error_message("pobyso_create_chain_from_unsigned_int_array",
149
                        "NULL_POINTER_ARGUMENT",
150
                        "The array is a NULL pointer");
151
    return(NULL);
152
  }
153
  for (i = arrayLength - 1 ; i >= 0 ; i--)
154
  {
155
    currentInt = malloc(sizeof(unsigned int));
156
    if (currentInt == NULL)
157
    {
158
      pobyso_error_message("pobyso_create_chain_from_unsigned_int_array",
159
                          "MEMORY_ALLOCATION_ERROR",
160
                          "Could not allocate one of the integers");
161
      freeChain(newChain, free);
162
      return(NULL);
163
    }
164
    *currentInt = intArray[i];
165
    newChain = addElement(newChain, currentInt);
166
  }
167
  return(newChain);
168
} // End pobyso_create_chain_from_unsigned_int_array. */
169

170
node*
171
pobyso_differentiate(node *functionNode)
172
{
173
  /* Argument checking. */
174
  node *differentialNode;
175
  if (functionNode == NULL)
176
  {
177
    pobyso_error_message("pobyso_differentiate",
178
                        "NULL_POINTER_ARGUMENT",
179
                        "The function to differentiate is a NULL pointer");
180
    return(NULL);
181
  }
182
  differentialNode = differentiate(functionNode);
183
  if (differentialNode == NULL)
184
  {
185
    pobyso_error_message("pobyso_differentiate",
186
                        "INTERNAL ERROR",
187
                        "Sollya could not differentiate the function");
188
  }
189
  return(differentialNode);
190
} // End pobyso_differentiate
191

192

193
int
194
pobyso_dirty_infnorm(mpfr_t infNorm,
195
                      node *functionNode,
196
                      mpfr_t lowerBound,
197
                      mpfr_t upperBound,
198
                      mp_prec_t precision)
199
{
200
  int functionCallResult;
201
  /* Arguments checking. */
202
  if (functionNode == NULL)
203
  {
204
    pobyso_error_message("pobyso_dirty_infnorm",
205
                        "NULL_POINTER_ARGUMENT",
206
                        "The function to compute is a NULL pointer");
207
    return(1);
208
  }
209
  if (mpfr_cmp(lowerBound, upperBound) > 0)
210
  {
211
    pobyso_error_message("pobyso_dirty_infnorm",
212
                        "INCOHERENT_INPUT_DATA",
213
                        "The lower bond is greater than the upper bound");
214
    return(1);
215
  }
216
  /* Particular cases. */
217
  if (mpfr_cmp(lowerBound, upperBound) == 0)
218
  {
219
    functionCallResult = pobyso_evaluate_faithful(infNorm,
220
                                                  functionNode,
221
                                                  lowerBound,
222
                                                  precision);
223
    return(functionCallResult);
224
  }
225
  if (isConstant(functionNode))
226
  {
227
    functionCallResult = pobyso_evaluate_faithful(infNorm,
228
                                                  functionNode,
229
                                                  lowerBound,
230
                                                  precision);
231
    if (!functionCallResult)
232
    {
233
      mpfr_abs(infNorm, infNorm, MPFR_RNDN);
234
    }
235
    return(functionCallResult);
236
  }
237
  uncertifiedInfnorm(infNorm,
238
                      functionNode,
239
                      lowerBound,
240
                      upperBound,
241
                      POBYSO_DEFAULT_POINTS,
242
                      precision);
243
  return(0);
244
} /* End pobyso_dirty_infnorm. */
245

246
int
247
pobyso_evaluate_faithful(mpfr_t faithfulEvaluation,
248
                          node *nodeToEvaluate,
249
                          mpfr_t argument,
250
                          mpfr_prec_t precision)
251
{
252
  /* Check input arguments. */
253
  if (nodeToEvaluate == NULL)
254
  {
255
    pobyso_error_message("pobyso_evaluate_faithful",
256
                        "NULL_POINTER_ARGUMENT",
257
                        "nodeToEvaluate is a NULL pointer");
258
    return(1);
259
  }
260
  evaluateFaithful(faithfulEvaluation,
261
                   nodeToEvaluate,
262
                   argument,
263
                   precision);
264
  return(0);
265
} /* End pobyso_evaluate_faithfull. */
266

267
chain*
268
pobyso_find_zeros(node *function,
269
                  mpfr_t *lower_bound,
270
                  mpfr_t *upper_bound)
271
{
272
  mp_prec_t currentPrecision;
273
  mpfr_t currentDiameter;
274
  rangetype bounds;
275

276
  currentPrecision = getToolPrecision();
277
  mpfr_init2(currentDiameter, currentPrecision);
278

279
  bounds.a = lower_bound;
280
  bounds.b = upper_bound;
281

282
  if (bounds.a == NULL || bounds.b == NULL)
283
  {
284
    pobyso_error_message("pobyso_find_zeros",
285
                        "MEMORY_ALLOCATION_ERROR",
286
                        "Could not allocate one of the bounds");
287
    return(NULL);
288
  }
289
  return(findZerosFunction(function,
290
                            bounds,
291
                            currentPrecision,
292
                            currentDiameter));
293
} /* End pobyso_find_zeros. */
294

295
void
296
pobyso_free_chain_of_nodes(chain *theChainOfNodes)
297
{
298
  node *currentNode           = NULL;
299
  chain *currentChainElement  = NULL;
300
  chain *nextChainElement     = NULL;
301

302
  nextChainElement = theChainOfNodes;
303

304
  while(nextChainElement != NULL)
305
  {
306
    currentChainElement = nextChainElement;
307
    currentNode = (node*)(currentChainElement->value);
308
    nextChainElement = nextChainElement->next;
309
    free_memory(currentNode);
310
    free((void*)(currentChainElement));
311
  }
312
} /* End pobyso_free_chain_of_nodes. */
313

314
void
315
pobyso_free_range(rangetype range)
316
{
317

318
  mpfr_clear(*(range.a));
319
  mpfr_clear(*(range.b));
320
  free(range.a);
321
  free(range.b);
322
} /* End pobyso_free_range. */
323

324
node*
325
pobyso_fp_minimax_canonical_monomials_base(node *function,
326
                                      int degree,
327
                                      chain *formats,
328
                                      chain *points,
329
                                      mpfr_t lowerBound,
330
                                      mpfr_t upperBound,
331
                                      int fpFixedArg,
332
                                      int absRel,
333
                                      node *constPart,
334
                                      node *minimax)
335
{
336
  return(NULL);
337
} /* End pobyso_fp_minimax_canonical_monomials_base. */
338

339
node*
340
pobyso_parse_function(char *functionString,
341
                      char *freeVariableNameString)
342
{
343
  if (functionString == NULL || freeVariableNameString == NULL)
344
  {
345
    pobyso_error_message("pobyso_parse_function",
346
                        "NULL_POINTER_ARGUMENT",
347
                        "One of the arguments is a NULL pointer");
348
    return(NULL);
349
  }
350
  return(parseString(functionString));
351

352
} /* End pobyso_parse_function */
353

354
node*
355
pobyso_remez_approx_canonical_monomials_base_for_error(node *functionNode,
356
                                                  unsigned int mode,
357
                                                  mpfr_t lowerBound,
358
                                                  mpfr_t upperBound,
359
                                                  mpfr_t eps)
360
{
361
  node *weight              = NULL;
362
  node *bestApproxPolyNode  = NULL;
363
  node *bestApproxHorner    = NULL;
364
  node *errorNode           = NULL;
365
  rangetype degreeRange;
366
  mpfr_t quality;
367
  mpfr_t currentError;
368
  unsigned int degree;
369

370
  /* Check the parameters. */
371
  if (functionNode == NULL)
372
  {
373
    pobyso_error_message("remezApproxCanonicalMonomialsBaseForError",
374
                        "NULL_POINTER_ARGUMENT",
375
                        "functionNode is a NULL pointer");
376
    return(NULL);
377
  }
378
  if (mpfr_cmp(lowerBound, upperBound) >= 0)
379
  {
380
    pobyso_error_message("remezApproxCanonicalMonomialsBaseForError",
381
                        "INCOHERENT_INPUT_DATA",
382
                        "the lower_bound >= upper_bound");
383
    return(NULL);
384
  }
385
  /* Set the weight. */
386
  if (mode == POBYSO_ABSOLUTE)
387
  {
388
    /* Set the weight to 1 for the ABSOLUTE_MODE. */
389
    weight = makeConstantDouble(1.0);
390
  }
391
  else
392
  {
393
    if (mode == POBYSO_RELATIVE)
394
    {
395
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
396
                          "NOT_IMPLEMENTED",
397
                          "the search for relative error is not implemented yet");
398
      return(NULL);
399
    }
400
    else
401
    {
402
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
403
                          "INCOHERENT_INPUT_DATA",
404
                          "the mode is node of POBYSO_ABOLUTE or POBYSO_RELATIVE");
405
      return(NULL);
406
    }
407
  }
408
  //fprintf(stderr, "\n\n\n******* I'm here! ********\n\n\n");
409
  degreeRange = guessDegree(functionNode,
410
                            weight,
411
                            lowerBound,
412
                            upperBound,
413
                            eps,
414
                            POBYSO_GUESS_DEGREE_BOUND);
415
  degree = mpfr_get_ui(*(degreeRange.a), MPFR_RNDN);
416
  //fprintf(stderr, "\n\n\n******* I'm back! ********\n\n\n");
417
  fprintf(stderr, "Guessed degree: ");
418
  mpfr_out_str(stderr, 10, 17, *(degreeRange.a), MPFR_RNDN);
419
  fprintf(stderr, " - as int: %u\n", degree);
420
  /* Reduce the degree by 1 in the foolish hope it could work. */
421
  if (degree > 0) degree--;
422
  /* Both elements of degreeRange where "inited" within guessDegree. */
423
  mpfr_clear(*(degreeRange.a));
424
  mpfr_clear(*(degreeRange.b));
425
  free(degreeRange.a);
426
  free(degreeRange.b);
427
  /* Mimic the default behavior of interactive Sollya. */
428
  mpfr_init(quality);
429
  mpfr_set_d(quality, 1e-5, MPFR_RNDN);
430
  mpfr_init2(currentError, getToolPrecision());
431
  mpfr_set_inf(currentError,1);
432

433
  /* Try to refine the initial guess: loop with increasing degrees until
434
   * we find a satisfactory one. */
435
  while(mpfr_cmp(currentError, eps) > 0)
436
  {
437
    /* Get rid of the previous polynomial, if any. */
438
    if (bestApproxPolyNode != NULL)
439
    {
440
      free_memory(bestApproxPolyNode);
441
    }
442
    fprintf(stderr, "Degree: %u\n", degree);
443
    fprintf(stderr, "Calling pobyso_remez_canonical_monomials_base...\n");
444
    /* Try to find a polynomial with the guessed degree. */
445
    bestApproxPolyNode = pobyso_remez_canonical_monomials_base(functionNode,
446
                                                            weight,
447
                                                            degree,
448
                                                            lowerBound,
449
                                                            upperBound,
450
                                                            quality);
451

452
    if (bestApproxPolyNode == NULL)
453
    {
454
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
455
                          "INTERNAL_ERROR",
456
                          "could not compute the bestApproxPolyNode");
457
      mpfr_clear(currentError);
458
      mpfr_clear(quality);
459
      return(NULL);
460
    }
461

462
    setDisplayMode(DISPLAY_MODE_DECIMAL);
463
    fprintTree(stderr, bestApproxPolyNode);
464
    fprintf(stderr, "\n\n");
465

466
    errorNode = makeSub(copyTree(functionNode), copyTree(bestApproxPolyNode));
467
    /* Check the error with the computed polynomial. */
468
    uncertifiedInfnorm(currentError,
469
                        errorNode,
470
                        lowerBound,
471
                        upperBound,
472
                        POBYSO_INF_NORM_NUM_POINTS,
473
                        getToolPrecision());
474
    fprintf(stderr, "Inf norm: ");
475
    mpfr_out_str(stderr, 10, 17, currentError, MPFR_RNDN);
476
    fprintf(stderr, "\n\n");
477
    /* Free the errorNode but not the bestApproxPolyNode (we need it if
478
     * we exit the loop at the next iteration). */
479
    free_memory(errorNode);
480
    degree++;
481
  }
482
  /* Use an intermediate variable, since horner() creates a new node
483
   * and does not reorder the argument "in place". This allows for the memory
484
   * reclaim of bestApproxHorner.
485
   */
486
  bestApproxHorner = horner(bestApproxPolyNode);
487
  free_memory(bestApproxPolyNode);
488
  mpfr_clear(currentError);
489
  mpfr_clear(quality);
490
  free_memory(weight);
491
  return(bestApproxHorner);
492
} /* End pobyso_remez_approx_canonical_monomials_base_for_error */
493

494
node*
495
pobyso_remez_canonical_monomials_base(node *function,
496
                                     node *weight,
497
                                     unsigned int degree,
498
                                     mpfr_t lowerBound,
499
                                     mpfr_t upperBound,
500
                                     mpfr_t quality)
501
{
502
  node  *bestApproxPoly = NULL;
503
  chain *monomials      = NULL;
504
  chain *curMonomial    = NULL;
505

506
  mpfr_t satisfying_error;
507
  mpfr_t target_error;
508

509
  /* Argument checking */
510
  /* Function tree. */
511
  if (function == NULL)
512
  {
513
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
514
                        "NULL_POINTER_ARGUMENT",
515
                        "the \"function\" argument is a NULL pointer");
516
    return(NULL);
517
  }
518
  if (weight == NULL)
519
  {
520
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
521
                        "NULL_POINTER_ARGUMENT",
522
                        "the \"weight\" argument is a NULL pointer");
523
    return(NULL);
524
  }
525
  /* Check the bounds. */
526
  if (mpfr_cmp(lowerBound, upperBound) >= 0)
527
  {
528
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
529
                        "INCOHERENT_IMPUT_DATA",
530
                        "the lower_bound >= upper_bound");
531
    return(NULL);
532
  }
533
  /* The quality must be a non null positive number. */
534
  if (mpfr_sgn(quality) <= 0)
535
  {
536
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
537
                        "INCOHERENT_INPUT_DATA",
538
                        "the quality <= 0");
539
  }
540
  /* End argument checking. */
541
  /* Create the monomials nodes chains. */
542
  monomials = pobyso_create_canonical_monomials_base(degree);
543
  fprintf(stderr, "monomials chain length = %d\n", lengthChain(monomials));
544
  if (monomials == NULL || (lengthChain(monomials) != degree + 1))
545
  {
546
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
547
                        "CHAIN_CREATION_ERROR",
548
                        "could not create the monomials chain");
549
    return(NULL);
550
  }
551
  curMonomial = monomials;
552

553
  while (curMonomial != NULL)
554
  {
555
    fprintf(stderr, "monomial tree: ");
556
    //mpfr_out_str(stderr, 10, 17, *((mpfr_t*)((node*)(curMonomial->value))->value), MPFR_RNDN);
557
    fprintTree(stderr, (node*)(curMonomial->value));
558
    fprintf(stderr, "\n");
559
    curMonomial = curMonomial->next;
560
  }
561

562
  /* Deal with NULL weight. */
563
  if (weight == NULL)
564
  {
565
    weight = makeConstantDouble(1.0);
566
  }
567
  /* Compute the best polynomial with the required quality.
568
     The behavior is as if satisfying error and target_error had
569
     not been used.*/
570
  mpfr_init(satisfying_error);
571
  mpfr_init(target_error);
572
  mpfr_set_str(satisfying_error, "0", 10, MPFR_RNDN);
573
  mpfr_set_inf(target_error, 1);
574

575

576
  fprintf(stderr, "satisfying_error: ");
577
  mpfr_out_str(stderr, 10, 17, satisfying_error, MPFR_RNDN);
578
  fprintf(stderr, ".\n");
579
  fprintf(stderr, "target_error: ");
580
  mpfr_out_str(stderr, 10, 17, target_error,MPFR_RNDN);
581
  fprintf(stderr, ".\n");
582

583
  fprintf(stderr,
584
          "current precision: %li\n", getToolPrecision());
585
  /* Call the Sollya function. */
586
  bestApproxPoly = remez(function,
587
                          weight,
588
                          monomials,
589
                          lowerBound,
590
                          upperBound,
591
                          quality,
592
                          satisfying_error,
593
                          target_error,
594
                          getToolPrecision());
595

596
  mpfr_clear(satisfying_error);
597
  mpfr_clear(target_error);
598
  pobyso_free_chain_of_nodes(monomials);
599

600
  return(bestApproxPoly);
601
} /* End pobyso_remez_canonical_monomials_base. */
602

603
#endif
604

    
605
void
606
pobyso_error_message(char *functionName, char *messageName, char* message)
607
{
608
  fprintf(stderr, "?%s: %s.\n%s.\n", functionName, messageName, message);
609
} /* End pobyso_error_message */