Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (19,92 ko)

1
/** @file pobyso.c
2
 * Name & purpose
3
 *
4
 * @author S.T.
5
 * @date 2011-10-12
6
 *
7
 *
8
 */
9

    
10
/******************************************************************************/
11
/* Headers, applying the "particular to general" convention.*/
12

    
13
#include "pobyso.h"
14

    
15
/* includes of local headers */
16

    
17
/* includes of project headers */
18

    
19
/* includes of system headers */
20

    
21
/* Other declarations */
22

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

    
28
/* Global variables */
29

    
30
/* Functions */
31

    
32
/* @see pobyso.h#pobyso_autprint */
33
void
34
pobyso_autoprint(sollya_obj_t solObj, ...)
35
{
36
  va_list va;
37
  va_start(va, solObj);
38
  sollya_lib_v_autoprint(solObj, va);
39
  va_end(va);
40
} /* End pobyso_autoprint. */
41

    
42
/* @see pobyso.h#pobyso_parse_string*/
43
sollya_obj_t
44
pobyso_parse_string(const char* expression)
45
{
46
  int expressionLength;
47
  char *expressionWithSemiCo;
48
  sollya_obj_t expressionSa;
49
  /* Arguments check. */
50
  if (expression == NULL)
51
  {
52
    pobyso_error_message("pobyso_parse_string",
53
                        "NULL_POINTER_ARGUMENT",
54
                        "The expression is a NULL pointer");
55
    return(sollya_lib_error());
56
  }
57
  expressionLength = strlen(expression);
58
  if (expressionLength == 0)
59
  {
60
    pobyso_error_message("pobyso_parse_string",
61
                        "EMPTY_STRING_ARGUMENT",
62
                        "The expression is an empty string");
63
  }
64
  /* If the final ";" has been forgotten. */
65
  if (expression[expressionLength-1] != ';')
66
  {
67
    expressionWithSemiCo = calloc(expressionLength + 2, sizeof(char));
68
    if (expressionWithSemiCo == NULL)
69
    {
70
      pobyso_error_message("pobyso_parse_string",
71
                            "MEMORY_ALLOCATION_ERROR",
72
                            "Could not allocate the expression string");
73
      return(sollya_lib_error());
74
    }
75
    expressionWithSemiCo = strcat(expressionWithSemiCo, expression);
76
    expressionWithSemiCo = strcat(expressionWithSemiCo, ";");
77
    expressionSa = sollya_lib_parse_string(expressionWithSemiCo);
78
    free(expressionWithSemiCo);
79
    return(expressionSa);
80
  } /* End ";" forgotten */
81
  else
82
  {
83
    return(sollya_lib_parse_string(expression));
84
  }
85
} /* pobyso_parse_string */
86

    
87
void
88
pobyso_set_verbosity_off(sollya_obj_t* currentVerbosityLevel)
89
{
90
  sollya_obj_t verbosityLevelZero;
91
  if (currentVerbosityLevel != NULL)
92
  {
93
     *currentVerbosityLevel = sollya_lib_get_verbosity();
94
  }
95
  verbosityLevelZero = sollya_lib_constant_from_int(0);
96
  sollya_lib_set_verbosity(verbosityLevelZero);
97
  sollya_lib_clear_obj(verbosityLevelZero);
98
} /* End of pobyso_set_verbosity_off. */
99

    
100
void
101
pobyso_set_verbosity_to(sollya_obj_t newVerbosityLevel)
102
{
103
  if (newVerbosityLevel == NULL)
104
  {
105
    pobyso_error_message("pobyso_set_verbosity_to",
106
                        "NULL_POINTER_ARGUMENT",
107
                        "The new verbosity level is a NULL pointer");
108
    return;
109
  }
110
  sollya_lib_set_verbosity(newVerbosityLevel);
111
} /* End of pobyso_set_verbosity_to. */
112

    
113
/* Attic from the sollya_lib < 4. */
114
#if 0
115
chain*
116
pobyso_create_canonical_monomials_base(const unsigned int degree)
117
{
118
  int i    = 0;
119
  chain *monomials  = NULL;
120
  node  *monomial   = NULL;
121

122
  for(i = degree ; i >= 0  ; i--)
123
  {
124
     monomial   = makePow(makeVariable(), makeConstantDouble((double)i));
125
     monomials  = addElement(monomials, monomial);
126
     fprintf(stderr, "pobyso_create_canonical_monomials_base: %u\n", i);
127
  }
128
  if (monomials == NULL)
129
  {
130
    pobyso_error_message("pobyso_create_canonical_monomial_base",
131
                        "CHAIN_CREATION_ERROR",
132
                        "Could not create the monomials chain");
133
    return(NULL);
134
  }
135
  return(monomials);
136
} /* End pobyso_create_canonical_monomials_base. */
137

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

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

