Statistiques
| Révision :

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

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
/******************************************************************************/
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
void
32
pobyso_autoprint(sollya_obj_t solObj, ...)
33
{
34
  va_list va;
35
  va_start(va, solObj);
36
  sollya_lib_v_autoprint(solObj, va);
37
  va_end(va);
38
} /* End pobyso_autoprint. */
39

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

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

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

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

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

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

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

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

145
  /* Argument checking. */
146
  if (arrayLength == 0) return(NULL);
147
  if (intArray == NULL)
148
  {
149
    pobyso_error_message("pobyso_create_chain_from_unsigned_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(unsigned int));
157
    if (currentInt == NULL)
158
    {
159
      pobyso_error_message("pobyso_create_chain_from_unsigned_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_unsigned_int_array. */
170

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

193

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

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

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

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

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

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

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

303
  nextChainElement = theChainOfNodes;
304

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

315
void
316
pobyso_free_range(rangetype range)
317
{
318

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

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

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

353
} /* End pobyso_parse_function */
354

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

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

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

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

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

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

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

507
  mpfr_t satisfying_error;
508
  mpfr_t target_error;
509

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

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

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

576

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

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

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

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

604
#endif
605

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