171
chain*
172
pobyso_create_chain_from_unsigned_int_array(unsigned int* intArray,
173
                                        const unsigned int arrayLength)
174
{
175
  int i = 0;
176
  chain *newChain = NULL;
177
  unsigned int *currentInt;
178

179
  /* Argument checking. */
180
  if (arrayLength == 0) return(NULL);
181
  if (intArray == NULL)
182
  {
183
    pobyso_error_message("pobyso_create_chain_from_unsigned_int_array",
184
                        "NULL_POINTER_ARGUMENT",
185
                        "The array is a NULL pointer");
186
    return(NULL);
187
  }
188
  for (i = arrayLength - 1 ; i >= 0 ; i--)
189
  {
190
    currentInt = malloc(sizeof(unsigned int));
191
    if (currentInt == NULL)
192
    {
193
      pobyso_error_message("pobyso_create_chain_from_unsigned_int_array",
194
                          "MEMORY_ALLOCATION_ERROR",
195
                          "Could not allocate one of the integers");
196
      freeChain(newChain, free);
197
      return(NULL);
198
    }
199
    *currentInt = intArray[i];
200
    newChain = addElement(newChain, currentInt);
201
  }
202
  return(newChain);
203
} // End pobyso_create_chain_from_unsigned_int_array. */
204

205
node*
206
pobyso_differentiate(node *functionNode)
207
{
208
  /* Argument checking. */
209
  node *differentialNode;
210
  if (functionNode == NULL)
211
  {
212
    pobyso_error_message("pobyso_differentiate",
213
                        "NULL_POINTER_ARGUMENT",
214
                        "The function to differentiate is a NULL pointer");
215
    return(NULL);
216
  }
217
  differentialNode = differentiate(functionNode);
218
  if (differentialNode == NULL)
219
  {
220
    pobyso_error_message("pobyso_differentiate",
221
                        "INTERNAL ERROR",
222
                        "Sollya could not differentiate the function");
223
  }
224
  return(differentialNode);
225
} // End pobyso_differentiate
226

227

228
int
229
pobyso_dirty_infnorm(mpfr_t infNorm,
230
                      node *functionNode,
231
                      mpfr_t lowerBound,
232
                      mpfr_t upperBound,
233
                      mp_prec_t precision)
234
{
235
  int functionCallResult;
236
  /* Arguments checking. */
237
  if (functionNode == NULL)
238
  {
239
    pobyso_error_message("pobyso_dirty_infnorm",
240
                        "NULL_POINTER_ARGUMENT",
241
                        "The function to compute is a NULL pointer");
242
    return(1);
243
  }
244
  if (mpfr_cmp(lowerBound, upperBound) > 0)
245
  {
246
    pobyso_error_message("pobyso_dirty_infnorm",
247
                        "INCOHERENT_INPUT_DATA",
248
                        "The lower bond is greater than the upper bound");
249
    return(1);
250
  }
251
  /* Particular cases. */
252
  if (mpfr_cmp(lowerBound, upperBound) == 0)
253
  {
254
    functionCallResult = pobyso_evaluate_faithful(infNorm,
255
                                                  functionNode,
256
                                                  lowerBound,
257
                                                  precision);
258
    return(functionCallResult);
259
  }
260
  if (isConstant(functionNode))
261
  {
262
    functionCallResult = pobyso_evaluate_faithful(infNorm,
263
                                                  functionNode,
264
                                                  lowerBound,
265
                                                  precision);
266
    if (!functionCallResult)
267
    {
268
      mpfr_abs(infNorm, infNorm, MPFR_RNDN);
269
    }
270
    return(functionCallResult);
271
  }
272
  uncertifiedInfnorm(infNorm,
273
                      functionNode,
274
                      lowerBound,
275
                      upperBound,
276
                      POBYSO_DEFAULT_POINTS,
277
                      precision);
278
  return(0);
279
} /* End pobyso_dirty_infnorm. */
280

281
int
282
pobyso_evaluate_faithful(mpfr_t faithfulEvaluation,
283
                          node *nodeToEvaluate,
284
                          mpfr_t argument,
285
                          mpfr_prec_t precision)
286
{
287
  /* Check input arguments. */
288
  if (nodeToEvaluate == NULL)
289
  {
290
    pobyso_error_message("pobyso_evaluate_faithful",
291
                        "NULL_POINTER_ARGUMENT",
292
                        "nodeToEvaluate is a NULL pointer");
293
    return(1);
294
  }
295
  evaluateFaithful(faithfulEvaluation,
296
                   nodeToEvaluate,
297
                   argument,
298
                   precision);
299
  return(0);
300
} /* End pobyso_evaluate_faithfull. */
301

302
chain*
303
pobyso_find_zeros(node *function,
304
                  mpfr_t *lower_bound,
305
                  mpfr_t *upper_bound)
306
{
307
  mp_prec_t currentPrecision;
308
  mpfr_t currentDiameter;
309
  rangetype bounds;
310

311
  currentPrecision = getToolPrecision();
312
  mpfr_init2(currentDiameter, currentPrecision);
313

314
  bounds.a = lower_bound;
315
  bounds.b = upper_bound;
316

317
  if (bounds.a == NULL || bounds.b == NULL)
318
  {
319
    pobyso_error_message("pobyso_find_zeros",
320
                        "MEMORY_ALLOCATION_ERROR",
321
                        "Could not allocate one of the bounds");
322
    return(NULL);
323
  }
324
  return(findZerosFunction(function,
325
                            bounds,
326
                            currentPrecision,
327
                            currentDiameter));
328
} /* End pobyso_find_zeros. */
329

330
void
331
pobyso_free_chain_of_nodes(chain *theChainOfNodes)
332
{
333
  node *currentNode           = NULL;
334
  chain *currentChainElement  = NULL;
335
  chain *nextChainElement     = NULL;
336

337
  nextChainElement = theChainOfNodes;
338

339
  while(nextChainElement != NULL)
340
  {
341
    currentChainElement = nextChainElement;
342
    currentNode = (node*)(currentChainElement->value);
343
    nextChainElement = nextChainElement->next;
344
    free_memory(currentNode);
345
    free((void*)(currentChainElement));
346
  }
347
} /* End pobyso_free_chain_of_nodes. */
348

349
void
350
pobyso_free_range(rangetype range)
351
{
352

353
  mpfr_clear(*(range.a));
354
  mpfr_clear(*(range.b));
355
  free(range.a);
356
  free(range.b);
357
} /* End pobyso_free_range. */
358

359
node*
360
pobyso_fp_minimax_canonical_monomials_base(node *function,
361
                                      int degree,
362
                                      chain *formats,
363
                                      chain *points,
364
                                      mpfr_t lowerBound,
365
                                      mpfr_t upperBound,
366
                                      int fpFixedArg,
367
                                      int absRel,
368
                                      node *constPart,
369
                                      node *minimax)
370
{
371
  return(NULL);
372
} /* End pobyso_fp_minimax_canonical_monomials_base. */
373

374
node*
375
pobyso_parse_function(char *functionString,
376
                      char *freeVariableNameString)
377
{
378
  if (functionString == NULL || freeVariableNameString == NULL)
379
  {
380
    pobyso_error_message("pobyso_parse_function",
381
                        "NULL_POINTER_ARGUMENT",
382
                        "One of the arguments is a NULL pointer");
383
    return(NULL);
384
  }
385
  return(parseString(functionString));
386

387
} /* End pobyso_parse_function */
388

389
node*
390
pobyso_remez_approx_canonical_monomials_base_for_error(node *functionNode,
391
                                                  unsigned int mode,
392
                                                  mpfr_t lowerBound,
393
                                                  mpfr_t upperBound,
394
                                                  mpfr_t eps)
395
{
396
  node *weight              = NULL;
397
  node *bestApproxPolyNode  = NULL;
398
  node *bestApproxHorner    = NULL;
399
  node *errorNode           = NULL;
400
  rangetype degreeRange;
401
  mpfr_t quality;
402
  mpfr_t currentError;
403
  unsigned int degree;
404

405
  /* Check the parameters. */
406
  if (functionNode == NULL)
407
  {
408
    pobyso_error_message("remezApproxCanonicalMonomialsBaseForError",
409
                        "NULL_POINTER_ARGUMENT",
410
                        "functionNode is a NULL pointer");
411
    return(NULL);
412
  }
413
  if (mpfr_cmp(lowerBound, upperBound) >= 0)
414
  {
415
    pobyso_error_message("remezApproxCanonicalMonomialsBaseForError",
416
                        "INCOHERENT_INPUT_DATA",
417
                        "the lower_bound >= upper_bound");
418
    return(NULL);
419
  }
420
  /* Set the weight. */
421
  if (mode == POBYSO_ABSOLUTE)
422
  {
423
    /* Set the weight to 1 for the ABSOLUTE_MODE. */
424
    weight = makeConstantDouble(1.0);
425
  }
426
  else
427
  {
428
    if (mode == POBYSO_RELATIVE)
429
    {
430
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
431
                          "NOT_IMPLEMENTED",
432
                          "the search for relative error is not implemented yet");
433
      return(NULL);
434
    }
435
    else
436
    {
437
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
438
                          "INCOHERENT_INPUT_DATA",
439
                          "the mode is node of POBYSO_ABOLUTE or POBYSO_RELATIVE");
440
      return(NULL);
441
    }
442
  }
443
  //fprintf(stderr, "\n\n\n******* I'm here! ********\n\n\n");
444
  degreeRange = guessDegree(functionNode,
445
                            weight,
446
                            lowerBound,
447
                            upperBound,
448
                            eps,
449
                            POBYSO_GUESS_DEGREE_BOUND);
450
  degree = mpfr_get_ui(*(degreeRange.a), MPFR_RNDN);
451
  //fprintf(stderr, "\n\n\n******* I'm back! ********\n\n\n");
452
  fprintf(stderr, "Guessed degree: ");
453
  mpfr_out_str(stderr, 10, 17, *(degreeRange.a), MPFR_RNDN);
454
  fprintf(stderr, " - as int: %u\n", degree);
455
  /* Reduce the degree by 1 in the foolish hope it could work. */
456
  if (degree > 0) degree--;
457
  /* Both elements of degreeRange where "inited" within guessDegree. */
458
  mpfr_clear(*(degreeRange.a));
459
  mpfr_clear(*(degreeRange.b));
460
  free(degreeRange.a);
461
  free(degreeRange.b);
462
  /* Mimic the default behavior of interactive Sollya. */
463
  mpfr_init(quality);
464
  mpfr_set_d(quality, 1e-5, MPFR_RNDN);
465
  mpfr_init2(currentError, getToolPrecision());
466
  mpfr_set_inf(currentError,1);
467

468
  /* Try to refine the initial guess: loop with increasing degrees until
469
   * we find a satisfactory one. */
470
  while(mpfr_cmp(currentError, eps) > 0)
471
  {
472
    /* Get rid of the previous polynomial, if any. */
473
    if (bestApproxPolyNode != NULL)
474
    {
475
      free_memory(bestApproxPolyNode);
476
    }
477
    fprintf(stderr, "Degree: %u\n", degree);
478
    fprintf(stderr, "Calling pobyso_remez_canonical_monomials_base...\n");
479
    /* Try to find a polynomial with the guessed degree. */
480
    bestApproxPolyNode = pobyso_remez_canonical_monomials_base(functionNode,
481
                                                            weight,
482
                                                            degree,
483
                                                            lowerBound,
484
                                                            upperBound,
485
                                                            quality);
486

487
    if (bestApproxPolyNode == NULL)
488
    {
489
      pobyso_error_message("computeRemezApproxCanonicalMonomialsBaseForError",
490
                          "INTERNAL_ERROR",
491
                          "could not compute the bestApproxPolyNode");
492
      mpfr_clear(currentError);
493
      mpfr_clear(quality);
494
      return(NULL);
495
    }
496

497
    setDisplayMode(DISPLAY_MODE_DECIMAL);
498
    fprintTree(stderr, bestApproxPolyNode);
499
    fprintf(stderr, "\n\n");
500

501
    errorNode = makeSub(copyTree(functionNode), copyTree(bestApproxPolyNode));
502
    /* Check the error with the computed polynomial. */
503
    uncertifiedInfnorm(currentError,
504
                        errorNode,
505
                        lowerBound,
506
                        upperBound,
507
                        POBYSO_INF_NORM_NUM_POINTS,
508
                        getToolPrecision());
509
    fprintf(stderr, "Inf norm: ");
510
    mpfr_out_str(stderr, 10, 17, currentError, MPFR_RNDN);
511
    fprintf(stderr, "\n\n");
512
    /* Free the errorNode but not the bestApproxPolyNode (we need it if
513
     * we exit the loop at the next iteration). */
514
    free_memory(errorNode);
515
    degree++;
516
  }
517
  /* Use an intermediate variable, since horner() creates a new node
518
   * and does not reorder the argument "in place". This allows for the memory
519
   * reclaim of bestApproxHorner.
520
   */
521
  bestApproxHorner = horner(bestApproxPolyNode);
522
  free_memory(bestApproxPolyNode);
523
  mpfr_clear(currentError);
524
  mpfr_clear(quality);
525
  free_memory(weight);
526
  return(bestApproxHorner);
527
} /* End pobyso_remez_approx_canonical_monomials_base_for_error */
528

529
node*
530
pobyso_remez_canonical_monomials_base(node *function,
531
                                     node *weight,
532
                                     unsigned int degree,
533
                                     mpfr_t lowerBound,
534
                                     mpfr_t upperBound,
535
                                     mpfr_t quality)
536
{
537
  node  *bestApproxPoly = NULL;
538
  chain *monomials      = NULL;
539
  chain *curMonomial    = NULL;
540

541
  mpfr_t satisfying_error;
542
  mpfr_t target_error;
543

544
  /* Argument checking */
545
  /* Function tree. */
546
  if (function == NULL)
547
  {
548
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
549
                        "NULL_POINTER_ARGUMENT",
550
                        "the \"function\" argument is a NULL pointer");
551
    return(NULL);
552
  }
553
  if (weight == NULL)
554
  {
555
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
556
                        "NULL_POINTER_ARGUMENT",
557
                        "the \"weight\" argument is a NULL pointer");
558
    return(NULL);
559
  }
560
  /* Check the bounds. */
561
  if (mpfr_cmp(lowerBound, upperBound) >= 0)
562
  {
563
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
564
                        "INCOHERENT_IMPUT_DATA",
565
                        "the lower_bound >= upper_bound");
566
    return(NULL);
567
  }
568
  /* The quality must be a non null positive number. */
569
  if (mpfr_sgn(quality) <= 0)
570
  {
571
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
572
                        "INCOHERENT_INPUT_DATA",
573
                        "the quality <= 0");
574
  }
575
  /* End argument checking. */
576
  /* Create the monomials nodes chains. */
577
  monomials = pobyso_create_canonical_monomials_base(degree);
578
  fprintf(stderr, "monomials chain length = %d\n", lengthChain(monomials));
579
  if (monomials == NULL || (lengthChain(monomials) != degree + 1))
580
  {
581
    pobyso_error_message("pobyso_remez_canonical_monomials_base",
582
                        "CHAIN_CREATION_ERROR",
583
                        "could not create the monomials chain");
584
    return(NULL);
585
  }
586
  curMonomial = monomials;
587

588
  while (curMonomial != NULL)
589
  {
590
    fprintf(stderr, "monomial tree: ");
591
    //mpfr_out_str(stderr, 10, 17, *((mpfr_t*)((node*)(curMonomial->value))->value), MPFR_RNDN);
592
    fprintTree(stderr, (node*)(curMonomial->value));
593
    fprintf(stderr, "\n");
594
    curMonomial = curMonomial->next;
595
  }
596

597
  /* Deal with NULL weight. */
598
  if (weight == NULL)
599
  {
600
    weight = makeConstantDouble(1.0);
601
  }
602
  /* Compute the best polynomial with the required quality.
603
     The behavior is as if satisfying error and target_error had
604
     not been used.*/
605
  mpfr_init(satisfying_error);
606
  mpfr_init(target_error);
607
  mpfr_set_str(satisfying_error, "0", 10, MPFR_RNDN);
608
  mpfr_set_inf(target_error, 1);
609

610

611
  fprintf(stderr, "satisfying_error: ");
612
  mpfr_out_str(stderr, 10, 17, satisfying_error, MPFR_RNDN);
613
  fprintf(stderr, ".\n");
614
  fprintf(stderr, "target_error: ");
615
  mpfr_out_str(stderr, 10, 17, target_error,MPFR_RNDN);
616
  fprintf(stderr, ".\n");
617

618
  fprintf(stderr,
619
          "current precision: %li\n", getToolPrecision());
620
  /* Call the Sollya function. */
621
  bestApproxPoly = remez(function,
622
                          weight,
623
                          monomials,
624
                          lowerBound,
625
                          upperBound,
626
                          quality,
627
                          satisfying_error,
628
                          target_error,
629
                          getToolPrecision());
630

631
  mpfr_clear(satisfying_error);
632
  mpfr_clear(target_error);
633
  pobyso_free_chain_of_nodes(monomials);
634

635
  return(bestApproxPoly);
636
} /* End pobyso_remez_canonical_monomials_base. */
637

638
#endif
639

    
640
void
641
pobyso_error_message(char *functionName, char *messageName, char* message)
642
{
643
  fprintf(stderr, "?%s: %s.\n%s.\n", functionName, messageName, message);
644
} /* End pobyso_error_message */